commit 155efabb1513ab1f5871d308eb8a2ae310e9e4ae
parent fb6fd17f26a6abfecdf373c0e5f6dae66f07e0d8
Author: zeertzjq <zeertzjq@outlook.com>
Date: Mon, 27 Oct 2025 09:34:52 +0800
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()
https://github.com/vim/vim/commit/ef5bf58d8cb2c6332d4cbc89c1d352466772ecc3
Co-authored-by: Girish Palya <girishji@gmail.com>
Diffstat:
6 files changed, 74 insertions(+), 32 deletions(-)
diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt
@@ -1207,10 +1207,8 @@ complete_info([{what}]) *complete_info()*
Returns a |Dictionary| with information about Insert mode
completion. See |ins-completion|.
The items are:
- mode Current completion mode name string.
- See |complete_info_mode| for the values.
- pum_visible |TRUE| if popup menu is visible.
- See |pumvisible()|.
+ completed Return a dictionary containing the entries of
+ the currently selected index item.
items List of all completion candidates. Each item
is a dictionary containing the entries "word",
"abbr", "menu", "kind", "info" and
@@ -1221,13 +1219,18 @@ complete_info([{what}]) *complete_info()*
and "items" are in "what", the returned list
will still be named "items", but each item
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.
Index is -1 if no item is selected (showing
typed text only, or the last completion after
no item is selected when using the <Up> or
<Down> keys)
- completed Return a dictionary containing the entries of
- the currently selected index item.
preview_winid Info floating preview window id.
preview_bufnr Info floating preview buffer id.
diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua
@@ -1055,10 +1055,8 @@ function vim.fn.complete_check() end
--- Returns a |Dictionary| with information about Insert mode
--- completion. See |ins-completion|.
--- The items are:
---- mode Current completion mode name string.
---- See |complete_info_mode| for the values.
---- pum_visible |TRUE| if popup menu is visible.
---- See |pumvisible()|.
+--- completed Return a dictionary containing the entries of
+--- the currently selected index item.
--- items List of all completion candidates. Each item
--- is a dictionary containing the entries "word",
--- "abbr", "menu", "kind", "info" and
@@ -1069,13 +1067,18 @@ function vim.fn.complete_check() end
--- and "items" are in "what", the returned list
--- will still be named "items", but each item
--- 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.
--- Index is -1 if no item is selected (showing
--- typed text only, or the last completion after
--- no item is selected when using the <Up> or
--- <Down> keys)
---- completed Return a dictionary containing the entries of
---- the currently selected index item.
--- preview_winid Info floating preview window id.
--- preview_bufnr Info floating preview buffer id.
---
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
@@ -1420,10 +1420,8 @@ M.funcs = {
Returns a |Dictionary| with information about Insert mode
completion. See |ins-completion|.
The items are:
- mode Current completion mode name string.
- See |complete_info_mode| for the values.
- pum_visible |TRUE| if popup menu is visible.
- See |pumvisible()|.
+ completed Return a dictionary containing the entries of
+ the currently selected index item.
items List of all completion candidates. Each item
is a dictionary containing the entries "word",
"abbr", "menu", "kind", "info" and
@@ -1434,13 +1432,18 @@ M.funcs = {
and "items" are in "what", the returned list
will still be named "items", but each item
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.
Index is -1 if no item is selected (showing
typed text only, or the last completion after
no item is selected when using the <Up> or
<Down> keys)
- completed Return a dictionary containing the entries of
- the currently selected index item.
preview_winid Info floating preview window id.
preview_bufnr Info floating preview buffer id.
diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c
@@ -3643,13 +3643,14 @@ static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match)
/// Get complete information
static void get_complete_info(list_T *what_list, dict_T *retdict)
{
-#define CI_WHAT_MODE 0x01
-#define CI_WHAT_PUM_VISIBLE 0x02
-#define CI_WHAT_ITEMS 0x04
-#define CI_WHAT_SELECTED 0x08
-#define CI_WHAT_COMPLETED 0x10
-#define CI_WHAT_MATCHES 0x20
-#define CI_WHAT_ALL 0xff
+#define CI_WHAT_MODE 0x01
+#define CI_WHAT_PUM_VISIBLE 0x02
+#define CI_WHAT_ITEMS 0x04
+#define CI_WHAT_SELECTED 0x08
+#define CI_WHAT_COMPLETED 0x10
+#define CI_WHAT_MATCHES 0x20
+#define CI_WHAT_PREINSERTED_TEXT 0x40
+#define CI_WHAT_ALL 0xff
int what_flag;
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;
} else if (strcmp(what, "completed") == 0) {
what_flag |= CI_WHAT_COMPLETED;
+ } else if (strcmp(what, "preinserted_text") == 0) {
+ what_flag |= CI_WHAT_PREINSERTED_TEXT;
} else if (strcmp(what, "matches") == 0) {
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());
}
+ 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
|CI_WHAT_MATCHES|CI_WHAT_COMPLETED))) {
list_T *li = NULL;
diff --git a/test/old/testdir/test_ins_complete.vim b/test/old/testdir/test_ins_complete.vim
@@ -577,15 +577,15 @@ func Test_completefunc_info()
set completeopt=menuone
set completefunc=CompleteTest
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
set complete=.,FCompleteTest
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
set complete=.,F
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 complete&
set completefunc&
@@ -705,17 +705,17 @@ func CompleteInfoTestUserDefinedFn(mvmt, idx, noselect)
set completefunc=CompleteInfoUserDefinedFn
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) : ''
- 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
set complete=.,FCompleteInfoUserDefinedFn
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) : ''
- 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
set complete=.,F
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) : ''
- 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!
set completeopt& completefunc& complete&
endfunc
@@ -6017,6 +6017,26 @@ func Test_autocomplete_longest()
call DoTest("f", 'foobar', 2)
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
%delete _
let &l:undolevels = &l:undolevels
diff --git a/test/old/testdir/test_popup.vim b/test/old/testdir/test_popup.vim
@@ -1152,6 +1152,7 @@ func Test_popup_complete_info_02()
\ {'word': 'Apr', 'menu': 'April', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''},
\ {'word': 'May', 'menu': 'May', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}
\ ],
+ \ 'preinserted_text': '',
\ 'selected': 0,
\ }
@@ -1159,7 +1160,7 @@ func Test_popup_complete_info_02()
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
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 feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info)
@@ -1167,6 +1168,7 @@ func Test_popup_complete_info_02()
let g:compl_what = ['mode']
call remove(d, 'selected')
call remove(d, 'pum_visible')
+ call remove(d, 'preinserted_text')
call feedkeys("i\<C-X>\<C-U>\<F5>", 'tx')
call assert_equal(d, g:compl_info)
bwipe!
@@ -1180,6 +1182,7 @@ func Test_popup_complete_info_no_pum()
\ 'mode': '',
\ 'pum_visible': 0,
\ 'items': [],
+ \ 'preinserted_text': '',
\ 'selected': -1,
\ }
call assert_equal( d, complete_info() )