Skip to content

Commit

Permalink
patch 9.0.0285: it is not easy to change the command line from a plugin
Browse files Browse the repository at this point in the history
Problem:    It is not easy to change the command line from a plugin.
Solution:   Add setcmdline(). (Shougo Matsushita, closes #10869)
  • Loading branch information
Shougo authored and brammool committed Aug 27, 2022
1 parent 5ff595d commit 07ea5f1
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 11 deletions.
27 changes: 21 additions & 6 deletions runtime/doc/builtin.txt
Expand Up @@ -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
Expand Down Expand Up @@ -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()*
Expand All @@ -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()|.

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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()
Expand Down
1 change: 1 addition & 0 deletions runtime/doc/usr_41.txt
Expand Up @@ -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
Expand Down
9 changes: 4 additions & 5 deletions src/evalfunc.c
Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand All @@ -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);
}

/*
Expand Down
58 changes: 58 additions & 0 deletions src/ex_getln.c
Expand Up @@ -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.
Expand All @@ -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
*/
Expand Down
2 changes: 2 additions & 0 deletions src/proto/ex_getln.pro
Expand Up @@ -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);
Expand Down
40 changes: 40 additions & 0 deletions src/testdir/test_cmdline.vim
Expand Up @@ -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
6 changes: 6 additions & 0 deletions src/testdir/test_vim9_builtin.vim
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/version.c
Expand Up @@ -707,6 +707,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
/**/
285,
/**/
284,
/**/
Expand Down

0 comments on commit 07ea5f1

Please sign in to comment.