patch 9.0.0285: it is not easy to change the command line from a plugin

Problem:    It is not easy to change the command line from a plugin.
Solution:   Add setcmdline(). (Shougo Matsushita, closes #10869)
This commit is contained in:
Shougo Matsushita
2022-08-27 12:22:25 +01:00
committed by Bram Moolenaar
parent 5ff595d9db
commit 07ea5f1509
8 changed files with 134 additions and 11 deletions

View File

@ -505,6 +505,7 @@ setbufvar({buf}, {varname}, {val})
setcellwidths({list}) none set character cell width overrides
setcharpos({expr}, {list}) Number set the {expr} position to {list}
setcharsearch({dict}) Dict set character search from {dict}
setcmdline({str} [, {pos}]) Number set command-line
setcmdpos({pos}) Number set cursor position in command-line
setcursorcharpos({list}) Number move cursor to position in {list}
setenv({name}, {val}) none set environment variable
@ -3425,7 +3426,8 @@ getcmdcompltype() *getcmdcompltype()*
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()| and |getcmdline()|.
Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and
|setcmdline()|.
Returns an empty string when completion is not defined.
getcmdline() *getcmdline()*
@ -3434,7 +3436,8 @@ getcmdline() *getcmdline()*
|c_CTRL-R_=|.
Example: >
:cmap <F7> <C-\>eescape(getcmdline(), ' \')<CR>
< Also see |getcmdtype()|, |getcmdpos()| and |setcmdpos()|.
< Also see |getcmdtype()|, |getcmdpos()|, |setcmdpos()| and
|setcmdline()|.
Returns an empty string when entering a password or using
|inputsecret()|.
@ -3444,7 +3447,8 @@ getcmdpos() *getcmdpos()*
Only works when editing the command line, thus requires use of
|c_CTRL-\_e| or |c_CTRL-R_=| or an expression mapping.
Returns 0 otherwise.
Also see |getcmdtype()|, |setcmdpos()| and |getcmdline()|.
Also see |getcmdtype()|, |setcmdpos()|, |getcmdline()| and
|setcmdline()|.
getcmdscreenpos() *getcmdscreenpos()*
Return the screen position of the cursor in the command line
@ -3453,7 +3457,8 @@ getcmdscreenpos() *getcmdscreenpos()*
Only works when editing the command line, thus requires use of
|c_CTRL-\_e| or |c_CTRL-R_=| or an expression mapping.
Returns 0 otherwise.
Also see |getcmdpos()|, |setcmdpos()|.
Also see |getcmdpos()|, |setcmdpos()|, |getcmdline()| and
|setcmdline()|.
getcmdtype() *getcmdtype()*
Return the current command-line type. Possible return values
@ -7925,6 +7930,16 @@ setcharsearch({dict}) *setcharsearch()*
Can also be used as a |method|: >
SavedSearch()->setcharsearch()
setcmdline({str} [, {pos}]) *setcmdline()*
Set the command line to {str} and set the cursor position to
{pos}.
If {pos} is omitted, the cursor is positioned after the text.
Returns 0 when successful, 1 when not editing the command
line.
Can also be used as a |method|: >
GetText()->setcmdline()
setcmdpos({pos}) *setcmdpos()*
Set the cursor position in the command line to byte position
{pos}. The first position is 1.
@ -7937,8 +7952,8 @@ setcmdpos({pos}) *setcmdpos()*
before inserting the resulting text.
When the number is too big the cursor is put at the end of the
line. A number smaller than one has undefined results.
Returns FALSE when successful, TRUE when not editing the
command line.
Returns 0 when successful, 1 when not editing the command
line.
Can also be used as a |method|: >
GetPos()->setcmdpos()

View File

@ -1038,6 +1038,7 @@ Command line: *command-line-functions*
getcmdpos() get position of the cursor in the command line
getcmdscreenpos() get screen position of the cursor in the
command line
setcmdline() set the current command line
setcmdpos() set position of the cursor in the command line
getcmdtype() return the current command-line type
getcmdwintype() return the current command-line window type

View File

@ -2369,6 +2369,8 @@ static funcentry_T global_functions[] =
ret_number_bool, f_setcharpos},
{"setcharsearch", 1, 1, FEARG_1, arg1_dict_any,
ret_void, f_setcharsearch},
{"setcmdline", 1, 2, FEARG_1, arg2_string_number,
ret_number_bool, f_setcmdline},
{"setcmdpos", 1, 1, FEARG_1, arg1_number,
ret_number_bool, f_setcmdpos},
{"setcursorcharpos", 1, 3, FEARG_1, arg13_cursor,
@ -3607,7 +3609,6 @@ f_debugbreak(typval_T *argvars, typval_T *rettv)
f_deepcopy(typval_T *argvars, typval_T *rettv)
{
varnumber_T noref = 0;
int copyID;
if (in_vim9script()
&& (check_for_opt_bool_arg(argvars, 1) == FAIL))
@ -3618,10 +3619,8 @@ f_deepcopy(typval_T *argvars, typval_T *rettv)
if (noref < 0 || noref > 1)
semsg(_(e_using_number_as_bool_nr), noref);
else
{
copyID = get_copyID();
item_copy(&argvars[0], rettv, TRUE, TRUE, noref == 0 ? copyID : 0);
}
item_copy(&argvars[0], rettv, TRUE, TRUE,
noref == 0 ? get_copyID() : 0);
}
/*

View File

@ -4211,6 +4211,35 @@ f_getcmdscreenpos(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = get_cmdline_screen_pos() + 1;
}
// Set the command line str to "str".
// Returns 1 when failed, 0 when OK.
int
set_cmdline_str(char_u *str, int pos)
{
cmdline_info_T *p = get_ccline_ptr();
int cmdline_type;
int len;
if (p == NULL)
return 1;
len = (int)STRLEN(str);
realloc_cmdbuff(len + 1);
p->cmdlen = len;
STRCPY(p->cmdbuff, str);
p->cmdpos = pos < 0 || pos > p->cmdlen ? p->cmdlen : pos;
new_cmdpos = p->cmdpos;
redrawcmd();
// Trigger CmdlineChanged autocommands.
cmdline_type = ccline.cmdfirstc == NUL ? '-' : ccline.cmdfirstc;
trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED);
return 0;
}
/*
* Set the command line byte position to "pos". Zero is the first position.
* Only works when the command line is being edited.
@ -4234,6 +4263,35 @@ set_cmdline_pos(
return 0;
}
// "setcmdline()" function
void
f_setcmdline(typval_T *argvars, typval_T *rettv)
{
int pos = -1;
if (argvars[0].v_type != VAR_STRING || argvars[0].vval.v_string == NULL)
{
emsg(_(e_string_required));
return;
}
if (argvars[1].v_type != VAR_UNKNOWN)
{
int error = FALSE;
pos = (int)tv_get_number_chk(&argvars[1], &error) - 1;
if (error)
return;
if (pos < 0)
{
emsg(_(e_argument_must_be_positive));
return;
}
}
rettv->vval.v_number = set_cmdline_str(argvars[0].vval.v_string, pos);
}
/*
* "setcmdpos()" function
*/

View File

@ -34,6 +34,8 @@ void f_getcmdcompltype(typval_T *argvars, typval_T *rettv);
void f_getcmdline(typval_T *argvars, typval_T *rettv);
void f_getcmdpos(typval_T *argvars, typval_T *rettv);
void f_getcmdscreenpos(typval_T *argvars, typval_T *rettv);
int set_cmdline_str(char_u *str, int pos);
void f_setcmdline(typval_T *argvars, typval_T *rettv);
void f_setcmdpos(typval_T *argvars, typval_T *rettv);
void f_getcmdtype(typval_T *argvars, typval_T *rettv);
int get_cmdline_firstc(void);

View File

@ -3262,4 +3262,44 @@ func Test_wildmenu_pum_disable_while_shown()
set wildoptions& wildmenu&
endfunc
func Test_setcmdline()
func SetText(text, pos)
call assert_equal(0, setcmdline(a:text))
call assert_equal(a:text, getcmdline())
call assert_equal(len(a:text) + 1, getcmdpos())
call assert_equal(0, setcmdline(a:text, a:pos))
call assert_equal(a:text, getcmdline())
call assert_equal(a:pos, getcmdpos())
call assert_fails('call setcmdline("' .. a:text .. '", -1)', 'E487:')
call assert_fails('call setcmdline({}, 0)', 'E928:')
call assert_fails('call setcmdline("' .. a:text .. '", {})', 'E728:')
return ''
endfunc
call feedkeys(":\<C-R>=SetText('set rtp?', 2)\<CR>\<CR>", 'xt')
call assert_equal('set rtp?', @:)
" setcmdline() returns 1 when not editing the command line.
call assert_equal(1, 'foo'->setcmdline())
" Called in custom function
func CustomComplete(A, L, P)
call assert_equal(0, setcmdline("DoCmd "))
return "January\nFebruary\nMars\n"
endfunc
com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
" Called in <expr>
cnoremap <expr>a setcmdline('let foo=')
call feedkeys(":a\<CR>", 'tx')
call assert_equal('let foo=0', @:)
cunmap a
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -3657,6 +3657,12 @@ def Test_setcharsearch()
assert_equal(d, getcharsearch())
enddef
def Test_setcmdline()
v9.CheckDefAndScriptSuccess(['setcmdline("ls", 2)'])
v9.CheckDefAndScriptFailure(['setcmdline(123)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E928: String required'])
v9.CheckDefAndScriptFailure(['setcmdline("ls", "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1030: Using a String as a Number'])
enddef
def Test_setcmdpos()
v9.CheckDefAndScriptFailure(['setcmdpos("x")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
enddef

View File

@ -707,6 +707,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
285,
/**/
284,
/**/