summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/insexpand.c36
-rw-r--r--src/testdir/test_ins_complete.vim69
-rw-r--r--src/version.c2
3 files changed, 102 insertions, 5 deletions
diff --git a/src/insexpand.c b/src/insexpand.c
index ad4edc184e..43fb8ca505 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -3044,14 +3044,44 @@ ins_compl_update_sequence_numbers(void)
info_add_completion_info(list_T *li)
{
compl_T *match;
+ int forward = compl_dir_forward();
if (compl_first_match == NULL)
return OK;
+ match = compl_first_match;
+ // There are four cases to consider here:
+ // 1) when just going forward through the menu,
+ // compl_first_match should point to the initial entry with
+ // number zero and CP_ORIGINAL_TEXT flag set
+ // 2) when just going backwards,
+ // compl-first_match should point to the last entry before
+ // the entry with the CP_ORIGINAL_TEXT flag set
+ // 3) when first going forwards and then backwards, e.g.
+ // pressing C-N, C-P, compl_first_match points to the
+ // last entry before the entry with the CP_ORIGINAL_TEXT
+ // flag set and next-entry moves opposite through the list
+ // compared to case 2, so pretend the direction is forward again
+ // 4) when first going backwards and then forwards, e.g.
+ // pressing C-P, C-N, compl_first_match points to the
+ // first entry with the CP_ORIGINAL_TEXT
+ // flag set and next-entry moves in opposite direction through the list
+ // compared to case 1, so pretend the direction is backwards again
+ //
+ // But only do this when the 'noselect' option is not active!
+
+ if (!compl_no_select)
+ {
+ if (forward && !match_at_original_text(match))
+ forward = FALSE;
+ else if (!forward && match_at_original_text(match))
+ forward = TRUE;
+ }
+
// Skip the element with the CP_ORIGINAL_TEXT flag at the beginning, in case of
// forward completion, or at the end, in case of backward completion.
- match = compl_dir_forward()
- ? compl_first_match->cp_next : compl_first_match->cp_prev->cp_prev;
+ match = forward ? match->cp_next : (compl_no_select ? match->cp_prev : match->cp_prev->cp_prev);
+
while (match != NULL && !match_at_original_text(match))
{
dict_T *di = dict_alloc();
@@ -3071,7 +3101,7 @@ info_add_completion_info(list_T *li)
else
dict_add_tv(di, "user_data", &match->cp_user_data);
- match = compl_dir_forward() ? match->cp_next : match->cp_prev;
+ match = forward ? match->cp_next : match->cp_prev;
}
return OK;
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index a4ac26e06c..3e6d8da7da 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -2267,17 +2267,72 @@ func Test_complete_info_index()
" Ensure 'index' in complete_info() is coherent with the 'items' array.
set completeopt=menu,preview
- " Search forward.
+ " Search forward
call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>_dd", 'tx')
call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
call feedkeys("Go\<C-X>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
call assert_equal("bbb", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("ccc", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("ddd", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("eee", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ " Search forward: unselected item
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal(6 , len(g:compl_info['items']))
+ call assert_equal(-1 , g:compl_info['selected'])
- " Search backward.
+ " Search backward
call feedkeys("Go\<C-X>\<C-P>\<F5>\<Esc>_dd", 'tx')
call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
call feedkeys("Go\<C-X>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
call assert_equal("eee", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("ddd", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("ccc", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("bbb", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ " search backwards: unselected item
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal(6 , len(g:compl_info['items']))
+ call assert_equal(-1 , g:compl_info['selected'])
+
+ " switch direction: forwards, then backwards
+ call feedkeys("Go\<C-X>\<C-N>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ " switch direction: forwards, then backwards, then forwards again
+ call feedkeys("Go\<C-X>\<C-N>\<C-P>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-P>\<C-P>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+
+ " switch direction: backwards, then forwards
+ call feedkeys("Go\<C-X>\<C-P>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ " switch direction: backwards, then forwards, then backwards again
+ call feedkeys("Go\<C-X>\<C-P>\<C-P>\<C-N>\<C-N>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
" Add 'noselect', check that 'selected' is -1 when nothing is selected.
set completeopt+=noselect
@@ -2289,6 +2344,16 @@ func Test_complete_info_index()
call feedkeys("Go\<C-X>\<C-P>\<F5>\<Esc>_dd", 'tx')
call assert_equal(-1, g:compl_info['selected'])
+ " Check if index out of range
+ " https://github.com/vim/vim/pull/12971
+ call feedkeys("Go\<C-X>\<C-N>\<C-P>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal(0, g:compl_info['selected'])
+ call assert_equal(6 , len(g:compl_info['items']))
+ call assert_equal("fff", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call feedkeys("Go\<C-X>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<C-N>\<F5>\<Esc>_dd", 'tx')
+ call assert_equal("aaa", g:compl_info['items'][g:compl_info['selected']]['word'])
+ call assert_equal(6 , len(g:compl_info['items']))
+
set completeopt&
bwipe!
endfunc
diff --git a/src/version.c b/src/version.c
index ec86352ed6..55465a2147 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2074,
+/**/
2073,
/**/
2072,