Skip to content
Browse files

patch 8.1.0573: cannot redefine user command without ! in same script

Problem:    Cannot redefine user command without ! in same script
Solution:   Allow redefining user command without ! in same script, like with
  • Loading branch information...
brammool committed Dec 8, 2018
1 parent 76ab4fd commit 55d46913084745a48749d7ac4f48930852e1d87e
Showing with 59 additions and 13 deletions.
  1. +23 −11 runtime/doc/map.txt
  2. +6 −2 src/ex_docmd.c
  3. +28 −0 src/testdir/test_usercommands.vim
  4. +2 −0 src/version.c
@@ -1223,14 +1223,19 @@ See |:verbose-cmd| for more information.
attributes (see below) are {attr}. If the command
already exists, an error is reported, unless a ! is
specified, in which case the command is redefined.
There is one exception: When sourcing a script again,
a command that was previously defined in that script
will be silently replaced.

:delc[ommand] {cmd} *:delc* *:delcommand* *E184*
Delete the user-defined command {cmd}.

:comc[lear] *:comc* *:comclear*
Delete all user-defined commands.

Command attributes

Command attributes ~

User-defined commands are treated by Vim just like any other Ex commands. They
can have arguments, or have a range specified. Arguments are subject to
@@ -1241,8 +1246,9 @@ There are a number of attributes, split into four categories: argument
handling, completion behavior, range handling, and special cases. The
attributes are described below, by category.

Argument handling *E175* *E176* *:command-nargs*

Argument handling ~
*E175* *E176* *:command-nargs*
By default, a user defined command will take no arguments (and an error is
reported if any are supplied). However, it is possible to specify that the
command can take arguments, using the -nargs attribute. Valid cases are:
@@ -1271,8 +1277,10 @@ defined, not where it is invoked! Example:
Executing script2.vim will result in "None" being echoed. Not what you
intended! Calling a function may be an alternative.

Completion behavior *:command-completion* *E179*
*E180* *E181* *:command-complete*

Completion behavior ~
*:command-completion* *E179* *E180* *E181*
By default, the arguments of user defined commands do not undergo completion.
However, by specifying one or the other of the following attributes, argument
completion can be enabled:
@@ -1317,9 +1325,9 @@ completion can be enabled:
Note: That some completion methods might expand environment variables.

Custom completion *:command-completion-custom*
*E467* *E468*
Custom completion ~
*:command-completion-customlist* *E467* *E468*
It is possible to define customized completion schemes via the "custom,{func}"
or the "customlist,{func}" completion argument. The {func} part should be a
function with the following signature: >
@@ -1364,8 +1372,8 @@ the 'path' option: >
This example does not work for file names with spaces!

Range handling *E177* *E178* *:command-range*
Range handling ~
*E177* *E178* *:command-range* *:command-count*
By default, user-defined commands do not accept a line number range. However,
it is possible to specify that the command does take a range (the -range
attribute), or that it takes an arbitrary count value, either in the line
@@ -1399,8 +1407,11 @@ Possible values are:
-addr=loaded_buffers Range for loaded buffers
-addr=windows Range for windows
-addr=tabs Range for tab pages
-addr=other other kind of range

Special cases *:command-bang* *:command-bar*

Special cases ~
*:command-bang* *:command-bar*
*:command-register* *:command-buffer*
There are some special cases as well:

@@ -1418,7 +1429,8 @@ replacement text separately.
Note that these arguments can be abbreviated, but that is a deprecated
feature. Use the full name for new scripts.

Replacement text

Replacement text ~

The replacement text for a user defined command is scanned for special escape
sequences, using <...> notation. Escape sequences are replaced with values
@@ -5869,9 +5869,13 @@ uc_add_command(

if (cmp == 0)
if (!force)
// Command can be replaced with "command!" and when sourcing the
// same script again, but only once.
if (!force && (cmd->uc_script_ctx.sc_sid != current_sctx.sc_sid
|| cmd->uc_script_ctx.sc_seq == current_sctx.sc_seq))
EMSG(_("E174: Command already exists: add ! to replace it"));
EMSG2(_("E174: Command already exists: add ! to replace it: %s"),
goto fail;

@@ -90,6 +90,34 @@ func Test_Ambiguous()
delcommand Dothat

func Test_redefine_on_reload()
call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists')
call assert_equal(0, exists(':ExistingCommand'))
source Xcommandexists
call assert_equal(2, exists(':ExistingCommand'))
" Redefining a command when reloading a script is OK.
source Xcommandexists
call assert_equal(2, exists(':ExistingCommand'))

" But redefining in another script is not OK.
call writefile(['command ExistingCommand echo "yes"'], 'Xcommandexists2')
call assert_fails('source Xcommandexists2', 'E174:')
call delete('Xcommandexists2')

" And defining twice in one script is not OK.
delcommand ExistingCommand
call assert_equal(0, exists(':ExistingCommand'))
call writefile([
\ 'command ExistingCommand echo "yes"',
\ 'command ExistingCommand echo "no"',
\ ], 'Xcommandexists')
call assert_fails('source Xcommandexists', 'E174:')
call assert_equal(2, exists(':ExistingCommand'))

call delete('Xcommandexists')
delcommand ExistingCommand

func Test_CmdUndefined()
call assert_fails('Doit', 'E492:')
au CmdUndefined Doit :command Doit let g:didit = 'yes'
@@ -792,6 +792,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */

0 comments on commit 55d4691

Please sign in to comment.
You can’t perform that action at this time.