diff options
| -rw-r--r-- | src/nvim/eval.c | 84 | ||||
| -rw-r--r-- | src/nvim/version.c | 2 | ||||
| -rw-r--r-- | test/functional/legacy/eval_spec.lua | 18 | 
3 files changed, 72 insertions, 32 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 982c14cd08..7273acb839 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -173,6 +173,7 @@ static char *e_illvar = N_("E461: Illegal variable name: %s");  static char *e_float_as_string = N_("E806: using Float as a String");  static char_u * const empty_string = (char_u *)""; +static char_u * const namespace_char = (char_u *)"abglstvw";  static dictitem_T globvars_var;                 /* variable used for g: */  #define globvarht globvardict.dv_hashtab @@ -17801,21 +17802,28 @@ static int get_env_len(char_u **arg)    return len;  } -/* - * Get the length of the name of a function or internal variable. - * "arg" is advanced to the first non-white character after the name. - * Return 0 if something is wrong. - */ -static int get_id_len(char_u **arg) -{ -  char_u      *p; +// Get the length of the name of a function or internal variable. +// "arg" is advanced to the first non-white character after the name. +// Return 0 if something is wrong. +static int get_id_len(char_u **arg) { +  char_u *p;    int len; -  /* Find the end of the name. */ -  for (p = *arg; eval_isnamec(*p); ++p) -    ; -  if (p == *arg)            /* no name found */ +  // Find the end of the name. +  for (p = *arg; eval_isnamec(*p); p++) { +    if (*p == ':') { +      // "s:" is start of "s:var", but "n:" is not and can be used in +      // slice "[n:]". Also "xx:" is not a namespace. +      len = (int)(p - *arg); +      if (len > 1 +          || (len == 1 && vim_strchr(namespace_char, **arg) == NULL)) { +        break; +      } +    } +  } +  if (p == *arg) {  // no name found      return 0; +  }    len = (int)(p - *arg);    *arg = skipwhite(p); @@ -17886,28 +17894,28 @@ static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose)    return len;  } -/* - * Find the end of a variable or function name, taking care of magic braces. - * If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the - * start and end of the first magic braces item. - * "flags" can have FNE_INCL_BR and FNE_CHECK_START. - * Return a pointer to just after the name.  Equal to "arg" if there is no - * valid name. - */ +// Find the end of a variable or function name, taking care of magic braces. +// If "expr_start" is not NULL then "expr_start" and "expr_end" are set to the +// start and end of the first magic braces item. +// "flags" can have FNE_INCL_BR and FNE_CHECK_START. +// Return a pointer to just after the name.  Equal to "arg" if there is no +// valid name.  static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags)  {    int mb_nest = 0;    int br_nest = 0; -  char_u      *p; +  char_u *p; +  int len;    if (expr_start != NULL) {      *expr_start = NULL;      *expr_end = NULL;    } -  /* Quick check for valid starting character. */ -  if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{') +  // Quick check for valid starting character. +  if ((flags & FNE_CHECK_START) && !eval_isnamec1(*arg) && *arg != '{') {      return arg; +  }    for (p = arg; *p != NUL         && (eval_isnamec(*p) @@ -17922,30 +17930,44 @@ static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end        if (*p == NUL)          break;      } else if (*p == '"') { -      /* skip over "str\"ing" to avoid counting [ and ] inside it. */ -      for (p = p + 1; *p != NUL && *p != '"'; mb_ptr_adv(p)) -        if (*p == '\\' && p[1] != NUL) +      // skip over "str\"ing" to avoid counting [ and ] inside it. +      for (p = p + 1; *p != NUL && *p != '"'; mb_ptr_adv(p)) { +        if (*p == '\\' && p[1] != NUL) {            ++p; -      if (*p == NUL) +        } +      } +      if (*p == NUL) { +        break; +      } +    } else if (br_nest == 0 && mb_nest == 0 && *p == ':') { +      // "s:" is start of "s:var", but "n:" is not and can be used in +      // slice "[n:]".  Also "xx:" is not a namespace. +      len = (int)(p - arg); +      if (len > 1 +          || (len == 1 && vim_strchr(namespace_char, *arg) == NULL)) {          break; +      }      }      if (mb_nest == 0) { -      if (*p == '[') +      if (*p == '[') {          ++br_nest; -      else if (*p == ']') +      } else if (*p == ']') {          --br_nest; +      }      }      if (br_nest == 0) {        if (*p == '{') {          mb_nest++; -        if (expr_start != NULL && *expr_start == NULL) +        if (expr_start != NULL && *expr_start == NULL) {            *expr_start = p; +        }        } else if (*p == '}') {          mb_nest--; -        if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL) +        if (expr_start != NULL && mb_nest == 0 && *expr_end == NULL) {            *expr_end = p; +        }        }      }    } diff --git a/src/nvim/version.c b/src/nvim/version.c index 80b1b236dd..efd3c230a7 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -185,7 +185,7 @@ static int included_patches[] = {    // 1108,    // 1107,    // 1106 NA -  // 1105, +  1105,    // 1104 NA    // 1103 NA    // 1102, diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua index 1c81b47ed6..9304e3b331 100644 --- a/test/functional/legacy/eval_spec.lua +++ b/test/functional/legacy/eval_spec.lua @@ -693,4 +693,22 @@ describe('eval', function()        start:        6]])    end) + +  it('substring and variable name', function() +    execute("let str = 'abcdef'") +    execute('let n = 3') +    eq('def', eval('str[n:]')) +    eq('abcd', eval('str[:n]')) +    eq('d', eval('str[n:n]')) +    execute('unlet n') +    execute('let nn = 3') +    eq('def', eval('str[nn:]')) +    eq('abcd', eval('str[:nn]')) +    eq('d', eval('str[nn:nn]')) +    execute('unlet nn') +    execute('let b:nn = 4') +    eq('ef', eval('str[b:nn:]')) +    eq('abcde', eval('str[:b:nn]')) +    eq('e', eval('str[b:nn:b:nn]')) +  end)  end) | 
