-*map.txt* For Vim version 9.2. Last change: 2026 May 02
+*map.txt* For Vim version 9.2. Last change: 2026 May 17
VIM REFERENCE MANUAL by Bram Moolenaar
command can take arguments, using the -nargs attribute. Valid cases are:
-nargs=0 No arguments are allowed (the default)
- -nargs=1 Exactly one argument is required, it includes spaces
+ -nargs=1 Exactly one argument is required, it includes spaces;
+ completion treats white spaces as argument separation
+ -nargs=_ Exactly one argument is required, it includes spaces;
+ completion treats white spaces as part of the argument
-nargs=* Any number of arguments are allowed (0, 1, or many),
separated by white space
-nargs=? 0 or 1 arguments are allowed
Arguments are considered to be separated by (unescaped) spaces or tabs in this
context, except when there is one argument, then the white space is part of
-the argument.
+the argument. The difference between the "-nargs=1" and "-nargs=_": >
+
+ func MyComplete(ArgLead, CmdLine, CursorPos)
+ return ["one value", "two values", "three values"]
+ \->matchfuzzy(a:ArgLead)
+ endfunc
+ :command -nargs=1 -complete=customlist,MyComplete MyCmd1 echo <q-args>
+ :command -nargs=_ -complete=customlist,MyComplete MyCmd2 echo <q-args>
+
+Completing ":MyCmd1 two va<tab>" will complete with: >
+
+ :MyCmd1 two one value
+
+Completing ":MyCmd2 two va<tab>" will complete with: >
+
+ :MyCmd2 two values
+
Note that arguments are used as text, not as expressions. Specifically,
"s:var" will use the script-local variable in the script where the command was
com! -nargs=1 DoCmd :
call assert_fails('DoCmd', 'E471:')
+ com! -nargs=_ DoCmd :
+ call assert_fails('DoCmd', 'E471:')
+
com! -nargs=+ DoCmd :
call assert_fails('DoCmd', 'E471:')
return [ "Monday", "Tuesday", "Wednesday", {}, test_null_string()]
endfunc
+func CustomCompleteListWithSpaces(A, L, P)
+ return [ "Monday Here", "Tuesday There", "Wednesday OK", {}, test_null_string()]
+endfunc
+
+func CustomCompleteListFuzzy(A, L, P)
+ return [ "Monday Here", "Tuesday There", "Wednesday OK", {}, test_null_string()]->matchfuzzy(a:A)
+endfunc
+
func Test_CmdCompletion()
call feedkeys(":com -\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -addr bang bar buffer complete count keepscript nargs range register', @:)
call assert_equal('"com -nargs=0 -addr bang bar buffer complete count keepscript nargs range register', @:)
call feedkeys(":com -nargs=\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"com -nargs=* + 0 1 ?', @:)
+ call assert_equal('"com -nargs=* + 0 1 ? _', @:)
call feedkeys(":com -addr=\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -addr=arguments buffers lines loaded_buffers other quickfix tabs windows', @:)
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd mswin xterm', @:)
+ com! -nargs=_ -complete=behave DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd mswin xterm', @:)
+
com! -nargs=1 -complete=retab DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd -indentonly', @:)
+ com! -nargs=_ -complete=retab DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd -indentonly', @:)
+
" Test for file name completion
com! -nargs=1 -complete=file DoCmd :
call feedkeys(":DoCmd READM\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd README.txt', @:)
+ com! -nargs=_ -complete=file DoCmd :
+ call feedkeys(":DoCmd READM\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd README.txt', @:)
+
" Test for buffer name completion
com! -nargs=1 -complete=buffer DoCmd :
let bnum = bufadd('BufForUserCmd')
call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd BufFor', @:)
+ com! -nargs=_ -complete=buffer DoCmd :
+ let bnum = bufadd('BufForUserCmd')
+ call setbufvar(bnum, '&buflisted', 1)
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufForUserCmd', @:)
+ bwipe BufForUserCmd
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufFor', @:)
+
com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd Monday Tuesday Wednesday', @:)
+ com! -nargs=_ -complete=customlist,CustomCompleteListWithSpaces DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd Monday Here Tuesday There Wednesday OK', @:)
+
+ com! -nargs=_ -complete=customlist,CustomCompleteListFuzzy DoCmd :
+ call feedkeys(":DoCmd mo he\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd Monday Here', @:)
+
com! -nargs=+ -complete=custom,CustomCompleteList DoCmd :
call assert_fails("call feedkeys(':DoCmd \<C-D>', 'tx')", 'E730:')
delcommand DoSomething
endfunc
+func Test_nargs_underscore_fargs()
+ " -nargs=_ must behave like -nargs=1 for <f-args>/<q-args>:
+ " the whole argument is one token, whitespace is part of it.
+ let g:res = []
+ com! -nargs=1 DoCmd1 call add(g:res, [<f-args>])
+ com! -nargs=_ DoCmdU call add(g:res, [<f-args>])
+ DoCmd1 a b c
+ DoCmdU a b c
+ call assert_equal([['a b c'], ['a b c']], g:res)
+
+ let g:res = []
+ com! -nargs=_ DoCmdQ call add(g:res, <q-args>)
+ DoCmdQ a b c
+ call assert_equal(['a b c'], g:res)
+
+ delcom DoCmd1
+ delcom DoCmdU
+ delcom DoCmdQ
+ unlet g:res
+endfunc
+
func Test_command_list()
command! DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 1 arglist :",
\ execute('command DoCmd'))
+ command! -nargs=_ -complete=arglist DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd _ arglist :",
+ \ execute('command DoCmd'))
command! -nargs=* -complete=augroup DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd * augroup :",
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd 1 :",
\ execute('command DoCmd'))
+ command! -nargs=_ DoCmd :
+ call assert_equal("\n Name Args Address Complete Definition"
+ \ .. "\n DoCmd _ :",
+ \ execute('command DoCmd'))
command! -nargs=* DoCmd :
call assert_equal("\n Name Args Address Complete Definition"
\ .. "\n DoCmd * :",
return set_context_in_map_cmd(xp, (char_u *)"map", arg, forceit, FALSE,
FALSE, CMD_map);
// Find start of last argument.
- p = arg;
- while (*p)
+ if (!(argt & EX_ARGSPACE))
{
- if (*p == ' ')
- // argument starts after a space
- arg = p + 1;
- else if (*p == '\\' && *(p + 1) != NUL)
- ++p; // skip over escaped character
- MB_PTR_ADV(p);
+ p = arg;
+ while (*p)
+ {
+ if (*p == ' ')
+ // argument starts after a space
+ arg = p + 1;
+ else if (*p == '\\' && *(p + 1) != NUL)
+ ++p; // skip over escaped character
+ MB_PTR_ADV(p);
+ }
}
xp->xp_pattern = arg;
xp->xp_context = context;
char_u *
get_user_cmd_nargs(expand_T *xp UNUSED, int idx)
{
- static char *user_cmd_nargs[] = {"0", "1", "*", "?", "+"};
+ static char *user_cmd_nargs[] = {"0", "1", "_", "*", "?", "+"};
if (idx < 0 || idx >= (int)ARRAY_LENGTH(user_cmd_nargs))
return NULL;
len = 0;
// Arguments
- switch ((int)(a & (EX_EXTRA|EX_NOSPC|EX_NEEDARG)))
+ switch ((int)(a & (EX_EXTRA|EX_NOSPC|EX_NEEDARG|EX_ARGSPACE)))
{
case 0: IObuff[len++] = '0'; break;
case (EX_EXTRA): IObuff[len++] = '*'; break;
case (EX_EXTRA|EX_NOSPC): IObuff[len++] = '?'; break;
case (EX_EXTRA|EX_NEEDARG): IObuff[len++] = '+'; break;
case (EX_EXTRA|EX_NOSPC|EX_NEEDARG): IObuff[len++] = '1'; break;
+ case (EX_EXTRA|EX_NOSPC|EX_NEEDARG|EX_ARGSPACE): IObuff[len++] = '_'; break;
}
do
*argt |= (EX_EXTRA | EX_NOSPC);
else if (*val == '+')
*argt |= (EX_EXTRA | EX_NEEDARG);
+ else if (*val == '_')
+ *argt |= (EX_EXTRA | EX_NOSPC | EX_NEEDARG | EX_ARGSPACE);
else
goto wrong_nargs;
}