Skip to content

Commit b5b9480

Browse files
committed
patch 8.2.2138: Vim9: "exit_cb" causes Vim to exit
Problem: Vim9: "exit_cb" causes Vim to exit. Solution: Require white space after a command in Vim9 script. (closes #7467) Also fix that Vim9 style heredoc was not always recognized.
1 parent e498429 commit b5b9480

8 files changed

Lines changed: 59 additions & 18 deletions

File tree

src/errors.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,8 @@ EXTERN char e_indexable_type_required[]
316316
EXTERN char e_non_empty_string_required[]
317317
INIT(= N_("E1142: Non-empty string required"));
318318
EXTERN char e_empty_expression_str[]
319-
INIT(= N_("E1143: empty expression: \"%s\""));
319+
INIT(= N_("E1143: Empty expression: \"%s\""));
320+
EXTERN char e_command_not_followed_by_white_space_str[]
321+
INIT(= N_("E1144: Command is not followed by white space: %s"));
322+
EXTERN char e_missing_heredoc_end_marker_str[]
323+
INIT(= N_("E1145: Missing heredoc end marker: %s"));

src/ex_cmds.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#define EX_LOCK_OK 0x1000000 // command can be executed when textlock is
5656
// set; when missing disallows editing another
5757
// buffer when curbuf_lock is set
58+
#define EX_NONWHITE_OK 0x2000000 // command can be followed by non-white
5859

5960
#define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed
6061
#define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file
@@ -632,7 +633,7 @@ EXCMD(CMD_function, "function", ex_function,
632633
EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
633634
ADDR_NONE),
634635
EXCMD(CMD_global, "global", ex_global,
635-
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
636+
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
636637
ADDR_LINES),
637638
EXCMD(CMD_goto, "goto", ex_goto,
638639
EX_RANGE|EX_COUNT|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1277,7 +1278,7 @@ EXCMD(CMD_rviminfo, "rviminfo", ex_viminfo,
12771278
EX_BANG|EX_FILE1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
12781279
ADDR_NONE),
12791280
EXCMD(CMD_substitute, "substitute", ex_substitute,
1280-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK,
1281+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
12811282
ADDR_LINES),
12821283
EXCMD(CMD_sNext, "sNext", ex_previous,
12831284
EX_EXTRA|EX_RANGE|EX_COUNT|EX_BANG|EX_CMDARG|EX_ARGOPT|EX_TRLBAR,
@@ -1652,7 +1653,7 @@ EXCMD(CMD_update, "update", ex_update,
16521653
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR,
16531654
ADDR_LINES),
16541655
EXCMD(CMD_vglobal, "vglobal", ex_global,
1655-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK,
1656+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
16561657
ADDR_LINES),
16571658
EXCMD(CMD_var, "var", ex_var,
16581659
EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1792,16 +1793,16 @@ EXCMD(CMD_z, "z", ex_z,
17921793

17931794
// commands that don't start with a letter
17941795
EXCMD(CMD_bang, "!", ex_bang,
1795-
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK,
1796+
EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
17961797
ADDR_LINES),
17971798
EXCMD(CMD_pound, "#", ex_print,
17981799
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
17991800
ADDR_LINES),
18001801
EXCMD(CMD_and, "&", ex_substitute,
1801-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
1802+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
18021803
ADDR_LINES),
18031804
EXCMD(CMD_star, "*", ex_at,
1804-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
1805+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
18051806
ADDR_LINES),
18061807
EXCMD(CMD_lshift, "<", ex_operators,
18071808
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
@@ -1813,7 +1814,7 @@ EXCMD(CMD_rshift, ">", ex_operators,
18131814
EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
18141815
ADDR_LINES),
18151816
EXCMD(CMD_at, "@", ex_at,
1816-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
1817+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
18171818
ADDR_LINES),
18181819
EXCMD(CMD_block, "{{{{{{{{", ex_block, // not found normally
18191820
0,
@@ -1822,7 +1823,7 @@ EXCMD(CMD_endblock, "}", ex_endblock,
18221823
EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
18231824
ADDR_NONE),
18241825
EXCMD(CMD_tilde, "~", ex_substitute,
1825-
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
1826+
EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
18261827
ADDR_LINES),
18271828

18281829
// commands that start with an uppercase letter

src/ex_docmd.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3528,6 +3528,14 @@ find_ex_command(
35283528
if (eap->cmdidx == CMD_final && p - eap->cmd == 4)
35293529
eap->cmdidx = CMD_finally;
35303530

3531+
if (eap->cmdidx != CMD_SIZE && in_vim9script()
3532+
&& !IS_WHITE_OR_NUL(*p) && !ends_excmd(*p) && *p != '!'
3533+
&& (cmdnames[eap->cmdidx].cmd_argt & EX_NONWHITE_OK) == 0)
3534+
{
3535+
semsg(_(e_command_not_followed_by_white_space_str), eap->cmd);
3536+
eap->cmdidx = CMD_SIZE;
3537+
}
3538+
35313539
return p;
35323540
}
35333541

@@ -5114,7 +5122,7 @@ ex_blast(exarg_T *eap)
51145122

51155123
/*
51165124
* Check if "c" ends an Ex command.
5117-
* In Vim9 script does not check for white space before # or #{.
5125+
* In Vim9 script does not check for white space before #.
51185126
*/
51195127
int
51205128
ends_excmd(int c)

src/testdir/test_let.vim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ func Test_let_heredoc_fails()
338338
endfunc
339339
END
340340
call writefile(text, 'XheredocFail')
341-
call assert_fails('source XheredocFail', 'E126:')
341+
call assert_fails('source XheredocFail', 'E1145:')
342342
call delete('XheredocFail')
343343

344344
let text =<< trim CodeEnd
@@ -347,7 +347,7 @@ func Test_let_heredoc_fails()
347347
endfunc
348348
CodeEnd
349349
call writefile(text, 'XheredocWrong')
350-
call assert_fails('source XheredocWrong', 'E126:')
350+
call assert_fails('source XheredocWrong', 'E1145:')
351351
call delete('XheredocWrong')
352352

353353
let text =<< trim TEXTend

src/testdir/test_vim9_assign.vim

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,17 @@ def Test_heredoc()
982982
var&lines =<< trim END
983983
x
984984
x
985+
enddef
986+
defcompile
987+
[END]
988+
CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
989+
delfunc! g:Func
990+
991+
lines =<< trim [END]
992+
def Func()
993+
var lines =<< trim END
994+
x
995+
x
985996
x
986997
x
987998
x
@@ -991,7 +1002,7 @@ def Test_heredoc()
9911002
enddef
9921003
call Func()
9931004
[END]
994-
CheckScriptFailure(lines, 'E990:')
1005+
CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
9951006
delfunc! g:Func
9961007
enddef
9971008

src/testdir/test_vim9_script.vim

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3058,7 +3058,7 @@ def Test_put_with_linebreak()
30583058
new
30593059
var lines =<< trim END
30603060
vim9script
3061-
pu=split('abc', '\zs')
3061+
pu =split('abc', '\zs')
30623062
->join()
30633063
END
30643064
CheckScriptSuccess(lines)
@@ -3079,6 +3079,13 @@ def Test_invoke_normal_in_visual_mode()
30793079
xunmap <F3>
30803080
enddef
30813081

3082+
def Test_white_space_after_command()
3083+
var lines =<< trim END
3084+
exit_cb: Func})
3085+
END
3086+
CheckDefAndScriptFailure(lines, 'E1144:', 1)
3087+
enddef
3088+
30823089
" Keep this last, it messes up highlighting.
30833090
def Test_substitute_cmd()
30843091
new

src/userfunc.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,7 +3185,9 @@ define_function(exarg_T *eap, char_u *name_arg)
31853185
lines_left = Rows - 1;
31863186
if (theline == NULL)
31873187
{
3188-
if (eap->cmdidx == CMD_def)
3188+
if (skip_until != NULL)
3189+
semsg(_(e_missing_heredoc_end_marker_str), skip_until);
3190+
else if (eap->cmdidx == CMD_def)
31893191
emsg(_(e_missing_enddef));
31903192
else
31913193
emsg(_("E126: Missing :endfunction"));
@@ -3352,18 +3354,24 @@ define_function(exarg_T *eap, char_u *name_arg)
33523354

33533355
// Check for ":cmd v =<< [trim] EOF"
33543356
// and ":cmd [a, b] =<< [trim] EOF"
3357+
// and "lines =<< [trim] EOF" for Vim9
33553358
// Where "cmd" can be "let", "var", "final" or "const".
33563359
arg = skipwhite(skiptowhite(p));
33573360
if (*arg == '[')
33583361
arg = vim_strchr(arg, ']');
33593362
if (arg != NULL)
33603363
{
3361-
arg = skipwhite(skiptowhite(arg));
3362-
if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
3364+
int found = (eap->cmdidx == CMD_def && arg[0] == '='
3365+
&& arg[1] == '<' && arg[2] =='<');
3366+
3367+
if (!found)
3368+
// skip over the argument after "cmd"
3369+
arg = skipwhite(skiptowhite(arg));
3370+
if (found || (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
33633371
&& (checkforcmd(&p, "let", 2)
33643372
|| checkforcmd(&p, "var", 3)
33653373
|| checkforcmd(&p, "final", 5)
3366-
|| checkforcmd(&p, "const", 5)))
3374+
|| checkforcmd(&p, "const", 5))))
33673375
{
33683376
p = skipwhite(arg + 3);
33693377
if (STRNCMP(p, "trim", 4) == 0)

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2138,
753755
/**/
754756
2137,
755757
/**/

0 commit comments

Comments
 (0)