]> granicus.if.org Git - vim/commitdiff
patch 8.2.3293: finding completions may cause an endless loop v8.2.3293
authorAndy Gozas <andy@gozas.me>
Thu, 5 Aug 2021 14:23:27 +0000 (16:23 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 5 Aug 2021 14:23:27 +0000 (16:23 +0200)
Problem:    Finding completions may cause an endless loop.
Solution:   Use a better way to check coming back where the search started.
            (Andy Gozas, closes #8672, closes #8671)

src/insexpand.c
src/testdir/Make_all.mak
src/testdir/test_ins_complete_no_halt.vim [new file with mode: 0644]
src/version.c

index 3b58891fccdea2d0d58a411f8ff0e00fb7f679bc..4f8a6265175f192b4d95464cf9459416f8a21dd5 100644 (file)
@@ -2712,6 +2712,8 @@ ins_compl_get_exp(pos_T *ini)
     char_u     *dict = NULL;
     int                dict_f = 0;
     int                set_match_pos;
+    pos_T      prev_pos = {0, 0, 0};
+    int                looped_around = FALSE;
 
     if (!compl_started)
     {
@@ -2964,6 +2966,7 @@ ins_compl_get_exp(pos_T *ini)
                p_ws = FALSE;
            else if (*e_cpt == '.')
                p_ws = TRUE;
+           looped_around = FALSE;
            for (;;)
            {
                int     cont_s_ipos = FALSE;
@@ -2991,8 +2994,31 @@ ins_compl_get_exp(pos_T *ini)
                    set_match_pos = FALSE;
                }
                else if (first_match_pos.lnum == last_match_pos.lnum
-                                && first_match_pos.col == last_match_pos.col)
+                                && first_match_pos.col == last_match_pos.col)
+               {
                    found_new_match = FAIL;
+               }
+               else if ((compl_direction == FORWARD)
+                       && (prev_pos.lnum > pos->lnum
+                           || (prev_pos.lnum == pos->lnum
+                               && prev_pos.col >= pos->col)))
+               {
+                   if (looped_around)
+                       found_new_match = FAIL;
+                   else
+                       looped_around = TRUE;
+               }
+               else if ((compl_direction != FORWARD)
+                       && (prev_pos.lnum < pos->lnum
+                           || (prev_pos.lnum == pos->lnum
+                               && prev_pos.col <= pos->col)))
+               {
+                   if (looped_around)
+                       found_new_match = FAIL;
+                   else
+                       looped_around = TRUE;
+               }
+               prev_pos = *pos;
                if (found_new_match == FAIL)
                {
                    if (ins_buf == curbuf)
index 6feeecd3a856633f43dd7ce6d68fc575f369220b..3c54087a6dbc84aff149667e5743383d944b79f7 100644 (file)
@@ -162,6 +162,7 @@ NEW_TESTS = \
        test_increment_dbcs \
        test_indent \
        test_ins_complete \
+       test_ins_complete_no_halt \
        test_interrupt \
        test_job_fails \
        test_join \
@@ -405,6 +406,7 @@ NEW_TESTS_RES = \
        test_increment_dbcs.res \
        test_indent.res \
        test_ins_complete.res \
+       test_ins_complete_no_halt.res \
        test_interrupt.res \
        test_job_fails.res \
        test_join.res \
diff --git a/src/testdir/test_ins_complete_no_halt.vim b/src/testdir/test_ins_complete_no_halt.vim
new file mode 100644 (file)
index 0000000..e12925d
--- /dev/null
@@ -0,0 +1,51 @@
+" Test insert mode completion does not get stuck when looping around.
+" In a separate file to avoid the settings to leak to other test cases.
+
+set complete+=kspell
+set completeopt+=menu
+set completeopt+=menuone
+set completeopt+=noselect
+set completeopt+=noinsert
+let g:autocompletion = v:true
+
+func Test_ins_complete_no_halt()
+  function! OpenCompletion()
+    if pumvisible() && (g:autocompletion == v:true)
+      call feedkeys("\<C-e>\<C-n>", "i")
+      return
+    endif
+    if ((v:char >= 'a' && v:char <= 'z') || (v:char >= 'A' && v:char <= 'Z')) && (g:autocompletion == v:true)
+      call feedkeys("\<C-n>", "i")
+      redraw
+    endif
+  endfunction
+
+  autocmd InsertCharPre * noautocmd call OpenCompletion()
+
+  setlocal spell! spelllang=en_us
+
+  call feedkeys("iauto-complete-halt-test test test test test test test test test test test test test test test test test test test\<C-c>", "tx!")
+  call assert_equal(["auto-complete-halt-test test test test test test test test test test test test test test test test test test test"], getline(1, "$"))
+endfunc
+
+func Test_auto_complete_backwards_no_halt()
+  function! OpenCompletion()
+    if pumvisible() && (g:autocompletion == v:true)
+      call feedkeys("\<C-e>\<C-p>", "i")
+      return
+    endif
+    if ((v:char >= 'a' && v:char <= 'z') || (v:char >= 'A' && v:char <= 'Z')) && (g:autocompletion == v:true)
+      call feedkeys("\<C-p>", "i")
+      redraw
+    endif
+  endfunction
+
+  autocmd InsertCharPre * noautocmd call OpenCompletion()
+
+  setlocal spell! spelllang=en_us
+
+  call feedkeys("iauto-complete-halt-test test test test test test test test test test test test test test test test test test test\<C-c>", "tx!")
+  call assert_equal(["auto-complete-halt-test test test test test test test test test test test test test test test test test test test"], getline(1, "$"))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
index 4ad59790cc4629f01d4dcacc7e07edf5917ff4a7..2db7988ce2c6a784502ecec74a8f470300ca702d 100644 (file)
@@ -755,6 +755,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3293,
 /**/
     3292,
 /**/