forked from aniani/vim
patch 8.2.1308: Vim9: accidentally using "x" causes Vim to exit
Problem: Vim9: accidentally using "x" causes Vim to exit. Solution: Disallow using ":x" or "xit" in Vim9 script. (closes #6399)
This commit is contained in:
parent
0aac67a431
commit
ae616494d7
@ -71,16 +71,17 @@ comments start with #. >
|
|||||||
|
|
||||||
The reason is that a double quote can also be the start of a string. In many
|
The reason is that a double quote can also be the start of a string. In many
|
||||||
places, especially halfway an expression with a line break, it's hard to tell
|
places, especially halfway an expression with a line break, it's hard to tell
|
||||||
what the meaning is. To avoid confusion only # comments are recognized.
|
what the meaning is, since both a string and a comment can be followed by
|
||||||
This is the same as in shell scripts and Python programs.
|
arbitrary text. To avoid confusion only # comments are recognized. This is
|
||||||
|
the same as in shell scripts and Python programs.
|
||||||
|
|
||||||
In Vi # is a command to list text with numbers. In Vim9 script you can use
|
In Vi # is a command to list text with numbers. In Vim9 script you can use
|
||||||
`:number` for that. >
|
`:number` for that. >
|
||||||
101number
|
101 number
|
||||||
|
|
||||||
To improve readability there must be a space between a command and the #
|
To improve readability there must be a space between a command and the #
|
||||||
that starts a comment. Note that #{ is the start of a dictionary, therefore
|
that starts a comment. Note that #{ is the start of a dictionary, therefore
|
||||||
it cannot start a comment.
|
it does not start a comment.
|
||||||
|
|
||||||
|
|
||||||
Vim9 functions ~
|
Vim9 functions ~
|
||||||
@ -93,7 +94,7 @@ The syntax is strict, to enforce code that is easy to read and understand.
|
|||||||
|
|
||||||
Compilation is done when the function is first called, or when the
|
Compilation is done when the function is first called, or when the
|
||||||
`:defcompile` command is encountered in the script where the function was
|
`:defcompile` command is encountered in the script where the function was
|
||||||
defined.
|
defined. `:disassemble` also compiles the function.
|
||||||
|
|
||||||
`:def` has no options like `:function` does: "range", "abort", "dict" or
|
`:def` has no options like `:function` does: "range", "abort", "dict" or
|
||||||
"closure". A `:def` function always aborts on an error, does not get a range
|
"closure". A `:def` function always aborts on an error, does not get a range
|
||||||
@ -104,7 +105,7 @@ be used, type checking will then be done at runtime, like with legacy
|
|||||||
functions.
|
functions.
|
||||||
|
|
||||||
Arguments are accessed by name, without "a:". There is no "a:" dictionary or
|
Arguments are accessed by name, without "a:". There is no "a:" dictionary or
|
||||||
"a:000" list.
|
"a:000" list. Just like any other language.
|
||||||
|
|
||||||
Variable arguments are defined as the last argument, with a name and have a
|
Variable arguments are defined as the last argument, with a name and have a
|
||||||
list type, similar to Typescript. For example, a list of numbers: >
|
list type, similar to Typescript. For example, a list of numbers: >
|
||||||
@ -216,29 +217,29 @@ Functions can be called without `:call`: >
|
|||||||
Using `:call` is still possible, but this is discouraged.
|
Using `:call` is still possible, but this is discouraged.
|
||||||
|
|
||||||
A method call without `eval` is possible, so long as the start is an
|
A method call without `eval` is possible, so long as the start is an
|
||||||
identifier or can't be an Ex command. It does NOT work for string constants: >
|
identifier or can't be an Ex command. Examples: >
|
||||||
myList->add(123) # works
|
myList->add(123)
|
||||||
g:myList->add(123) # works
|
g:myList->add(123)
|
||||||
[1, 2, 3]->Process() # works
|
[1, 2, 3]->Process()
|
||||||
#{a: 1, b: 2}->Process() # works
|
#{a: 1, b: 2}->Process()
|
||||||
{'a': 1, 'b': 2}->Process() # works
|
{'a': 1, 'b': 2}->Process()
|
||||||
"foobar"->Process() # does NOT work
|
"foobar"->Process()
|
||||||
("foobar")->Process() # works
|
("foobar")->Process()
|
||||||
'foobar'->Process() # does NOT work
|
'foobar'->Process()
|
||||||
('foobar')->Process() # works
|
('foobar')->Process()
|
||||||
|
|
||||||
In case there is ambiguity between a function name and an Ex command, use ":"
|
In rare case there is ambiguity between a function name and an Ex command, use
|
||||||
to make clear you want to use the Ex command. For example, there is both the
|
":" to make clear you want to use the Ex command. For example, there is both
|
||||||
`:substitute` command and the `substitute()` function. When the line starts
|
the `:substitute` command and the `substitute()` function. When the line
|
||||||
with `substitute(` this will use the function, prepend a colon to use the
|
starts with `substitute(` this will use the function. Prepend a colon to use
|
||||||
command instead: >
|
the command instead: >
|
||||||
:substitute(pattern (replacement (
|
:substitute(pattern (replacement (
|
||||||
|
|
||||||
Note that while variables need to be defined before they can be used,
|
Note that while variables need to be defined before they can be used,
|
||||||
functions can be called before being defined. This is required to be able
|
functions can be called before being defined. This is required to be able
|
||||||
have cyclic dependencies between functions. It is slightly less efficient,
|
have cyclic dependencies between functions. It is slightly less efficient,
|
||||||
since the function has to be looked up by name. And a typo in the function
|
since the function has to be looked up by name. And a typo in the function
|
||||||
name will only be found when the call is executed.
|
name will only be found when the function is called.
|
||||||
|
|
||||||
|
|
||||||
Omitting function() ~
|
Omitting function() ~
|
||||||
@ -347,9 +348,10 @@ No curly braces expansion ~
|
|||||||
|curly-braces-names| cannot be used.
|
|curly-braces-names| cannot be used.
|
||||||
|
|
||||||
|
|
||||||
No :append, :change or :insert ~
|
No :xit, :append, :change or :insert ~
|
||||||
|
|
||||||
These commands are too quickly confused with local variable names.
|
These commands are too easily confused with local variable names. Instead of
|
||||||
|
`:x` or `:xit` you can use `:exit`.
|
||||||
|
|
||||||
|
|
||||||
Comparators ~
|
Comparators ~
|
||||||
|
@ -3176,6 +3176,9 @@ ex_append(exarg_T *eap)
|
|||||||
int vcol;
|
int vcol;
|
||||||
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
|
int empty = (curbuf->b_ml.ml_flags & ML_EMPTY);
|
||||||
|
|
||||||
|
if (not_in_vim9(eap) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
// the ! flag toggles autoindent
|
// the ! flag toggles autoindent
|
||||||
if (eap->forceit)
|
if (eap->forceit)
|
||||||
curbuf->b_p_ai = !curbuf->b_p_ai;
|
curbuf->b_p_ai = !curbuf->b_p_ai;
|
||||||
@ -3317,6 +3320,9 @@ ex_change(exarg_T *eap)
|
|||||||
{
|
{
|
||||||
linenr_T lnum;
|
linenr_T lnum;
|
||||||
|
|
||||||
|
if (not_in_vim9(eap) == FAIL)
|
||||||
|
return;
|
||||||
|
|
||||||
if (eap->line2 >= eap->line1
|
if (eap->line2 >= eap->line1
|
||||||
&& u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
|
&& u_save(eap->line1 - 1, eap->line2 + 1) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
@ -5686,6 +5686,8 @@ ex_stop(exarg_T *eap)
|
|||||||
static void
|
static void
|
||||||
ex_exit(exarg_T *eap)
|
ex_exit(exarg_T *eap)
|
||||||
{
|
{
|
||||||
|
if (not_in_vim9(eap) == FAIL)
|
||||||
|
return;
|
||||||
#ifdef FEAT_CMDWIN
|
#ifdef FEAT_CMDWIN
|
||||||
if (cmdwin_type != 0)
|
if (cmdwin_type != 0)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* vim9script.c */
|
/* vim9script.c */
|
||||||
int in_vim9script(void);
|
int in_vim9script(void);
|
||||||
void ex_vim9script(exarg_T *eap);
|
void ex_vim9script(exarg_T *eap);
|
||||||
|
int not_in_vim9(exarg_T *eap);
|
||||||
void ex_export(exarg_T *eap);
|
void ex_export(exarg_T *eap);
|
||||||
void free_imports(int sid);
|
void free_imports(int sid);
|
||||||
void ex_import(exarg_T *eap);
|
void ex_import(exarg_T *eap);
|
||||||
|
@ -1515,6 +1515,21 @@ def Test_fixed_size_list()
|
|||||||
assert_equal([2, 99, 3, 4, 5], l)
|
assert_equal([2, 99, 3, 4, 5], l)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_no_insert_xit()
|
||||||
|
call CheckDefExecFailure(['x = 1'], 'E1100:')
|
||||||
|
call CheckDefExecFailure(['a = 1'], 'E1100:')
|
||||||
|
call CheckDefExecFailure(['i = 1'], 'E1100:')
|
||||||
|
call CheckDefExecFailure(['c = 1'], 'E1100:')
|
||||||
|
|
||||||
|
CheckScriptFailure(['vim9script', 'x = 1'], 'E1100:')
|
||||||
|
CheckScriptFailure(['vim9script', 'a = 1'], 'E488:')
|
||||||
|
CheckScriptFailure(['vim9script', 'a'], 'E1100:')
|
||||||
|
CheckScriptFailure(['vim9script', 'i = 1'], 'E488:')
|
||||||
|
CheckScriptFailure(['vim9script', 'i'], 'E1100:')
|
||||||
|
CheckScriptFailure(['vim9script', 'c = 1'], 'E488:')
|
||||||
|
CheckScriptFailure(['vim9script', 'c'], 'E1100:')
|
||||||
|
enddef
|
||||||
|
|
||||||
def IfElse(what: number): string
|
def IfElse(what: number): string
|
||||||
let res = ''
|
let res = ''
|
||||||
if what == 1
|
if what == 1
|
||||||
|
@ -754,6 +754,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1308,
|
||||||
/**/
|
/**/
|
||||||
1307,
|
1307,
|
||||||
/**/
|
/**/
|
||||||
|
@ -7409,6 +7409,13 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx)
|
|||||||
|
|
||||||
// TODO: other commands with an expression argument
|
// TODO: other commands with an expression argument
|
||||||
|
|
||||||
|
case CMD_append:
|
||||||
|
case CMD_change:
|
||||||
|
case CMD_insert:
|
||||||
|
case CMD_xit:
|
||||||
|
not_in_vim9(&ea);
|
||||||
|
goto erret;
|
||||||
|
|
||||||
case CMD_SIZE:
|
case CMD_SIZE:
|
||||||
semsg(_("E476: Invalid command: %s"), ea.cmd);
|
semsg(_("E476: Invalid command: %s"), ea.cmd);
|
||||||
goto erret;
|
goto erret;
|
||||||
|
@ -58,13 +58,30 @@ ex_vim9script(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When in Vim9 script give an error and return FAIL.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
not_in_vim9(exarg_T *eap)
|
||||||
|
{
|
||||||
|
switch (eap->cmdidx)
|
||||||
|
{
|
||||||
|
case CMD_insert:
|
||||||
|
case CMD_append:
|
||||||
|
case CMD_change:
|
||||||
|
case CMD_xit:
|
||||||
|
semsg(_("E1100: Missing :let: %s"), eap->cmd);
|
||||||
|
return FAIL;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":export let Name: type"
|
* ":export let Name: type"
|
||||||
* ":export const Name: type"
|
* ":export const Name: type"
|
||||||
* ":export def Name(..."
|
* ":export def Name(..."
|
||||||
* ":export class Name ..."
|
* ":export class Name ..."
|
||||||
*
|
|
||||||
* ":export {Name, ...}"
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ex_export(exarg_T *eap)
|
ex_export(exarg_T *eap)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user