vim-patch:9.1.1876: pre-inserted text not exposed in complete_info() (#36342)

Problem:  pre-inserted text not exposed in complete_info()
Solution: Add the pre-inserted text to the complete_info() Vim script
          function (Girish Palya)

closes: vim/vim#18571

Feat: expose preinserted text in complete_info()

ef5bf58d8c

Co-authored-by: Girish Palya <girishji@gmail.com>
This commit is contained in:
zeertzjq
2025-10-27 09:34:52 +08:00
committed by GitHub
parent fb6fd17f26
commit 155efabb15
6 changed files with 74 additions and 32 deletions

View File

@@ -1207,10 +1207,8 @@ complete_info([{what}]) *complete_info()*
Returns a |Dictionary| with information about Insert mode Returns a |Dictionary| with information about Insert mode
completion. See |ins-completion|. completion. See |ins-completion|.
The items are: The items are:
mode Current completion mode name string. completed Return a dictionary containing the entries of
See |complete_info_mode| for the values. the currently selected index item.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
items List of all completion candidates. Each item items List of all completion candidates. Each item
is a dictionary containing the entries "word", is a dictionary containing the entries "word",
"abbr", "menu", "kind", "info" and "abbr", "menu", "kind", "info" and
@@ -1221,13 +1219,18 @@ complete_info([{what}]) *complete_info()*
and "items" are in "what", the returned list and "items" are in "what", the returned list
will still be named "items", but each item will still be named "items", but each item
will have an additional "match" field. will have an additional "match" field.
mode Current completion mode name string.
See |complete_info_mode| for the values.
preinserted_text
The actual text that is pre-inserted, see
|preinserted()|.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
selected Selected item index. First index is zero. selected Selected item index. First index is zero.
Index is -1 if no item is selected (showing Index is -1 if no item is selected (showing
typed text only, or the last completion after typed text only, or the last completion after
no item is selected when using the <Up> or no item is selected when using the <Up> or
<Down> keys) <Down> keys)
completed Return a dictionary containing the entries of
the currently selected index item.
preview_winid Info floating preview window id. preview_winid Info floating preview window id.
preview_bufnr Info floating preview buffer id. preview_bufnr Info floating preview buffer id.

View File

@@ -1055,10 +1055,8 @@ function vim.fn.complete_check() end
--- Returns a |Dictionary| with information about Insert mode --- Returns a |Dictionary| with information about Insert mode
--- completion. See |ins-completion|. --- completion. See |ins-completion|.
--- The items are: --- The items are:
--- mode Current completion mode name string. --- completed Return a dictionary containing the entries of
--- See |complete_info_mode| for the values. --- the currently selected index item.
--- pum_visible |TRUE| if popup menu is visible.
--- See |pumvisible()|.
--- items List of all completion candidates. Each item --- items List of all completion candidates. Each item
--- is a dictionary containing the entries "word", --- is a dictionary containing the entries "word",
--- "abbr", "menu", "kind", "info" and --- "abbr", "menu", "kind", "info" and
@@ -1069,13 +1067,18 @@ function vim.fn.complete_check() end
--- and "items" are in "what", the returned list --- and "items" are in "what", the returned list
--- will still be named "items", but each item --- will still be named "items", but each item
--- will have an additional "match" field. --- will have an additional "match" field.
--- mode Current completion mode name string.
--- See |complete_info_mode| for the values.
--- preinserted_text
--- The actual text that is pre-inserted, see
--- |preinserted()|.
--- pum_visible |TRUE| if popup menu is visible.
--- See |pumvisible()|.
--- selected Selected item index. First index is zero. --- selected Selected item index. First index is zero.
--- Index is -1 if no item is selected (showing --- Index is -1 if no item is selected (showing
--- typed text only, or the last completion after --- typed text only, or the last completion after
--- no item is selected when using the <Up> or --- no item is selected when using the <Up> or
--- <Down> keys) --- <Down> keys)
--- completed Return a dictionary containing the entries of
--- the currently selected index item.
--- preview_winid Info floating preview window id. --- preview_winid Info floating preview window id.
--- preview_bufnr Info floating preview buffer id. --- preview_bufnr Info floating preview buffer id.
--- ---

View File

@@ -1420,10 +1420,8 @@ M.funcs = {
Returns a |Dictionary| with information about Insert mode Returns a |Dictionary| with information about Insert mode
completion. See |ins-completion|. completion. See |ins-completion|.
The items are: The items are:
mode Current completion mode name string. completed Return a dictionary containing the entries of
See |complete_info_mode| for the values. the currently selected index item.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
items List of all completion candidates. Each item items List of all completion candidates. Each item
is a dictionary containing the entries "word", is a dictionary containing the entries "word",
"abbr", "menu", "kind", "info" and "abbr", "menu", "kind", "info" and
@@ -1434,13 +1432,18 @@ M.funcs = {
and "items" are in "what", the returned list and "items" are in "what", the returned list
will still be named "items", but each item will still be named "items", but each item
will have an additional "match" field. will have an additional "match" field.
mode Current completion mode name string.
See |complete_info_mode| for the values.
preinserted_text
The actual text that is pre-inserted, see
|preinserted()|.
pum_visible |TRUE| if popup menu is visible.
See |pumvisible()|.
selected Selected item index. First index is zero. selected Selected item index. First index is zero.
Index is -1 if no item is selected (showing Index is -1 if no item is selected (showing
typed text only, or the last completion after typed text only, or the last completion after
no item is selected when using the <Up> or no item is selected when using the <Up> or
<Down> keys) <Down> keys)
completed Return a dictionary containing the entries of
the currently selected index item.
preview_winid Info floating preview window id. preview_winid Info floating preview window id.
preview_bufnr Info floating preview buffer id. preview_bufnr Info floating preview buffer id.

View File

@@ -3643,13 +3643,14 @@ static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match)
/// Get complete information /// Get complete information
static void get_complete_info(list_T *what_list, dict_T *retdict) static void get_complete_info(list_T *what_list, dict_T *retdict)
{ {
#define CI_WHAT_MODE 0x01 #define CI_WHAT_MODE 0x01
#define CI_WHAT_PUM_VISIBLE 0x02 #define CI_WHAT_PUM_VISIBLE 0x02
#define CI_WHAT_ITEMS 0x04 #define CI_WHAT_ITEMS 0x04
#define CI_WHAT_SELECTED 0x08 #define CI_WHAT_SELECTED 0x08
#define CI_WHAT_COMPLETED 0x10 #define CI_WHAT_COMPLETED 0x10
#define CI_WHAT_MATCHES 0x20 #define CI_WHAT_MATCHES 0x20
#define CI_WHAT_ALL 0xff #define CI_WHAT_PREINSERTED_TEXT 0x40
#define CI_WHAT_ALL 0xff
int what_flag; int what_flag;
if (what_list == NULL) { if (what_list == NULL) {
@@ -3671,6 +3672,8 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
what_flag |= CI_WHAT_SELECTED; what_flag |= CI_WHAT_SELECTED;
} else if (strcmp(what, "completed") == 0) { } else if (strcmp(what, "completed") == 0) {
what_flag |= CI_WHAT_COMPLETED; what_flag |= CI_WHAT_COMPLETED;
} else if (strcmp(what, "preinserted_text") == 0) {
what_flag |= CI_WHAT_PREINSERTED_TEXT;
} else if (strcmp(what, "matches") == 0) { } else if (strcmp(what, "matches") == 0) {
what_flag |= CI_WHAT_MATCHES; what_flag |= CI_WHAT_MATCHES;
} }
@@ -3686,6 +3689,13 @@ static void get_complete_info(list_T *what_list, dict_T *retdict)
ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible()); ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
} }
if (ret == OK && (what_flag & CI_WHAT_PREINSERTED_TEXT)) {
char *line = get_cursor_line_ptr();
int len = compl_ins_end_col - curwin->w_cursor.col;
ret = tv_dict_add_str_len(retdict, S_LEN("preinserted_text"),
len > 0 ? line + curwin->w_cursor.col : "", len);
}
if (ret == OK && (what_flag & (CI_WHAT_ITEMS|CI_WHAT_SELECTED if (ret == OK && (what_flag & (CI_WHAT_ITEMS|CI_WHAT_SELECTED
|CI_WHAT_MATCHES|CI_WHAT_COMPLETED))) { |CI_WHAT_MATCHES|CI_WHAT_COMPLETED))) {
list_T *li = NULL; list_T *li = NULL;

View File

@@ -577,15 +577,15 @@ func Test_completefunc_info()
set completeopt=menuone set completeopt=menuone
set completefunc=CompleteTest set completefunc=CompleteTest
call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
call assert_equal("matched{'pum_visible': 1, 'mode': 'function', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) call assert_equal("matched{'preinserted_text': '', 'pum_visible': 1, 'mode': 'function', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1))
%d %d
set complete=.,FCompleteTest set complete=.,FCompleteTest
call feedkeys("i\<C-N>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-N>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
call assert_equal("matched{'pum_visible': 1, 'mode': 'keyword', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) call assert_equal("matched{'preinserted_text': '', 'pum_visible': 1, 'mode': 'keyword', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1))
%d %d
set complete=.,F set complete=.,F
call feedkeys("i\<C-N>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-N>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
call assert_equal("matched{'pum_visible': 1, 'mode': 'keyword', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) call assert_equal("matched{'preinserted_text': '', 'pum_visible': 1, 'mode': 'keyword', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1))
set completeopt& set completeopt&
set complete& set complete&
set completefunc& set completefunc&
@@ -705,17 +705,17 @@ func CompleteInfoTestUserDefinedFn(mvmt, idx, noselect)
set completefunc=CompleteInfoUserDefinedFn set completefunc=CompleteInfoUserDefinedFn
call feedkeys("i\<C-X>\<C-U>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-X>\<C-U>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : '' let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : ''
call assert_equal(completed. "{'pum_visible': 1, 'mode': 'function', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1)) call assert_equal(completed. "{'preinserted_text': '', 'pum_visible': 1, 'mode': 'function', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1))
%d %d
set complete=.,FCompleteInfoUserDefinedFn set complete=.,FCompleteInfoUserDefinedFn
call feedkeys("i\<C-N>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-N>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : '' let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : ''
call assert_equal(completed. "{'pum_visible': 1, 'mode': 'keyword', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1)) call assert_equal(completed. "{'preinserted_text': '', 'pum_visible': 1, 'mode': 'keyword', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1))
%d %d
set complete=.,F set complete=.,F
call feedkeys("i\<C-N>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") call feedkeys("i\<C-N>" . a:mvmt . "\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx")
let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : '' let completed = a:idx != -1 ? ['foo', 'bar', 'baz', 'qux']->get(a:idx) : ''
call assert_equal(completed. "{'pum_visible': 1, 'mode': 'keyword', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1)) call assert_equal(completed. "{'preinserted_text': '', 'pum_visible': 1, 'mode': 'keyword', 'selected': " . a:idx . ", 'items': " . items . "}", getline(1))
bwipe! bwipe!
set completeopt& completefunc& complete& set completeopt& completefunc& complete&
endfunc endfunc
@@ -6017,6 +6017,26 @@ func Test_autocomplete_longest()
call DoTest("f", 'foobar', 2) call DoTest("f", 'foobar', 2)
call assert_equal(1, g:preinserted) call assert_equal(1, g:preinserted)
" complete_info()
%delete
func GetPreinsert()
let g:cinfo = complete_info(['preinserted_text'])
return ""
endfunc
inoremap <buffer><F6> <C-R>=GetPreinsert()<CR>
call setline(1, ["foo_bar_xyz", "foo__xyz"])
set completeopt& completeopt+=preinsert
call feedkeys("G4li\<F6>\<C-Y>", 'tx')
call assert_equal("bar_xyz", g:cinfo.preinserted_text)
set completeopt& completeopt+=longest
call feedkeys("Gof\<F6>\<ESC>", 'tx')
call assert_equal("oo_bar_xyz", g:cinfo.preinserted_text)
unlet g:cinfo
delfunc GetPreinsert
set completeopt&
" Undo " Undo
%delete _ %delete _
let &l:undolevels = &l:undolevels let &l:undolevels = &l:undolevels

View File

@@ -1152,6 +1152,7 @@ func Test_popup_complete_info_02()
\ {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}, \ {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''} \ {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
\ ], \ ],
\ 'preinserted_text': '',
\ 'selected': 0, \ 'selected': 0,
\ } \ }
@@ -1159,7 +1160,7 @@ func Test_popup_complete_info_02()
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info) call assert_equal(d, g:compl_info)
let g:compl_what = ['mode', 'pum_visible', 'selected'] let g:compl_what = ['mode', 'pum_visible', 'preinserted_text', 'selected']
call remove(d, 'items') call remove(d, 'items')
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info) call assert_equal(d, g:compl_info)
@@ -1167,6 +1168,7 @@ func Test_popup_complete_info_02()
let g:compl_what = ['mode'] let g:compl_what = ['mode']
call remove(d, 'selected') call remove(d, 'selected')
call remove(d, 'pum_visible') call remove(d, 'pum_visible')
call remove(d, 'preinserted_text')
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx') call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info) call assert_equal(d, g:compl_info)
bwipe! bwipe!
@@ -1180,6 +1182,7 @@ func Test_popup_complete_info_no_pum()
\ 'mode': '', \ 'mode': '',
\ 'pum_visible': 0, \ 'pum_visible': 0,
\ 'items': [], \ 'items': [],
\ 'preinserted_text': '',
\ 'selected': -1, \ 'selected': -1,
\ } \ }
call assert_equal( d, complete_info() ) call assert_equal( d, complete_info() )