From 2e80095501238e0c6b702ac7cdfa2e2b763dba28 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 23 Aug 2020 19:34:48 +0200 Subject: patch 8.2.1518: Vim9: cannot assign to local option Problem: Vim9: cannot assign to local option. Solution: Skip over "&l:" and "&g:". (closes #6749) --- src/ex_docmd.c | 25 ++++++++++++++++++++++--- src/proto/ex_docmd.pro | 1 + src/testdir/test_vim9_script.vim | 25 +++++++++++++++---------- src/testdir/vim9.vim | 5 +++++ src/version.c | 2 ++ src/vim9compile.c | 11 ++++++----- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 854ff4dfb0..e252b05794 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -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)) diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 1955ccf6cf..3ed152316b 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -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); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 6417d21ee1..45384d1d8b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -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(['¬ex += 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' diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index 2f92cf954e..7fbe4a5ed3 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -41,6 +41,11 @@ def CheckScriptSuccess(lines: list) delete('Xdef') enddef +def CheckDefAndScriptSuccess(lines: list) + 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, error: string, lnum = -3) diff --git a/src/version.c b/src/version.c index 9eb448b2df..7b52e0546a 100644 --- a/src/version.c +++ b/src/version.c @@ -754,6 +754,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1518, /**/ 1517, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c0cea2992c..2c3dc70d6d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -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 -- cgit v1.2.3