diff options
-rw-r--r-- | src/nvim/insexpand.c | 37 | ||||
-rw-r--r-- | test/old/testdir/test_ins_complete.vim | 69 |
2 files changed, 101 insertions, 5 deletions
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 427088e414..09575c64d9 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -2702,10 +2702,41 @@ static int info_add_completion_info(list_T *li) return OK; } + bool forward = compl_dir_forward(); + compl_T *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. - compl_T *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 = tv_dict_alloc(); @@ -2722,7 +2753,7 @@ static int info_add_completion_info(list_T *li) tv_dict_add_tv(di, S_LEN("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/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim index 8162c23634..3aafa8cdca 100644 --- a/test/old/testdir/test_ins_complete.vim +++ b/test/old/testdir/test_ins_complete.vim @@ -2315,17 +2315,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 @@ -2337,6 +2392,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 |