mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
patch 9.2.0573: Vim9: missing EX_WHOLE on some block keywords
Problem: Several Vim9 keywords lack EX_WHOLE and can be shortened in
Vim9 script, inconsistent with endif/enddef/endfor/endwhile/
endtry which already have it. The error from :endd in a
nested function also hardcodes "enddef" instead of reporting
what the user typed. fullcommand("ho") returns "horizontal"
even though :ho is below the documented 3-char minimum.
Solution: Add EX_WHOLE to :class, :def, :endclass, :endinterface,
:endenum, :public and :static. In get_function_body() pass
the user-typed command to the error message. Force :ho to
CMD_SIZE in find_ex_command() so fullcommand() reflects the
modifier minimum. Extend tests and documentation accordingly
(Peter Kenny).
fixes: #20032
closes: #20191
Signed-off-by: Peter Kenny <github.com@k1w1.cyou>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
905312e0e6
commit
38d9a16eba
+16
-8
@@ -1,4 +1,4 @@
|
||||
*builtin.txt* For Vim version 9.2. Last change: 2026 May 21
|
||||
*builtin.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -3672,14 +3672,22 @@ fullcommand({name} [, {vim9}]) *fullcommand()*
|
||||
ambiguous (for user-defined commands) or cannot be shortened
|
||||
this way. |vim9-no-shorten|
|
||||
|
||||
Without the {vim9} argument uses the current script version.
|
||||
If {vim9} is present and FALSE then legacy script rules are
|
||||
used. When {vim9} is present and TRUE then Vim9 rules are
|
||||
used, e.g. "en" is not a short form of "endif".
|
||||
|
||||
For example `fullcommand('s')`, `fullcommand('sub')`,
|
||||
`fullcommand(':%substitute')` all return "substitute".
|
||||
Without the {vim9} argument, the current script version is
|
||||
used. When {vim9} is present and FALSE, legacy script rules
|
||||
are used. When {vim9} is present and TRUE, Vim9 rules are
|
||||
used (e.g., "en" is not a short form of "endif").
|
||||
|
||||
Note: Command validation is not performed. Results depend on
|
||||
Vim's internal command-specific identification rules.
|
||||
Examples:
|
||||
>vim
|
||||
echo [fullcommand('s')] |" ['substitute']
|
||||
echo [fullcommand('sub')] |" ['substitute']
|
||||
echo [fullcommand(': mark word')] |" ['mark']
|
||||
echo [fullcommand(': markword')] |" ['']
|
||||
echo [fullcommand('en')] |" ['endif']
|
||||
echo [fullcommand('en', v:true)] |" ['']
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
GetName()->fullcommand()
|
||||
<
|
||||
|
||||
+18
-14
@@ -1,4 +1,4 @@
|
||||
*change.txt* For Vim version 9.2. Last change: 2026 Mar 31
|
||||
*change.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -75,18 +75,21 @@ For inserting text see |insert.txt|.
|
||||
*:d* *:de* *:del* *:delete* *:dl* *:dp*
|
||||
:[range]d[elete] [x] Delete [range] lines (default: current line) [into
|
||||
register x].
|
||||
Note these weird abbreviations:
|
||||
:dl delete and list
|
||||
:dell idem
|
||||
:delel idem
|
||||
:deletl idem
|
||||
:deletel idem
|
||||
:dp delete and print
|
||||
:dep idem
|
||||
:delp idem
|
||||
:delep idem
|
||||
:deletp idem
|
||||
:deletep idem
|
||||
Note these weird abbreviations applicable only to
|
||||
legacy Vim script:
|
||||
:dl delete and list
|
||||
:dell idem
|
||||
:delel idem
|
||||
:deletl idem
|
||||
:deletel idem
|
||||
:dp delete and print
|
||||
:dep idem
|
||||
:delp idem
|
||||
:delep idem
|
||||
:deletp idem
|
||||
:deletep idem
|
||||
Warning: These give |E492| in |Vim9| script and `:dl`
|
||||
executes as `:dlist`.
|
||||
|
||||
:[range]d[elete] [x] {count}
|
||||
Delete {count} lines, starting with [range]
|
||||
@@ -798,7 +801,8 @@ out then. Example: >
|
||||
:%s/TESTING
|
||||
This deletes "TESTING" from all lines, but only one per line.
|
||||
*E1270*
|
||||
For compatibility with Vi these two exceptions are allowed in legacy script:
|
||||
For compatibility with Vi these two exceptions are allowed in legacy Vim
|
||||
script:
|
||||
"\/{string}/" and "\?{string}?" do the same as "//{string}/r".
|
||||
"\&{string}&" does the same as "//{string}/".
|
||||
*pattern-delimiter* *E146* *E1241* *E1242*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*eval.txt* For Vim version 9.2. Last change: 2026 May 21
|
||||
*eval.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -3384,7 +3384,7 @@ text...
|
||||
s: script-local variables
|
||||
l: local function variables
|
||||
v: Vim variables.
|
||||
This does not work in Vim9 script. |vim9-declaration|
|
||||
This does not work in Vim9 script. |vim9-declaration|
|
||||
|
||||
:let List the values of all variables. The type of the
|
||||
variable is indicated before the value:
|
||||
@@ -3660,7 +3660,7 @@ text...
|
||||
all nested `:try`s inside the loop. The outermost
|
||||
`:endtry` then jumps back to the start of the loop.
|
||||
|
||||
In |Vim9| script `:cont` is the shortest form, to
|
||||
In |Vim9| script `:continue` cannot be shortened, to
|
||||
improve script readability.
|
||||
*:break* *:brea* *E587*
|
||||
:brea[k] When used inside a `:while` or `:for` loop, skips to
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*repeat.txt* For Vim version 9.2. Last change: 2026 Feb 14
|
||||
*repeat.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -454,6 +454,9 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
||||
nested ":try"s in the script. The outermost ":endtry"
|
||||
then stops sourcing the script.
|
||||
|
||||
In |Vim9| script `:finish` cannot be shortened, to
|
||||
improve script readability.
|
||||
|
||||
All commands and command sequences can be repeated by putting them in a named
|
||||
register and then executing it. There are two ways to get the commands in the
|
||||
register:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*tagsrch.txt* For Vim version 9.2. Last change: 2026 May 17
|
||||
*tagsrch.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -833,8 +833,9 @@ CTRL-W i Open a new window, with the cursor on the first line
|
||||
Like `[D` and `]D`, but search in [range] lines
|
||||
(default: whole file).
|
||||
See |:search-args| for [/] and [!].
|
||||
Note that `:dl` works like `:delete` with the "l"
|
||||
flag, not `:dlist`.
|
||||
Note: In legacy Vim script, `:dl` works like
|
||||
`:delete` with the "l" flag, not `:dlist`, whereas in
|
||||
|Vim9| script `:dl` does work like `:dlist`.
|
||||
|
||||
*[_CTRL-D*
|
||||
[ CTRL-D Jump to the first macro definition that contains the
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*userfunc.txt* For Vim version 9.2. Last change: 2026 Feb 14
|
||||
*userfunc.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -27,13 +27,13 @@ make them script-local. If you do use a global function then avoid obvious,
|
||||
short names. A good habit is to start the function name with the name of the
|
||||
script, e.g., "HTMLcolor()".
|
||||
|
||||
In legacy script it is also possible to use curly braces, see
|
||||
In legacy Vim script it is also possible to use curly braces, see
|
||||
|curly-braces-names|.
|
||||
|
||||
The |autoload| facility is useful to define a function only when it's called.
|
||||
|
||||
*local-function*
|
||||
A function local to a legacy script must start with "s:". A local script
|
||||
A function local to a legacy Vim script must start with "s:". A local script
|
||||
function can only be called from within the script and from functions, user
|
||||
commands and autocommands defined in the script. It is also possible to call
|
||||
the function from a mapping defined in the script, but then |<SID>| must be
|
||||
@@ -195,9 +195,19 @@ See |:verbose-cmd| for more information.
|
||||
When a function ends without an explicit ":return",
|
||||
the number 0 is returned.
|
||||
|
||||
In a :def function *E1095* is given if unreachable
|
||||
code follows after the `:return`.
|
||||
In legacy script there is no check for unreachable
|
||||
In |Vim9| script:
|
||||
- `:return` cannot be shortened, and
|
||||
- *E1095* is given if unreachable code follows after
|
||||
the `:return`. For example:
|
||||
>vim9
|
||||
vim9script
|
||||
var L: func = (): bool => {
|
||||
return false
|
||||
echo 'no' # E1095: Unreachable code after :return
|
||||
}
|
||||
echo L()
|
||||
<
|
||||
In legacy Vim script there is no check for unreachable
|
||||
lines, thus there is no warning if commands follow
|
||||
`:return`. Also, there is no check if the following
|
||||
line contains a valid command. Forgetting the line
|
||||
|
||||
+12
-5
@@ -1,9 +1,7 @@
|
||||
*usr_20.txt* For Vim version 9.2. Last change: 2026 Feb 14
|
||||
|
||||
*usr_20.txt* For Vim version 9.2. Last change: 2026 May 31
|
||||
|
||||
VIM USER MANUAL by Bram Moolenaar
|
||||
|
||||
|
||||
Typing command-line commands quickly
|
||||
|
||||
|
||||
@@ -116,9 +114,18 @@ command. It's like deleting the ":" or "/" that the line starts with.
|
||||
*20.2* Command line abbreviations
|
||||
|
||||
Some of the ":" commands are really long. We already mentioned that
|
||||
":substitute" can be abbreviated to ":s". This is a generic mechanism, all
|
||||
":" commands can be abbreviated.
|
||||
":substitute" can be abbreviated to ":s". This is a generic mechanism, and
|
||||
most ":" commands can be abbreviated. However, in Vim9 script some commands
|
||||
cannot be shortened to improve readability - see |vim9-no-shorten|.
|
||||
|
||||
The builtin function |fullcommand()| can be used to return an abbreviated
|
||||
command's full name. For example, the following commands echo "edit", "echo",
|
||||
and "echowindow":
|
||||
>vim
|
||||
:echo fullcommand('e')
|
||||
:echo fullcommand('ec')
|
||||
:echo fullcommand('echow')
|
||||
<
|
||||
How short can a command get? There are 26 letters, and many more commands.
|
||||
For example, ":set" also starts with ":s", but ":s" doesn't start a ":set"
|
||||
command. Instead ":set" can be abbreviated to ":se".
|
||||
|
||||
+7
-7
@@ -362,7 +362,7 @@ EXCMD(CMD_clast, "clast", ex_cc,
|
||||
EX_RANGE|EX_COUNT|EX_TRLBAR|EX_BANG,
|
||||
ADDR_UNSIGNED),
|
||||
EXCMD(CMD_class, "class", ex_class,
|
||||
EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||
EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_close, "close", ex_close,
|
||||
EX_BANG|EX_RANGE|EX_COUNT|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
@@ -470,7 +470,7 @@ EXCMD(CMD_debuggreedy, "debuggreedy", ex_debuggreedy,
|
||||
EX_RANGE|EX_ZEROR|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
ADDR_OTHER),
|
||||
EXCMD(CMD_def, "def", ex_function,
|
||||
EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
|
||||
EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_defcompile, "defcompile", ex_defcompile,
|
||||
EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_TRLBAR|EX_EXTRA,
|
||||
@@ -575,16 +575,16 @@ EXCMD(CMD_endif, "endif", ex_endif,
|
||||
EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_endinterface, "endinterface", ex_wrongmodifier,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_endclass, "endclass", ex_wrongmodifier,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_enddef, "enddef", ex_endfunction,
|
||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_endenum, "endenum", ex_wrongmodifier,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_endfunction, "endfunction", ex_endfunction,
|
||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
@@ -1229,7 +1229,7 @@ EXCMD(CMD_put, "put", ex_put,
|
||||
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_REGSTR|EX_TRLBAR|EX_ZEROR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
|
||||
ADDR_LINES),
|
||||
EXCMD(CMD_public, "public", ex_wrongmodifier,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_pwd, "pwd", ex_pwd,
|
||||
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
@@ -1508,7 +1508,7 @@ EXCMD(CMD_startreplace, "startreplace", ex_startinsert,
|
||||
EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_static, "static", ex_wrongmodifier,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
|
||||
ADDR_NONE),
|
||||
EXCMD(CMD_stopinsert, "stopinsert", ex_stopinsert,
|
||||
EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
|
||||
|
||||
@@ -4025,6 +4025,13 @@ find_ex_command(
|
||||
if (eap->cmdidx == CMD_final && p - eap->cmd == 4 && !vim9)
|
||||
eap->cmdidx = CMD_finally;
|
||||
|
||||
// Force ":ho" to be unresolved. Without this, find_ex_command()
|
||||
// matches it to CMD_horizontal (the only "ho*" entry), which makes
|
||||
// fullcommand("ho") return "horizontal" even though ":ho" cannot be
|
||||
// used as the modifier (cmdmods[] requires 3 chars, "hor").
|
||||
if (eap->cmdidx == CMD_horizontal && p - eap->cmd == 2)
|
||||
eap->cmdidx = CMD_SIZE;
|
||||
|
||||
#ifdef FEAT_EVAL
|
||||
if (eap->cmdidx < CMD_SIZE
|
||||
&& vim9
|
||||
|
||||
@@ -50,12 +50,18 @@ def Test_cmdmods_array()
|
||||
enddef
|
||||
|
||||
def Test_keep_cmdmods_names()
|
||||
# :k only available in legacy script
|
||||
legacy call assert_equal('k', fullcommand(':k'))
|
||||
legacy call assert_equal('k', fullcommand(':ke'))
|
||||
# single character commands not supported in Vim9
|
||||
assert_equal('', fullcommand(':k'))
|
||||
assert_equal('keepmarks', fullcommand(':ke'))
|
||||
# :k is only available in legacy Vim script
|
||||
assert_equal('k', fullcommand(':k', false))
|
||||
# many single character commands are not supported in Vim9 script, incl. :k
|
||||
assert_equal('', fullcommand(':k', true))
|
||||
# :k{a-zA-Z'} in legacy Vim script
|
||||
assert_equal('k', fullcommand(':ka', false))
|
||||
assert_equal('', fullcommand(':ka', true))
|
||||
# :ke is an exception - it is 'keepmarks', not 'k', in Vim9 script
|
||||
assert_equal('k', fullcommand(':ke', false))
|
||||
assert_equal('keepmarks', fullcommand(':ke', true))
|
||||
# :kee* shortenings
|
||||
assert_equal('keepmarks', fullcommand(':kee', false))
|
||||
assert_equal('keepmarks', fullcommand(':kee'))
|
||||
assert_equal('keepmarks', fullcommand(':keep'))
|
||||
assert_equal('keepmarks', fullcommand(':keepm'))
|
||||
@@ -63,14 +69,17 @@ def Test_keep_cmdmods_names()
|
||||
assert_equal('keepmarks', fullcommand(':keepmar'))
|
||||
assert_equal('keepmarks', fullcommand(':keepmark'))
|
||||
assert_equal('keepmarks', fullcommand(':keepmarks'))
|
||||
assert_equal('keepalt', fullcommand(':keepa', false))
|
||||
assert_equal('keepalt', fullcommand(':keepa'))
|
||||
assert_equal('keepalt', fullcommand(':keepal'))
|
||||
assert_equal('keepalt', fullcommand(':keepalt'))
|
||||
assert_equal('keepjumps', fullcommand(':keepj', false))
|
||||
assert_equal('keepjumps', fullcommand(':keepj'))
|
||||
assert_equal('keepjumps', fullcommand(':keepju'))
|
||||
assert_equal('keepjumps', fullcommand(':keepjum'))
|
||||
assert_equal('keepjumps', fullcommand(':keepjump'))
|
||||
assert_equal('keepjumps', fullcommand(':keepjumps'))
|
||||
assert_equal('keeppatterns', fullcommand(':keepp', false))
|
||||
assert_equal('keeppatterns', fullcommand(':keepp'))
|
||||
assert_equal('keeppatterns', fullcommand(':keeppa'))
|
||||
assert_equal('keeppatterns', fullcommand(':keeppat'))
|
||||
|
||||
@@ -254,7 +254,14 @@ func Test_marks_k_cmd()
|
||||
call setline(1, ['foo', 'bar', 'baz', 'qux'])
|
||||
1,3kr
|
||||
call assert_equal([0, 3, 1, 0], getpos("'r"))
|
||||
" whitespace before mark
|
||||
4k f
|
||||
call assert_equal([0, 4, 1, 0], getpos("'f"))
|
||||
:2 k g
|
||||
call assert_equal([0, 2, 1, 0], getpos("'g"))
|
||||
bw!
|
||||
call assert_fails(':kz7', 'E488: Trailing characters: z7')
|
||||
call assert_fails(':execute ":k^"', 'E191: Argument must be a letter or forward/backward quote')
|
||||
endfunc
|
||||
|
||||
" Test for file marks (A-Z)
|
||||
|
||||
@@ -42,7 +42,8 @@ def Test_class_basic()
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E475: Invalid argument: classy Something', 2)
|
||||
|
||||
# The complete "endclass" should be specified.
|
||||
# Test for "endclass" cannot be shortened. Test_shortened_invalid_vim9() in
|
||||
# test_vim9_script.vim has complete coverage (:endc to :endclas)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class Something
|
||||
@@ -50,7 +51,7 @@ def Test_class_basic()
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: endcl', 3)
|
||||
|
||||
# "endclass" cannot be shortened (variant incl. whitespace and colon)
|
||||
# "endclass" cannot be shortened (variant incl. colon-whitespace)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class Something
|
||||
@@ -1361,13 +1362,14 @@ def Test_instance_variable_access()
|
||||
echo Foo.new()
|
||||
.Add(1).Add(2).x
|
||||
echo Foo.new()
|
||||
.Add(1)
|
||||
.Add(1)
|
||||
.Add(2)
|
||||
.x
|
||||
END
|
||||
v9.CheckSourceSuccess(lines)
|
||||
|
||||
# Test for "public" cannot be abbreviated
|
||||
# Test for "public" cannot be shortened. Test_shortened_invalid_vim9() in
|
||||
# test_vim9_script.vim has complete coverage (:pub to :publi)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class Something
|
||||
@@ -1460,7 +1462,8 @@ enddef
|
||||
|
||||
" Test for class variable access
|
||||
def Test_class_variable_access()
|
||||
# Test for "static" cannot be abbreviated
|
||||
# Test for "static" cannot be shortened. Test_shortened_invalid_vim9() in
|
||||
# test_vim9_script.vim has complete coverage (:stat and :stati)
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
class Something
|
||||
@@ -2951,7 +2954,8 @@ def Test_abstract_class()
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E1316: Class can only be defined in Vim9 script', 1)
|
||||
|
||||
# Test for "abstract" cannot be abbreviated
|
||||
# Test for "abstract" cannot be shortened. Test_shortened_invalid_vim9() in
|
||||
# test_vim9_script.vim has complete coverage (:abs to :abstrac)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
abs class A
|
||||
@@ -5580,15 +5584,6 @@ def Test_abstract_method()
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E1404: Abstract cannot be used in an interface', 3)
|
||||
|
||||
# Abbreviate the "abstract" keyword
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
class A
|
||||
abs def Foo()
|
||||
endclass
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: abs def Foo()', 3)
|
||||
|
||||
# Use "abstract" with a member variable
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
|
||||
@@ -389,6 +389,12 @@ def Test_endfunc_enddef()
|
||||
enddef there
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1173: Text found after enddef: there', 6)
|
||||
|
||||
lines =<< trim END
|
||||
def ShortEnddef()
|
||||
endd
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1065: Command cannot be shortened: endd', 2)
|
||||
enddef
|
||||
|
||||
def Test_missing_endfunc_enddef()
|
||||
|
||||
@@ -86,7 +86,7 @@ def Test_interface_basics()
|
||||
END
|
||||
v9.CheckSourceFailure(lines, 'E1065: Command cannot be shortened: endin', 3)
|
||||
|
||||
# "endinterface" cannot be shortened (variant incl. whitespace and colon)
|
||||
# "endinterface" cannot be shortened (variant incl. colon-whitespace)
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
interface Short
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import './util/vim9.vim' as v9
|
||||
source util/screendump.vim
|
||||
|
||||
" Test for has('vim9script')
|
||||
def Test_vim9script_feature()
|
||||
# example from the help, here the feature is always present
|
||||
var lines =<< trim END
|
||||
@@ -1216,7 +1217,7 @@ def Test_error_in_catch()
|
||||
v9.CheckDefExecFailure(lines, 'E684:', 4)
|
||||
enddef
|
||||
|
||||
" :while at the very start of a function that :continue jumps to
|
||||
" Test for :while at the very start of a function that :continue jumps to
|
||||
def s:TryContinueFunc()
|
||||
while g:Count < 2
|
||||
g:sequence ..= 't'
|
||||
@@ -1330,8 +1331,8 @@ def Test_nocatch_throw_silenced()
|
||||
source XthrowSilenced
|
||||
enddef
|
||||
|
||||
" g:DeletedFunc() is found when compiling Test_try_catch_throw() and then
|
||||
" deleted, this should give a runtime error.
|
||||
" Test for g:DeletedFunc() is found when compiling Test_try_catch_throw() and
|
||||
" then deleted, this should give a runtime error.
|
||||
def DeletedFunc(): list<any>
|
||||
return ['delete me']
|
||||
enddef
|
||||
@@ -1522,7 +1523,7 @@ def Try_catch_skipped()
|
||||
endif
|
||||
enddef
|
||||
|
||||
" The skipped try/endtry was updating the wrong instruction.
|
||||
" Test for when the skipped try/endtry was updating the wrong instruction.
|
||||
def Test_try_catch_skipped()
|
||||
var instr = execute('disassemble Try_catch_skipped')
|
||||
assert_match("NEWLIST size 0\n", instr)
|
||||
@@ -4376,62 +4377,144 @@ def Run_test_reject_declaration()
|
||||
g:StopVimInTerminal(buf)
|
||||
enddef
|
||||
|
||||
def Test_minimal_command_name_length()
|
||||
var names = [
|
||||
'cons',
|
||||
'brea',
|
||||
'cat',
|
||||
'catc',
|
||||
'con',
|
||||
'cont',
|
||||
'conti',
|
||||
'contin',
|
||||
'continu',
|
||||
'el',
|
||||
'els',
|
||||
'elsei',
|
||||
'endfo',
|
||||
'en',
|
||||
'end',
|
||||
'endi',
|
||||
'endw',
|
||||
'endt',
|
||||
'endtr',
|
||||
'exp',
|
||||
'expo',
|
||||
'expor',
|
||||
'fina',
|
||||
'finall',
|
||||
'fini',
|
||||
'finis',
|
||||
'imp',
|
||||
'impo',
|
||||
'impor',
|
||||
'retu',
|
||||
'retur',
|
||||
'th',
|
||||
'thr',
|
||||
'thro',
|
||||
'wh',
|
||||
'whi',
|
||||
'whil',
|
||||
]
|
||||
for name in names
|
||||
v9.CheckDefAndScriptFailure([name .. ' '], 'E1065:')
|
||||
" Test shortened commands that are invalid in Vim9 script
|
||||
def Test_shortened_invalid_vim9()
|
||||
# Many Vim9 script commands cannot be shortened/abbreviated.
|
||||
# SHORTENED is a list of dicts, each with a single key (the exact shortened
|
||||
# command) and a list value with four items:
|
||||
# [0] list<string> Lines passed to the check function (without 'vim9script'
|
||||
# for SourceFailure lines)
|
||||
# [1] number Line number where the error is expected ('vimscript',
|
||||
# which is not in the list, is line 1 in the
|
||||
# 'SourceFailure' and 'DefFailure lines, so needs to be
|
||||
# included in the count)
|
||||
# [2] string 'DefAndScriptFailure', 'SourceFailure', or 'DefFailure'
|
||||
# specifying the applicable 'Check' function to call
|
||||
const SHORTENED: list<dict<list<any>>> = [
|
||||
# abstract
|
||||
{abs: [['abs class A'], 1, 'DefAndScriptFailure']},
|
||||
{abst: [['abst class A'], 1, 'DefAndScriptFailure']},
|
||||
{abstr: [['abstr class A'], 1, 'DefAndScriptFailure']},
|
||||
{abstra: [['abstra class A'], 1, 'DefAndScriptFailure']},
|
||||
{abstrac: [['abstrac class A'], 1, 'DefAndScriptFailure']},
|
||||
# break
|
||||
{brea: [['for k in range(0, 2)', 'brea', 'endfor'], 2, 'DefAndScriptFailure']},
|
||||
# catch
|
||||
{cat: [['try', 'echo 0', 'cat'], 3, 'DefAndScriptFailure']},
|
||||
{catc: [['try', 'echo 0', 'catc'], 3, 'DefAndScriptFailure']},
|
||||
# class - n/a because :clas is :clast
|
||||
# const
|
||||
{cons: [['cons C = 0'], 1, 'DefAndScriptFailure']},
|
||||
# continue
|
||||
{con: [['var n: number', 'while n < 9', '++n', 'con'], 4, 'DefAndScriptFailure']},
|
||||
{cont: [['var n: number', 'while n < 9', '++n', 'cont'], 4, 'DefAndScriptFailure']},
|
||||
{conti: [['var n: number', 'while n < 9', '++n', 'conti'], 4, 'DefAndScriptFailure']},
|
||||
{contin: [['var n: number', 'while n < 9', '++n', 'contin'], 4, 'DefAndScriptFailure']},
|
||||
{continu: [['var n: number', 'while n < 9', '++n', 'continu'], 4, 'DefAndScriptFailure']},
|
||||
# def has no applicable shortened form (:de is :delete)
|
||||
# else
|
||||
{els: [['if true', 'els'], 2, 'DefAndScriptFailure']},
|
||||
# elseif
|
||||
{elsei: [['if true', 'elsei false'], 2, 'DefAndScriptFailure']},
|
||||
# endclass
|
||||
{endc: [['class C', 'endc'], 3, 'SourceFailure']},
|
||||
{endcl: [['class C', 'endcl'], 3, 'SourceFailure']},
|
||||
{endcla: [['class C', 'endcla'], 3, 'SourceFailure']},
|
||||
{endclas: [['class C', 'endclas'], 3, 'SourceFailure']},
|
||||
# enddef
|
||||
# (NB: The separate DefFailure check tests them nested -
|
||||
# DefAndScriptFailure cannot be used for testing :endd[e])
|
||||
{endd: [['def D()', 'endd'], 3, 'SourceFailure']},
|
||||
{endde: [['def D()', 'endde'], 3, 'SourceFailure']},
|
||||
{endd: [['var R: func = (): bool => {', 'def D()', 'endd', '}'], 4, 'DefFailure']},
|
||||
{endde: [['var R: func = (): bool => {', 'def D()', 'endde', '}'], 4, 'DefFailure']},
|
||||
# endenum
|
||||
{ende: [['enum E', 'ende'], 3, 'SourceFailure']},
|
||||
{enden: [['enum E', 'enden'], 3, 'SourceFailure']},
|
||||
{endenu: [['enum E', 'endenu'], 3, 'SourceFailure']},
|
||||
# endfor
|
||||
{endfo: [['for n in range(0, 2)', 'endfo'], 2, 'DefAndScriptFailure']},
|
||||
# endif
|
||||
{en: [['if true', 'en'], 2, 'DefAndScriptFailure']},
|
||||
{end: [['if true', 'end'], 2, 'DefAndScriptFailure']},
|
||||
{endi: [['if true', 'endi'], 2, 'DefAndScriptFailure']},
|
||||
# endinterface
|
||||
{endin: [['interface I', 'endin'], 3, 'SourceFailure']},
|
||||
{endint: [['interface I', 'endint'], 3, 'SourceFailure']},
|
||||
{endinte: [['interface I', 'endinte'], 3, 'SourceFailure']},
|
||||
{endinter: [['interface I', 'endinter'], 3, 'SourceFailure']},
|
||||
{endinterf: [['interface I', 'endinterf'], 3, 'SourceFailure']},
|
||||
{endinterfa: [['interface I', 'endinterfa'], 3, 'SourceFailure']},
|
||||
{endinterfac: [['interface I', 'endinterfac'], 3, 'SourceFailure']},
|
||||
# endtry
|
||||
{endt: [['try', 'echo 0', 'endt'], 3, 'DefAndScriptFailure']},
|
||||
{endtr: [['try', 'echo 0', 'endtr'], 3, 'DefAndScriptFailure']},
|
||||
# endwhile
|
||||
{endw: [['var n = 9', 'while n > 0', '--n', 'endw'], 4, 'DefAndScriptFailure']},
|
||||
{endwh: [['var n = 9', 'while n > 0', '--n', 'endwh'], 4, 'DefAndScriptFailure']},
|
||||
{endwhi: [['var n = 9', 'while n > 0', '--n', 'endwhi'], 4, 'DefAndScriptFailure']},
|
||||
{endwhil: [['var n = 9', 'while n > 0', '--n', 'endwhil'], 4, 'DefAndScriptFailure']},
|
||||
# enum
|
||||
{enu: [['enu E', 'endenum'], 2, 'SourceFailure']},
|
||||
# export
|
||||
{exp: [['exp var b: bool'], 2, 'SourceFailure']},
|
||||
{expo: [['expo var b: bool'], 2, 'SourceFailure']},
|
||||
{expor: [['expor var b: bool'], 2, 'SourceFailure']},
|
||||
# final has no applicable shortened form (because :fina is short for :finally)
|
||||
# finally
|
||||
{fina: [['try', '# Do something', 'fina'], 3, 'DefAndScriptFailure']},
|
||||
# finish
|
||||
{fini: [['fini'], 1, 'DefAndScriptFailure']},
|
||||
# import
|
||||
{imp: [['imp $"{$VIMRUNTIME}/autoload/ccomplete.vim"'], 2, 'SourceFailure']},
|
||||
{impo: [['impo $"{$VIMRUNTIME}/autoload/ccomplete.vim"'], 2, 'SourceFailure']},
|
||||
{impor: [['impor $"{$VIMRUNTIME}/autoload/ccomplete.vim"'], 2, 'SourceFailure']},
|
||||
# interface
|
||||
{inte: [['inte I', 'endinterface'], 2, 'SourceFailure']},
|
||||
{inter: [['inter I', 'endinterface'], 2, 'SourceFailure']},
|
||||
{interf: [['interf I', 'endinterface'], 2, 'SourceFailure']},
|
||||
{interfa: [['interfa I', 'endinterface'], 2, 'SourceFailure']},
|
||||
{interfac: [['interfac I', 'endinterface'], 2, 'SourceFailure']},
|
||||
# public
|
||||
{pub: [['class P', 'pub var b: bool', 'endclass'], 3, 'SourceFailure']},
|
||||
{publ: [['class P', 'publ var b: bool', 'endclass'], 3, 'SourceFailure']},
|
||||
{publi: [['class P', 'publi var b: bool', 'endclass'], 3, 'SourceFailure']},
|
||||
# return (NB: line is 0 - for CheckDefAndScriptFailure the first line of the Vim9 script lambda function is considered 0)
|
||||
{retu: [['var R: func = (): bool => {', 'retu false', '}'], 0, 'DefAndScriptFailure']},
|
||||
{retur: [['var R: func = (): bool => {', 'retur false', '}'], 0, 'DefAndScriptFailure']},
|
||||
# static
|
||||
{stat: [['class S', 'stat var b: bool', 'endclass'], 3, 'SourceFailure']},
|
||||
{stati: [['class S', 'stati var b: bool', 'endclass'], 3, 'SourceFailure']},
|
||||
# this
|
||||
{thi: [['thi'], 1, 'DefAndScriptFailure']},
|
||||
# throw
|
||||
{th: [['try', 'th 9', 'catch 9', 'echo "Should give E1065"', 'thr'], 2, 'DefAndScriptFailure']},
|
||||
{thr: [['try', 'thr 9', 'catch 9', 'echo "Should give E1065"', 'thr'], 2, 'DefAndScriptFailure']},
|
||||
{thro: [['try', 'thro 9', 'catch 9', 'echo "Should give E1065"', 'thro'], 2, 'DefAndScriptFailure']},
|
||||
# type
|
||||
{ty: [['ty ListOfBools = list<bool>'], 1, 'DefAndScriptFailure']},
|
||||
{typ: [['typ ListOfBools = list<bool>'], 1, 'DefAndScriptFailure']},
|
||||
# var
|
||||
{va: [['va b: bool'], 1, 'DefAndScriptFailure']},
|
||||
# while
|
||||
{wh: [['var n = 9', 'wh n > 0', '--n', 'endwhile'], 2, 'DefAndScriptFailure']},
|
||||
{whi: [['var n = 9', 'whi n > 0', '--n', 'endwhile'], 2, 'DefAndScriptFailure']},
|
||||
{whil: [['var n = 9', 'whil n > 0', '--n', 'endwhile'], 2, 'DefAndScriptFailure']},
|
||||
]
|
||||
for short in SHORTENED
|
||||
const CMD: string = short->keys()[0]
|
||||
const LINES: list<string> = short[CMD][0]
|
||||
const E1065: string = "E1065: Command cannot be shortened: " .. CMD
|
||||
const LNUM: number = short[CMD][1]
|
||||
const CHECK: string = short[CMD][2]
|
||||
if CHECK == 'SourceFailure'
|
||||
v9.CheckSourceFailure(['vim9script', LINES]->flattennew(), E1065, LNUM)
|
||||
elseif CHECK == 'DefAndScriptFailure'
|
||||
v9.CheckDefAndScriptFailure(LINES, E1065, LNUM)
|
||||
elseif CHECK == 'DefFailure'
|
||||
v9.CheckDefFailure(LINES, E1065, LNUM)
|
||||
endif
|
||||
endfor
|
||||
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
def SomeFunc()
|
||||
endd
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1065:')
|
||||
lines =<< trim END
|
||||
vim9script
|
||||
def SomeFunc()
|
||||
endde
|
||||
END
|
||||
v9.CheckScriptFailure(lines, 'E1065:')
|
||||
enddef
|
||||
|
||||
def Test_unset_any_variable()
|
||||
@@ -5792,27 +5875,6 @@ def Test_type_func_with_void()
|
||||
v9.CheckSourceFailure(lines, 'E1031: Cannot use void value', 4)
|
||||
enddef
|
||||
|
||||
" Keep this last, it messes up highlighting.
|
||||
def Test_substitute_cmd()
|
||||
new
|
||||
setline(1, 'something')
|
||||
:substitute(some(other(
|
||||
assert_equal('otherthing', getline(1))
|
||||
bwipe!
|
||||
|
||||
# also when the context is Vim9 script
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
new
|
||||
setline(1, 'something')
|
||||
:substitute(some(other(
|
||||
assert_equal('otherthing', getline(1))
|
||||
bwipe!
|
||||
END
|
||||
writefile(lines, 'Xvim9lines', 'D')
|
||||
source Xvim9lines
|
||||
enddef
|
||||
|
||||
def Test_call_stack_string()
|
||||
CheckScreendump
|
||||
var lines =<< trim END
|
||||
@@ -5994,4 +6056,66 @@ def Test_if_false_elseif_true_still_takes_elseif()
|
||||
v9.CheckScriptSuccess(lines)
|
||||
enddef
|
||||
|
||||
" Test for correct fullcommand() outputs: return the correct command (or '')
|
||||
def Test_builtin_fullcommand()
|
||||
# :hor is the minimum abbreviation of :horizontal; :ho is invalid
|
||||
assert_equal('', fullcommand('ho', true))
|
||||
assert_equal('horizontal', fullcommand('hor', true))
|
||||
|
||||
# :k is an invalid one-letter command in Vim9 script
|
||||
assert_equal('', fullcommand('k', true))
|
||||
assert_equal('', fullcommand(':k', true))
|
||||
assert_equal('', fullcommand('karrrrrgh!', true))
|
||||
assert_equal('k', fullcommand('k', false))
|
||||
assert_equal('k', fullcommand(':k', false))
|
||||
assert_equal('k', fullcommand('karrrrrgh!', false))
|
||||
|
||||
# :dl is "delete and list" in legacy Vim script but, because :dl itself is
|
||||
# invalid in Vim9 script, :dl is 'dlist' in Vim9 script
|
||||
assert_equal('delete', fullcommand('dl', v:false))
|
||||
assert_equal('dlist', fullcommand('dl', v:true))
|
||||
|
||||
# Substitute :s two and three letter commands in legacy Vim script are
|
||||
# invalid in Vim9 script
|
||||
assert_equal('', fullcommand('sIr', true))
|
||||
assert_equal('', fullcommand('sIrarrrrrgh!', true))
|
||||
assert_equal('substitute', fullcommand('sIr', false))
|
||||
assert_equal('substitute', fullcommand('sIrarrrrrgh!', false))
|
||||
|
||||
# Three :s? commands are exceptionss, returning different commands depending
|
||||
# on whether the scope is legacy Vim script or Vim9 script
|
||||
assert_equal('scriptnames', fullcommand('sc', true))
|
||||
assert_equal('simalt', fullcommand('si', true))
|
||||
assert_equal('srewind', fullcommand('sr', true))
|
||||
assert_equal('substitute', fullcommand('sc', false))
|
||||
assert_equal('substitute', fullcommand('si', false))
|
||||
assert_equal('substitute', fullcommand('sr', false))
|
||||
|
||||
# :finally cannot be shortened in Vim9 script but :final should return 'final'
|
||||
assert_equal('', fullcommand('fina', true))
|
||||
assert_equal('final', fullcommand('final', true))
|
||||
assert_equal('', fullcommand('finall', true))
|
||||
enddef
|
||||
|
||||
" Keep this last, it messes up highlighting.
|
||||
def Test_substitute_cmd()
|
||||
new
|
||||
setline(1, 'something')
|
||||
:substitute(some(other(
|
||||
assert_equal('otherthing', getline(1))
|
||||
bwipe!
|
||||
|
||||
# also when the context is Vim9 script
|
||||
var lines =<< trim END
|
||||
vim9script
|
||||
new
|
||||
setline(1, 'something')
|
||||
:substitute(some(other(
|
||||
assert_equal('otherthing', getline(1))
|
||||
bwipe!
|
||||
END
|
||||
writefile(lines, 'Xvim9lines', 'D')
|
||||
source Xvim9lines
|
||||
enddef
|
||||
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
||||
@@ -7702,6 +7702,33 @@ func Test_function_long_generic_name()
|
||||
delfunc TestFunc
|
||||
endfunc
|
||||
|
||||
" Test using fullcommand() {{{1
|
||||
func Test_builtin_fullcommand()
|
||||
" :hor is the minimum abbreviation of :horizontal; :ho is invalid
|
||||
call assert_equal('', fullcommand('ho'))
|
||||
call assert_equal('horizontal', fullcommand('hor'))
|
||||
|
||||
" :k takes one {a-zA-Z'} mark argument and optional whitespace
|
||||
call assert_equal('k', fullcommand('k'))
|
||||
call assert_equal('k', fullcommand(':k'))
|
||||
call assert_equal('k', fullcommand('karrrrrgh!'))
|
||||
|
||||
" :dl is "delete and list" in a legacy Vim script scope
|
||||
call assert_equal('delete', fullcommand('dl'))
|
||||
|
||||
" :s two and three letter commands
|
||||
call assert_equal('substitute', fullcommand('sIr'))
|
||||
call assert_equal('substitute', fullcommand('sIrarrrrrgh!'))
|
||||
|
||||
" :finally
|
||||
call assert_equal('finally', fullcommand('fina'))
|
||||
" 'final' - returns 'final', a Vim9 script-exclusive keyword
|
||||
" - is a valid shortening of :finally in legacy Vim script
|
||||
call assert_equal('final', fullcommand('final'))
|
||||
call assert_equal('finally', fullcommand('finall'))
|
||||
|
||||
endfunc
|
||||
|
||||
"-------------------------------------------------------------------------------
|
||||
" Modelines {{{1
|
||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||
|
||||
+1
-1
@@ -1132,7 +1132,7 @@ get_function_body(
|
||||
{
|
||||
if (!nesting_inline[nesting] && nesting_def[nesting]
|
||||
&& p < cmd + 6)
|
||||
semsg(_(e_command_cannot_be_shortened_str), "enddef");
|
||||
semsg(_(e_command_cannot_be_shortened_str), cmd);
|
||||
if (nesting-- == 0)
|
||||
{
|
||||
char_u *nextcmd = NULL;
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
573,
|
||||
/**/
|
||||
572,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user