From 6ebcb4a4d6ce8c3b1f405c144a0e398c9e6bf068 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 6 Jul 2025 08:29:46 +0800 Subject: [PATCH 1/2] vim-patch:9.1.1505: not possible to return completion type for :ex command Problem: not possible to return command-line completion type for :ex command Solution: make getcmdcompltype() accept an optional and return the command-line completion for that arg (Shougo Matsushita). closes: vim/vim#17606 https://github.com/vim/vim/commit/5d2354fc07b642f8835bef27e6dd46ee705726b5 Co-authored-by: Shougo Matsushita --- runtime/doc/usr_41.txt | 3 +- runtime/doc/vimfn.txt | 12 +++++--- runtime/lua/vim/_meta/vimfn.lua | 10 +++--- src/nvim/eval.lua | 13 +++++--- src/nvim/ex_getln.c | 51 ++++++++++++++++++++----------- test/old/testdir/test_cmdline.vim | 10 ++++++ 6 files changed, 67 insertions(+), 32 deletions(-) diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 6bce7e0ab3..ede9dd83bf 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -908,8 +908,7 @@ Buffers, windows and the argument list: Command line: *command-line-functions* getcmdcomplpat() get completion pattern of the current command line - getcmdcompltype() get the type of the current command line - completion + getcmdcompltype() get the type of the command line completion getcmdline() get the current command line input getcmdprompt() get the current command line prompt getcmdpos() get position of the cursor in the command line diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt index 172eb72675..c15ada1b5b 100644 --- a/runtime/doc/vimfn.txt +++ b/runtime/doc/vimfn.txt @@ -3342,15 +3342,19 @@ getcmdcomplpat() *getcmdcomplpat()* Return: ~ (`string`) -getcmdcompltype() *getcmdcompltype()* - Return the type of the current command-line completion. - Only works when the command line is being edited, thus - requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. +getcmdcompltype([{pat}]) *getcmdcompltype()* + Return the type of command-line completion using {pat}. + If {pat} is omited, only works when the command line is being + edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. + Parameters: ~ + • {pat} (`string?`) + Return: ~ (`string`) diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 4443e8c729..9f82fe41ff 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2994,16 +2994,18 @@ function vim.fn.getcharstr(expr, opts) end --- @return string function vim.fn.getcmdcomplpat() end ---- Return the type of the current command-line completion. ---- Only works when the command line is being edited, thus ---- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. +--- Return the type of command-line completion using {pat}. +--- If {pat} is omited, only works when the command line is being +--- edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. +--- --- See |:command-completion| for the return string. --- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, --- |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. --- Returns an empty string when completion is not defined. --- +--- @param pat? string --- @return string -function vim.fn.getcmdcompltype() end +function vim.fn.getcmdcompltype(pat) end --- Return the current command-line input. Only works when the --- command line is being edited, thus requires use of diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 61e76707bc..0407a7bdbe 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3751,19 +3751,22 @@ M.funcs = { signature = 'getcmdcomplpat()', }, getcmdcompltype = { + args = { 0, 1 }, + base = 1, desc = [=[ - Return the type of the current command-line completion. - Only works when the command line is being edited, thus - requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + Return the type of command-line completion using {pat}. + If {pat} is omited, only works when the command line is being + edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. + See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. ]=], name = 'getcmdcompltype', - params = {}, + params = { { 'pat', 'string' } }, returns = 'string', - signature = 'getcmdcompltype()', + signature = 'getcmdcompltype([{pat}])', }, getcmdline = { desc = [=[ diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c67253e142..570c2086c5 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4198,22 +4198,13 @@ static char *get_cmdline_completion_pattern(void) } /// Get the current command-line completion type. -static char *get_cmdline_completion(void) +static char *get_cmdline_completion(expand_T *xpc) { - if (cmdline_star > 0) { - return NULL; - } - - CmdlineInfo *p = get_ccline_ptr(); - if (p == NULL || p->xpc == NULL) { - return NULL; - } - - int xp_context = p->xpc->xp_context; + int xp_context = xpc->xp_context; if (xp_context == EXPAND_NOTHING) { - set_expand_context(p->xpc); - xp_context = p->xpc->xp_context; - p->xpc->xp_context = EXPAND_NOTHING; + set_expand_context(xpc); + xp_context = xpc->xp_context; + xpc->xp_context = EXPAND_NOTHING; } if (xp_context == EXPAND_UNSUCCESSFUL) { return NULL; @@ -4225,9 +4216,9 @@ static char *get_cmdline_completion(void) } if (xp_context == EXPAND_USER_LIST || xp_context == EXPAND_USER_DEFINED) { - size_t buflen = strlen(cmd_compl) + strlen(p->xpc->xp_arg) + 2; + size_t buflen = strlen(cmd_compl) + strlen(xpc->xp_arg) + 2; char *buffer = xmalloc(buflen); - snprintf(buffer, buflen, "%s,%s", cmd_compl, p->xpc->xp_arg); + snprintf(buffer, buflen, "%s,%s", cmd_compl, xpc->xp_arg); return buffer; } @@ -4244,8 +4235,34 @@ void f_getcmdcomplpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "getcmdcompltype()" function void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { + if (tv_check_for_opt_string_arg(argvars, 0) == FAIL) { + return; + } + rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_cmdline_completion(); + + if (argvars[0].v_type != VAR_UNKNOWN) { + char *pat = (char *)tv_get_string(&argvars[0]); + expand_T xpc; + ExpandInit(&xpc); + + int cmdline_len = (int)strlen(pat); + set_cmd_context(&xpc, pat, cmdline_len, cmdline_len, false); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + xpc.xp_col = cmdline_len; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = get_cmdline_completion(&xpc); + + ExpandCleanup(&xpc); + } else { + CmdlineInfo *p = get_ccline_ptr(); + if (cmdline_star > 0 || p == NULL || p->xpc == NULL) { + return; + } + + rettv->vval.v_string = get_cmdline_completion(p->xpc); + } } /// "getcmdline()" function diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 454390dd6b..e80ede04c4 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -4601,4 +4601,14 @@ func Test_range_complete() set wildcharm=0 endfunc +func Test_getcmdcompltype_with_pat() + call assert_fails('call getcmdcompltype({})', 'E1174:') + call assert_equal(getcmdcompltype(''), 'command') + call assert_equal(getcmdcompltype('dummy '), '') + call assert_equal(getcmdcompltype('cd '), 'dir_in_path') + call assert_equal(getcmdcompltype('let v:n'), 'var') + call assert_equal(getcmdcompltype('call tag'), 'function') + call assert_equal(getcmdcompltype('help '), 'help') +endfunc + " vim: shiftwidth=2 sts=2 expandtab From 9c04eb02adde4f7daae2c4986ed58037358ce4ad Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 6 Jul 2025 08:41:41 +0800 Subject: [PATCH 2/2] vim-patch:9.1.1509: patch 9.1.1505 was not good Problem: Patch 9.1.1505 was not good Solution: Revert "patch 9.1.1505: not possible to return completion type for :ex command" and instead add the getcompletiontype() function (Hirohito Higashi). related: vim/vim#17606 closes: vim/vim#17662 https://github.com/vim/vim/commit/96b3ef23896ce70b2fdf3425ba2c013ce2840db6 Cherry-pick Test_multibyte_expression() from Vim, as it passes. Co-authored-by: Hirohito Higashi Co-authored-by: Shougo Matsushita --- runtime/doc/news.txt | 1 + runtime/doc/usr_41.txt | 5 ++++- runtime/doc/vimfn.txt | 26 ++++++++++++++++------- runtime/lua/vim/_meta/vimfn.lua | 23 ++++++++++++++------ src/nvim/cmdexpand.c | 24 +++++++++++++++++++++ src/nvim/eval.lua | 31 ++++++++++++++++++++------- src/nvim/ex_getln.c | 35 +++++++------------------------ test/old/testdir/test_cmdline.vim | 35 ++++++++++++++++++++++--------- 8 files changed, 121 insertions(+), 59 deletions(-) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index df62f5a5d3..76cc711c63 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -269,6 +269,7 @@ UI VIMSCRIPT • |cmdcomplete_info()| gets current cmdline completion info. +• |getcompletiontype()| gets command-line completion type for any string. • |prompt_getinput()| gets current user-input in prompt-buffer. ============================================================================== diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index ede9dd83bf..45d996effb 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -908,7 +908,8 @@ Buffers, windows and the argument list: Command line: *command-line-functions* getcmdcomplpat() get completion pattern of the current command line - getcmdcompltype() get the type of the command line completion + getcmdcompltype() get the type of the current command line + completion getcmdline() get the current command line input getcmdprompt() get the current command line prompt getcmdpos() get position of the cursor in the command line @@ -919,6 +920,8 @@ Command line: *command-line-functions* getcmdtype() return the current command-line type getcmdwintype() return the current command-line window type getcompletion() list of command-line completion matches + getcompletiontype() get the type of the command-line completion + for specified string fullcommand() get full command name cmdcomplete_info() get command-line completion information diff --git a/runtime/doc/vimfn.txt b/runtime/doc/vimfn.txt index c15ada1b5b..e549042687 100644 --- a/runtime/doc/vimfn.txt +++ b/runtime/doc/vimfn.txt @@ -3342,18 +3342,17 @@ getcmdcomplpat() *getcmdcomplpat()* Return: ~ (`string`) -getcmdcompltype([{pat}]) *getcmdcompltype()* - Return the type of command-line completion using {pat}. - If {pat} is omited, only works when the command line is being - edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. - +getcmdcompltype() *getcmdcompltype()* + Return the type of the current command-line completion. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. - Parameters: ~ - • {pat} (`string?`) + To get the type of the command-line completion for the + specified string, use |getcompletiontype()|. Return: ~ (`string`) @@ -3514,6 +3513,19 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()* Return: ~ (`string[]`) +getcompletiontype({pat}) *getcompletiontype()* + Return the type of the command-line completion using {pat}. + When no corresponding completion type is found, an empty + string is returned. + To get the current command-line completion type, use + |getcmdcompltype()|. + + Parameters: ~ + • {pat} (`string`) + + Return: ~ + (`string`) + getcurpos([{winid}]) *getcurpos()* Get the position of the cursor. This is like getpos('.'), but includes an extra "curswant" item in the list: diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 9f82fe41ff..d690eaa34a 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2994,18 +2994,19 @@ function vim.fn.getcharstr(expr, opts) end --- @return string function vim.fn.getcmdcomplpat() end ---- Return the type of command-line completion using {pat}. ---- If {pat} is omited, only works when the command line is being ---- edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. ---- +--- Return the type of the current command-line completion. +--- Only works when the command line is being edited, thus +--- requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. --- See |:command-completion| for the return string. --- Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, --- |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. --- Returns an empty string when completion is not defined. --- ---- @param pat? string +--- To get the type of the command-line completion for the +--- specified string, use |getcompletiontype()|. +--- --- @return string -function vim.fn.getcmdcompltype(pat) end +function vim.fn.getcmdcompltype() end --- Return the current command-line input. Only works when the --- command line is being edited, thus requires use of @@ -3154,6 +3155,16 @@ function vim.fn.getcmdwintype() end --- @return string[] function vim.fn.getcompletion(pat, type, filtered) end +--- Return the type of the command-line completion using {pat}. +--- When no corresponding completion type is found, an empty +--- string is returned. +--- To get the current command-line completion type, use +--- |getcmdcompltype()|. +--- +--- @param pat string +--- @return string +function vim.fn.getcompletiontype(pat) end + --- Get the position of the cursor. This is like getpos('.'), but --- includes an extra "curswant" item in the list: --- [0, lnum, col, off, curswant] ~ diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index a1d7ae7e2c..4132e56142 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -3838,6 +3838,30 @@ theend: ExpandCleanup(&xpc); } +/// "getcompletiontype()" function +void f_getcompletiontype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (tv_check_for_string_arg(argvars, 0) == FAIL) { + return; + } + + const char *pat = tv_get_string(&argvars[0]); + expand_T xpc; + ExpandInit(&xpc); + + int cmdline_len = (int)strlen(pat); + set_cmd_context(&xpc, (char *)pat, cmdline_len, cmdline_len, false); + xpc.xp_pattern_len = strlen(xpc.xp_pattern); + xpc.xp_col = cmdline_len; + + rettv->vval.v_string = get_cmdline_completion(&xpc); + + ExpandCleanup(&xpc); +} + /// "cmdcomplete_info()" function void f_cmdcomplete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 0407a7bdbe..80f73ac209 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3751,22 +3751,22 @@ M.funcs = { signature = 'getcmdcomplpat()', }, getcmdcompltype = { - args = { 0, 1 }, - base = 1, desc = [=[ - Return the type of command-line completion using {pat}. - If {pat} is omited, only works when the command line is being - edited, thus requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. - + Return the type of the current command-line completion. + Only works when the command line is being edited, thus + requires use of |c_CTRL-\_e| or |c_CTRL-R_=|. See |:command-completion| for the return string. Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()|, |getcmdprompt()|, |getcmdcomplpat()| and |setcmdline()|. Returns an empty string when completion is not defined. + + To get the type of the command-line completion for the + specified string, use |getcompletiontype()|. ]=], name = 'getcmdcompltype', - params = { { 'pat', 'string' } }, + params = {}, returns = 'string', - signature = 'getcmdcompltype([{pat}])', + signature = 'getcmdcompltype()', }, getcmdline = { desc = [=[ @@ -3943,6 +3943,21 @@ M.funcs = { returns = 'string[]', signature = 'getcompletion({pat}, {type} [, {filtered}])', }, + getcompletiontype = { + args = 1, + base = 1, + desc = [=[ + Return the type of the command-line completion using {pat}. + When no corresponding completion type is found, an empty + string is returned. + To get the current command-line completion type, use + |getcmdcompltype()|. + ]=], + name = 'getcompletiontype', + params = { { 'pat', 'string' } }, + returns = 'string', + signature = 'getcompletiontype({pat})', + }, getcurpos = { args = { 0, 1 }, base = 1, diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 570c2086c5..8ad5739bb3 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4197,8 +4197,8 @@ static char *get_cmdline_completion_pattern(void) return xstrdup(compl_pat); } -/// Get the current command-line completion type. -static char *get_cmdline_completion(expand_T *xpc) +/// Get the command-line completion type. +char *get_cmdline_completion(expand_T *xpc) { int xp_context = xpc->xp_context; if (xp_context == EXPAND_NOTHING) { @@ -4235,34 +4235,15 @@ void f_getcmdcomplpat(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "getcmdcompltype()" function void f_getcmdcompltype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - if (tv_check_for_opt_string_arg(argvars, 0) == FAIL) { + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + CmdlineInfo *p = get_ccline_ptr(); + if (cmdline_star > 0 || p == NULL || p->xpc == NULL) { return; } - rettv->v_type = VAR_STRING; - - if (argvars[0].v_type != VAR_UNKNOWN) { - char *pat = (char *)tv_get_string(&argvars[0]); - expand_T xpc; - ExpandInit(&xpc); - - int cmdline_len = (int)strlen(pat); - set_cmd_context(&xpc, pat, cmdline_len, cmdline_len, false); - xpc.xp_pattern_len = strlen(xpc.xp_pattern); - xpc.xp_col = cmdline_len; - - rettv->v_type = VAR_STRING; - rettv->vval.v_string = get_cmdline_completion(&xpc); - - ExpandCleanup(&xpc); - } else { - CmdlineInfo *p = get_ccline_ptr(); - if (cmdline_star > 0 || p == NULL || p->xpc == NULL) { - return; - } - - rettv->vval.v_string = get_cmdline_completion(p->xpc); - } + rettv->vval.v_string = get_cmdline_completion(p->xpc); } /// "getcmdline()" function diff --git a/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index e80ede04c4..9b13bc948e 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -737,6 +737,31 @@ func Test_getcompletion() call assert_fails('call getcompletion("abc", [])', 'E1174:') endfunc +func Test_getcompletiontype() + call assert_fails('call getcompletiontype()', 'E119:') + call assert_fails('call getcompletiontype({})', 'E1174:') + call assert_equal(getcompletiontype(''), 'command') + call assert_equal(getcompletiontype('dummy '), '') + call assert_equal(getcompletiontype('cd '), 'dir_in_path') + call assert_equal(getcompletiontype('let v:n'), 'var') + call assert_equal(getcompletiontype('call tag'), 'function') + call assert_equal(getcompletiontype('help '), 'help') +endfunc + +func Test_multibyte_expression() + " Get a dialog in the GUI + CheckNotGui + + " This was using uninitialized memory. + let lines =<< trim END + set verbose=6 + norm @=ٷ + qall! + END + call writefile(lines, 'XmultiScript', 'D') + call RunVim('', '', '-u NONE -n -e -s -S XmultiScript') +endfunc + " Test for getcompletion() with "fuzzy" in 'wildoptions' func Test_getcompletion_wildoptions() let save_wildoptions = &wildoptions @@ -4601,14 +4626,4 @@ func Test_range_complete() set wildcharm=0 endfunc -func Test_getcmdcompltype_with_pat() - call assert_fails('call getcmdcompltype({})', 'E1174:') - call assert_equal(getcmdcompltype(''), 'command') - call assert_equal(getcmdcompltype('dummy '), '') - call assert_equal(getcmdcompltype('cd '), 'dir_in_path') - call assert_equal(getcmdcompltype('let v:n'), 'var') - call assert_equal(getcmdcompltype('call tag'), 'function') - call assert_equal(getcmdcompltype('help '), 'help') -endfunc - " vim: shiftwidth=2 sts=2 expandtab