Patch 8.1.1957
Problem:    More code can be moved to evalvars.c.
Solution:   Move code to where it fits better. (Yegappan Lakshmanan,
            closes #4883)
Files:      src/eval.c, src/evalvars.c, src/ex_getln.c, src/globals.h,
            src/if_py_both.h, src/proto/eval.pro, src/proto/evalvars.pro,
            src/proto/ex_getln.pro, src/proto/scriptfile.pro,
            src/scriptfile.c, src/session.c, src/viminfo.c


*** ../vim-8.1.1956/src/eval.c  2019-08-30 15:46:27.188906163 +0200
--- src/eval.c  2019-09-01 15:46:52.568427240 +0200
***************
*** 38,46 ****
  
  static int echo_attr = 0;   /* attributes used for ":echo" */
  
- /* The names of packages that once were loaded are remembered. */
- static garray_T               ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
- 
  /*
   * Info used by a ":for" loop.
   */
--- 38,43 ----
***************
*** 156,163 ****
      free_scriptnames();
      free_locales();
  
!     /* autoloaded script names */
!     ga_clear_strings(&ga_loaded);
  
      // unreferenced lists and dicts
      (void)garbage_collect(FALSE);
--- 153,160 ----
      free_scriptnames();
      free_locales();
  
!     // autoloaded script names
!     free_autoload_scriptnames();
  
      // unreferenced lists and dicts
      (void)garbage_collect(FALSE);
***************
*** 167,406 ****
  }
  #endif
  
- 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 */
- static char_u *redir_endp = NULL;
- static char_u *redir_varname = NULL;
- 
- /*
-  * Start recording command output to a variable
-  * When "append" is TRUE append to an existing variable.
-  * Returns OK if successfully completed the setup.  FAIL otherwise.
-  */
-     int
- var_redir_start(char_u *name, int append)
- {
-     int               save_emsg;
-     int               err;
-     typval_T  tv;
- 
-     /* Catch a bad name early. */
-     if (!eval_isnamec1(*name))
-     {
-       emsg(_(e_invarg));
-       return FAIL;
-     }
- 
-     /* Make a copy of the name, it is used in redir_lval until redir ends. */
-     redir_varname = vim_strsave(name);
-     if (redir_varname == NULL)
-       return FAIL;
- 
-     redir_lval = ALLOC_CLEAR_ONE(lval_T);
-     if (redir_lval == NULL)
-     {
-       var_redir_stop();
-       return FAIL;
-     }
- 
-     /* The output is stored in growarray "redir_ga" until redirection ends. */
-     ga_init2(&redir_ga, (int)sizeof(char), 500);
- 
-     /* Parse the variable name (can be a dict or list entry). */
-     redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
-                                                            FNE_CHECK_START);
-     if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != 
NUL)
-     {
-       clear_lval(redir_lval);
-       if (redir_endp != NULL && *redir_endp != NUL)
-           /* Trailing characters are present after the variable name */
-           emsg(_(e_trailing));
-       else
-           emsg(_(e_invarg));
-       redir_endp = NULL;  /* don't store a value, only cleanup */
-       var_redir_stop();
-       return FAIL;
-     }
- 
-     /* check if we can write to the variable: set it to or append an empty
-      * string */
-     save_emsg = did_emsg;
-     did_emsg = FALSE;
-     tv.v_type = VAR_STRING;
-     tv.vval.v_string = (char_u *)"";
-     if (append)
-       set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)".");
-     else
-       set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
-     clear_lval(redir_lval);
-     err = did_emsg;
-     did_emsg |= save_emsg;
-     if (err)
-     {
-       redir_endp = NULL;  /* don't store a value, only cleanup */
-       var_redir_stop();
-       return FAIL;
-     }
- 
-     return OK;
- }
- 
- /*
-  * Append "value[value_len]" to the variable set by var_redir_start().
-  * The actual appending is postponed until redirection ends, because the value
-  * appended may in fact be the string we write to, changing it may cause freed
-  * memory to be used:
-  *   :redir => foo
-  *   :let foo
-  *   :redir END
-  */
-     void
- var_redir_str(char_u *value, int value_len)
- {
-     int               len;
- 
-     if (redir_lval == NULL)
-       return;
- 
-     if (value_len == -1)
-       len = (int)STRLEN(value);       /* Append the entire string */
-     else
-       len = value_len;                /* Append only "value_len" characters */
- 
-     if (ga_grow(&redir_ga, len) == OK)
-     {
-       mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
-       redir_ga.ga_len += len;
-     }
-     else
-       var_redir_stop();
- }
- 
- /*
-  * Stop redirecting command output to a variable.
-  * Frees the allocated memory.
-  */
-     void
- var_redir_stop(void)
- {
-     typval_T  tv;
- 
-     if (EVALCMD_BUSY)
-     {
-       redir_lval = NULL;
-       return;
-     }
- 
-     if (redir_lval != NULL)
-     {
-       /* If there was no error: assign the text to the variable. */
-       if (redir_endp != NULL)
-       {
-           ga_append(&redir_ga, NUL);  /* Append the trailing NUL. */
-           tv.v_type = VAR_STRING;
-           tv.vval.v_string = redir_ga.ga_data;
-           /* Call get_lval() again, if it's inside a Dict or List it may
-            * have changed. */
-           redir_endp = get_lval(redir_varname, NULL, redir_lval,
-                                       FALSE, FALSE, 0, FNE_CHECK_START);
-           if (redir_endp != NULL && redir_lval->ll_name != NULL)
-               set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE,
-                                                               (char_u *)".");
-           clear_lval(redir_lval);
-       }
- 
-       /* free the collected output */
-       VIM_CLEAR(redir_ga.ga_data);
- 
-       VIM_CLEAR(redir_lval);
-     }
-     VIM_CLEAR(redir_varname);
- }
- 
-     int
- eval_charconvert(
-     char_u    *enc_from,
-     char_u    *enc_to,
-     char_u    *fname_from,
-     char_u    *fname_to)
- {
-     int               err = FALSE;
- 
-     set_vim_var_string(VV_CC_FROM, enc_from, -1);
-     set_vim_var_string(VV_CC_TO, enc_to, -1);
-     set_vim_var_string(VV_FNAME_IN, fname_from, -1);
-     set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
-     if (eval_to_bool(p_ccv, &err, NULL, FALSE))
-       err = TRUE;
-     set_vim_var_string(VV_CC_FROM, NULL, -1);
-     set_vim_var_string(VV_CC_TO, NULL, -1);
-     set_vim_var_string(VV_FNAME_IN, NULL, -1);
-     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
- 
-     if (err)
-       return FAIL;
-     return OK;
- }
- 
- # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
-     int
- eval_printexpr(char_u *fname, char_u *args)
- {
-     int               err = FALSE;
- 
-     set_vim_var_string(VV_FNAME_IN, fname, -1);
-     set_vim_var_string(VV_CMDARG, args, -1);
-     if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
-       err = TRUE;
-     set_vim_var_string(VV_FNAME_IN, NULL, -1);
-     set_vim_var_string(VV_CMDARG, NULL, -1);
- 
-     if (err)
-     {
-       mch_remove(fname);
-       return FAIL;
-     }
-     return OK;
- }
- # endif
- 
- # if defined(FEAT_DIFF) || defined(PROTO)
-     void
- eval_diff(
-     char_u    *origfile,
-     char_u    *newfile,
-     char_u    *outfile)
- {
-     int               err = FALSE;
- 
-     set_vim_var_string(VV_FNAME_IN, origfile, -1);
-     set_vim_var_string(VV_FNAME_NEW, newfile, -1);
-     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
-     (void)eval_to_bool(p_dex, &err, NULL, FALSE);
-     set_vim_var_string(VV_FNAME_IN, NULL, -1);
-     set_vim_var_string(VV_FNAME_NEW, NULL, -1);
-     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
- }
- 
-     void
- eval_patch(
-     char_u    *origfile,
-     char_u    *difffile,
-     char_u    *outfile)
- {
-     int               err;
- 
-     set_vim_var_string(VV_FNAME_IN, origfile, -1);
-     set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
-     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
-     (void)eval_to_bool(p_pex, &err, NULL, FALSE);
-     set_vim_var_string(VV_FNAME_IN, NULL, -1);
-     set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
-     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
- }
- # endif
- 
  /*
   * Top level evaluation function, returning a boolean.
   * Sets "error" to TRUE if there was an error.
--- 164,169 ----
***************
*** 671,735 ****
      return retval;
  }
  
- #if defined(FEAT_SPELL) || defined(PROTO)
- /*
-  * Evaluate an expression to a list with suggestions.
-  * For the "expr:" part of 'spellsuggest'.
-  * Returns NULL when there is an error.
-  */
-     list_T *
- eval_spell_expr(char_u *badword, char_u *expr)
- {
-     typval_T  save_val;
-     typval_T  rettv;
-     list_T    *list = NULL;
-     char_u    *p = skipwhite(expr);
- 
-     /* 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;
- 
-     if (eval1(&p, &rettv, TRUE) == OK)
-     {
-       if (rettv.v_type != VAR_LIST)
-           clear_tv(&rettv);
-       else
-           list = rettv.vval.v_list;
-     }
- 
-     if (p_verbose == 0)
-       --emsg_off;
-     clear_tv(get_vim_var_tv(VV_VAL));
-     restore_vimvar(VV_VAL, &save_val);
- 
-     return list;
- }
- 
- /*
-  * "list" is supposed to contain two items: a word and a number.  Return the
-  * word in "pp" and the number as the return value.
-  * Return -1 if anything isn't right.
-  * Used to get the good word and score from the eval_spell_expr() result.
-  */
-     int
- get_spellword(list_T *list, char_u **pp)
- {
-     listitem_T        *li;
- 
-     li = list->lv_first;
-     if (li == NULL)
-       return -1;
-     *pp = tv_get_string(&li->li_tv);
- 
-     li = li->li_next;
-     if (li == NULL)
-       return -1;
-     return (int)tv_get_number(&li->li_tv);
- }
- #endif
- 
  /*
   * Top level evaluation function.
   * Returns an allocated typval_T with the result.
--- 434,439 ----
***************
*** 1153,1159 ****
            if (lp->ll_di == NULL)
            {
                // Can't add "v:" or "a:" variable.
!               if (lp->ll_dict == &vimvardict
                         || &lp->ll_dict->dv_hashtab == get_funccal_args_ht())
                {
                    semsg(_(e_illvar), name);
--- 857,863 ----
            if (lp->ll_di == NULL)
            {
                // Can't add "v:" or "a:" variable.
!               if (lp->ll_dict == get_vimvar_dict()
                         || &lp->ll_dict->dv_hashtab == get_funccal_args_ht())
                {
                    semsg(_(e_illvar), name);
***************
*** 1921,1951 ****
      xp->xp_pattern = arg;
  }
  
- #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
- /*
-  * Delete all "menutrans_" variables.
-  */
-     void
- del_menutrans_vars(void)
- {
-     hashitem_T        *hi;
-     int               todo;
- 
-     hash_lock(&globvarht);
-     todo = (int)globvarht.ht_used;
-     for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
-     {
-       if (!HASHITEM_EMPTY(hi))
-       {
-           --todo;
-           if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
-               delete_var(&globvarht, hi);
-       }
-     }
-     hash_unlock(&globvarht);
- }
- #endif
- 
  /*
   * Return TRUE if "pat" matches "text".
   * Does not use 'cpo' and always uses 'magic'.
--- 1625,1630 ----
***************
*** 4215,4221 ****
        abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
                                                                  NULL, NULL);
      /* global variables */
!     abort = abort || set_ref_in_ht(&globvarht, copyID, NULL);
  
      /* function-local variables */
      abort = abort || set_ref_in_call_stack(copyID);
--- 3894,3900 ----
        abort = abort || set_ref_in_item(&tp->tp_winvar.di_tv, copyID,
                                                                  NULL, NULL);
      /* global variables */
!     abort = abort || garbage_collect_globvars(copyID);
  
      /* function-local variables */
      abort = abort || set_ref_in_call_stack(copyID);
***************
*** 4630,4649 ****
      return abort;
  }
  
-     static char *
- get_var_special_name(int nr)
- {
-     switch (nr)
-     {
-       case VVAL_FALSE: return "v:false";
-       case VVAL_TRUE:  return "v:true";
-       case VVAL_NONE:  return "v:none";
-       case VVAL_NULL:  return "v:null";
-     }
-     internal_error("get_var_special_name()");
-     return "42";
- }
- 
  /*
   * Return a string with the string representation of a variable.
   * If the memory is allocated "tofree" is set to it, otherwise NULL.
--- 4309,4314 ----
***************
*** 6204,6315 ****
  }
  
  /*
-  * This function is used by f_input() and f_inputdialog() functions. The third
-  * argument to f_input() specifies the type of completion to use at the
-  * prompt. The third argument to f_inputdialog() specifies the value to return
-  * when the user cancels the prompt.
-  */
-     void
- get_user_input(
-     typval_T  *argvars,
-     typval_T  *rettv,
-     int               inputdialog,
-     int               secret)
- {
-     char_u    *prompt = tv_get_string_chk(&argvars[0]);
-     char_u    *p = NULL;
-     int               c;
-     char_u    buf[NUMBUFLEN];
-     int               cmd_silent_save = cmd_silent;
-     char_u    *defstr = (char_u *)"";
-     int               xp_type = EXPAND_NOTHING;
-     char_u    *xp_arg = NULL;
- 
-     rettv->v_type = VAR_STRING;
-     rettv->vval.v_string = NULL;
- 
- #ifdef NO_CONSOLE_INPUT
-     /* While starting up, there is no place to enter text. When running tests
-      * with --not-a-term we assume feedkeys() will be used. */
-     if (no_console_input() && !is_not_a_term())
-       return;
- #endif
- 
-     cmd_silent = FALSE;               /* Want to see the prompt. */
-     if (prompt != NULL)
-     {
-       /* Only the part of the message after the last NL is considered as
-        * prompt for the command line */
-       p = vim_strrchr(prompt, '\n');
-       if (p == NULL)
-           p = prompt;
-       else
-       {
-           ++p;
-           c = *p;
-           *p = NUL;
-           msg_start();
-           msg_clr_eos();
-           msg_puts_attr((char *)prompt, echo_attr);
-           msg_didout = FALSE;
-           msg_starthere();
-           *p = c;
-       }
-       cmdline_row = msg_row;
- 
-       if (argvars[1].v_type != VAR_UNKNOWN)
-       {
-           defstr = tv_get_string_buf_chk(&argvars[1], buf);
-           if (defstr != NULL)
-               stuffReadbuffSpec(defstr);
- 
-           if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
-           {
-               char_u  *xp_name;
-               int     xp_namelen;
-               long    argt;
- 
-               /* input() with a third argument: completion */
-               rettv->vval.v_string = NULL;
- 
-               xp_name = tv_get_string_buf_chk(&argvars[2], buf);
-               if (xp_name == NULL)
-                   return;
- 
-               xp_namelen = (int)STRLEN(xp_name);
- 
-               if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
-                                                            &xp_arg) == FAIL)
-                   return;
-           }
-       }
- 
-       if (defstr != NULL)
-       {
-           int save_ex_normal_busy = ex_normal_busy;
- 
-           ex_normal_busy = 0;
-           rettv->vval.v_string =
-               getcmdline_prompt(secret ? NUL : '@', p, echo_attr,
-                                                             xp_type, xp_arg);
-           ex_normal_busy = save_ex_normal_busy;
-       }
-       if (inputdialog && rettv->vval.v_string == NULL
-               && argvars[1].v_type != VAR_UNKNOWN
-               && argvars[2].v_type != VAR_UNKNOWN)
-           rettv->vval.v_string = vim_strsave(tv_get_string_buf(
-                                                          &argvars[2], buf));
- 
-       vim_free(xp_arg);
- 
-       /* since the user typed this, no need to wait for return */
-       need_wait_return = FALSE;
-       msg_didout = FALSE;
-     }
-     cmd_silent = cmd_silent_save;
- }
- 
- /*
   * ":echo expr1 ..."  print each argument separated with a space, add a
   *                    newline at the end.
   * ":echon expr1 ..." print each argument plain.
--- 5869,5874 ----
***************
*** 6425,6430 ****
--- 5984,5998 ----
  }
  
  /*
+  * Returns the :echo attribute
+  */
+     int
+ get_echo_attr(void)
+ {
+     return echo_attr;
+ }
+ 
+ /*
   * ":execute expr1 ..."       execute the result of an expression.
   * ":echomsg expr1 ..."       Print a message
   * ":echoerr expr1 ..."       Print an error
***************
*** 6551,6628 ****
  }
  
  /*
-  * Return the autoload script name for a function or variable name.
-  * Returns NULL when out of memory.
-  * Caller must make sure that "name" contains AUTOLOAD_CHAR.
-  */
-     char_u *
- autoload_name(char_u *name)
- {
-     char_u    *p, *q = NULL;
-     char_u    *scriptname;
- 
-     // Get the script file name: replace '#' with '/', append ".vim".
-     scriptname = alloc(STRLEN(name) + 14);
-     if (scriptname == NULL)
-       return NULL;
-     STRCPY(scriptname, "autoload/");
-     STRCAT(scriptname, name);
-     for (p = scriptname + 9; (p = vim_strchr(p, AUTOLOAD_CHAR)) != NULL;
-                                                                   q = p, ++p)
-       *p = '/';
-     STRCPY(q, ".vim");
-     return scriptname;
- }
- 
- /*
-  * If "name" has a package name try autoloading the script for it.
-  * Return TRUE if a package was loaded.
-  */
-     int
- script_autoload(
-     char_u    *name,
-     int               reload)     /* load script again when already loaded */
- {
-     char_u    *p;
-     char_u    *scriptname, *tofree;
-     int               ret = FALSE;
-     int               i;
- 
-     /* If there is no '#' after name[0] there is no package name. */
-     p = vim_strchr(name, AUTOLOAD_CHAR);
-     if (p == NULL || p == name)
-       return FALSE;
- 
-     tofree = scriptname = autoload_name(name);
-     if (scriptname == NULL)
-       return FALSE;
- 
-     /* Find the name in the list of previously loaded package names.  Skip
-      * "autoload/", it's always the same. */
-     for (i = 0; i < ga_loaded.ga_len; ++i)
-       if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
-           break;
-     if (!reload && i < ga_loaded.ga_len)
-       ret = FALSE;        /* was loaded already */
-     else
-     {
-       /* Remember the name if it wasn't loaded already. */
-       if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
-       {
-           ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
-           tofree = NULL;
-       }
- 
-       /* Try loading the package from $VIMRUNTIME/autoload/<name>.vim */
-       if (source_runtime(scriptname, 0) == OK)
-           ret = TRUE;
-     }
- 
-     vim_free(tofree);
-     return ret;
- }
- 
- /*
   * Display script name where an item was last set.
   * Should only be invoked when 'verbose' is non-zero.
   */
--- 6119,6124 ----
***************
*** 7739,7744 ****
--- 7235,7242 ----
        prepare_vimvar(VV_KEY, &save_key);
        if (argvars[0].v_type == VAR_DICT)
        {
+           set_vim_var_type(VV_KEY, VAR_STRING);
+ 
            ht = &d->dv_hashtab;
            hash_lock(ht);
            todo = (int)ht->ht_used;
*** ../vim-8.1.1956/src/evalvars.c      2019-08-30 15:46:27.188906163 +0200
--- src/evalvars.c      2019-09-01 15:46:52.568427240 +0200
***************
*** 18,23 ****
--- 18,25 ----
  static char *e_letunexp       = N_("E18: Unexpected characters in :let");
  
  static dictitem_T     globvars_var;           // variable used for g:
+ static dict_T         globvardict;            // Dictionary with g: variables
+ #define globvarht globvardict.dv_hashtab
  
  /*
   * Old Vim variables such as "v:version" are also available without the "v:".
***************
*** 154,159 ****
--- 156,162 ----
  #define vv_tv         vv_di.di_tv
  
  static dictitem_T     vimvars_var;            // variable used for v:
+ static dict_T         vimvardict;             // Dictionary with v: variables
  #define vimvarht  vimvardict.dv_hashtab
  
  // for VIM_VERSION_ defines
***************
*** 185,190 ****
--- 188,194 ----
  static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit);
  static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
  static void item_lock(typval_T *tv, int deep, int lock);
+ static void delete_var(hashtab_T *ht, hashitem_T *hi);
  static void list_one_var(dictitem_T *v, char *prefix, int *first);
  static void list_one_var_a(char *prefix, char_u *name, int type, char_u 
*string, int *first);
  
***************
*** 296,301 ****
--- 300,311 ----
  #endif
  
      int
+ garbage_collect_globvars(int copyID)
+ {
+     return set_ref_in_ht(&globvarht, copyID, NULL);
+ }
+ 
+     int
  garbage_collect_vimvars(int copyID)
  {
      return set_ref_in_ht(&vimvarht, copyID, NULL);
***************
*** 335,340 ****
--- 345,492 ----
      }
  }
  
+     int
+ eval_charconvert(
+     char_u    *enc_from,
+     char_u    *enc_to,
+     char_u    *fname_from,
+     char_u    *fname_to)
+ {
+     int               err = FALSE;
+ 
+     set_vim_var_string(VV_CC_FROM, enc_from, -1);
+     set_vim_var_string(VV_CC_TO, enc_to, -1);
+     set_vim_var_string(VV_FNAME_IN, fname_from, -1);
+     set_vim_var_string(VV_FNAME_OUT, fname_to, -1);
+     if (eval_to_bool(p_ccv, &err, NULL, FALSE))
+       err = TRUE;
+     set_vim_var_string(VV_CC_FROM, NULL, -1);
+     set_vim_var_string(VV_CC_TO, NULL, -1);
+     set_vim_var_string(VV_FNAME_IN, NULL, -1);
+     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+ 
+     if (err)
+       return FAIL;
+     return OK;
+ }
+ 
+ # if defined(FEAT_POSTSCRIPT) || defined(PROTO)
+     int
+ eval_printexpr(char_u *fname, char_u *args)
+ {
+     int               err = FALSE;
+ 
+     set_vim_var_string(VV_FNAME_IN, fname, -1);
+     set_vim_var_string(VV_CMDARG, args, -1);
+     if (eval_to_bool(p_pexpr, &err, NULL, FALSE))
+       err = TRUE;
+     set_vim_var_string(VV_FNAME_IN, NULL, -1);
+     set_vim_var_string(VV_CMDARG, NULL, -1);
+ 
+     if (err)
+     {
+       mch_remove(fname);
+       return FAIL;
+     }
+     return OK;
+ }
+ # endif
+ 
+ # if defined(FEAT_DIFF) || defined(PROTO)
+     void
+ eval_diff(
+     char_u    *origfile,
+     char_u    *newfile,
+     char_u    *outfile)
+ {
+     int               err = FALSE;
+ 
+     set_vim_var_string(VV_FNAME_IN, origfile, -1);
+     set_vim_var_string(VV_FNAME_NEW, newfile, -1);
+     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+     (void)eval_to_bool(p_dex, &err, NULL, FALSE);
+     set_vim_var_string(VV_FNAME_IN, NULL, -1);
+     set_vim_var_string(VV_FNAME_NEW, NULL, -1);
+     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+ }
+ 
+     void
+ eval_patch(
+     char_u    *origfile,
+     char_u    *difffile,
+     char_u    *outfile)
+ {
+     int               err;
+ 
+     set_vim_var_string(VV_FNAME_IN, origfile, -1);
+     set_vim_var_string(VV_FNAME_DIFF, difffile, -1);
+     set_vim_var_string(VV_FNAME_OUT, outfile, -1);
+     (void)eval_to_bool(p_pex, &err, NULL, FALSE);
+     set_vim_var_string(VV_FNAME_IN, NULL, -1);
+     set_vim_var_string(VV_FNAME_DIFF, NULL, -1);
+     set_vim_var_string(VV_FNAME_OUT, NULL, -1);
+ }
+ # endif
+ 
+ #if defined(FEAT_SPELL) || defined(PROTO)
+ /*
+  * Evaluate an expression to a list with suggestions.
+  * For the "expr:" part of 'spellsuggest'.
+  * Returns NULL when there is an error.
+  */
+     list_T *
+ eval_spell_expr(char_u *badword, char_u *expr)
+ {
+     typval_T  save_val;
+     typval_T  rettv;
+     list_T    *list = NULL;
+     char_u    *p = skipwhite(expr);
+ 
+     // 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;
+ 
+     if (eval1(&p, &rettv, TRUE) == OK)
+     {
+       if (rettv.v_type != VAR_LIST)
+           clear_tv(&rettv);
+       else
+           list = rettv.vval.v_list;
+     }
+ 
+     if (p_verbose == 0)
+       --emsg_off;
+     clear_tv(get_vim_var_tv(VV_VAL));
+     restore_vimvar(VV_VAL, &save_val);
+ 
+     return list;
+ }
+ 
+ /*
+  * "list" is supposed to contain two items: a word and a number.  Return the
+  * word in "pp" and the number as the return value.
+  * Return -1 if anything isn't right.
+  * Used to get the good word and score from the eval_spell_expr() result.
+  */
+     int
+ get_spellword(list_T *list, char_u **pp)
+ {
+     listitem_T        *li;
+ 
+     li = list->lv_first;
+     if (li == NULL)
+       return -1;
+     *pp = tv_get_string(&li->li_tv);
+ 
+     li = li->li_next;
+     if (li == NULL)
+       return -1;
+     return (int)tv_get_number(&li->li_tv);
+ }
+ #endif
+ 
  /*
   * Prepare v: variable "idx" to be used.
   * Save the current typeval in "save_tv".
***************
*** 1569,1574 ****
--- 1721,1751 ----
      --recurse;
  }
  
+ #if (defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)) || defined(PROTO)
+ /*
+  * Delete all "menutrans_" variables.
+  */
+     void
+ del_menutrans_vars(void)
+ {
+     hashitem_T        *hi;
+     int               todo;
+ 
+     hash_lock(&globvarht);
+     todo = (int)globvarht.ht_used;
+     for (hi = globvarht.ht_array; todo > 0 && !got_int; ++hi)
+     {
+       if (!HASHITEM_EMPTY(hi))
+       {
+           --todo;
+           if (STRNCMP(HI2DI(hi)->di_key, "menutrans_", 10) == 0)
+               delete_var(&globvarht, hi);
+       }
+     }
+     hash_unlock(&globvarht);
+ }
+ #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
***************
*** 1688,1693 ****
--- 1865,1911 ----
      return NULL;
  }
  
+     char *
+ get_var_special_name(int nr)
+ {
+     switch (nr)
+     {
+       case VVAL_FALSE: return "v:false";
+       case VVAL_TRUE:  return "v:true";
+       case VVAL_NONE:  return "v:none";
+       case VVAL_NULL:  return "v:null";
+     }
+     internal_error("get_var_special_name()");
+     return "42";
+ }
+ 
+ /*
+  * Returns the global variable dictionary
+  */
+     dict_T *
+ get_globvar_dict(void)
+ {
+     return &globvardict;
+ }
+ 
+ /*
+  * Returns the global variable hash table
+  */
+     hashtab_T *
+ get_globvar_ht(void)
+ {
+     return &globvarht;
+ }
+ 
+ /*
+  * Returns the v: variable dictionary
+  */
+     dict_T *
+ get_vimvar_dict(void)
+ {
+     return &vimvardict;
+ }
+ 
  /*
   * Set type of v: variable to "type".
   */
***************
*** 2321,2327 ****
   * Delete a variable from hashtab "ht" at item "hi".
   * Clear the variable value and free the dictitem.
   */
!     void
  delete_var(hashtab_T *ht, hashitem_T *hi)
  {
      dictitem_T        *di = HI2DI(hi);
--- 2539,2545 ----
   * Delete a variable from hashtab "ht" at item "hi".
   * Clear the variable value and free the dictitem.
   */
!     static void
  delete_var(hashtab_T *ht, hashitem_T *hi)
  {
      dictitem_T        *di = HI2DI(hi);
***************
*** 2853,2858 ****
--- 3071,3227 ----
      return n;
  }
  
+ 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
+ static char_u *redir_endp = NULL;
+ static char_u *redir_varname = NULL;
+ 
+ /*
+  * Start recording command output to a variable
+  * When "append" is TRUE append to an existing variable.
+  * Returns OK if successfully completed the setup.  FAIL otherwise.
+  */
+     int
+ var_redir_start(char_u *name, int append)
+ {
+     int               save_emsg;
+     int               err;
+     typval_T  tv;
+ 
+     // Catch a bad name early.
+     if (!eval_isnamec1(*name))
+     {
+       emsg(_(e_invarg));
+       return FAIL;
+     }
+ 
+     // Make a copy of the name, it is used in redir_lval until redir ends.
+     redir_varname = vim_strsave(name);
+     if (redir_varname == NULL)
+       return FAIL;
+ 
+     redir_lval = ALLOC_CLEAR_ONE(lval_T);
+     if (redir_lval == NULL)
+     {
+       var_redir_stop();
+       return FAIL;
+     }
+ 
+     // The output is stored in growarray "redir_ga" until redirection ends.
+     ga_init2(&redir_ga, (int)sizeof(char), 500);
+ 
+     // Parse the variable name (can be a dict or list entry).
+     redir_endp = get_lval(redir_varname, NULL, redir_lval, FALSE, FALSE, 0,
+                                                            FNE_CHECK_START);
+     if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != 
NUL)
+     {
+       clear_lval(redir_lval);
+       if (redir_endp != NULL && *redir_endp != NUL)
+           // Trailing characters are present after the variable name
+           emsg(_(e_trailing));
+       else
+           emsg(_(e_invarg));
+       redir_endp = NULL;  // don't store a value, only cleanup
+       var_redir_stop();
+       return FAIL;
+     }
+ 
+     // check if we can write to the variable: set it to or append an empty
+     // string
+     save_emsg = did_emsg;
+     did_emsg = FALSE;
+     tv.v_type = VAR_STRING;
+     tv.vval.v_string = (char_u *)"";
+     if (append)
+       set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)".");
+     else
+       set_var_lval(redir_lval, redir_endp, &tv, TRUE, FALSE, (char_u *)"=");
+     clear_lval(redir_lval);
+     err = did_emsg;
+     did_emsg |= save_emsg;
+     if (err)
+     {
+       redir_endp = NULL;  // don't store a value, only cleanup
+       var_redir_stop();
+       return FAIL;
+     }
+ 
+     return OK;
+ }
+ 
+ /*
+  * Append "value[value_len]" to the variable set by var_redir_start().
+  * The actual appending is postponed until redirection ends, because the value
+  * appended may in fact be the string we write to, changing it may cause freed
+  * memory to be used:
+  *   :redir => foo
+  *   :let foo
+  *   :redir END
+  */
+     void
+ var_redir_str(char_u *value, int value_len)
+ {
+     int               len;
+ 
+     if (redir_lval == NULL)
+       return;
+ 
+     if (value_len == -1)
+       len = (int)STRLEN(value);       // Append the entire string
+     else
+       len = value_len;                // Append only "value_len" characters
+ 
+     if (ga_grow(&redir_ga, len) == OK)
+     {
+       mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len);
+       redir_ga.ga_len += len;
+     }
+     else
+       var_redir_stop();
+ }
+ 
+ /*
+  * Stop redirecting command output to a variable.
+  * Frees the allocated memory.
+  */
+     void
+ var_redir_stop(void)
+ {
+     typval_T  tv;
+ 
+     if (EVALCMD_BUSY)
+     {
+       redir_lval = NULL;
+       return;
+     }
+ 
+     if (redir_lval != NULL)
+     {
+       // If there was no error: assign the text to the variable.
+       if (redir_endp != NULL)
+       {
+           ga_append(&redir_ga, NUL);  // Append the trailing NUL.
+           tv.v_type = VAR_STRING;
+           tv.vval.v_string = redir_ga.ga_data;
+           // Call get_lval() again, if it's inside a Dict or List it may
+           // have changed.
+           redir_endp = get_lval(redir_varname, NULL, redir_lval,
+                                       FALSE, FALSE, 0, FNE_CHECK_START);
+           if (redir_endp != NULL && redir_lval->ll_name != NULL)
+               set_var_lval(redir_lval, redir_endp, &tv, FALSE, FALSE,
+                                                               (char_u *)".");
+           clear_lval(redir_lval);
+       }
+ 
+       // free the collected output
+       VIM_CLEAR(redir_ga.ga_data);
+ 
+       VIM_CLEAR(redir_lval);
+     }
+     VIM_CLEAR(redir_varname);
+ }
+ 
  /*
   * "gettabvar()" function
   */
*** ../vim-8.1.1956/src/ex_getln.c      2019-08-21 14:36:29.387376100 +0200
--- src/ex_getln.c      2019-09-01 15:46:52.568427240 +0200
***************
*** 4317,4319 ****
--- 4317,4427 ----
  
      return (char_u *)ga.ga_data;
  }
+ 
+ #if defined(FEAT_EVAL) || defined(PROTO)
+ /*
+  * This function is used by f_input() and f_inputdialog() functions. The third
+  * argument to f_input() specifies the type of completion to use at the
+  * prompt. The third argument to f_inputdialog() specifies the value to return
+  * when the user cancels the prompt.
+  */
+     void
+ get_user_input(
+     typval_T  *argvars,
+     typval_T  *rettv,
+     int               inputdialog,
+     int               secret)
+ {
+     char_u    *prompt = tv_get_string_chk(&argvars[0]);
+     char_u    *p = NULL;
+     int               c;
+     char_u    buf[NUMBUFLEN];
+     int               cmd_silent_save = cmd_silent;
+     char_u    *defstr = (char_u *)"";
+     int               xp_type = EXPAND_NOTHING;
+     char_u    *xp_arg = NULL;
+ 
+     rettv->v_type = VAR_STRING;
+     rettv->vval.v_string = NULL;
+ 
+ #ifdef NO_CONSOLE_INPUT
+     // While starting up, there is no place to enter text. When running tests
+     // with --not-a-term we assume feedkeys() will be used.
+     if (no_console_input() && !is_not_a_term())
+       return;
+ #endif
+ 
+     cmd_silent = FALSE;               // Want to see the prompt.
+     if (prompt != NULL)
+     {
+       // Only the part of the message after the last NL is considered as
+       // prompt for the command line
+       p = vim_strrchr(prompt, '\n');
+       if (p == NULL)
+           p = prompt;
+       else
+       {
+           ++p;
+           c = *p;
+           *p = NUL;
+           msg_start();
+           msg_clr_eos();
+           msg_puts_attr((char *)prompt, get_echo_attr());
+           msg_didout = FALSE;
+           msg_starthere();
+           *p = c;
+       }
+       cmdline_row = msg_row;
+ 
+       if (argvars[1].v_type != VAR_UNKNOWN)
+       {
+           defstr = tv_get_string_buf_chk(&argvars[1], buf);
+           if (defstr != NULL)
+               stuffReadbuffSpec(defstr);
+ 
+           if (!inputdialog && argvars[2].v_type != VAR_UNKNOWN)
+           {
+               char_u  *xp_name;
+               int     xp_namelen;
+               long    argt;
+ 
+               // input() with a third argument: completion
+               rettv->vval.v_string = NULL;
+ 
+               xp_name = tv_get_string_buf_chk(&argvars[2], buf);
+               if (xp_name == NULL)
+                   return;
+ 
+               xp_namelen = (int)STRLEN(xp_name);
+ 
+               if (parse_compl_arg(xp_name, xp_namelen, &xp_type, &argt,
+                                                            &xp_arg) == FAIL)
+                   return;
+           }
+       }
+ 
+       if (defstr != NULL)
+       {
+           int save_ex_normal_busy = ex_normal_busy;
+ 
+           ex_normal_busy = 0;
+           rettv->vval.v_string =
+               getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(),
+                                                             xp_type, xp_arg);
+           ex_normal_busy = save_ex_normal_busy;
+       }
+       if (inputdialog && rettv->vval.v_string == NULL
+               && argvars[1].v_type != VAR_UNKNOWN
+               && argvars[2].v_type != VAR_UNKNOWN)
+           rettv->vval.v_string = vim_strsave(tv_get_string_buf(
+                                                          &argvars[2], buf));
+ 
+       vim_free(xp_arg);
+ 
+       // since the user typed this, no need to wait for return
+       need_wait_return = FALSE;
+       msg_didout = FALSE;
+     }
+     cmd_silent = cmd_silent_save;
+ }
+ #endif
*** ../vim-8.1.1956/src/globals.h       2019-08-27 22:48:12.741480663 +0200
--- src/globals.h       2019-09-01 15:46:52.568427240 +0200
***************
*** 191,199 ****
  EXTERN int    emsg_severe INIT(= FALSE);  // use message of next of several
                                            // emsg() calls for throw
  EXTERN int    did_endif INIT(= FALSE);    // just had ":endif"
- EXTERN dict_T vimvardict;                 // Dictionary with v: variables
- EXTERN dict_T globvardict;                // Dictionary with g: variables
- #define globvarht globvardict.dv_hashtab
  #endif
  EXTERN int    did_emsg;                   // set by emsg() when the message
                                            // is displayed or thrown
--- 191,196 ----
*** ../vim-8.1.1956/src/if_py_both.h    2019-06-23 01:46:11.840059790 +0200
--- src/if_py_both.h    2019-09-01 15:46:52.568427240 +0200
***************
*** 6847,6854 ****
        return -1;
      ADD_OBJECT(m, "error", VimError);
  
!     ADD_CHECKED_OBJECT(m, "vars",  NEW_DICTIONARY(&globvardict));
!     ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(&vimvardict));
      ADD_CHECKED_OBJECT(m, "options",
            OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL));
  
--- 6847,6854 ----
        return -1;
      ADD_OBJECT(m, "error", VimError);
  
!     ADD_CHECKED_OBJECT(m, "vars",  NEW_DICTIONARY(get_globvar_dict()));
!     ADD_CHECKED_OBJECT(m, "vvars", NEW_DICTIONARY(get_vimvar_dict()));
      ADD_CHECKED_OBJECT(m, "options",
            OptionsNew(SREQ_GLOBAL, NULL, dummy_check, NULL));
  
*** ../vim-8.1.1956/src/proto/eval.pro  2019-08-30 15:46:27.188906163 +0200
--- src/proto/eval.pro  2019-09-01 15:46:52.568427240 +0200
***************
*** 3,15 ****
  varnumber_T num_modulus(varnumber_T n1, varnumber_T n2);
  void eval_init(void);
  void eval_clear(void);
- int var_redir_start(char_u *name, int append);
- void var_redir_str(char_u *value, int value_len);
- void var_redir_stop(void);
- int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, 
char_u *fname_to);
- int eval_printexpr(char_u *fname, char_u *args);
- void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
- void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
  int eval_to_bool(char_u *arg, int *error, char_u **nextcmd, int skip);
  int eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T 
*rettv);
  int eval_expr_to_bool(typval_T *expr, int *error);
--- 3,8 ----
***************
*** 33,39 ****
  int next_for_item(void *fi_void, char_u *arg);
  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);
  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);
--- 26,31 ----
***************
*** 76,88 ****
  char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf);
  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);
  void ex_echo(exarg_T *eap);
  void ex_echohl(exarg_T *eap);
  void ex_execute(exarg_T *eap);
  char_u *find_option_end(char_u **arg, int *opt_flags);
- char_u *autoload_name(char_u *name);
- int script_autoload(char_u *name, int reload);
  void last_set_msg(sctx_T script_ctx);
  int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int 
type_is, int ic);
  char_u *typval_tostring(typval_T *arg);
--- 68,78 ----
  char_u *tv_get_string_buf_chk(typval_T *varp, char_u *buf);
  void copy_tv(typval_T *from, typval_T *to);
  int item_copy(typval_T *from, typval_T *to, int deep, int copyID);
  void ex_echo(exarg_T *eap);
  void ex_echohl(exarg_T *eap);
+ int get_echo_attr(void);
  void ex_execute(exarg_T *eap);
  char_u *find_option_end(char_u **arg, int *opt_flags);
  void last_set_msg(sctx_T script_ctx);
  int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int 
type_is, int ic);
  char_u *typval_tostring(typval_T *arg);
*** ../vim-8.1.1956/src/proto/evalvars.pro      2019-08-30 15:46:27.188906163 
+0200
--- src/proto/evalvars.pro      2019-09-01 15:46:52.568427240 +0200
***************
*** 1,9 ****
--- 1,14 ----
  /* evalvars.c */
  void evalvars_init(void);
  void evalvars_clear(void);
+ int garbage_collect_globvars(int copyID);
  int garbage_collect_vimvars(int copyID);
  int garbage_collect_scriptvars(int copyID);
  void set_internal_string_var(char_u *name, char_u *value);
+ int eval_charconvert(char_u *enc_from, char_u *enc_to, char_u *fname_from, 
char_u *fname_to);
+ int eval_printexpr(char_u *fname, char_u *args);
+ void eval_diff(char_u *origfile, char_u *newfile, char_u *outfile);
+ void eval_patch(char_u *origfile, char_u *difffile, char_u *outfile);
  void prepare_vimvar(int idx, typval_T *save_tv);
  void restore_vimvar(int idx, typval_T *save_tv);
  void ex_let(exarg_T *eap);
***************
*** 14,20 ****
--- 19,30 ----
  void ex_unlet(exarg_T *eap);
  void ex_lockvar(exarg_T *eap);
  int do_unlet(char_u *name, int forceit);
+ void del_menutrans_vars(void);
  char_u *get_user_var_name(expand_T *xp, int idx);
+ char *get_var_special_name(int nr);
+ dict_T *get_globvar_dict(void);
+ hashtab_T *get_globvar_ht(void);
+ dict_T *get_vimvar_dict(void);
  void set_vim_var_type(int idx, vartype_T type);
  void set_vim_var_nr(int idx, varnumber_T val);
  typval_T *get_vim_var_tv(int idx);
***************
*** 44,50 ****
  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);
  void set_var(char_u *name, typval_T *tv, int copy);
  void set_var_const(char_u *name, typval_T *tv, int copy, int is_const);
  int var_check_ro(int flags, char_u *name, int use_gettext);
--- 54,59 ----
***************
*** 55,60 ****
--- 64,72 ----
  void reset_v_option_vars(void);
  void assert_error(garray_T *gap);
  int var_exists(char_u *var);
+ int var_redir_start(char_u *name, int append);
+ void var_redir_str(char_u *value, int value_len);
+ void var_redir_stop(void);
  void f_gettabvar(typval_T *argvars, typval_T *rettv);
  void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
  void f_getwinvar(typval_T *argvars, typval_T *rettv);
*** ../vim-8.1.1956/src/proto/ex_getln.pro      2019-08-18 21:43:52.138401489 
+0200
--- src/proto/ex_getln.pro      2019-09-01 15:46:52.568427240 +0200
***************
*** 35,38 ****
--- 35,39 ----
  int get_cmdline_firstc(void);
  int get_list_range(char_u **str, int *num1, int *num2);
  char_u *script_get(exarg_T *eap, char_u *cmd);
+ void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog, int 
secret);
  /* vim: set ft=c : */
*** ../vim-8.1.1956/src/proto/scriptfile.pro    2019-08-25 15:40:39.662739502 
+0200
--- src/proto/scriptfile.pro    2019-09-01 15:46:52.568427240 +0200
***************
*** 20,25 ****
--- 20,26 ----
  void scriptnames_slash_adjust(void);
  char_u *get_scriptname(scid_T id);
  void free_scriptnames(void);
+ void free_autoload_scriptnames(void);
  linenr_T get_sourced_lnum(char_u *(*fgetline)(int, void *, int, int), void 
*cookie);
  char_u *getsourceline(int c, void *cookie, int indent, int do_concat);
  void ex_scriptencoding(exarg_T *eap);
***************
*** 27,30 ****
--- 28,33 ----
  void ex_finish(exarg_T *eap);
  void do_finish(exarg_T *eap, int reanimate);
  int source_finished(char_u *(*fgetline)(int, void *, int, int), void *cookie);
+ char_u *autoload_name(char_u *name);
+ int script_autoload(char_u *name, int reload);
  /* vim: set ft=c : */
*** ../vim-8.1.1956/src/scriptfile.c    2019-08-25 15:40:39.662739502 +0200
--- src/scriptfile.c    2019-09-01 15:46:52.572427200 +0200
***************
*** 13,18 ****
--- 13,23 ----
  
  #include "vim.h"
  
+ #if defined(FEAT_EVAL) || defined(PROTO)
+ // The names of packages that once were loaded are remembered.
+ static garray_T               ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
+ #endif
+ 
  /*
   * ":runtime [what] {name}"
   */
***************
*** 1334,1339 ****
--- 1339,1350 ----
        vim_free(SCRIPT_ITEM(i).sn_name);
      ga_clear(&script_items);
  }
+ 
+     void
+ free_autoload_scriptnames(void)
+ {
+     ga_clear_strings(&ga_loaded);
+ }
  # endif
  
  #endif
***************
*** 1690,1693 ****
--- 1701,1776 ----
            && ((struct source_cookie *)getline_cookie(
                                                fgetline, cookie))->finished);
  }
+ 
+ /*
+  * Return the autoload script name for a function or variable name.
+  * Returns NULL when out of memory.
+  * Caller must make sure that "name" contains AUTOLOAD_CHAR.
+  */
+     char_u *
+ autoload_name(char_u *name)
+ {
+     char_u    *p, *q = NULL;
+     char_u    *scriptname;
+ 
+     // Get the script file name: replace '#' with '/', append ".vim".
+     scriptname = alloc(STRLEN(name) + 14);
+     if (scriptname == NULL)
+       return NULL;
+     STRCPY(scriptname, "autoload/");
+     STRCAT(scriptname, name);
+     for (p = scriptname + 9; (p = vim_strchr(p, AUTOLOAD_CHAR)) != NULL;
+                                                                   q = p, ++p)
+       *p = '/';
+     STRCPY(q, ".vim");
+     return scriptname;
+ }
+ 
+ /*
+  * If "name" has a package name try autoloading the script for it.
+  * Return TRUE if a package was loaded.
+  */
+     int
+ script_autoload(
+     char_u    *name,
+     int               reload)     // load script again when already loaded
+ {
+     char_u    *p;
+     char_u    *scriptname, *tofree;
+     int               ret = FALSE;
+     int               i;
+ 
+     // If there is no '#' after name[0] there is no package name.
+     p = vim_strchr(name, AUTOLOAD_CHAR);
+     if (p == NULL || p == name)
+       return FALSE;
+ 
+     tofree = scriptname = autoload_name(name);
+     if (scriptname == NULL)
+       return FALSE;
+ 
+     // Find the name in the list of previously loaded package names.  Skip
+     // "autoload/", it's always the same.
+     for (i = 0; i < ga_loaded.ga_len; ++i)
+       if (STRCMP(((char_u **)ga_loaded.ga_data)[i] + 9, scriptname + 9) == 0)
+           break;
+     if (!reload && i < ga_loaded.ga_len)
+       ret = FALSE;        // was loaded already
+     else
+     {
+       // Remember the name if it wasn't loaded already.
+       if (i == ga_loaded.ga_len && ga_grow(&ga_loaded, 1) == OK)
+       {
+           ((char_u **)ga_loaded.ga_data)[ga_loaded.ga_len++] = scriptname;
+           tofree = NULL;
+       }
+ 
+       // Try loading the package from $VIMRUNTIME/autoload/<name>.vim
+       if (source_runtime(scriptname, 0) == OK)
+           ret = TRUE;
+     }
+ 
+     vim_free(tofree);
+     return ret;
+ }
  #endif
*** ../vim-8.1.1956/src/session.c       2019-07-28 15:21:50.809275875 +0200
--- src/session.c       2019-09-01 15:46:52.572427200 +0200
***************
*** 500,512 ****
      static int
  store_session_globals(FILE *fd)
  {
      hashitem_T        *hi;
      dictitem_T        *this_var;
      int               todo;
      char_u    *p, *t;
  
!     todo = (int)globvarht.ht_used;
!     for (hi = globvarht.ht_array; todo > 0; ++hi)
      {
        if (!HASHITEM_EMPTY(hi))
        {
--- 500,513 ----
      static int
  store_session_globals(FILE *fd)
  {
+     hashtab_T *gvht = get_globvar_ht();
      hashitem_T        *hi;
      dictitem_T        *this_var;
      int               todo;
      char_u    *p, *t;
  
!     todo = (int)gvht->ht_used;
!     for (hi = gvht->ht_array; todo > 0; ++hi)
      {
        if (!HASHITEM_EMPTY(hi))
        {
*** ../vim-8.1.1956/src/viminfo.c       2019-08-06 21:59:37.763982481 +0200
--- src/viminfo.c       2019-09-01 15:46:52.572427200 +0200
***************
*** 1277,1282 ****
--- 1277,1283 ----
      static void
  write_viminfo_varlist(FILE *fp)
  {
+     hashtab_T *gvht = get_globvar_ht();
      hashitem_T        *hi;
      dictitem_T        *this_var;
      int               todo;
***************
*** 1290,1297 ****
  
      fputs(_("\n# global variables:\n"), fp);
  
!     todo = (int)globvarht.ht_used;
!     for (hi = globvarht.ht_array; todo > 0; ++hi)
      {
        if (!HASHITEM_EMPTY(hi))
        {
--- 1291,1298 ----
  
      fputs(_("\n# global variables:\n"), fp);
  
!     todo = (int)gvht->ht_used;
!     for (hi = gvht->ht_array; todo > 0; ++hi)
      {
        if (!HASHITEM_EMPTY(hi))
        {
*** ../vim-8.1.1956/src/version.c       2019-09-01 15:26:20.043537901 +0200
--- src/version.c       2019-09-01 16:00:36.061152573 +0200
***************
*** 763,764 ****
--- 763,766 ----
  {   /* Add new patch number below this line */
+ /**/
+     1957,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
160. You get in the elevator and double-click the button for the floor
     you want.

 /// Bram Moolenaar -- b...@moolenaar.net -- 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 vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201909011403.x81E3GEf032375%40masaka.moolenaar.net.

Raspunde prin e-mail lui