]> granicus.if.org Git - vim/commitdiff
patch 8.2.3503: Vim9: using g:pat:cmd is confusing v8.2.3503
authorBram Moolenaar <Bram@vim.org>
Wed, 13 Oct 2021 14:04:34 +0000 (15:04 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 13 Oct 2021 14:04:34 +0000 (15:04 +0100)
Problem:    Vim9: using g:pat:cmd is confusing.
Solution:   Do not recognize g: as the :global command.  Also for s:pat:repl.
            (closes #8982)

runtime/doc/vim9.txt
src/errors.h
src/ex_cmds.c
src/ex_docmd.c
src/proto/vim9compile.pro
src/testdir/test_vim9_cmd.vim
src/version.c
src/vim9compile.c

index b6feebf84f46ddc1f4697136ccfd11dbcb697777..b661097805dfc80c318ebdb5d4b26c1da8480fb7 100644 (file)
@@ -942,9 +942,22 @@ Ex command ranges need to be prefixed with a colon. >
 
 Some Ex commands can be confused with assignments in Vim9 script: >
        g:name = value    # assignment
-       g:pattern:cmd     # invalid command - ERROR
        :g:pattern:cmd    # :global command
 
+To avoid confusion between a `:global` or `:substitute` command and an
+expression or assignment, a few separators cannot be used when these commands
+are abbreviated to a single character: ':', '-' and '.'. >
+       g:pattern:cmd     # invalid command - ERROR
+       s:pattern:repl    # invalid command - ERROR
+       g-pattern-cmd     # invalid command - ERROR
+       s-pattern-repl    # invalid command - ERROR
+       g.pattern.cmd     # invalid command - ERROR
+       s.pattern.repl    # invalid command - ERROR
+
+Also, there cannot be a space between the command and the separator: >
+       g /pattern/cmd    # invalid command - ERROR
+       s /pattern/repl   # invalid command - ERROR
+
 Functions defined with `:def` compile the whole function.  Legacy functions
 can bail out, and the following lines are not parsed: >
        func Maybe()
index 4cc50e42c126375b7aef7e73ef9499b90bdfb588..a2a1394e84db9b0316d71d8a34b9f7a06146b1d6 100644 (file)
@@ -666,3 +666,7 @@ EXTERN char e_invalid_value_for_blob_nr[]
        INIT(= N_("E1239: Invalid value for blob: %d"));
 EXTERN char e_resulting_text_too_long[]
        INIT(= N_("E1240: Resulting text too long"));
+EXTERN char e_separator_not_supported_str[]
+       INIT(= N_("E1241: Separator not supported: %s"));
+EXTERN char e_no_white_space_allowed_before_separator_str[]
+       INIT(= N_("E1242: No white space allowed before separator: %s"));
index 5c92e094e1f9fc58f2e111c8fe4112343c8b3717..78a87e76ac4c425fd7c2dae53afe97afd898bcaf 100644 (file)
@@ -3724,6 +3724,9 @@ ex_substitute(exarg_T *eap)
                                // don't accept alphanumeric for separator
        if (check_regexp_delim(*cmd) == FAIL)
            return;
+       if (in_vim9script() && check_global_and_subst(eap->cmd, eap->arg)
+                                                                     == FAIL)
+           return;
 
        /*
         * undocumented vi feature:
@@ -4899,6 +4902,9 @@ ex_global(exarg_T *eap)
     cmd = eap->arg;
     which_pat = RE_LAST;           // default: use last used regexp
 
+    if (in_vim9script() && check_global_and_subst(eap->cmd, eap->arg) == FAIL)
+       return;
+
     /*
      * undocumented vi feature:
      * "\/" and "\?": use previous search pattern.
index 08a48305ed0bcba8cb3d73828187ebc7d4563013..072effdec41c8a4f83e62e22600108b6f04ca659 100644 (file)
@@ -3600,6 +3600,15 @@ find_ex_command(
            }
        }
 
+       // "g:", "s:" and "l:" are always assumed to be a variable, thus start
+       // an expression.  A global/substitute/list command needs to use a
+       // longer name.
+       if (vim_strchr((char_u *)"gsl", *p) != NULL && p[1] == ':')
+       {
+           eap->cmdidx = CMD_eval;
+           return eap->cmd;
+       }
+
        // If it is an ID it might be a variable with an operator on the next
        // line, if the variable exists it can't be an Ex command.
        if (p > eap->cmd && ends_excmd(*skipwhite(p))
index 2b62b6c88b549f3e347a0524e306e1c7f265e6ae..5910c67d6c78dbf6db9817e04bf6add7206fa4a1 100644 (file)
@@ -17,6 +17,7 @@ void fill_exarg_from_cctx(exarg_T *eap, cctx_T *cctx);
 int assignment_len(char_u *p, int *heredoc);
 void vim9_declare_error(char_u *name);
 int check_vim9_unlet(char_u *name);
+int check_global_and_subst(char_u *cmd, char_u *arg);
 int compile_def_function(ufunc_T *ufunc, int check_return_type, compiletype_T compile_type, cctx_T *outer_cctx);
 void set_function_type(ufunc_T *ufunc);
 void delete_instr(isn_T *isn);
index 93b1295d4ca9a92ef8cb590f2ca400e88fd7af19..802bae363bc3702a6f3c0a814241d5fc8f5ef5ab 100644 (file)
@@ -1489,5 +1489,54 @@ def Test_cmdwin_block()
   au! justTesting
 enddef
 
+def Test_var_not_cmd()
+  var lines =<< trim END
+      g:notexist:cmd
+  END
+  CheckDefAndScriptFailure2(lines, 'E488: Trailing characters: :cmd', 'E121: Undefined variable: g:notexist', 1)
+
+  lines =<< trim END
+      g-pat-cmd
+  END
+  CheckDefAndScriptFailure(lines, 'E1241:', 1)
+
+  lines =<< trim END
+      s:notexist:repl
+  END
+  CheckDefAndScriptFailure2(lines, 'E488: Trailing characters: :repl', 'E121: Undefined variable: s:notexist', 1)
+
+  lines =<< trim END
+      s-pat-repl
+  END
+  CheckDefAndScriptFailure(lines, 'E1241:', 1)
+
+  lines =<< trim END
+      w:notexist->len()
+  END
+  CheckDefExecAndScriptFailure(lines, 'E121: Undefined variable: w:notexist', 1)
+
+  lines =<< trim END
+      b:notexist->len()
+  END
+  CheckDefExecAndScriptFailure(lines, 'E121: Undefined variable: b:notexist', 1)
+
+  lines =<< trim END
+      t:notexist->len()
+  END
+  CheckDefExecAndScriptFailure(lines, 'E121: Undefined variable: t:notexist', 1)
+enddef
+
+def Test_no_space_after_command()
+  var lines =<< trim END
+      g /pat/cmd
+  END
+  CheckDefAndScriptFailure(lines, 'E1242:', 1)
+
+  lines =<< trim END
+      s /pat/repl
+  END
+  CheckDefAndScriptFailure(lines, 'E1242:', 1)
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
index 7640153215f87ec9ea2d8e02d86a5bd6643e3559..1be4d5440d7ef5dea9c2bab54ba0ed3fbeadaa96 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3503,
 /**/
     3502,
 /**/
index e9931731cd4ba67fb3ed9175dcdd43b93bb29031..5bb0359aeac34b57cd415caedfa24fc53f33476e 100644 (file)
@@ -9472,6 +9472,26 @@ compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
 }
 #endif
 
+/*
+ * Check if the separator for a :global or :substitute command is OK.
+ */
+    int
+check_global_and_subst(char_u *cmd, char_u *arg)
+{
+    if (arg == cmd + 1 && vim_strchr(":-.", *arg) != NULL)
+    {
+       semsg(_(e_separator_not_supported_str), arg);
+       return FAIL;
+    }
+    if (VIM_ISWHITE(cmd[1]))
+    {
+       semsg(_(e_no_white_space_allowed_before_separator_str), cmd);
+       return FAIL;
+    }
+    return OK;
+}
+
+
 /*
  * Add a function to the list of :def functions.
  * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
@@ -10066,6 +10086,8 @@ compile_def_function(
                    break;
 
            case CMD_substitute:
+                   if (check_global_and_subst(ea.cmd, p) == FAIL)
+                       goto erret;
                    if (cctx.ctx_skip == SKIP_YES)
                        line = (char_u *)"";
                    else
@@ -10132,6 +10154,10 @@ compile_def_function(
                        line = compile_script(line, &cctx);
                    break;
 
+           case CMD_global:
+                   if (check_global_and_subst(ea.cmd, p) == FAIL)
+                       goto erret;
+                   // FALLTHROUGH
            default:
                    // Not recognized, execute with do_cmdline_cmd().
                    ea.arg = p;