]> granicus.if.org Git - vim/commitdiff
patch 8.2.1518: Vim9: cannot assign to local option v8.2.1518
authorBram Moolenaar <Bram@vim.org>
Sun, 23 Aug 2020 17:34:48 +0000 (19:34 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 23 Aug 2020 17:34:48 +0000 (19:34 +0200)
Problem:    Vim9: cannot assign to local option.
Solution:   Skip over "&l:" and "&g:". (closes #6749)

src/ex_docmd.c
src/proto/ex_docmd.pro
src/testdir/test_vim9_script.vim
src/testdir/vim9.vim
src/version.c
src/vim9compile.c

index 854ff4dfb0a004a88d9c25579b7bbfc53374b48b..e252b05794571cb3456baa06458d0080a7af4f43 100644 (file)
@@ -3242,6 +3242,27 @@ append_command(char_u *cmd)
     *d = NUL;
 }
 
+/*
+ * If "start" points "&opt", "&l:opt", "&g:opt" or "$ENV" return a pointer to
+ * the name.  Otherwise just return "start".
+ */
+    char_u *
+skip_option_env_lead(char_u *start)
+{
+    char_u *name = start;
+
+    if (*start == '&')
+    {
+       if ((start[1] == 'l' || start[1] == 'g') && start[2] == ':')
+           name += 3;
+       else
+           name += 1;
+    }
+    else if (*start == '$')
+       name += 1;
+    return name;
+}
+
 /*
  * Find an Ex command by its name, either built-in or user.
  * Start of the name can be found at eap->cmd.
@@ -3273,9 +3294,7 @@ find_ex_command(
     p = eap->cmd;
     if (lookup != NULL)
     {
-       // Skip over first char for "&opt = val", "$ENV = val" and "@r = val".
-       char_u *pskip = (*eap->cmd == '&' || *eap->cmd == '$')
-                                                    ? eap->cmd + 1 : eap->cmd;
+       char_u *pskip = skip_option_env_lead(eap->cmd);
 
        if (vim_strchr((char_u *)"{('[\"@", *p) != NULL
               || ((p = to_name_const_end(pskip)) > eap->cmd && *p != NUL))
index 1955ccf6cfe2d89e2d1ed5e6a4778489d37daa1d..3ed152316b7e666fed81456a8a7c73d8d64199f3 100644 (file)
@@ -10,6 +10,7 @@ int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
 void undo_cmdmod(exarg_T *eap, int save_msg_scroll);
 int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
 int checkforcmd(char_u **pp, char *cmd, int len);
+char_u *skip_option_env_lead(char_u *start);
 char_u *find_ex_command(exarg_T *eap, int *full, void *(*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx);
 int modifier_len(char_u *cmd);
 int cmd_exists(char_u *name);
index 6417d21ee1e0b4d7e33c1c8d378c27f6ec5ca932..45384d1d8b84d8aa2549d2fa165da61b5fc9bfc0 100644 (file)
@@ -110,12 +110,21 @@ def Test_assignment()
   endif
 
   lines =<< trim END
-    vim9script
     &ts = 6
     &ts += 3
     assert_equal(9, &ts)
+
+    &l:ts = 6
+    assert_equal(6, &ts)
+    &l:ts += 2
+    assert_equal(8, &ts)
+
+    &g:ts = 6
+    assert_equal(6, &g:ts)
+    &g:ts += 2
+    assert_equal(8, &g:ts)
   END
-  CheckScriptSuccess(lines)
+  CheckDefAndScriptSuccess(lines)
 
   CheckDefFailure(['&notex += 3'], 'E113:')
   CheckDefFailure(['&ts ..= "xxx"'], 'E1019:')
@@ -163,19 +172,15 @@ def Test_assignment()
   call CheckDefFailure(['$SOME_ENV_VAR += "more"'], 'E1051:')
   call CheckDefFailure(['$SOME_ENV_VAR += 123'], 'E1012:')
 
-  @a = 'areg'
-  @a ..= 'add'
-  assert_equal('aregadd', @a)
-  call CheckDefFailure(['@a += "more"'], 'E1051:')
-  call CheckDefFailure(['@a += 123'], 'E1012:')
-
   lines =<< trim END
-    vim9script
     @c = 'areg'
     @c ..= 'add'
     assert_equal('aregadd', @c)
   END
-  call CheckScriptSuccess(lines)
+  CheckDefAndScriptSuccess(lines)
+
+  call CheckDefFailure(['@a += "more"'], 'E1051:')
+  call CheckDefFailure(['@a += 123'], 'E1012:')
 
   v:errmsg = 'none'
   v:errmsg ..= 'again'
index 2f92cf954e6fb9b540a74cfe11f5a29927827d40..7fbe4a5ed33421e772e7e238448242d39cf6409c 100644 (file)
@@ -41,6 +41,11 @@ def CheckScriptSuccess(lines: list<string>)
   delete('Xdef')
 enddef
 
+def CheckDefAndScriptSuccess(lines: list<string>)
+  CheckDefSuccess(lines)
+  CheckScriptSuccess(['vim9script'] + lines)
+enddef
+
 " Check that a command fails both when used in a :def function and when used
 " in Vim9 script.
 def CheckScriptAndDefFailure(lines: list<string>, error: string, lnum = -3)
index 9eb448b2df0d469dfcf848ffd74814a7bb420101..7b52e0546afae144187de3b5a0d33068e5471be0 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1518,
 /**/
     1517,
 /**/
index c0cea2992cdd488bf187aa4a2d66be78164f4371..2c3dc70d6d420cd5710a897ab9105615c2e81467 100644 (file)
@@ -4550,8 +4550,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            p = var_start + 2;
        else
        {
-           p = (*var_start == '&' || *var_start == '$')
-                                                  ? var_start + 1 : var_start;
+           // skip over the leading "&", "&l:", "&g:" and "$"
+           p = skip_option_env_lead(var_start);
            p = to_name_end(p, TRUE);
        }
 
@@ -4595,8 +4595,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                }
                cc = *p;
                *p = NUL;
-               opt_type = get_option_value(var_start + 1, &numval,
-                                                             NULL, opt_flags);
+               opt_type = get_option_value(skip_option_env_lead(var_start),
+                                                    &numval, NULL, opt_flags);
                *p = cc;
                if (opt_type == -3)
                {
@@ -5131,7 +5131,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
            switch (dest)
            {
                case dest_option:
-                   generate_STOREOPT(cctx, name + 1, opt_flags);
+                   generate_STOREOPT(cctx, skip_option_env_lead(name),
+                                                                   opt_flags);
                    break;
                case dest_global:
                    // include g: with the name, easier to execute that way