Patch 8.1.1939
Problem:    Code for handling v: variables in generic eval file.
Solution:   Move v: variables to evalvars.c. (Yegappan Lakshmanan,
            closes #4872)
Files:      src/eval.c, src/evalvars.c, src/proto/eval.pro,
            src/proto/evalvars.pro


*** ../vim-8.1.1938/src/eval.c  2019-08-27 22:48:12.737480696 +0200
--- src/eval.c  2019-08-29 22:02:16.891931613 +0200
***************
*** 29,42 ****
  
  #define NAMESPACE_CHAR        (char_u *)"abglstvw"
  
- static dictitem_T     globvars_var;           /* variable used for g: */
- 
- /*
-  * Old Vim variables such as "v:version" are also available without the "v:".
-  * Also in functions.  We need a special hashtable for them.
-  */
- static hashtab_T      compat_hashtab;
- 
  /*
   * When recursively copying lists and dicts we need to remember which ones we
   * have done to avoid endless recursiveness.  This unique ID is used for that.
--- 29,34 ----
***************
*** 44,63 ****
   */
  static int current_copyID = 0;
  
- /*
-  * Array to hold the hashtab with variables local to each sourced script.
-  * Each item holds a variable (nameless) that points to the dict_T.
-  */
- typedef struct
- {
-     dictitem_T        sv_var;
-     dict_T    sv_dict;
- } scriptvar_T;
- 
- static garray_T           ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
- #define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1])
- #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
- 
  static int echo_attr = 0;   /* attributes used for ":echo" */
  
  /* The names of packages that once were loaded are remembered. */
--- 36,41 ----
***************
*** 76,215 ****
      blob_T    *fi_blob;       /* blob being used */
  } forinfo_T;
  
- 
- /*
-  * Array to hold the value of v: variables.
-  * The value is in a dictitem, so that it can also be used in the v: scope.
-  * The reason to use this table anyway is for very quick access to the
-  * variables with the VV_ defines.
-  */
- 
- /* values for vv_flags: */
- #define VV_COMPAT     1       /* compatible, also used without "v:" */
- #define VV_RO         2       /* read-only */
- #define VV_RO_SBX     4       /* read-only in the sandbox */
- 
- #define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}
- 
- static struct vimvar
- {
-     char      *vv_name;       /* name of variable, without v: */
-     dictitem16_T vv_di;               /* value and name for key (max 16 
chars!) */
-     char      vv_flags;       /* VV_COMPAT, VV_RO, VV_RO_SBX */
- } vimvars[VV_LEN] =
- {
-     /*
-      * The order here must match the VV_ defines in vim.h!
-      * Initializing a union does not work, leave tv.vval empty to get zero's.
-      */
-     {VV_NAME("count",          VAR_NUMBER), VV_COMPAT+VV_RO},
-     {VV_NAME("count1",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("prevcount",      VAR_NUMBER), VV_RO},
-     {VV_NAME("errmsg",                 VAR_STRING), VV_COMPAT},
-     {VV_NAME("warningmsg",     VAR_STRING), 0},
-     {VV_NAME("statusmsg",      VAR_STRING), 0},
-     {VV_NAME("shell_error",    VAR_NUMBER), VV_COMPAT+VV_RO},
-     {VV_NAME("this_session",   VAR_STRING), VV_COMPAT},
-     {VV_NAME("version",                VAR_NUMBER), VV_COMPAT+VV_RO},
-     {VV_NAME("lnum",           VAR_NUMBER), VV_RO_SBX},
-     {VV_NAME("termresponse",   VAR_STRING), VV_RO},
-     {VV_NAME("fname",          VAR_STRING), VV_RO},
-     {VV_NAME("lang",           VAR_STRING), VV_RO},
-     {VV_NAME("lc_time",                VAR_STRING), VV_RO},
-     {VV_NAME("ctype",          VAR_STRING), VV_RO},
-     {VV_NAME("charconvert_from", VAR_STRING), VV_RO},
-     {VV_NAME("charconvert_to",         VAR_STRING), VV_RO},
-     {VV_NAME("fname_in",       VAR_STRING), VV_RO},
-     {VV_NAME("fname_out",      VAR_STRING), VV_RO},
-     {VV_NAME("fname_new",      VAR_STRING), VV_RO},
-     {VV_NAME("fname_diff",     VAR_STRING), VV_RO},
-     {VV_NAME("cmdarg",                 VAR_STRING), VV_RO},
-     {VV_NAME("foldstart",      VAR_NUMBER), VV_RO_SBX},
-     {VV_NAME("foldend",                VAR_NUMBER), VV_RO_SBX},
-     {VV_NAME("folddashes",     VAR_STRING), VV_RO_SBX},
-     {VV_NAME("foldlevel",      VAR_NUMBER), VV_RO_SBX},
-     {VV_NAME("progname",       VAR_STRING), VV_RO},
-     {VV_NAME("servername",     VAR_STRING), VV_RO},
-     {VV_NAME("dying",          VAR_NUMBER), VV_RO},
-     {VV_NAME("exception",      VAR_STRING), VV_RO},
-     {VV_NAME("throwpoint",     VAR_STRING), VV_RO},
-     {VV_NAME("register",       VAR_STRING), VV_RO},
-     {VV_NAME("cmdbang",                VAR_NUMBER), VV_RO},
-     {VV_NAME("insertmode",     VAR_STRING), VV_RO},
-     {VV_NAME("val",            VAR_UNKNOWN), VV_RO},
-     {VV_NAME("key",            VAR_UNKNOWN), VV_RO},
-     {VV_NAME("profiling",      VAR_NUMBER), VV_RO},
-     {VV_NAME("fcs_reason",     VAR_STRING), VV_RO},
-     {VV_NAME("fcs_choice",     VAR_STRING), 0},
-     {VV_NAME("beval_bufnr",    VAR_NUMBER), VV_RO},
-     {VV_NAME("beval_winnr",    VAR_NUMBER), VV_RO},
-     {VV_NAME("beval_winid",    VAR_NUMBER), VV_RO},
-     {VV_NAME("beval_lnum",     VAR_NUMBER), VV_RO},
-     {VV_NAME("beval_col",      VAR_NUMBER), VV_RO},
-     {VV_NAME("beval_text",     VAR_STRING), VV_RO},
-     {VV_NAME("scrollstart",    VAR_STRING), 0},
-     {VV_NAME("swapname",       VAR_STRING), VV_RO},
-     {VV_NAME("swapchoice",     VAR_STRING), 0},
-     {VV_NAME("swapcommand",    VAR_STRING), VV_RO},
-     {VV_NAME("char",           VAR_STRING), 0},
-     {VV_NAME("mouse_win",      VAR_NUMBER), 0},
-     {VV_NAME("mouse_winid",    VAR_NUMBER), 0},
-     {VV_NAME("mouse_lnum",     VAR_NUMBER), 0},
-     {VV_NAME("mouse_col",      VAR_NUMBER), 0},
-     {VV_NAME("operator",       VAR_STRING), VV_RO},
-     {VV_NAME("searchforward",  VAR_NUMBER), 0},
-     {VV_NAME("hlsearch",       VAR_NUMBER), 0},
-     {VV_NAME("oldfiles",       VAR_LIST), 0},
-     {VV_NAME("windowid",       VAR_NUMBER), VV_RO},
-     {VV_NAME("progpath",       VAR_STRING), VV_RO},
-     {VV_NAME("completed_item",         VAR_DICT), VV_RO},
-     {VV_NAME("option_new",     VAR_STRING), VV_RO},
-     {VV_NAME("option_old",     VAR_STRING), VV_RO},
-     {VV_NAME("option_oldlocal",        VAR_STRING), VV_RO},
-     {VV_NAME("option_oldglobal", VAR_STRING), VV_RO},
-     {VV_NAME("option_command",         VAR_STRING), VV_RO},
-     {VV_NAME("option_type",    VAR_STRING), VV_RO},
-     {VV_NAME("errors",                 VAR_LIST), 0},
-     {VV_NAME("false",          VAR_SPECIAL), VV_RO},
-     {VV_NAME("true",           VAR_SPECIAL), VV_RO},
-     {VV_NAME("null",           VAR_SPECIAL), VV_RO},
-     {VV_NAME("none",           VAR_SPECIAL), VV_RO},
-     {VV_NAME("vim_did_enter",  VAR_NUMBER), VV_RO},
-     {VV_NAME("testing",                VAR_NUMBER), 0},
-     {VV_NAME("t_number",       VAR_NUMBER), VV_RO},
-     {VV_NAME("t_string",       VAR_NUMBER), VV_RO},
-     {VV_NAME("t_func",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("t_list",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("t_dict",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("t_float",                VAR_NUMBER), VV_RO},
-     {VV_NAME("t_bool",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("t_none",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("t_job",          VAR_NUMBER), VV_RO},
-     {VV_NAME("t_channel",      VAR_NUMBER), VV_RO},
-     {VV_NAME("t_blob",                 VAR_NUMBER), VV_RO},
-     {VV_NAME("termrfgresp",    VAR_STRING), VV_RO},
-     {VV_NAME("termrbgresp",    VAR_STRING), VV_RO},
-     {VV_NAME("termu7resp",     VAR_STRING), VV_RO},
-     {VV_NAME("termstyleresp",  VAR_STRING), VV_RO},
-     {VV_NAME("termblinkresp",  VAR_STRING), VV_RO},
-     {VV_NAME("event",          VAR_DICT), VV_RO},
-     {VV_NAME("versionlong",    VAR_NUMBER), VV_RO},
-     {VV_NAME("echospace",      VAR_NUMBER), VV_RO},
- };
- 
- /* shorthand */
- #define vv_type               vv_di.di_tv.v_type
- #define vv_nr         vv_di.di_tv.vval.v_number
- #define vv_float      vv_di.di_tv.vval.v_float
- #define vv_str                vv_di.di_tv.vval.v_string
- #define vv_list               vv_di.di_tv.vval.v_list
- #define vv_dict               vv_di.di_tv.vval.v_dict
- #define vv_blob               vv_di.di_tv.vval.v_blob
- #define vv_tv         vv_di.di_tv
- 
- static dictitem_T     vimvars_var;            /* variable used for v: */
- #define vimvarht  vimvardict.dv_hashtab
- 
  static int tv_op(typval_T *tv1, typval_T *tv2, char_u  *op);
  static int eval2(char_u **arg, typval_T *rettv, int evaluate);
  static int eval3(char_u **arg, typval_T *rettv, int evaluate);
--- 54,59 ----
***************
*** 224,236 ****
  static int free_unref_items(int copyID);
  static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
  static char_u *make_expanded_name(char_u *in_start, char_u *expr_start, 
char_u *expr_end, char_u *in_end);
- static void check_vars(char_u *name, int len);
- static typval_T *alloc_string_tv(char_u *string);
  static int tv_check_lock(typval_T *tv, char_u *name, int use_gettext);
  
- /* for VIM_VERSION_ defines */
- #include "version.h"
- 
  /*
   * Return "n1" divided by "n2", taking care of dividing by zero.
   */
--- 68,75 ----
***************
*** 264,270 ****
      return (n2 == 0) ? 0 : (n1 % n2);
  }
  
- 
  #if defined(EBCDIC) || defined(PROTO)
  /*
   * Compare struct fst by function name.
--- 103,108 ----
***************
*** 292,366 ****
  }
  #endif
  
- 
  /*
   * Initialize the global and v: variables.
   */
      void
  eval_init(void)
  {
!     int                   i;
!     struct vimvar   *p;
! 
!     init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
!     init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
!     vimvardict.dv_lock = VAR_FIXED;
!     hash_init(&compat_hashtab);
      func_init();
  
-     for (i = 0; i < VV_LEN; ++i)
-     {
-       p = &vimvars[i];
-       if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
-       {
-           iemsg("INTERNAL: name too long, increase size of dictitem16_T");
-           getout(1);
-       }
-       STRCPY(p->vv_di.di_key, p->vv_name);
-       if (p->vv_flags & VV_RO)
-           p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
-       else if (p->vv_flags & VV_RO_SBX)
-           p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
-       else
-           p->vv_di.di_flags = DI_FLAGS_FIX;
- 
-       /* add to v: scope dict, unless the value is not always available */
-       if (p->vv_type != VAR_UNKNOWN)
-           hash_add(&vimvarht, p->vv_di.di_key);
-       if (p->vv_flags & VV_COMPAT)
-           /* add to compat scope dict */
-           hash_add(&compat_hashtab, p->vv_di.di_key);
-     }
-     vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
-     vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
- 
-     set_vim_var_nr(VV_SEARCHFORWARD, 1L);
-     set_vim_var_nr(VV_HLSEARCH, 1L);
-     set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
-     set_vim_var_list(VV_ERRORS, list_alloc());
-     set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
- 
-     set_vim_var_nr(VV_FALSE, VVAL_FALSE);
-     set_vim_var_nr(VV_TRUE, VVAL_TRUE);
-     set_vim_var_nr(VV_NONE, VVAL_NONE);
-     set_vim_var_nr(VV_NULL, VVAL_NULL);
- 
-     set_vim_var_nr(VV_TYPE_NUMBER,  VAR_TYPE_NUMBER);
-     set_vim_var_nr(VV_TYPE_STRING,  VAR_TYPE_STRING);
-     set_vim_var_nr(VV_TYPE_FUNC,    VAR_TYPE_FUNC);
-     set_vim_var_nr(VV_TYPE_LIST,    VAR_TYPE_LIST);
-     set_vim_var_nr(VV_TYPE_DICT,    VAR_TYPE_DICT);
-     set_vim_var_nr(VV_TYPE_FLOAT,   VAR_TYPE_FLOAT);
-     set_vim_var_nr(VV_TYPE_BOOL,    VAR_TYPE_BOOL);
-     set_vim_var_nr(VV_TYPE_NONE,    VAR_TYPE_NONE);
-     set_vim_var_nr(VV_TYPE_JOB,     VAR_TYPE_JOB);
-     set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
-     set_vim_var_nr(VV_TYPE_BLOB,    VAR_TYPE_BLOB);
- 
-     set_vim_var_nr(VV_ECHOSPACE,    sc_col - 1);
- 
-     set_reg_var(0);  /* default for v:register is not 0 but '"' */
- 
  #ifdef EBCDIC
      /*
       * Sort the function table, to enable binary search.
--- 130,144 ----
  }
  #endif
  
  /*
   * Initialize the global and v: variables.
   */
      void
  eval_init(void)
  {
!     evalvars_init();
      func_init();
  
  #ifdef EBCDIC
      /*
       * Sort the function table, to enable binary search.
***************
*** 373,414 ****
      void
  eval_clear(void)
  {
!     int                   i;
!     struct vimvar   *p;
! 
!     for (i = 0; i < VV_LEN; ++i)
!     {
!       p = &vimvars[i];
!       if (p->vv_di.di_tv.v_type == VAR_STRING)
!           VIM_CLEAR(p->vv_str);
!       else if (p->vv_di.di_tv.v_type == VAR_LIST)
!       {
!           list_unref(p->vv_list);
!           p->vv_list = NULL;
!       }
!     }
!     hash_clear(&vimvarht);
!     hash_init(&vimvarht);  /* garbage_collect() will access it */
!     hash_clear(&compat_hashtab);
  
      free_scriptnames();
      free_locales();
  
-     /* global variables */
-     vars_clear(&globvarht);
- 
      /* autoloaded script names */
      ga_clear_strings(&ga_loaded);
  
-     /* Script-local variables. First clear all the variables and in a second
-      * loop free the scriptvar_T, because a variable in one script might hold
-      * a reference to the whole scope of another script. */
-     for (i = 1; i <= ga_scripts.ga_len; ++i)
-       vars_clear(&SCRIPT_VARS(i));
-     for (i = 1; i <= ga_scripts.ga_len; ++i)
-       vim_free(SCRIPT_SV(i));
-     ga_clear(&ga_scripts);
- 
      // unreferenced lists and dicts
      (void)garbage_collect(FALSE);
  
--- 151,164 ----
      void
  eval_clear(void)
  {
!     evalvars_clear();
  
      free_scriptnames();
      free_locales();
  
      /* autoloaded script names */
      ga_clear_strings(&ga_loaded);
  
      // unreferenced lists and dicts
      (void)garbage_collect(FALSE);
  
***************
*** 417,445 ****
  }
  #endif
  
- 
- /*
-  * Set an internal variable to a string value. Creates the variable if it does
-  * not already exist.
-  */
-     void
- set_internal_string_var(char_u *name, char_u *value)
- {
-     char_u    *val;
-     typval_T  *tvp;
- 
-     val = vim_strsave(value);
-     if (val != NULL)
-     {
-       tvp = alloc_string_tv(val);
-       if (tvp != NULL)
-       {
-           set_var(name, tvp, FALSE);
-           free_tv(tvp);
-       }
-     }
- }
- 
  static lval_T *redir_lval = NULL;
  #define EVALCMD_BUSY (redir_lval == (lval_T *)&redir_lval)
  static garray_T redir_ga;     /* only valid when redir_lval is not NULL */
--- 167,172 ----
***************
*** 944,1014 ****
      return retval;
  }
  
- /*
-  * List Vim variables.
-  */
-     void
- list_vim_vars(int *first)
- {
-     list_hashtable_vars(&vimvarht, "v:", FALSE, first);
- }
- 
- /*
-  * List script-local variables, if there is a script.
-  */
-     void
- list_script_vars(int *first)
- {
-     if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
-       list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
-                                                          "s:", FALSE, first);
- }
- 
-     int
- is_vimvarht(hashtab_T *ht)
- {
-     return ht == &vimvarht;
- }
- 
-     int
- is_compatht(hashtab_T *ht)
- {
-     return ht == &compat_hashtab;
- }
- 
- /*
-  * Prepare v: variable "idx" to be used.
-  * Save the current typeval in "save_tv".
-  * When not used yet add the variable to the v: hashtable.
-  */
-     void
- prepare_vimvar(int idx, typval_T *save_tv)
- {
-     *save_tv = vimvars[idx].vv_tv;
-     if (vimvars[idx].vv_type == VAR_UNKNOWN)
-       hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
- }
- 
- /*
-  * Restore v: variable "idx" to typeval "save_tv".
-  * When no longer defined, remove the variable from the v: hashtable.
-  */
-     void
- restore_vimvar(int idx, typval_T *save_tv)
- {
-     hashitem_T        *hi;
- 
-     vimvars[idx].vv_tv = *save_tv;
-     if (vimvars[idx].vv_type == VAR_UNKNOWN)
-     {
-       hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
-       if (HASHITEM_EMPTY(hi))
-           internal_error("restore_vimvar()");
-       else
-           hash_remove(&vimvarht, hi);
-     }
- }
- 
  #if defined(FEAT_SPELL) || defined(PROTO)
  /*
   * Evaluate an expression to a list with suggestions.
--- 671,676 ----
***************
*** 1025,1032 ****
  
      /* Set "v:val" to the bad word. */
      prepare_vimvar(VV_VAL, &save_val);
!     vimvars[VV_VAL].vv_type = VAR_STRING;
!     vimvars[VV_VAL].vv_str = badword;
      if (p_verbose == 0)
        ++emsg_off;
  
--- 687,693 ----
  
      /* Set "v:val" to the bad word. */
      prepare_vimvar(VV_VAL, &save_val);
!     set_vim_var_string(VV_VAL, badword, -1);
      if (p_verbose == 0)
        ++emsg_off;
  
***************
*** 1040,1045 ****
--- 701,707 ----
  
      if (p_verbose == 0)
        --emsg_off;
+     clear_tv(get_vim_var_tv(VV_VAL));
      restore_vimvar(VV_VAL, &save_val);
  
      return list;
***************
*** 1085,1091 ****
      return tv;
  }
  
- 
  /*
   * Call some Vim script function and return the result in "*rettv".
   * Uses argv[0] to argv[argc - 1] for the function arguments.  argv[argc]
--- 747,752 ----
***************
*** 1186,1192 ****
      return rettv.vval.v_list;
  }
  
- 
  #ifdef FEAT_FOLDING
  /*
   * Evaluate 'foldexpr'.  Returns the foldlevel, and any character preceding
--- 847,852 ----
***************
*** 2287,2411 ****
  #endif
  
  /*
-  * Local string buffer for the next two functions to store a variable name
-  * with its prefix. Allocated in cat_prefix_varname(), freed later in
-  * get_user_var_name().
-  */
- 
- static char_u *varnamebuf = NULL;
- static int    varnamebuflen = 0;
- 
- /*
-  * Function to concatenate a prefix and a variable name.
-  */
-     static char_u *
- cat_prefix_varname(int prefix, char_u *name)
- {
-     int               len;
- 
-     len = (int)STRLEN(name) + 3;
-     if (len > varnamebuflen)
-     {
-       vim_free(varnamebuf);
-       len += 10;                      /* some additional space */
-       varnamebuf = alloc(len);
-       if (varnamebuf == NULL)
-       {
-           varnamebuflen = 0;
-           return NULL;
-       }
-       varnamebuflen = len;
-     }
-     *varnamebuf = prefix;
-     varnamebuf[1] = ':';
-     STRCPY(varnamebuf + 2, name);
-     return varnamebuf;
- }
- 
- /*
-  * Function given to ExpandGeneric() to obtain the list of user defined
-  * (global/buffer/window/built-in) variable names.
-  */
-     char_u *
- get_user_var_name(expand_T *xp, int idx)
- {
-     static long_u     gdone;
-     static long_u     bdone;
-     static long_u     wdone;
-     static long_u     tdone;
-     static int                vidx;
-     static hashitem_T *hi;
-     hashtab_T         *ht;
- 
-     if (idx == 0)
-     {
-       gdone = bdone = wdone = vidx = 0;
-       tdone = 0;
-     }
- 
-     /* Global variables */
-     if (gdone < globvarht.ht_used)
-     {
-       if (gdone++ == 0)
-           hi = globvarht.ht_array;
-       else
-           ++hi;
-       while (HASHITEM_EMPTY(hi))
-           ++hi;
-       if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
-           return cat_prefix_varname('g', hi->hi_key);
-       return hi->hi_key;
-     }
- 
-     /* b: variables */
-     ht = &curbuf->b_vars->dv_hashtab;
-     if (bdone < ht->ht_used)
-     {
-       if (bdone++ == 0)
-           hi = ht->ht_array;
-       else
-           ++hi;
-       while (HASHITEM_EMPTY(hi))
-           ++hi;
-       return cat_prefix_varname('b', hi->hi_key);
-     }
- 
-     /* w: variables */
-     ht = &curwin->w_vars->dv_hashtab;
-     if (wdone < ht->ht_used)
-     {
-       if (wdone++ == 0)
-           hi = ht->ht_array;
-       else
-           ++hi;
-       while (HASHITEM_EMPTY(hi))
-           ++hi;
-       return cat_prefix_varname('w', hi->hi_key);
-     }
- 
-     /* t: variables */
-     ht = &curtab->tp_vars->dv_hashtab;
-     if (tdone < ht->ht_used)
-     {
-       if (tdone++ == 0)
-           hi = ht->ht_array;
-       else
-           ++hi;
-       while (HASHITEM_EMPTY(hi))
-           ++hi;
-       return cat_prefix_varname('t', hi->hi_key);
-     }
- 
-     /* v: variables */
-     if (vidx < VV_LEN)
-       return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
- 
-     VIM_CLEAR(varnamebuf);
-     varnamebuflen = 0;
-     return NULL;
- }
- 
- /*
   * Return TRUE if "pat" matches "text".
   * Does not use 'cpo' and always uses 'magic'.
   */
--- 1947,1952 ----
***************
*** 4619,4625 ****
      int               abort = FALSE;
      buf_T     *buf;
      win_T     *wp;
-     int               i;
      int               did_free = FALSE;
      tabpage_T *tp;
  
--- 4160,4165 ----
***************
*** 4646,4653 ****
      abort = abort || set_ref_in_previous_funccal(copyID);
  
      /* script-local variables */
!     for (i = 1; i <= ga_scripts.ga_len; ++i)
!       abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
  
      /* buffer-local variables */
      FOR_ALL_BUFFERS(buf)
--- 4186,4192 ----
      abort = abort || set_ref_in_previous_funccal(copyID);
  
      /* script-local variables */
!     abort = abort || garbage_collect_scriptvars(copyID);
  
      /* buffer-local variables */
      FOR_ALL_BUFFERS(buf)
***************
*** 4688,4694 ****
      abort = abort || set_ref_in_func_args(copyID);
  
      /* v: vars */
!     abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL);
  
      // callbacks in buffers
      abort = abort || set_ref_in_buffers(copyID);
--- 4227,4233 ----
      abort = abort || set_ref_in_func_args(copyID);
  
      /* v: vars */
!     abort = abort || garbage_collect_vimvars(copyID);
  
      // callbacks in buffers
      abort = abort || set_ref_in_buffers(copyID);
***************
*** 5475,5482 ****
      return OK;
  }
  
- 
- 
  /*
   * Translate a String variable into a position.
   * Returns NULL when there is an error.
--- 5014,5019 ----
***************
*** 5957,6272 ****
  }
  
  /*
-  * Set number v: variable to "val".
-  */
-     void
- set_vim_var_nr(int idx, varnumber_T val)
- {
-     vimvars[idx].vv_nr = val;
- }
- 
- /*
-  * Get typval_T v: variable value.
-  */
-     typval_T *
- get_vim_var_tv(int idx)
- {
-     return &vimvars[idx].vv_tv;
- }
- 
- /*
-  * Get number v: variable value.
-  */
-     varnumber_T
- get_vim_var_nr(int idx)
- {
-     return vimvars[idx].vv_nr;
- }
- 
- /*
-  * Get string v: variable value.  Uses a static buffer, can only be used once.
-  * If the String variable has never been set, return an empty string.
-  * Never returns NULL;
-  */
-     char_u *
- get_vim_var_str(int idx)
- {
-     return tv_get_string(&vimvars[idx].vv_tv);
- }
- 
- /*
-  * Get List v: variable value.  Caller must take care of reference count when
-  * needed.
-  */
-     list_T *
- get_vim_var_list(int idx)
- {
-     return vimvars[idx].vv_list;
- }
- 
- /*
-  * Get Dict v: variable value.  Caller must take care of reference count when
-  * needed.
-  */
-     dict_T *
- get_vim_var_dict(int idx)
- {
-     return vimvars[idx].vv_dict;
- }
- 
- /*
-  * Set v:char to character "c".
-  */
-     void
- set_vim_var_char(int c)
- {
-     char_u    buf[MB_MAXBYTES + 1];
- 
-     if (has_mbyte)
-       buf[(*mb_char2bytes)(c, buf)] = NUL;
-     else
-     {
-       buf[0] = c;
-       buf[1] = NUL;
-     }
-     set_vim_var_string(VV_CHAR, buf, -1);
- }
- 
- /*
-  * Set v:count to "count" and v:count1 to "count1".
-  * When "set_prevcount" is TRUE first set v:prevcount from v:count.
-  */
-     void
- set_vcount(
-     long      count,
-     long      count1,
-     int               set_prevcount)
- {
-     if (set_prevcount)
-       vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
-     vimvars[VV_COUNT].vv_nr = count;
-     vimvars[VV_COUNT1].vv_nr = count1;
- }
- 
- /*
-  * Save variables that might be changed as a side effect.  Used when executing
-  * a timer callback.
-  */
-     void
- save_vimvars(vimvars_save_T *vvsave)
- {
-     vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
-     vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
-     vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
- }
- 
- /*
-  * Restore variables saved by save_vimvars().
-  */
-     void
- restore_vimvars(vimvars_save_T *vvsave)
- {
-     vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
-     vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
-     vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
- }
- 
- /*
-  * Set string v: variable to a copy of "val".
-  */
-     void
- set_vim_var_string(
-     int               idx,
-     char_u    *val,
-     int               len)        /* length of "val" to use or -1 (whole 
string) */
- {
-     clear_tv(&vimvars[idx].vv_di.di_tv);
-     vimvars[idx].vv_type = VAR_STRING;
-     if (val == NULL)
-       vimvars[idx].vv_str = NULL;
-     else if (len == -1)
-       vimvars[idx].vv_str = vim_strsave(val);
-     else
-       vimvars[idx].vv_str = vim_strnsave(val, len);
- }
- 
- /*
-  * Set List v: variable to "val".
-  */
-     void
- set_vim_var_list(int idx, list_T *val)
- {
-     clear_tv(&vimvars[idx].vv_di.di_tv);
-     vimvars[idx].vv_type = VAR_LIST;
-     vimvars[idx].vv_list = val;
-     if (val != NULL)
-       ++val->lv_refcount;
- }
- 
- /*
-  * Set Dictionary v: variable to "val".
-  */
-     void
- set_vim_var_dict(int idx, dict_T *val)
- {
-     clear_tv(&vimvars[idx].vv_di.di_tv);
-     vimvars[idx].vv_type = VAR_DICT;
-     vimvars[idx].vv_dict = val;
-     if (val != NULL)
-     {
-       ++val->dv_refcount;
-       dict_set_items_ro(val);
-     }
- }
- 
- /*
-  * Set v:register if needed.
-  */
-     void
- set_reg_var(int c)
- {
-     char_u    regname;
- 
-     if (c == 0 || c == ' ')
-       regname = '"';
-     else
-       regname = c;
-     /* Avoid free/alloc when the value is already right. */
-     if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
-       set_vim_var_string(VV_REG, &regname, 1);
- }
- 
- /*
-  * Get or set v:exception.  If "oldval" == NULL, return the current value.
-  * Otherwise, restore the value to "oldval" and return NULL.
-  * Must always be called in pairs to save and restore v:exception!  Does not
-  * take care of memory allocations.
-  */
-     char_u *
- v_exception(char_u *oldval)
- {
-     if (oldval == NULL)
-       return vimvars[VV_EXCEPTION].vv_str;
- 
-     vimvars[VV_EXCEPTION].vv_str = oldval;
-     return NULL;
- }
- 
- /*
-  * Get or set v:throwpoint.  If "oldval" == NULL, return the current value.
-  * Otherwise, restore the value to "oldval" and return NULL.
-  * Must always be called in pairs to save and restore v:throwpoint!  Does not
-  * take care of memory allocations.
-  */
-     char_u *
- v_throwpoint(char_u *oldval)
- {
-     if (oldval == NULL)
-       return vimvars[VV_THROWPOINT].vv_str;
- 
-     vimvars[VV_THROWPOINT].vv_str = oldval;
-     return NULL;
- }
- 
- /*
-  * Set v:cmdarg.
-  * If "eap" != NULL, use "eap" to generate the value and return the old value.
-  * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
-  * Must always be called in pairs!
-  */
-     char_u *
- set_cmdarg(exarg_T *eap, char_u *oldarg)
- {
-     char_u    *oldval;
-     char_u    *newval;
-     unsigned  len;
- 
-     oldval = vimvars[VV_CMDARG].vv_str;
-     if (eap == NULL)
-     {
-       vim_free(oldval);
-       vimvars[VV_CMDARG].vv_str = oldarg;
-       return NULL;
-     }
- 
-     if (eap->force_bin == FORCE_BIN)
-       len = 6;
-     else if (eap->force_bin == FORCE_NOBIN)
-       len = 8;
-     else
-       len = 0;
- 
-     if (eap->read_edit)
-       len += 7;
- 
-     if (eap->force_ff != 0)
-       len += 10; /* " ++ff=unix" */
-     if (eap->force_enc != 0)
-       len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
-     if (eap->bad_char != 0)
-       len += 7 + 4;  /* " ++bad=" + "keep" or "drop" */
- 
-     newval = alloc(len + 1);
-     if (newval == NULL)
-       return NULL;
- 
-     if (eap->force_bin == FORCE_BIN)
-       sprintf((char *)newval, " ++bin");
-     else if (eap->force_bin == FORCE_NOBIN)
-       sprintf((char *)newval, " ++nobin");
-     else
-       *newval = NUL;
- 
-     if (eap->read_edit)
-       STRCAT(newval, " ++edit");
- 
-     if (eap->force_ff != 0)
-       sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
-                                               eap->force_ff == 'u' ? "unix"
-                                               : eap->force_ff == 'd' ? "dos"
-                                               : "mac");
-     if (eap->force_enc != 0)
-       sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
-                                              eap->cmd + eap->force_enc);
-     if (eap->bad_char == BAD_KEEP)
-       STRCPY(newval + STRLEN(newval), " ++bad=keep");
-     else if (eap->bad_char == BAD_DROP)
-       STRCPY(newval + STRLEN(newval), " ++bad=drop");
-     else if (eap->bad_char != 0)
-       sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
-     vimvars[VV_CMDARG].vv_str = newval;
-     return oldval;
- }
- 
- /*
-  * Check if variable "name[len]" is a local variable or an argument.
-  * If so, "*eval_lavars_used" is set to TRUE.
-  */
-     static void
- check_vars(char_u *name, int len)
- {
-     int               cc;
-     char_u    *varname;
-     hashtab_T *ht;
- 
-     if (eval_lavars_used == NULL)
-       return;
- 
-     /* truncate the name, so that we can use strcmp() */
-     cc = name[len];
-     name[len] = NUL;
- 
-     ht = find_var_ht(name, &varname);
-     if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
-     {
-       if (find_var(name, NULL, TRUE) != NULL)
-           *eval_lavars_used = TRUE;
-     }
- 
-     name[len] = cc;
- }
- 
- /*
   * Handle:
   * - expr[expr], expr[expr:expr] subscript
   * - ".name" lookup
--- 5494,5499 ----
***************
*** 6380,6386 ****
   * The string "s" must have been allocated, it is consumed.
   * Return NULL for out of memory, the variable otherwise.
   */
!     static typval_T *
  alloc_string_tv(char_u *s)
  {
      typval_T  *rettv;
--- 5607,5613 ----
   * The string "s" must have been allocated, it is consumed.
   * Return NULL for out of memory, the variable otherwise.
   */
!     typval_T *
  alloc_string_tv(char_u *s)
  {
      typval_T  *rettv;
***************
*** 6777,6985 ****
  }
  
  /*
-  * Find variable "name" in the list of variables.
-  * Return a pointer to it if found, NULL if not found.
-  * Careful: "a:0" variables don't have a name.
-  * When "htp" is not NULL we are writing to the variable, set "htp" to the
-  * hashtab_T used.
-  */
-     dictitem_T *
- find_var(char_u *name, hashtab_T **htp, int no_autoload)
- {
-     char_u    *varname;
-     hashtab_T *ht;
-     dictitem_T        *ret = NULL;
- 
-     ht = find_var_ht(name, &varname);
-     if (htp != NULL)
-       *htp = ht;
-     if (ht == NULL)
-       return NULL;
-     ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
-     if (ret != NULL)
-       return ret;
- 
-     /* Search in parent scope for lambda */
-     return find_var_in_scoped_ht(name, no_autoload || htp != NULL);
- }
- 
- /*
-  * Find variable "varname" in hashtab "ht" with name "htname".
-  * Returns NULL if not found.
-  */
-     dictitem_T *
- find_var_in_ht(
-     hashtab_T *ht,
-     int               htname,
-     char_u    *varname,
-     int               no_autoload)
- {
-     hashitem_T        *hi;
- 
-     if (*varname == NUL)
-     {
-       /* Must be something like "s:", otherwise "ht" would be NULL. */
-       switch (htname)
-       {
-           case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
-           case 'g': return &globvars_var;
-           case 'v': return &vimvars_var;
-           case 'b': return &curbuf->b_bufvar;
-           case 'w': return &curwin->w_winvar;
-           case 't': return &curtab->tp_winvar;
-           case 'l': return get_funccal_local_var();
-           case 'a': return get_funccal_args_var();
-       }
-       return NULL;
-     }
- 
-     hi = hash_find(ht, varname);
-     if (HASHITEM_EMPTY(hi))
-     {
-       /* For global variables we may try auto-loading the script.  If it
-        * worked find the variable again.  Don't auto-load a script if it was
-        * loaded already, otherwise it would be loaded every time when
-        * checking if a function name is a Funcref variable. */
-       if (ht == &globvarht && !no_autoload)
-       {
-           /* Note: script_autoload() may make "hi" invalid. It must either
-            * be obtained again or not used. */
-           if (!script_autoload(varname, FALSE) || aborting())
-               return NULL;
-           hi = hash_find(ht, varname);
-       }
-       if (HASHITEM_EMPTY(hi))
-           return NULL;
-     }
-     return HI2DI(hi);
- }
- 
- /*
-  * Find the hashtab used for a variable name.
-  * Return NULL if the name is not valid.
-  * Set "varname" to the start of name without ':'.
-  */
-     hashtab_T *
- find_var_ht(char_u *name, char_u **varname)
- {
-     hashitem_T        *hi;
-     hashtab_T *ht;
- 
-     if (name[0] == NUL)
-       return NULL;
-     if (name[1] != ':')
-     {
-       /* The name must not start with a colon or #. */
-       if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
-           return NULL;
-       *varname = name;
- 
-       // "version" is "v:version" in all scopes if scriptversion < 3.
-       // Same for a few other variables marked with VV_COMPAT.
-       if (current_sctx.sc_version < 3)
-       {
-           hi = hash_find(&compat_hashtab, name);
-           if (!HASHITEM_EMPTY(hi))
-               return &compat_hashtab;
-       }
- 
-       ht = get_funccal_local_ht();
-       if (ht == NULL)
-           return &globvarht;                  /* global variable */
-       return ht;                              /* local variable */
-     }
-     *varname = name + 2;
-     if (*name == 'g')                         /* global variable */
-       return &globvarht;
-     // There must be no ':' or '#' in the rest of the name, unless g: is used
-     if (vim_strchr(name + 2, ':') != NULL
-                              || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
-       return NULL;
-     if (*name == 'b')                         /* buffer variable */
-       return &curbuf->b_vars->dv_hashtab;
-     if (*name == 'w')                         /* window variable */
-       return &curwin->w_vars->dv_hashtab;
-     if (*name == 't')                         /* tab page variable */
-       return &curtab->tp_vars->dv_hashtab;
-     if (*name == 'v')                         /* v: variable */
-       return &vimvarht;
-     if (*name == 'a')                         /* a: function argument */
-       return get_funccal_args_ht();
-     if (*name == 'l')                         /* l: local function variable */
-       return get_funccal_local_ht();
-     if (*name == 's'                          /* script variable */
-           && current_sctx.sc_sid > 0 && current_sctx.sc_sid <= 
ga_scripts.ga_len)
-       return &SCRIPT_VARS(current_sctx.sc_sid);
-     return NULL;
- }
- 
- /*
-  * Allocate a new hashtab for a sourced script.  It will be used while
-  * sourcing this script and when executing functions defined in the script.
-  */
-     void
- new_script_vars(scid_T id)
- {
-     int               i;
-     hashtab_T *ht;
-     scriptvar_T *sv;
- 
-     if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
-     {
-       /* Re-allocating ga_data means that an ht_array pointing to
-        * ht_smallarray becomes invalid.  We can recognize this: ht_mask is
-        * at its init value.  Also reset "v_dict", it's always the same. */
-       for (i = 1; i <= ga_scripts.ga_len; ++i)
-       {
-           ht = &SCRIPT_VARS(i);
-           if (ht->ht_mask == HT_INIT_SIZE - 1)
-               ht->ht_array = ht->ht_smallarray;
-           sv = SCRIPT_SV(i);
-           sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
-       }
- 
-       while (ga_scripts.ga_len < id)
-       {
-           sv = SCRIPT_SV(ga_scripts.ga_len + 1) =
-               ALLOC_CLEAR_ONE(scriptvar_T);
-           init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
-           ++ga_scripts.ga_len;
-       }
-     }
- }
- 
- /*
-  * Initialize dictionary "dict" as a scope and set variable "dict_var" to
-  * point to it.
-  */
-     void
- init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
- {
-     hash_init(&dict->dv_hashtab);
-     dict->dv_lock = 0;
-     dict->dv_scope = scope;
-     dict->dv_refcount = DO_NOT_FREE_CNT;
-     dict->dv_copyID = 0;
-     dict_var->di_tv.vval.v_dict = dict;
-     dict_var->di_tv.v_type = VAR_DICT;
-     dict_var->di_tv.v_lock = VAR_FIXED;
-     dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
-     dict_var->di_key[0] = NUL;
- }
- 
- /*
-  * Unreference a dictionary initialized by init_var_dict().
-  */
-     void
- unref_var_dict(dict_T *dict)
- {
-     /* Now the dict needs to be freed if no one else is using it, go back to
-      * normal reference counting. */
-     dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
-     dict_unref(dict);
- }
- 
- /*
   * Return TRUE if typeval "tv" and its value are set to be locked (immutable).
   * Also give an error message, using "name" or _("name") when use_gettext is
   * TRUE.
--- 6004,6009 ----
***************
*** 7730,7763 ****
  }
  
  /*
-  * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
-  * v:option_type, and v:option_command.
-  */
-     void
- reset_v_option_vars(void)
- {
-     set_vim_var_string(VV_OPTION_NEW,  NULL, -1);
-     set_vim_var_string(VV_OPTION_OLD,  NULL, -1);
-     set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
-     set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
-     set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
-     set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
- }
- 
- /*
-  * Add an assert error to v:errors.
-  */
-     void
- assert_error(garray_T *gap)
- {
-     struct vimvar   *vp = &vimvars[VV_ERRORS];
- 
-     if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
-       /* Make sure v:errors is a list. */
-       set_vim_var_list(VV_ERRORS, list_alloc());
-     list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
- }
- /*
   * Compare "typ1" and "typ2".  Put the result in "typ1".
   */
      int
--- 6754,6759 ----
***************
*** 8000,8006 ****
  
  #endif /* FEAT_EVAL */
  
- 
  #if defined(FEAT_MODIFY_FNAME) || defined(FEAT_EVAL) || defined(PROTO)
  
  #ifdef MSWIN
--- 6996,7001 ----
***************
*** 8754,8762 ****
      typval_T  argv[3];
      int               retval = FAIL;
  
!     copy_tv(tv, &vimvars[VV_VAL].vv_tv);
!     argv[0] = vimvars[VV_KEY].vv_tv;
!     argv[1] = vimvars[VV_VAL].vv_tv;
      if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
        goto theend;
      if (map)
--- 7749,7757 ----
      typval_T  argv[3];
      int               retval = FAIL;
  
!     copy_tv(tv, get_vim_var_tv(VV_VAL));
!     argv[0] = *get_vim_var_tv(VV_KEY);
!     argv[1] = *get_vim_var_tv(VV_VAL);
      if (eval_expr_typval(expr, argv, 2, &rettv) == FAIL)
        goto theend;
      if (map)
***************
*** 8780,8790 ****
      }
      retval = OK;
  theend:
!     clear_tv(&vimvars[VV_VAL].vv_tv);
      return retval;
  }
  
- 
  /*
   * Implementation of map() and filter().
   */
--- 7775,7784 ----
      }
      retval = OK;
  theend:
!     clear_tv(get_vim_var_tv(VV_VAL));
      return retval;
  }
  
  /*
   * Implementation of map() and filter().
   */
***************
*** 8848,8855 ****
        prepare_vimvar(VV_KEY, &save_key);
        if (argvars[0].v_type == VAR_DICT)
        {
-           vimvars[VV_KEY].vv_type = VAR_STRING;
- 
            ht = &d->dv_hashtab;
            hash_lock(ht);
            todo = (int)ht->ht_used;
--- 7842,7847 ----
***************
*** 8866,8874 ****
                                || var_check_ro(di->di_flags,
                                                           arg_errmsg, TRUE)))
                        break;
!                   vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
                    r = filter_map_one(&di->di_tv, expr, map, &rem);
!                   clear_tv(&vimvars[VV_KEY].vv_tv);
                    if (r == FAIL || did_emsg)
                        break;
                    if (!map && rem)
--- 7858,7866 ----
                                || var_check_ro(di->di_flags,
                                                           arg_errmsg, TRUE)))
                        break;
!                   set_vim_var_string(VV_KEY, di->di_key, -1);
                    r = filter_map_one(&di->di_tv, expr, map, &rem);
!                   clear_tv(get_vim_var_tv(VV_KEY));
                    if (r == FAIL || did_emsg)
                        break;
                    if (!map && rem)
***************
*** 8887,8898 ****
            int         i;
            typval_T    tv;
  
-           vimvars[VV_KEY].vv_type = VAR_NUMBER;
            for (i = 0; i < b->bv_ga.ga_len; i++)
            {
                tv.v_type = VAR_NUMBER;
                tv.vval.v_number = blob_get(b, i);
!               vimvars[VV_KEY].vv_nr = idx;
                if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
                    break;
                if (tv.v_type != VAR_NUMBER)
--- 7879,7889 ----
            int         i;
            typval_T    tv;
  
            for (i = 0; i < b->bv_ga.ga_len; i++)
            {
                tv.v_type = VAR_NUMBER;
                tv.vval.v_number = blob_get(b, i);
!               set_vim_var_nr(VV_KEY, idx);
                if (filter_map_one(&tv, expr, map, &rem) == FAIL || did_emsg)
                    break;
                if (tv.v_type != VAR_NUMBER)
***************
*** 8916,8929 ****
        else
        {
            // argvars[0].v_type == VAR_LIST
-           vimvars[VV_KEY].vv_type = VAR_NUMBER;
- 
            for (li = l->lv_first; li != NULL; li = nli)
            {
                if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
                    break;
                nli = li->li_next;
!               vimvars[VV_KEY].vv_nr = idx;
                if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
                                                                  || did_emsg)
                    break;
--- 7907,7918 ----
        else
        {
            // argvars[0].v_type == VAR_LIST
            for (li = l->lv_first; li != NULL; li = nli)
            {
                if (map && var_check_lock(li->li_tv.v_lock, arg_errmsg, TRUE))
                    break;
                nli = li->li_next;
!               set_vim_var_nr(VV_KEY, idx);
                if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
                                                                  || did_emsg)
                    break;
*** ../vim-8.1.1938/src/evalvars.c      2019-08-27 22:48:12.741480663 +0200
--- src/evalvars.c      2019-08-29 22:09:20.628579500 +0200
***************
*** 17,22 ****
--- 17,180 ----
  
  static char *e_letunexp       = N_("E18: Unexpected characters in :let");
  
+ static dictitem_T     globvars_var;           // variable used for g:
+ 
+ /*
+  * Old Vim variables such as "v:version" are also available without the "v:".
+  * Also in functions.  We need a special hashtable for them.
+  */
+ static hashtab_T      compat_hashtab;
+ 
+ /*
+  * Array to hold the value of v: variables.
+  * The value is in a dictitem, so that it can also be used in the v: scope.
+  * The reason to use this table anyway is for very quick access to the
+  * variables with the VV_ defines.
+  */
+ 
+ // values for vv_flags:
+ #define VV_COMPAT     1       // compatible, also used without "v:"
+ #define VV_RO         2       // read-only
+ #define VV_RO_SBX     4       // read-only in the sandbox
+ 
+ #define VV_NAME(s, t) s, {{t, 0, {0}}, 0, {0}}
+ 
+ static struct vimvar
+ {
+     char      *vv_name;       // name of variable, without v:
+     dictitem16_T vv_di;               // value and name for key (max 16 
chars!)
+     char      vv_flags;       // VV_COMPAT, VV_RO, VV_RO_SBX
+ } vimvars[VV_LEN] =
+ {
+     /*
+      * The order here must match the VV_ defines in vim.h!
+      * Initializing a union does not work, leave tv.vval empty to get zero's.
+      */
+     {VV_NAME("count",          VAR_NUMBER), VV_COMPAT+VV_RO},
+     {VV_NAME("count1",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("prevcount",      VAR_NUMBER), VV_RO},
+     {VV_NAME("errmsg",                 VAR_STRING), VV_COMPAT},
+     {VV_NAME("warningmsg",     VAR_STRING), 0},
+     {VV_NAME("statusmsg",      VAR_STRING), 0},
+     {VV_NAME("shell_error",    VAR_NUMBER), VV_COMPAT+VV_RO},
+     {VV_NAME("this_session",   VAR_STRING), VV_COMPAT},
+     {VV_NAME("version",                VAR_NUMBER), VV_COMPAT+VV_RO},
+     {VV_NAME("lnum",           VAR_NUMBER), VV_RO_SBX},
+     {VV_NAME("termresponse",   VAR_STRING), VV_RO},
+     {VV_NAME("fname",          VAR_STRING), VV_RO},
+     {VV_NAME("lang",           VAR_STRING), VV_RO},
+     {VV_NAME("lc_time",                VAR_STRING), VV_RO},
+     {VV_NAME("ctype",          VAR_STRING), VV_RO},
+     {VV_NAME("charconvert_from", VAR_STRING), VV_RO},
+     {VV_NAME("charconvert_to",         VAR_STRING), VV_RO},
+     {VV_NAME("fname_in",       VAR_STRING), VV_RO},
+     {VV_NAME("fname_out",      VAR_STRING), VV_RO},
+     {VV_NAME("fname_new",      VAR_STRING), VV_RO},
+     {VV_NAME("fname_diff",     VAR_STRING), VV_RO},
+     {VV_NAME("cmdarg",                 VAR_STRING), VV_RO},
+     {VV_NAME("foldstart",      VAR_NUMBER), VV_RO_SBX},
+     {VV_NAME("foldend",                VAR_NUMBER), VV_RO_SBX},
+     {VV_NAME("folddashes",     VAR_STRING), VV_RO_SBX},
+     {VV_NAME("foldlevel",      VAR_NUMBER), VV_RO_SBX},
+     {VV_NAME("progname",       VAR_STRING), VV_RO},
+     {VV_NAME("servername",     VAR_STRING), VV_RO},
+     {VV_NAME("dying",          VAR_NUMBER), VV_RO},
+     {VV_NAME("exception",      VAR_STRING), VV_RO},
+     {VV_NAME("throwpoint",     VAR_STRING), VV_RO},
+     {VV_NAME("register",       VAR_STRING), VV_RO},
+     {VV_NAME("cmdbang",                VAR_NUMBER), VV_RO},
+     {VV_NAME("insertmode",     VAR_STRING), VV_RO},
+     {VV_NAME("val",            VAR_UNKNOWN), VV_RO},
+     {VV_NAME("key",            VAR_UNKNOWN), VV_RO},
+     {VV_NAME("profiling",      VAR_NUMBER), VV_RO},
+     {VV_NAME("fcs_reason",     VAR_STRING), VV_RO},
+     {VV_NAME("fcs_choice",     VAR_STRING), 0},
+     {VV_NAME("beval_bufnr",    VAR_NUMBER), VV_RO},
+     {VV_NAME("beval_winnr",    VAR_NUMBER), VV_RO},
+     {VV_NAME("beval_winid",    VAR_NUMBER), VV_RO},
+     {VV_NAME("beval_lnum",     VAR_NUMBER), VV_RO},
+     {VV_NAME("beval_col",      VAR_NUMBER), VV_RO},
+     {VV_NAME("beval_text",     VAR_STRING), VV_RO},
+     {VV_NAME("scrollstart",    VAR_STRING), 0},
+     {VV_NAME("swapname",       VAR_STRING), VV_RO},
+     {VV_NAME("swapchoice",     VAR_STRING), 0},
+     {VV_NAME("swapcommand",    VAR_STRING), VV_RO},
+     {VV_NAME("char",           VAR_STRING), 0},
+     {VV_NAME("mouse_win",      VAR_NUMBER), 0},
+     {VV_NAME("mouse_winid",    VAR_NUMBER), 0},
+     {VV_NAME("mouse_lnum",     VAR_NUMBER), 0},
+     {VV_NAME("mouse_col",      VAR_NUMBER), 0},
+     {VV_NAME("operator",       VAR_STRING), VV_RO},
+     {VV_NAME("searchforward",  VAR_NUMBER), 0},
+     {VV_NAME("hlsearch",       VAR_NUMBER), 0},
+     {VV_NAME("oldfiles",       VAR_LIST), 0},
+     {VV_NAME("windowid",       VAR_NUMBER), VV_RO},
+     {VV_NAME("progpath",       VAR_STRING), VV_RO},
+     {VV_NAME("completed_item",         VAR_DICT), VV_RO},
+     {VV_NAME("option_new",     VAR_STRING), VV_RO},
+     {VV_NAME("option_old",     VAR_STRING), VV_RO},
+     {VV_NAME("option_oldlocal",        VAR_STRING), VV_RO},
+     {VV_NAME("option_oldglobal", VAR_STRING), VV_RO},
+     {VV_NAME("option_command",         VAR_STRING), VV_RO},
+     {VV_NAME("option_type",    VAR_STRING), VV_RO},
+     {VV_NAME("errors",                 VAR_LIST), 0},
+     {VV_NAME("false",          VAR_SPECIAL), VV_RO},
+     {VV_NAME("true",           VAR_SPECIAL), VV_RO},
+     {VV_NAME("null",           VAR_SPECIAL), VV_RO},
+     {VV_NAME("none",           VAR_SPECIAL), VV_RO},
+     {VV_NAME("vim_did_enter",  VAR_NUMBER), VV_RO},
+     {VV_NAME("testing",                VAR_NUMBER), 0},
+     {VV_NAME("t_number",       VAR_NUMBER), VV_RO},
+     {VV_NAME("t_string",       VAR_NUMBER), VV_RO},
+     {VV_NAME("t_func",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("t_list",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("t_dict",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("t_float",                VAR_NUMBER), VV_RO},
+     {VV_NAME("t_bool",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("t_none",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("t_job",          VAR_NUMBER), VV_RO},
+     {VV_NAME("t_channel",      VAR_NUMBER), VV_RO},
+     {VV_NAME("t_blob",                 VAR_NUMBER), VV_RO},
+     {VV_NAME("termrfgresp",    VAR_STRING), VV_RO},
+     {VV_NAME("termrbgresp",    VAR_STRING), VV_RO},
+     {VV_NAME("termu7resp",     VAR_STRING), VV_RO},
+     {VV_NAME("termstyleresp",  VAR_STRING), VV_RO},
+     {VV_NAME("termblinkresp",  VAR_STRING), VV_RO},
+     {VV_NAME("event",          VAR_DICT), VV_RO},
+     {VV_NAME("versionlong",    VAR_NUMBER), VV_RO},
+     {VV_NAME("echospace",      VAR_NUMBER), VV_RO},
+ };
+ 
+ // shorthand
+ #define vv_type               vv_di.di_tv.v_type
+ #define vv_nr         vv_di.di_tv.vval.v_number
+ #define vv_float      vv_di.di_tv.vval.v_float
+ #define vv_str                vv_di.di_tv.vval.v_string
+ #define vv_list               vv_di.di_tv.vval.v_list
+ #define vv_dict               vv_di.di_tv.vval.v_dict
+ #define vv_blob               vv_di.di_tv.vval.v_blob
+ #define vv_tv         vv_di.di_tv
+ 
+ static dictitem_T     vimvars_var;            // variable used for v:
+ #define vimvarht  vimvardict.dv_hashtab
+ 
+ // for VIM_VERSION_ defines
+ #include "version.h"
+ 
+ /*
+  * Array to hold the hashtab with variables local to each sourced script.
+  * Each item holds a variable (nameless) that points to the dict_T.
+  */
+ typedef struct
+ {
+     dictitem_T        sv_var;
+     dict_T    sv_dict;
+ } scriptvar_T;
+ 
+ static garray_T           ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
+ #define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1])
+ #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab)
+ 
  static void ex_let_const(exarg_T *eap, int is_const);
  static char_u *skip_var_one(char_u *arg);
  static void list_glob_vars(int *first);
***************
*** 33,38 ****
--- 191,396 ----
  static void list_one_var_a(char *prefix, char_u *name, int type, char_u 
*string, int *first);
  
  /*
+  * Initialize global and vim special variables
+  */
+     void
+ evalvars_init(void)
+ {
+     int                   i;
+     struct vimvar   *p;
+ 
+     init_var_dict(&globvardict, &globvars_var, VAR_DEF_SCOPE);
+     init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
+     vimvardict.dv_lock = VAR_FIXED;
+     hash_init(&compat_hashtab);
+ 
+     for (i = 0; i < VV_LEN; ++i)
+     {
+       p = &vimvars[i];
+       if (STRLEN(p->vv_name) > DICTITEM16_KEY_LEN)
+       {
+           iemsg("INTERNAL: name too long, increase size of dictitem16_T");
+           getout(1);
+       }
+       STRCPY(p->vv_di.di_key, p->vv_name);
+       if (p->vv_flags & VV_RO)
+           p->vv_di.di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+       else if (p->vv_flags & VV_RO_SBX)
+           p->vv_di.di_flags = DI_FLAGS_RO_SBX | DI_FLAGS_FIX;
+       else
+           p->vv_di.di_flags = DI_FLAGS_FIX;
+ 
+       // add to v: scope dict, unless the value is not always available
+       if (p->vv_type != VAR_UNKNOWN)
+           hash_add(&vimvarht, p->vv_di.di_key);
+       if (p->vv_flags & VV_COMPAT)
+           // add to compat scope dict
+           hash_add(&compat_hashtab, p->vv_di.di_key);
+     }
+     vimvars[VV_VERSION].vv_nr = VIM_VERSION_100;
+     vimvars[VV_VERSIONLONG].vv_nr = VIM_VERSION_100 * 10000 + highest_patch();
+ 
+     set_vim_var_nr(VV_SEARCHFORWARD, 1L);
+     set_vim_var_nr(VV_HLSEARCH, 1L);
+     set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
+     set_vim_var_list(VV_ERRORS, list_alloc());
+     set_vim_var_dict(VV_EVENT, dict_alloc_lock(VAR_FIXED));
+ 
+     set_vim_var_nr(VV_FALSE, VVAL_FALSE);
+     set_vim_var_nr(VV_TRUE, VVAL_TRUE);
+     set_vim_var_nr(VV_NONE, VVAL_NONE);
+     set_vim_var_nr(VV_NULL, VVAL_NULL);
+ 
+     set_vim_var_nr(VV_TYPE_NUMBER,  VAR_TYPE_NUMBER);
+     set_vim_var_nr(VV_TYPE_STRING,  VAR_TYPE_STRING);
+     set_vim_var_nr(VV_TYPE_FUNC,    VAR_TYPE_FUNC);
+     set_vim_var_nr(VV_TYPE_LIST,    VAR_TYPE_LIST);
+     set_vim_var_nr(VV_TYPE_DICT,    VAR_TYPE_DICT);
+     set_vim_var_nr(VV_TYPE_FLOAT,   VAR_TYPE_FLOAT);
+     set_vim_var_nr(VV_TYPE_BOOL,    VAR_TYPE_BOOL);
+     set_vim_var_nr(VV_TYPE_NONE,    VAR_TYPE_NONE);
+     set_vim_var_nr(VV_TYPE_JOB,     VAR_TYPE_JOB);
+     set_vim_var_nr(VV_TYPE_CHANNEL, VAR_TYPE_CHANNEL);
+     set_vim_var_nr(VV_TYPE_BLOB,    VAR_TYPE_BLOB);
+ 
+     set_vim_var_nr(VV_ECHOSPACE,    sc_col - 1);
+ 
+     set_reg_var(0);  // default for v:register is not 0 but '"'
+ }
+ 
+ #if defined(EXITFREE) || defined(PROTO)
+ /*
+  * Free all vim variables information on exit
+  */
+     void
+ evalvars_clear(void)
+ {
+     int                   i;
+     struct vimvar   *p;
+ 
+     for (i = 0; i < VV_LEN; ++i)
+     {
+       p = &vimvars[i];
+       if (p->vv_di.di_tv.v_type == VAR_STRING)
+           VIM_CLEAR(p->vv_str);
+       else if (p->vv_di.di_tv.v_type == VAR_LIST)
+       {
+           list_unref(p->vv_list);
+           p->vv_list = NULL;
+       }
+     }
+     hash_clear(&vimvarht);
+     hash_init(&vimvarht);  // garbage_collect() will access it
+     hash_clear(&compat_hashtab);
+ 
+     // global variables
+     vars_clear(&globvarht);
+ 
+     // Script-local variables. First clear all the variables and in a second
+     // loop free the scriptvar_T, because a variable in one script might hold
+     // a reference to the whole scope of another script.
+     for (i = 1; i <= ga_scripts.ga_len; ++i)
+       vars_clear(&SCRIPT_VARS(i));
+     for (i = 1; i <= ga_scripts.ga_len; ++i)
+       vim_free(SCRIPT_SV(i));
+     ga_clear(&ga_scripts);
+ }
+ #endif
+ 
+     int
+ garbage_collect_vimvars(int copyID)
+ {
+     return set_ref_in_ht(&vimvarht, copyID, NULL);
+ }
+ 
+     int
+ garbage_collect_scriptvars(int copyID)
+ {
+     int               i;
+     int               abort = FALSE;
+ 
+     for (i = 1; i <= ga_scripts.ga_len; ++i)
+       abort = abort || set_ref_in_ht(&SCRIPT_VARS(i), copyID, NULL);
+ 
+     return abort;
+ }
+ 
+ /*
+  * Set an internal variable to a string value. Creates the variable if it does
+  * not already exist.
+  */
+     void
+ set_internal_string_var(char_u *name, char_u *value)
+ {
+     char_u    *val;
+     typval_T  *tvp;
+ 
+     val = vim_strsave(value);
+     if (val != NULL)
+     {
+       tvp = alloc_string_tv(val);
+       if (tvp != NULL)
+       {
+           set_var(name, tvp, FALSE);
+           free_tv(tvp);
+       }
+     }
+ }
+ 
+ /*
+  * Prepare v: variable "idx" to be used.
+  * Save the current typeval in "save_tv".
+  * When not used yet add the variable to the v: hashtable.
+  */
+     void
+ prepare_vimvar(int idx, typval_T *save_tv)
+ {
+     *save_tv = vimvars[idx].vv_tv;
+     if (vimvars[idx].vv_type == VAR_UNKNOWN)
+       hash_add(&vimvarht, vimvars[idx].vv_di.di_key);
+ }
+ 
+ /*
+  * Restore v: variable "idx" to typeval "save_tv".
+  * When no longer defined, remove the variable from the v: hashtable.
+  */
+     void
+ restore_vimvar(int idx, typval_T *save_tv)
+ {
+     hashitem_T        *hi;
+ 
+     vimvars[idx].vv_tv = *save_tv;
+     if (vimvars[idx].vv_type == VAR_UNKNOWN)
+     {
+       hi = hash_find(&vimvarht, vimvars[idx].vv_di.di_key);
+       if (HASHITEM_EMPTY(hi))
+           internal_error("restore_vimvar()");
+       else
+           hash_remove(&vimvarht, hi);
+     }
+ }
+ 
+ /*
+  * List Vim variables.
+  */
+     static void
+ list_vim_vars(int *first)
+ {
+     list_hashtable_vars(&vimvarht, "v:", FALSE, first);
+ }
+ 
+ /*
+  * List script-local variables, if there is a script.
+  */
+     static void
+ list_script_vars(int *first)
+ {
+     if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
+       list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
+                                                          "s:", FALSE, first);
+ }
+ 
+ /*
   * Get a list of lines from a HERE document. The here document is a list of
   * lines surrounded by a marker.
   *    cmd << {marker}
***************
*** 1024,1030 ****
        {
            if (ht == &globvarht)
                d = &globvardict;
!           else if (is_compatht(ht))
                d = &vimvardict;
            else
            {
--- 1382,1388 ----
        {
            if (ht == &globvarht)
                d = &globvardict;
!           else if (ht == &compat_hashtab)
                d = &vimvardict;
            else
            {
***************
*** 1214,1219 ****
--- 1572,1980 ----
  }
  
  /*
+  * Local string buffer for the next two functions to store a variable name
+  * with its prefix. Allocated in cat_prefix_varname(), freed later in
+  * get_user_var_name().
+  */
+ 
+ static char_u *varnamebuf = NULL;
+ static int    varnamebuflen = 0;
+ 
+ /*
+  * Function to concatenate a prefix and a variable name.
+  */
+     static char_u *
+ cat_prefix_varname(int prefix, char_u *name)
+ {
+     int               len;
+ 
+     len = (int)STRLEN(name) + 3;
+     if (len > varnamebuflen)
+     {
+       vim_free(varnamebuf);
+       len += 10;                      /* some additional space */
+       varnamebuf = alloc(len);
+       if (varnamebuf == NULL)
+       {
+           varnamebuflen = 0;
+           return NULL;
+       }
+       varnamebuflen = len;
+     }
+     *varnamebuf = prefix;
+     varnamebuf[1] = ':';
+     STRCPY(varnamebuf + 2, name);
+     return varnamebuf;
+ }
+ 
+ /*
+  * Function given to ExpandGeneric() to obtain the list of user defined
+  * (global/buffer/window/built-in) variable names.
+  */
+     char_u *
+ get_user_var_name(expand_T *xp, int idx)
+ {
+     static long_u     gdone;
+     static long_u     bdone;
+     static long_u     wdone;
+     static long_u     tdone;
+     static int                vidx;
+     static hashitem_T *hi;
+     hashtab_T         *ht;
+ 
+     if (idx == 0)
+     {
+       gdone = bdone = wdone = vidx = 0;
+       tdone = 0;
+     }
+ 
+     // Global variables
+     if (gdone < globvarht.ht_used)
+     {
+       if (gdone++ == 0)
+           hi = globvarht.ht_array;
+       else
+           ++hi;
+       while (HASHITEM_EMPTY(hi))
+           ++hi;
+       if (STRNCMP("g:", xp->xp_pattern, 2) == 0)
+           return cat_prefix_varname('g', hi->hi_key);
+       return hi->hi_key;
+     }
+ 
+     // b: variables
+     ht = &curbuf->b_vars->dv_hashtab;
+     if (bdone < ht->ht_used)
+     {
+       if (bdone++ == 0)
+           hi = ht->ht_array;
+       else
+           ++hi;
+       while (HASHITEM_EMPTY(hi))
+           ++hi;
+       return cat_prefix_varname('b', hi->hi_key);
+     }
+ 
+     // w: variables
+     ht = &curwin->w_vars->dv_hashtab;
+     if (wdone < ht->ht_used)
+     {
+       if (wdone++ == 0)
+           hi = ht->ht_array;
+       else
+           ++hi;
+       while (HASHITEM_EMPTY(hi))
+           ++hi;
+       return cat_prefix_varname('w', hi->hi_key);
+     }
+ 
+     // t: variables
+     ht = &curtab->tp_vars->dv_hashtab;
+     if (tdone < ht->ht_used)
+     {
+       if (tdone++ == 0)
+           hi = ht->ht_array;
+       else
+           ++hi;
+       while (HASHITEM_EMPTY(hi))
+           ++hi;
+       return cat_prefix_varname('t', hi->hi_key);
+     }
+ 
+     // v: variables
+     if (vidx < VV_LEN)
+       return cat_prefix_varname('v', (char_u *)vimvars[vidx++].vv_name);
+ 
+     VIM_CLEAR(varnamebuf);
+     varnamebuflen = 0;
+     return NULL;
+ }
+ 
+ /*
+  * Set number v: variable to "val".
+  */
+     void
+ set_vim_var_nr(int idx, varnumber_T val)
+ {
+     vimvars[idx].vv_type = VAR_NUMBER;
+     vimvars[idx].vv_nr = val;
+ }
+ 
+ /*
+  * Get typval_T v: variable value.
+  */
+     typval_T *
+ get_vim_var_tv(int idx)
+ {
+     return &vimvars[idx].vv_tv;
+ }
+ 
+ /*
+  * Get number v: variable value.
+  */
+     varnumber_T
+ get_vim_var_nr(int idx)
+ {
+     return vimvars[idx].vv_nr;
+ }
+ 
+ /*
+  * Get string v: variable value.  Uses a static buffer, can only be used once.
+  * If the String variable has never been set, return an empty string.
+  * Never returns NULL;
+  */
+     char_u *
+ get_vim_var_str(int idx)
+ {
+     return tv_get_string(&vimvars[idx].vv_tv);
+ }
+ 
+ /*
+  * Get List v: variable value.  Caller must take care of reference count when
+  * needed.
+  */
+     list_T *
+ get_vim_var_list(int idx)
+ {
+     return vimvars[idx].vv_list;
+ }
+ 
+ /*
+  * Get Dict v: variable value.  Caller must take care of reference count when
+  * needed.
+  */
+     dict_T *
+ get_vim_var_dict(int idx)
+ {
+     return vimvars[idx].vv_dict;
+ }
+ 
+ /*
+  * Set v:char to character "c".
+  */
+     void
+ set_vim_var_char(int c)
+ {
+     char_u    buf[MB_MAXBYTES + 1];
+ 
+     if (has_mbyte)
+       buf[(*mb_char2bytes)(c, buf)] = NUL;
+     else
+     {
+       buf[0] = c;
+       buf[1] = NUL;
+     }
+     set_vim_var_string(VV_CHAR, buf, -1);
+ }
+ 
+ /*
+  * Set v:count to "count" and v:count1 to "count1".
+  * When "set_prevcount" is TRUE first set v:prevcount from v:count.
+  */
+     void
+ set_vcount(
+     long      count,
+     long      count1,
+     int               set_prevcount)
+ {
+     if (set_prevcount)
+       vimvars[VV_PREVCOUNT].vv_nr = vimvars[VV_COUNT].vv_nr;
+     vimvars[VV_COUNT].vv_nr = count;
+     vimvars[VV_COUNT1].vv_nr = count1;
+ }
+ 
+ /*
+  * Save variables that might be changed as a side effect.  Used when executing
+  * a timer callback.
+  */
+     void
+ save_vimvars(vimvars_save_T *vvsave)
+ {
+     vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
+     vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
+     vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
+ }
+ 
+ /*
+  * Restore variables saved by save_vimvars().
+  */
+     void
+ restore_vimvars(vimvars_save_T *vvsave)
+ {
+     vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
+     vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
+     vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
+ }
+ 
+ /*
+  * Set string v: variable to a copy of "val". If 'copy' is FALSE, then set the
+  * value.
+  */
+     void
+ set_vim_var_string(
+     int               idx,
+     char_u    *val,
+     int               len)        // length of "val" to use or -1 (whole 
string)
+ {
+     clear_tv(&vimvars[idx].vv_di.di_tv);
+     vimvars[idx].vv_type = VAR_STRING;
+     if (val == NULL)
+       vimvars[idx].vv_str = NULL;
+     else if (len == -1)
+       vimvars[idx].vv_str = vim_strsave(val);
+     else
+       vimvars[idx].vv_str = vim_strnsave(val, len);
+ }
+ 
+ /*
+  * Set List v: variable to "val".
+  */
+     void
+ set_vim_var_list(int idx, list_T *val)
+ {
+     clear_tv(&vimvars[idx].vv_di.di_tv);
+     vimvars[idx].vv_type = VAR_LIST;
+     vimvars[idx].vv_list = val;
+     if (val != NULL)
+       ++val->lv_refcount;
+ }
+ 
+ /*
+  * Set Dictionary v: variable to "val".
+  */
+     void
+ set_vim_var_dict(int idx, dict_T *val)
+ {
+     clear_tv(&vimvars[idx].vv_di.di_tv);
+     vimvars[idx].vv_type = VAR_DICT;
+     vimvars[idx].vv_dict = val;
+     if (val != NULL)
+     {
+       ++val->dv_refcount;
+       dict_set_items_ro(val);
+     }
+ }
+ 
+ /*
+  * Set v:register if needed.
+  */
+     void
+ set_reg_var(int c)
+ {
+     char_u    regname;
+ 
+     if (c == 0 || c == ' ')
+       regname = '"';
+     else
+       regname = c;
+     // Avoid free/alloc when the value is already right.
+     if (vimvars[VV_REG].vv_str == NULL || vimvars[VV_REG].vv_str[0] != c)
+       set_vim_var_string(VV_REG, &regname, 1);
+ }
+ 
+ /*
+  * Get or set v:exception.  If "oldval" == NULL, return the current value.
+  * Otherwise, restore the value to "oldval" and return NULL.
+  * Must always be called in pairs to save and restore v:exception!  Does not
+  * take care of memory allocations.
+  */
+     char_u *
+ v_exception(char_u *oldval)
+ {
+     if (oldval == NULL)
+       return vimvars[VV_EXCEPTION].vv_str;
+ 
+     vimvars[VV_EXCEPTION].vv_str = oldval;
+     return NULL;
+ }
+ 
+ /*
+  * Get or set v:throwpoint.  If "oldval" == NULL, return the current value.
+  * Otherwise, restore the value to "oldval" and return NULL.
+  * Must always be called in pairs to save and restore v:throwpoint!  Does not
+  * take care of memory allocations.
+  */
+     char_u *
+ v_throwpoint(char_u *oldval)
+ {
+     if (oldval == NULL)
+       return vimvars[VV_THROWPOINT].vv_str;
+ 
+     vimvars[VV_THROWPOINT].vv_str = oldval;
+     return NULL;
+ }
+ 
+ /*
+  * Set v:cmdarg.
+  * If "eap" != NULL, use "eap" to generate the value and return the old value.
+  * If "oldarg" != NULL, restore the value to "oldarg" and return NULL.
+  * Must always be called in pairs!
+  */
+     char_u *
+ set_cmdarg(exarg_T *eap, char_u *oldarg)
+ {
+     char_u    *oldval;
+     char_u    *newval;
+     unsigned  len;
+ 
+     oldval = vimvars[VV_CMDARG].vv_str;
+     if (eap == NULL)
+     {
+       vim_free(oldval);
+       vimvars[VV_CMDARG].vv_str = oldarg;
+       return NULL;
+     }
+ 
+     if (eap->force_bin == FORCE_BIN)
+       len = 6;
+     else if (eap->force_bin == FORCE_NOBIN)
+       len = 8;
+     else
+       len = 0;
+ 
+     if (eap->read_edit)
+       len += 7;
+ 
+     if (eap->force_ff != 0)
+       len += 10; // " ++ff=unix"
+     if (eap->force_enc != 0)
+       len += (unsigned)STRLEN(eap->cmd + eap->force_enc) + 7;
+     if (eap->bad_char != 0)
+       len += 7 + 4;  // " ++bad=" + "keep" or "drop"
+ 
+     newval = alloc(len + 1);
+     if (newval == NULL)
+       return NULL;
+ 
+     if (eap->force_bin == FORCE_BIN)
+       sprintf((char *)newval, " ++bin");
+     else if (eap->force_bin == FORCE_NOBIN)
+       sprintf((char *)newval, " ++nobin");
+     else
+       *newval = NUL;
+ 
+     if (eap->read_edit)
+       STRCAT(newval, " ++edit");
+ 
+     if (eap->force_ff != 0)
+       sprintf((char *)newval + STRLEN(newval), " ++ff=%s",
+                                               eap->force_ff == 'u' ? "unix"
+                                               : eap->force_ff == 'd' ? "dos"
+                                               : "mac");
+     if (eap->force_enc != 0)
+       sprintf((char *)newval + STRLEN(newval), " ++enc=%s",
+                                              eap->cmd + eap->force_enc);
+     if (eap->bad_char == BAD_KEEP)
+       STRCPY(newval + STRLEN(newval), " ++bad=keep");
+     else if (eap->bad_char == BAD_DROP)
+       STRCPY(newval + STRLEN(newval), " ++bad=drop");
+     else if (eap->bad_char != 0)
+       sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char);
+     vimvars[VV_CMDARG].vv_str = newval;
+     return oldval;
+ }
+ 
+ /*
   * Get the value of internal variable "name".
   * Return OK or FAIL.  If OK is returned "rettv" must be cleared.
   */
***************
*** 1259,1264 ****
--- 2020,2191 ----
  }
  
  /*
+  * Check if variable "name[len]" is a local variable or an argument.
+  * If so, "*eval_lavars_used" is set to TRUE.
+  */
+     void
+ check_vars(char_u *name, int len)
+ {
+     int               cc;
+     char_u    *varname;
+     hashtab_T *ht;
+ 
+     if (eval_lavars_used == NULL)
+       return;
+ 
+     // truncate the name, so that we can use strcmp()
+     cc = name[len];
+     name[len] = NUL;
+ 
+     ht = find_var_ht(name, &varname);
+     if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
+     {
+       if (find_var(name, NULL, TRUE) != NULL)
+           *eval_lavars_used = TRUE;
+     }
+ 
+     name[len] = cc;
+ }
+ 
+ /*
+  * Find variable "name" in the list of variables.
+  * Return a pointer to it if found, NULL if not found.
+  * Careful: "a:0" variables don't have a name.
+  * When "htp" is not NULL we are writing to the variable, set "htp" to the
+  * hashtab_T used.
+  */
+     dictitem_T *
+ find_var(char_u *name, hashtab_T **htp, int no_autoload)
+ {
+     char_u    *varname;
+     hashtab_T *ht;
+     dictitem_T        *ret = NULL;
+ 
+     ht = find_var_ht(name, &varname);
+     if (htp != NULL)
+       *htp = ht;
+     if (ht == NULL)
+       return NULL;
+     ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
+     if (ret != NULL)
+       return ret;
+ 
+     /* Search in parent scope for lambda */
+     return find_var_in_scoped_ht(name, no_autoload || htp != NULL);
+ }
+ 
+ /*
+  * Find variable "varname" in hashtab "ht" with name "htname".
+  * Returns NULL if not found.
+  */
+     dictitem_T *
+ find_var_in_ht(
+     hashtab_T *ht,
+     int               htname,
+     char_u    *varname,
+     int               no_autoload)
+ {
+     hashitem_T        *hi;
+ 
+     if (*varname == NUL)
+     {
+       // Must be something like "s:", otherwise "ht" would be NULL.
+       switch (htname)
+       {
+           case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
+           case 'g': return &globvars_var;
+           case 'v': return &vimvars_var;
+           case 'b': return &curbuf->b_bufvar;
+           case 'w': return &curwin->w_winvar;
+           case 't': return &curtab->tp_winvar;
+           case 'l': return get_funccal_local_var();
+           case 'a': return get_funccal_args_var();
+       }
+       return NULL;
+     }
+ 
+     hi = hash_find(ht, varname);
+     if (HASHITEM_EMPTY(hi))
+     {
+       // For global variables we may try auto-loading the script.  If it
+       // worked find the variable again.  Don't auto-load a script if it was
+       // loaded already, otherwise it would be loaded every time when
+       // checking if a function name is a Funcref variable.
+       if (ht == &globvarht && !no_autoload)
+       {
+           // Note: script_autoload() may make "hi" invalid. It must either
+           // be obtained again or not used.
+           if (!script_autoload(varname, FALSE) || aborting())
+               return NULL;
+           hi = hash_find(ht, varname);
+       }
+       if (HASHITEM_EMPTY(hi))
+           return NULL;
+     }
+     return HI2DI(hi);
+ }
+ 
+ /*
+  * Find the hashtab used for a variable name.
+  * Return NULL if the name is not valid.
+  * Set "varname" to the start of name without ':'.
+  */
+     hashtab_T *
+ find_var_ht(char_u *name, char_u **varname)
+ {
+     hashitem_T        *hi;
+     hashtab_T *ht;
+ 
+     if (name[0] == NUL)
+       return NULL;
+     if (name[1] != ':')
+     {
+       // The name must not start with a colon or #.
+       if (name[0] == ':' || name[0] == AUTOLOAD_CHAR)
+           return NULL;
+       *varname = name;
+ 
+       // "version" is "v:version" in all scopes if scriptversion < 3.
+       // Same for a few other variables marked with VV_COMPAT.
+       if (current_sctx.sc_version < 3)
+       {
+           hi = hash_find(&compat_hashtab, name);
+           if (!HASHITEM_EMPTY(hi))
+               return &compat_hashtab;
+       }
+ 
+       ht = get_funccal_local_ht();
+       if (ht == NULL)
+           return &globvarht;                  // global variable
+       return ht;                              // local variable
+     }
+     *varname = name + 2;
+     if (*name == 'g')                         // global variable
+       return &globvarht;
+     // There must be no ':' or '#' in the rest of the name, unless g: is used
+     if (vim_strchr(name + 2, ':') != NULL
+                              || vim_strchr(name + 2, AUTOLOAD_CHAR) != NULL)
+       return NULL;
+     if (*name == 'b')                         // buffer variable
+       return &curbuf->b_vars->dv_hashtab;
+     if (*name == 'w')                         // window variable
+       return &curwin->w_vars->dv_hashtab;
+     if (*name == 't')                         // tab page variable
+       return &curtab->tp_vars->dv_hashtab;
+     if (*name == 'v')                         // v: variable
+       return &vimvarht;
+     if (*name == 'a')                         // a: function argument
+       return get_funccal_args_ht();
+     if (*name == 'l')                         // l: local function variable
+       return get_funccal_local_ht();
+     if (*name == 's'                          // script variable
+           && current_sctx.sc_sid > 0
+           && current_sctx.sc_sid <= ga_scripts.ga_len)
+       return &SCRIPT_VARS(current_sctx.sc_sid);
+     return NULL;
+ }
+ 
+ /*
   * Get the string value of a (global/local) variable.
   * Note: see tv_get_string() for how long the pointer remains valid.
   * Returns NULL when it doesn't exist.
***************
*** 1275,1280 ****
--- 2202,2273 ----
  }
  
  /*
+  * Allocate a new hashtab for a sourced script.  It will be used while
+  * sourcing this script and when executing functions defined in the script.
+  */
+     void
+ new_script_vars(scid_T id)
+ {
+     int               i;
+     hashtab_T *ht;
+     scriptvar_T *sv;
+ 
+     if (ga_grow(&ga_scripts, (int)(id - ga_scripts.ga_len)) == OK)
+     {
+       /* Re-allocating ga_data means that an ht_array pointing to
+        * ht_smallarray becomes invalid.  We can recognize this: ht_mask is
+        * at its init value.  Also reset "v_dict", it's always the same. */
+       for (i = 1; i <= ga_scripts.ga_len; ++i)
+       {
+           ht = &SCRIPT_VARS(i);
+           if (ht->ht_mask == HT_INIT_SIZE - 1)
+               ht->ht_array = ht->ht_smallarray;
+           sv = SCRIPT_SV(i);
+           sv->sv_var.di_tv.vval.v_dict = &sv->sv_dict;
+       }
+ 
+       while (ga_scripts.ga_len < id)
+       {
+           sv = SCRIPT_SV(ga_scripts.ga_len + 1) =
+               ALLOC_CLEAR_ONE(scriptvar_T);
+           init_var_dict(&sv->sv_dict, &sv->sv_var, VAR_SCOPE);
+           ++ga_scripts.ga_len;
+       }
+     }
+ }
+ 
+ /*
+  * Initialize dictionary "dict" as a scope and set variable "dict_var" to
+  * point to it.
+  */
+     void
+ init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope)
+ {
+     hash_init(&dict->dv_hashtab);
+     dict->dv_lock = 0;
+     dict->dv_scope = scope;
+     dict->dv_refcount = DO_NOT_FREE_CNT;
+     dict->dv_copyID = 0;
+     dict_var->di_tv.vval.v_dict = dict;
+     dict_var->di_tv.v_type = VAR_DICT;
+     dict_var->di_tv.v_lock = VAR_FIXED;
+     dict_var->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
+     dict_var->di_key[0] = NUL;
+ }
+ 
+ /*
+  * Unreference a dictionary initialized by init_var_dict().
+  */
+     void
+ unref_var_dict(dict_T *dict)
+ {
+     /* Now the dict needs to be freed if no one else is using it, go back to
+      * normal reference counting. */
+     dict->dv_refcount -= DO_NOT_FREE_CNT - 1;
+     dict_unref(dict);
+ }
+ 
+ /*
   * Clean up a list of internal variables.
   * Frees all allocated variables and the value they contain.
   * Clears hashtab "ht", does not free it.
***************
*** 1453,1459 ****
  
        // Handle setting internal v: variables separately where needed to
        // prevent changing the type.
!       if (is_vimvarht(ht))
        {
            if (v->di_tv.v_type == VAR_STRING)
            {
--- 2446,2452 ----
  
        // Handle setting internal v: variables separately where needed to
        // prevent changing the type.
!       if (ht == &vimvarht)
        {
            if (v->di_tv.v_type == VAR_STRING)
            {
***************
*** 1501,1507 ****
      else                  // add a new variable
      {
        // Can't add "v:" or "a:" variable.
!       if (is_vimvarht(ht) || ht == get_funccal_args_ht())
        {
            semsg(_(e_illvar), name);
            return;
--- 2494,2500 ----
      else                  // add a new variable
      {
        // Can't add "v:" or "a:" variable.
!       if (ht == &vimvarht || ht == get_funccal_args_ht())
        {
            semsg(_(e_illvar), name);
            return;
***************
*** 1792,1797 ****
--- 2785,2819 ----
      }
  }
  
+ /*
+  * reset v:option_new, v:option_old, v:option_oldlocal, v:option_oldglobal,
+  * v:option_type, and v:option_command.
+  */
+     void
+ reset_v_option_vars(void)
+ {
+     set_vim_var_string(VV_OPTION_NEW,  NULL, -1);
+     set_vim_var_string(VV_OPTION_OLD,  NULL, -1);
+     set_vim_var_string(VV_OPTION_OLDLOCAL, NULL, -1);
+     set_vim_var_string(VV_OPTION_OLDGLOBAL, NULL, -1);
+     set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
+     set_vim_var_string(VV_OPTION_COMMAND, NULL, -1);
+ }
+ 
+ /*
+  * Add an assert error to v:errors.
+  */
+     void
+ assert_error(garray_T *gap)
+ {
+     struct vimvar   *vp = &vimvars[VV_ERRORS];
+ 
+     if (vp->vv_type != VAR_LIST || vimvars[VV_ERRORS].vv_list == NULL)
+       /* Make sure v:errors is a list. */
+       set_vim_var_list(VV_ERRORS, list_alloc());
+     list_append_string(vimvars[VV_ERRORS].vv_list, gap->ga_data, gap->ga_len);
+ }
+ 
      int
  var_exists(char_u *var)
  {
*** ../vim-8.1.1938/src/proto/eval.pro  2019-08-27 22:48:12.741480663 +0200
--- src/proto/eval.pro  2019-08-29 22:02:16.891931613 +0200
***************
*** 3,9 ****
  varnumber_T num_modulus(varnumber_T n1, varnumber_T n2);
  void eval_init(void);
  void eval_clear(void);
- void set_internal_string_var(char_u *name, char_u *value);
  int var_redir_start(char_u *name, int append);
  void var_redir_str(char_u *value, int value_len);
  void var_redir_stop(void);
--- 3,8 ----
***************
*** 19,30 ****
  char_u *eval_to_string(char_u *arg, char_u **nextcmd, int convert);
  char_u *eval_to_string_safe(char_u *arg, char_u **nextcmd, int use_sandbox);
  varnumber_T eval_to_number(char_u *expr);
- void list_vim_vars(int *first);
- void list_script_vars(int *first);
- int is_vimvarht(hashtab_T *ht);
- int is_compatht(hashtab_T *ht);
- void prepare_vimvar(int idx, typval_T *save_tv);
- void restore_vimvar(int idx, typval_T *save_tv);
  list_T *eval_spell_expr(char_u *badword, char_u *expr);
  int get_spellword(list_T *list, char_u **pp);
  typval_T *eval_expr(char_u *arg, char_u **nextcmd);
--- 18,23 ----
***************
*** 41,47 ****
  void free_for_info(void *fi_void);
  void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx);
  void del_menutrans_vars(void);
- char_u *get_user_var_name(expand_T *xp, int idx);
  int pattern_match(char_u *pat, char_u *text, int ic);
  int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
  int eval1(char_u **arg, typval_T *rettv, int evaluate);
--- 34,39 ----
***************
*** 69,93 ****
  char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, 
int flags);
  int eval_isnamec(int c);
  int eval_isnamec1(int c);
- void set_vim_var_nr(int idx, varnumber_T val);
- typval_T *get_vim_var_tv(int idx);
- varnumber_T get_vim_var_nr(int idx);
- char_u *get_vim_var_str(int idx);
- list_T *get_vim_var_list(int idx);
- dict_T *get_vim_var_dict(int idx);
- void set_vim_var_char(int c);
- void set_vcount(long count, long count1, int set_prevcount);
- void save_vimvars(vimvars_save_T *vvsave);
- void restore_vimvars(vimvars_save_T *vvsave);
- void set_vim_var_string(int idx, char_u *val, int len);
- void set_vim_var_list(int idx, list_T *val);
- void set_vim_var_dict(int idx, dict_T *val);
- void set_reg_var(int c);
- char_u *v_exception(char_u *oldval);
- char_u *v_throwpoint(char_u *oldval);
- char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
  int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int 
verbose, char_u *start_leader, char_u **end_leaderp);
  typval_T *alloc_tv(void);
  void free_tv(typval_T *varp);
  void clear_tv(typval_T *varp);
  void init_tv(typval_T *varp);
--- 61,69 ----
  char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, 
int flags);
  int eval_isnamec(int c);
  int eval_isnamec1(int c);
  int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int 
verbose, char_u *start_leader, char_u **end_leaderp);
  typval_T *alloc_tv(void);
+ typval_T *alloc_string_tv(char_u *s);
  void free_tv(typval_T *varp);
  void clear_tv(typval_T *varp);
  void init_tv(typval_T *varp);
***************
*** 98,109 ****
  char_u *tv_get_string_buf(typval_T *varp, char_u *buf);
  char_u *tv_get_string_chk(typval_T *varp);
  char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf);
- dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
- dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
- hashtab_T *find_var_ht(char_u *name, char_u **varname);
- void new_script_vars(scid_T id);
- void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
- void unref_var_dict(dict_T *dict);
  void copy_tv(typval_T *from, typval_T *to);
  int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
  void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog, int 
secret);
--- 74,79 ----
***************
*** 117,124 ****
  char_u *autoload_name(char_u *name);
  int script_autoload(char_u *name, int reload);
  void last_set_msg(sctx_T script_ctx);
- void reset_v_option_vars(void);
- void assert_error(garray_T *gap);
  int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int 
type_is, int ic);
  char_u *typval_tostring(typval_T *arg);
  int modify_fname(char_u *src, int tilde_file, int *usedlen, char_u **fnamep, 
char_u **bufp, int *fnamelen);
--- 87,92 ----
*** ../vim-8.1.1938/src/proto/evalvars.pro      2019-08-27 22:48:12.741480663 
+0200
--- src/proto/evalvars.pro      2019-08-29 22:02:16.891931613 +0200
***************
*** 1,4 ****
--- 1,11 ----
  /* evalvars.c */
+ void evalvars_init(void);
+ void evalvars_clear(void);
+ int garbage_collect_vimvars(int copyID);
+ int garbage_collect_scriptvars(int copyID);
+ void set_internal_string_var(char_u *name, char_u *value);
+ void prepare_vimvar(int idx, typval_T *save_tv);
+ void restore_vimvar(int idx, typval_T *save_tv);
  void ex_let(exarg_T *eap);
  void ex_const(exarg_T *eap);
  int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int 
var_count, int is_const, char_u *op);
***************
*** 7,14 ****
--- 14,46 ----
  void ex_unlet(exarg_T *eap);
  void ex_lockvar(exarg_T *eap);
  int do_unlet(char_u *name, int forceit);
+ char_u *get_user_var_name(expand_T *xp, int idx);
+ void set_vim_var_nr(int idx, varnumber_T val);
+ typval_T *get_vim_var_tv(int idx);
+ varnumber_T get_vim_var_nr(int idx);
+ char_u *get_vim_var_str(int idx);
+ list_T *get_vim_var_list(int idx);
+ dict_T *get_vim_var_dict(int idx);
+ void set_vim_var_char(int c);
+ void set_vcount(long count, long count1, int set_prevcount);
+ void save_vimvars(vimvars_save_T *vvsave);
+ void restore_vimvars(vimvars_save_T *vvsave);
+ void set_vim_var_string(int idx, char_u *val, int len);
+ void set_vim_var_list(int idx, list_T *val);
+ void set_vim_var_dict(int idx, dict_T *val);
+ void set_reg_var(int c);
+ char_u *v_exception(char_u *oldval);
+ char_u *v_throwpoint(char_u *oldval);
+ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg);
  int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int 
verbose, int no_autoload);
+ void check_vars(char_u *name, int len);
+ dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
+ dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int 
no_autoload);
+ hashtab_T *find_var_ht(char_u *name, char_u **varname);
  char_u *get_var_value(char_u *name);
+ void new_script_vars(scid_T id);
+ void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);
+ void unref_var_dict(dict_T *dict);
  void vars_clear(hashtab_T *ht);
  void vars_clear_ext(hashtab_T *ht, int free_val);
  void delete_var(hashtab_T *ht, hashitem_T *hi);
***************
*** 19,24 ****
--- 51,58 ----
  int var_check_func_name(char_u *name, int new_var);
  int var_check_lock(int lock, char_u *name, int use_gettext);
  int valid_varname(char_u *varname);
+ void reset_v_option_vars(void);
+ void assert_error(garray_T *gap);
  int var_exists(char_u *var);
  void f_gettabvar(typval_T *argvars, typval_T *rettv);
  void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.1938/src/version.c       2019-08-29 21:32:52.248093098 +0200
--- src/version.c       2019-08-29 22:05:49.498124809 +0200
***************
*** 763,764 ****
--- 763,766 ----
  {   /* Add new patch number below this line */
+ /**/
+     1939,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
133. You communicate with people on other continents more than you
     do with your own neighbors.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201908292010.x7TKAFAK010396%40masaka.moolenaar.net.

Raspunde prin e-mail lui