]> granicus.if.org Git - vim/commitdiff
patch 8.2.2138: Vim9: "exit_cb" causes Vim to exit v8.2.2138
authorBram Moolenaar <Bram@vim.org>
Sun, 13 Dec 2020 16:50:20 +0000 (17:50 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 13 Dec 2020 16:50:20 +0000 (17:50 +0100)
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.

src/errors.h
src/ex_cmds.h
src/ex_docmd.c
src/testdir/test_let.vim
src/testdir/test_vim9_assign.vim
src/testdir/test_vim9_script.vim
src/userfunc.c
src/version.c

index b8cb32f4b5cb38a8a9ee56077b13350cc7796e84..e761a4ea461c9cf217eb23bc9803082fcc80d1c3 100644 (file)
@@ -316,4 +316,8 @@ EXTERN char e_indexable_type_required[]
 EXTERN char e_non_empty_string_required[]
        INIT(= N_("E1142: Non-empty string required"));
 EXTERN char e_empty_expression_str[]
-       INIT(= N_("E1143: empty expression: \"%s\""));
+       INIT(= N_("E1143: Empty expression: \"%s\""));
+EXTERN char e_command_not_followed_by_white_space_str[]
+       INIT(= N_("E1144: Command is not followed by white space: %s"));
+EXTERN char e_missing_heredoc_end_marker_str[]
+       INIT(= N_("E1145: Missing heredoc end marker: %s"));
index 88734843c69d2d8b9c6dc60576a4a1f3f4ad2961..b5260b9f04b0572a308d7240a3a5fb29fc8d3658 100644 (file)
@@ -55,6 +55,7 @@
 #define EX_LOCK_OK  0x1000000  // command can be executed when textlock is
                                // set; when missing disallows editing another
                                // buffer when curbuf_lock is set
+#define EX_NONWHITE_OK 0x2000000  // command can be followed by non-white
 
 #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed
 #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file
@@ -632,7 +633,7 @@ EXCMD(CMD_function, "function",     ex_function,
        EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_global,      "global",       ex_global,
-       EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_goto,                "goto",         ex_goto,
        EX_RANGE|EX_COUNT|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1277,7 +1278,7 @@ EXCMD(CMD_rviminfo,       "rviminfo",     ex_viminfo,
        EX_BANG|EX_FILE1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_substitute,  "substitute",   ex_substitute,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_sNext,       "sNext",        ex_previous,
        EX_EXTRA|EX_RANGE|EX_COUNT|EX_BANG|EX_CMDARG|EX_ARGOPT|EX_TRLBAR,
@@ -1652,7 +1653,7 @@ EXCMD(CMD_update, "update",       ex_update,
        EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILE1|EX_ARGOPT|EX_DFLALL|EX_TRLBAR,
        ADDR_LINES),
 EXCMD(CMD_vglobal,     "vglobal",      ex_global,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_var,         "var",          ex_var,
        EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -1792,16 +1793,16 @@ EXCMD(CMD_z,            "z",            ex_z,
 
 // commands that don't start with a letter
 EXCMD(CMD_bang,                "!",            ex_bang,
-       EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_FILES|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_pound,       "#",            ex_print,
        EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
        ADDR_LINES),
 EXCMD(CMD_and,         "&",            ex_substitute,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_star,                "*",            ex_at,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_lshift,      "<",            ex_operators,
        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,
        EX_RANGE|EX_WHOLEFOLD|EX_COUNT|EX_FLAGS|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
        ADDR_LINES),
 EXCMD(CMD_at,          "@",            ex_at,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_block,       "{{{{{{{{",     ex_block,  // not found normally
        0,
@@ -1822,7 +1823,7 @@ EXCMD(CMD_endblock,       "}",            ex_endblock,
        EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_tilde,       "~",            ex_substitute,
-       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY,
+       EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK|EX_MODIFY|EX_NONWHITE_OK,
        ADDR_LINES),
 
 // commands that start with an uppercase letter
index c80d23e10f8010ebb210e054dab11cf3b95f4b9e..b7beabd2dd0f040c1dee70d1ce45616ed658af59 100644 (file)
@@ -3528,6 +3528,14 @@ find_ex_command(
     if (eap->cmdidx == CMD_final && p - eap->cmd == 4)
        eap->cmdidx = CMD_finally;
 
+    if (eap->cmdidx != CMD_SIZE && in_vim9script()
+           && !IS_WHITE_OR_NUL(*p) && !ends_excmd(*p) && *p != '!'
+           && (cmdnames[eap->cmdidx].cmd_argt & EX_NONWHITE_OK) == 0)
+    {
+       semsg(_(e_command_not_followed_by_white_space_str), eap->cmd);
+       eap->cmdidx = CMD_SIZE;
+    }
+
     return p;
 }
 
@@ -5114,7 +5122,7 @@ ex_blast(exarg_T *eap)
 
 /*
  * Check if "c" ends an Ex command.
- * In Vim9 script does not check for white space before # or #{.
+ * In Vim9 script does not check for white space before #.
  */
     int
 ends_excmd(int c)
index 6dc36ea96f0738061f2b1c12d618c669edc69cf6..2a37c198b1f84080a83994e677ab5537c4d1e2a5 100644 (file)
@@ -338,7 +338,7 @@ func Test_let_heredoc_fails()
   endfunc
   END
   call writefile(text, 'XheredocFail')
-  call assert_fails('source XheredocFail', 'E126:')
+  call assert_fails('source XheredocFail', 'E1145:')
   call delete('XheredocFail')
 
   let text =<< trim CodeEnd
@@ -347,7 +347,7 @@ func Test_let_heredoc_fails()
   endfunc
   CodeEnd
   call writefile(text, 'XheredocWrong')
-  call assert_fails('source XheredocWrong', 'E126:')
+  call assert_fails('source XheredocWrong', 'E1145:')
   call delete('XheredocWrong')
 
   let text =<< trim TEXTend
index 2b02cb960a050ade10c93f73b2cb5c3c9c8ec3fd..1075e171225673ec36553945d8de0372f78e86f7 100644 (file)
@@ -982,6 +982,17 @@ def Test_heredoc()
         var&lines =<< trim END
         x
         x
+      enddef
+      defcompile
+  [END]
+  CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
+  delfunc! g:Func
+
+  lines =<< trim [END]
+      def Func()
+        var lines =<< trim END
+        x
+        x
         x
         x
         x
@@ -991,7 +1002,7 @@ def Test_heredoc()
       enddef
       call Func()
   [END]
-  CheckScriptFailure(lines, 'E990:')
+  CheckScriptFailure(lines, 'E1145: Missing heredoc end marker: END')
   delfunc! g:Func
 enddef
 
index 13e824a2f905da8d4a957ccc17b3615941040b5e..ccc612f5a7809905f5c9e0829062afb21eecd3de 100644 (file)
@@ -3058,7 +3058,7 @@ def Test_put_with_linebreak()
   new
   var lines =<< trim END
     vim9script
-    pu=split('abc', '\zs')
+    pu =split('abc', '\zs')
             ->join()
   END
   CheckScriptSuccess(lines)
@@ -3079,6 +3079,13 @@ def Test_invoke_normal_in_visual_mode()
   xunmap <F3>
 enddef
 
+def Test_white_space_after_command()
+  var lines =<< trim END
+    exit_cb: Func})
+  END
+  CheckDefAndScriptFailure(lines, 'E1144:', 1)
+enddef
+
 " Keep this last, it messes up highlighting.
 def Test_substitute_cmd()
   new
index 70bbf33e13af3b897886758818a678ab6610074b..ccd1bd382e7061c20ffee7c59eeb38a09b56c68b 100644 (file)
@@ -3185,7 +3185,9 @@ define_function(exarg_T *eap, char_u *name_arg)
            lines_left = Rows - 1;
        if (theline == NULL)
        {
-           if (eap->cmdidx == CMD_def)
+           if (skip_until != NULL)
+               semsg(_(e_missing_heredoc_end_marker_str), skip_until);
+           else if (eap->cmdidx == CMD_def)
                emsg(_(e_missing_enddef));
            else
                emsg(_("E126: Missing :endfunction"));
@@ -3352,18 +3354,24 @@ define_function(exarg_T *eap, char_u *name_arg)
 
            // Check for ":cmd v =<< [trim] EOF"
            //       and ":cmd [a, b] =<< [trim] EOF"
+           //       and "lines =<< [trim] EOF" for Vim9
            // Where "cmd" can be "let", "var", "final" or "const".
            arg = skipwhite(skiptowhite(p));
            if (*arg == '[')
                arg = vim_strchr(arg, ']');
            if (arg != NULL)
            {
-               arg = skipwhite(skiptowhite(arg));
-               if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
+               int found = (eap->cmdidx == CMD_def && arg[0] == '='
+                                            && arg[1] == '<' && arg[2] =='<');
+
+               if (!found)
+                   // skip over the argument after "cmd"
+                   arg = skipwhite(skiptowhite(arg));
+               if (found || (arg[0] == '=' && arg[1] == '<' && arg[2] =='<'
                        && (checkforcmd(&p, "let", 2)
                            || checkforcmd(&p, "var", 3)
                            || checkforcmd(&p, "final", 5)
-                           || checkforcmd(&p, "const", 5)))
+                           || checkforcmd(&p, "const", 5))))
                {
                    p = skipwhite(arg + 3);
                    if (STRNCMP(p, "trim", 4) == 0)
index 64391b499600e05d02e26112bf395a8684dfbe7e..2d39c1be5a624fd49b748e353d6468a472b2a20c 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2138,
 /**/
     2137,
 /**/