Skip to content

Commit

Permalink
vim-patch:9.0.2018: complete_info() returns wrong index
Browse files Browse the repository at this point in the history
Problem:  complete_info() returns wrong index
Solution: Make order of 'info' in completion_info consistent

Start the iteration from the same point and follow the same direction as
done when assigning the completion numbers. This way we remove the
dependence on the completion direction and make the order of 'info'
consistent.

closes: vim/vim#12230
closes: vim/vim#12971

vim/vim@69fb5af

Co-authored-by: LemonBoy <thatlemon@gmail.com>
  • Loading branch information
zeertzjq and LemonBoy committed Oct 11, 2023
1 parent 3cbb02c commit 64104af
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 22 deletions.
56 changes: 34 additions & 22 deletions src/nvim/insexpand.c
Original file line number Diff line number Diff line change
Expand Up @@ -2693,6 +2693,38 @@ static void ins_compl_update_sequence_numbers(void)
}
}

static int info_add_completion_info(list_T *li)
{
if (compl_first_match == NULL) {
return OK;
}

// 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;
while (match != NULL && !match_at_original_text(match)) {
dict_T *di = tv_dict_alloc();

tv_list_append_dict(li, di);
tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
// Add an empty string for backwards compatibility
tv_dict_add_str(di, S_LEN("user_data"), "");
} else {
tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
}

match = compl_dir_forward() ? match->cp_next : match->cp_prev;
}

return OK;
}

/// Get complete information
static void get_complete_info(list_T *what_list, dict_T *retdict)
{
Expand Down Expand Up @@ -2738,29 +2770,9 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)

if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
list_T *li = tv_list_alloc(get_compl_len());

ret = tv_dict_add_list(retdict, S_LEN("items"), li);
if (ret == OK && compl_first_match != NULL) {
compl_T *match = compl_first_match;
do {
if (!match_at_original_text(match)) {
dict_T *di = tv_dict_alloc();

tv_list_append_dict(li, di);
tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str));
tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
if (match->cp_user_data.v_type == VAR_UNKNOWN) {
// Add an empty string for backwards compatibility
tv_dict_add_str(di, S_LEN("user_data"), "");
} else {
tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data);
}
}
match = match->cp_next;
} while (match != NULL && !is_first_match(match));
if (ret == OK) {
ret = info_add_completion_info(li);
}
}

Expand Down
61 changes: 61 additions & 0 deletions test/old/testdir/test_ins_complete.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2252,5 +2252,66 @@ func Test_tagfunc_wipes_out_buffer()
bwipe!
endfunc

func Test_ins_complete_popup_position()
CheckScreendump

let lines =<< trim END
vim9script
set nowrap
setline(1, ['one', 'two', 'this is line ', 'four'])
prop_type_add('test', {highlight: 'Error'})
prop_add(3, 0, {
text_align: 'above',
text: 'The quick brown fox jumps over the lazy dog',
type: 'test'
})
END
call writefile(lines, 'XinsPopup', 'D')
let buf = RunVimInTerminal('-S XinsPopup', #{rows: 10})

call term_sendkeys(buf, "3GA\<C-N>")
call VerifyScreenDump(buf, 'Test_ins_complete_popup_position_1', {})

call StopVimInTerminal(buf)
endfunc

func GetCompleteInfo()
let g:compl_info = complete_info()
return ''
endfunc

func Test_complete_info_index()
new
call setline(1, ["aaa", "bbb", "ccc", "ddd", "eee", "fff"])
inoremap <buffer><F5> <C-R>=GetCompleteInfo()<CR>
" Ensure 'index' in complete_info() is coherent with the 'items' array.

set completeopt=menu,preview
" 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 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'])

" 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 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'])

" Add 'noselect', check that 'selected' is -1 when nothing is selected.
set completeopt+=noselect
" Search forward.
call feedkeys("Go\<C-X>\<C-N>\<F5>\<Esc>_dd", 'tx')
call assert_equal(-1, g:compl_info['selected'])

" Search backward.
call feedkeys("Go\<C-X>\<C-P>\<F5>\<Esc>_dd", 'tx')
call assert_equal(-1, g:compl_info['selected'])

set completeopt&
bwipe!
endfunc

" vim: shiftwidth=2 sts=2 expandtab

0 comments on commit 64104af

Please sign in to comment.