Patch 8.2.4050
Problem:    Vim9: need to prefix every item in an autoload script.
Solution:   First step in supporting "vim9script autoload" and "import
            autoload".
Files:      runtime/doc/repeat.txt, runtime/doc/vim9.txt, src/structs.h,
            src/errors.h, src/vim9script.c, src/scriptfile.c,
            src/proto/scriptfile.pro, src/userfunc.c, src/eval.c,
            src/evalvars.c, src/vim9compile.c, src/proto/vim9compile.pro,
            src/vim9expr.c, src/testdir/test_vim9_script.vim


*** ../vim-8.2.4049/runtime/doc/repeat.txt      2021-02-14 11:57:32.552655477 
+0000
--- runtime/doc/repeat.txt      2022-01-09 14:53:57.822209348 +0000
***************
*** 354,369 ****
                        Vim version, or update Vim to a newer version.  See
                        |vimscript-version| for what changed between versions.
  
! :vim9s[cript] [noclear]                               *:vim9s* *:vim9script*
                        Marks a script file as containing |Vim9-script|
                        commands.  Also see |vim9-namespace|.
                        Must be the first command in the file.
                        For [noclear] see |vim9-reload|.
                        Without the |+eval| feature this changes the syntax
                        for some commands.
                        See |:vim9cmd| for executing one command with Vim9
                        syntax and semantics.
!                        
                                                *:scr* *:scriptnames*
  :scr[iptnames]                List all sourced script names, in the order 
they were
                        first sourced.  The number is used for the script ID
--- 365,381 ----
                        Vim version, or update Vim to a newer version.  See
                        |vimscript-version| for what changed between versions.
  
! :vim9s[cript] [noclear] [autoload]                    *:vim9s* *:vim9script*
                        Marks a script file as containing |Vim9-script|
                        commands.  Also see |vim9-namespace|.
                        Must be the first command in the file.
                        For [noclear] see |vim9-reload|.
+                       For [autoload] see |vim9-autoload|.
                        Without the |+eval| feature this changes the syntax
                        for some commands.
                        See |:vim9cmd| for executing one command with Vim9
                        syntax and semantics.
! 
                                                *:scr* *:scriptnames*
  :scr[iptnames]                List all sourced script names, in the order 
they were
                        first sourced.  The number is used for the script ID
*** ../vim-8.2.4049/runtime/doc/vim9.txt        2022-01-06 21:10:24.465027868 
+0000
--- runtime/doc/vim9.txt        2022-01-09 15:09:38.686342752 +0000
***************
*** 1484,1520 ****
  
  
  Import in an autoload script ~
! 
  For optimal startup speed, loading scripts should be postponed until they are
! actually needed.  A recommended mechanism:
  
  1. In the plugin define user commands, functions and/or mappings that refer to
!    an autoload script. >
!       command -nargs=1 SearchForStuff searchfor#Stuff(<f-args>)
  
  <   This goes in .../plugin/anyname.vim.  "anyname.vim" can be freely chosen.
  
! 2. In the autoload script do the actual work.  You can import items from
!    other files to split up functionality in appropriate pieces. >
!       vim9script
!       import "../import/someother.vim" as other
!       def searchfor#Stuff(arg: string)
!         var filtered = other.FilterFunc(arg)
          ...
- <   This goes in .../autoload/searchfor.vim.  "searchfor" in the file name
-    must be exactly the same as the prefix for the function name, that is how
-    Vim finds the file.
  
! 3. Other functionality, possibly shared between plugins, contains the exported
!    items and any private items. >
!       vim9script
!       var localVar = 'local'
!       export def FilterFunc(arg: string): string
!          ...
! <   This goes in .../import/someother.vim.
  
  When compiling a `:def` function and a function in an autoload script is
  encountered, the script is not loaded until the `:def` function is called.
  
  
  Import in legacy Vim script ~
--- 1501,1543 ----
  
  
  Import in an autoload script ~
!                                                       *vim9-autoload*
  For optimal startup speed, loading scripts should be postponed until they are
! actually needed.  Using the autoload mechanism is recommended:
  
  1. In the plugin define user commands, functions and/or mappings that refer to
!    items imported from an autoload script. >
!       import autoload 'for/search.vim'
!       command -nargs=1 SearchForStuff search.Stuff(<f-args>)
  
  <   This goes in .../plugin/anyname.vim.  "anyname.vim" can be freely chosen.
+    The "SearchForStuff" command is now available to the user.
  
!    The "autoload" argument to `:import` means that the script is not loaded
!    until one of the items is actually used.  The script will be found under
!    the "autoload" directory in 'runtimepath' instead of the "import"
!    directory.
! 
! 2. In the autoload script put the bulk of the code. >
!       vim9script autoload
!       export def Stuff(arg: string)
          ...
  
! <   This goes in .../autoload/for/search.vim.
! 
!    Adding "autoload" to `:vim9script` has the effect that "for#search#" will
!    be prefixed to every exported item.  The prefix is obtained from the file
!    name, as you would to manually in a legacy autoload script.  Thus the
!    exported function can be found with "for#search#Stuff", but you would
!    normally use `import autoload` and not need to specify the prefix.
! 
!    You can split up the functionality and import other scripts from the
!    autoload script as you like.  This way you can share code between plugins.
  
  When compiling a `:def` function and a function in an autoload script is
  encountered, the script is not loaded until the `:def` function is called.
+ This also means you get any errors only at runtime, since the argument and
+ return types are not known yet.
  
  
  Import in legacy Vim script ~
*** ../vim-8.2.4049/src/structs.h       2022-01-07 15:45:13.495500428 +0000
--- src/structs.h       2022-01-09 19:28:53.695433972 +0000
***************
*** 1827,1832 ****
--- 1827,1833 ----
  } imported_T;
  
  #define IMP_FLAGS_RELOAD      2   // script reloaded, OK to redefine
+ #define IMP_FLAGS_AUTOLOAD    4   // script still needs to be loaded
  
  /*
   * Info about an already sourced scripts.
***************
*** 1863,1868 ****
--- 1864,1870 ----
      int               sn_state;       // SN_STATE_ values
      char_u    *sn_save_cpo;   // 'cpo' value when :vim9script found
      char      sn_is_vimrc;    // .vimrc file, do not restore 'cpo'
+     char      sn_is_autoload; // "vim9script autoload"
  
  # ifdef FEAT_PROFILE
      int               sn_prof_on;     // TRUE when script is/was profiled
***************
*** 1886,1892 ****
  } scriptitem_T;
  
  #define SN_STATE_NEW          0   // newly loaded script, nothing done
! #define SN_STATE_RELOAD               1   // script loaded before, nothing 
done
  #define SN_STATE_HAD_COMMAND  9   // a command was executed
  
  // Struct passed through eval() functions.
--- 1888,1895 ----
  } scriptitem_T;
  
  #define SN_STATE_NEW          0   // newly loaded script, nothing done
! #define SN_STATE_NOT_LOADED   1   // script located but not loaded
! #define SN_STATE_RELOAD               2   // script loaded before, nothing 
done
  #define SN_STATE_HAD_COMMAND  9   // a command was executed
  
  // Struct passed through eval() functions.
*** ../vim-8.2.4049/src/errors.h        2022-01-09 12:49:19.400815606 +0000
--- src/errors.h        2022-01-09 18:26:24.178112518 +0000
***************
*** 3203,3206 ****
--- 3203,3210 ----
        INIT(= N_("E1261: Cannot import .vim without using \"as\""));
  EXTERN char e_cannot_import_same_script_twice_str[]
        INIT(= N_("E1262: Cannot import the same script twice: %s"));
+ EXTERN char e_using_autoload_in_script_not_under_autoload_directory[]
+       INIT(= N_("E1263: Using autoload in a script not under an autoload 
directory"));
+ EXTERN char e_autoload_import_cannot_use_absolute_or_relative_path[]
+       INIT(= N_("E1264: Autoload import cannot use absolute or relative path: 
%s"));
  #endif
*** ../vim-8.2.4049/src/vim9script.c    2022-01-08 17:03:51.600942321 +0000
--- src/vim9script.c    2022-01-09 19:56:48.099838627 +0000
***************
*** 68,73 ****
--- 68,76 ----
  #ifdef FEAT_EVAL
      int                   sid = current_sctx.sc_sid;
      scriptitem_T    *si;
+     int                   found_noclear = FALSE;
+     int                   found_autoload = FALSE;
+     char_u        *p;
  
      if (!getline_equal(eap->getline, eap->cookie, getsourceline))
      {
***************
*** 81,92 ****
        emsg(_(e_vim9script_must_be_first_command_in_script));
        return;
      }
!     if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0)
      {
!       semsg(_(e_invalid_argument_str), eap->arg);
!       return;
      }
!     if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg))
      {
        hashtab_T       *ht = &SCRIPT_VARS(sid);
  
--- 84,123 ----
        emsg(_(e_vim9script_must_be_first_command_in_script));
        return;
      }
! 
!     for (p = eap->arg; !IS_WHITE_OR_NUL(*p); p = skipwhite(skiptowhite(p)))
      {
!       if (STRNCMP(p, "noclear", 7) == 0 && IS_WHITE_OR_NUL(p[7]))
!       {
!           if (found_noclear)
!           {
!               semsg(_(e_duplicate_argument_str), p);
!               return;
!           }
!           found_noclear = TRUE;
!       }
!       else if (STRNCMP(p, "autoload", 8) == 0 && IS_WHITE_OR_NUL(p[8]))
!       {
!           if (found_autoload)
!           {
!               semsg(_(e_duplicate_argument_str), p);
!               return;
!           }
!           found_autoload = TRUE;
!           if (script_name_after_autoload(si) == NULL)
!           {
!               
emsg(_(e_using_autoload_in_script_not_under_autoload_directory));
!               return;
!           }
!       }
!       else
!       {
!           semsg(_(e_invalid_argument_str), eap->arg);
!           return;
!       }
      }
! 
!     if (si->sn_state == SN_STATE_RELOAD && !found_noclear)
      {
        hashtab_T       *ht = &SCRIPT_VARS(sid);
  
***************
*** 101,106 ****
--- 132,139 ----
      }
      si->sn_state = SN_STATE_HAD_COMMAND;
  
+     si->sn_is_autoload = found_autoload;
+ 
      current_sctx.sc_version = SCRIPT_VERSION_VIM9;
      si->sn_version = SCRIPT_VERSION_VIM9;
  
***************
*** 366,371 ****
--- 399,405 ----
  {
      char_u    *arg = arg_start;
      char_u    *nextarg;
+     int               is_autoload = FALSE;
      int               getnext;
      char_u    *expr_end;
      int               ret = FAIL;
***************
*** 377,382 ****
--- 411,422 ----
      garray_T  *import_gap;
      int               i;
  
+     if (STRNCMP(arg, "autoload", 8) == 0 && VIM_ISWHITE(arg[8]))
+     {
+       is_autoload = TRUE;
+       arg = skipwhite(arg + 8);
+     }
+ 
      // The name of the file can be an expression, which must evaluate to a
      // string.
      ret = eval0_retarg(arg, &tv, NULL, evalarg, &expr_end);
***************
*** 402,424 ****
        char_u          *tail = gettail(si->sn_name);
        char_u          *from_name;
  
!       // Relative to current script: "./name.vim", "../../name.vim".
!       len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2;
!       from_name = alloc((int)len);
!       if (from_name == NULL)
!           goto erret;
!       vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
!       add_pathsep(from_name);
!       STRCAT(from_name, tv.vval.v_string);
!       simplify_filename(from_name);
  
!       res = do_source(from_name, FALSE, DOSO_NONE, &sid);
!       vim_free(from_name);
      }
      else if (mch_isFullName(tv.vval.v_string))
      {
        // Absolute path: "/tmp/name.vim"
!       res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
      }
      else
      {
--- 442,489 ----
        char_u          *tail = gettail(si->sn_name);
        char_u          *from_name;
  
!       if (is_autoload)
!           res = FAIL;
!       else
!       {
  
!           // Relative to current script: "./name.vim", "../../name.vim".
!           len = STRLEN(si->sn_name) - STRLEN(tail)
!                                               + STRLEN(tv.vval.v_string) + 2;
!           from_name = alloc((int)len);
!           if (from_name == NULL)
!               goto erret;
!           vim_strncpy(from_name, si->sn_name, tail - si->sn_name);
!           add_pathsep(from_name);
!           STRCAT(from_name, tv.vval.v_string);
!           simplify_filename(from_name);
! 
!           res = do_source(from_name, FALSE, DOSO_NONE, &sid);
!           vim_free(from_name);
!       }
      }
      else if (mch_isFullName(tv.vval.v_string))
      {
        // Absolute path: "/tmp/name.vim"
!       if (is_autoload)
!           res = FAIL;
!       else
!           res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid);
!     }
!     else if (is_autoload)
!     {
!       size_t      len = 9 + STRLEN(tv.vval.v_string) + 1;
!       char_u      *from_name;
! 
!       // Find file in "autoload" subdirs in 'runtimepath'.
!       from_name = alloc((int)len);
!       if (from_name == NULL)
!           goto erret;
!       vim_snprintf((char *)from_name, len, "autoload/%s", tv.vval.v_string);
!       // we need a scriptitem without loading the script
!       sid = find_script_in_rtp(from_name);
!       vim_free(from_name);
!       res = SCRIPT_ID_VALID(sid) ? OK : FAIL;
      }
      else
      {
***************
*** 428,436 ****
        // Find file in "import" subdirs in 'runtimepath'.
        from_name = alloc((int)len);
        if (from_name == NULL)
-       {
            goto erret;
-       }
        vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string);
        res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid);
        vim_free(from_name);
--- 493,499 ----
***************
*** 438,444 ****
  
      if (res == FAIL || sid <= 0)
      {
!       semsg(_(e_could_not_import_str), tv.vval.v_string);
        goto erret;
      }
  
--- 501,509 ----
  
      if (res == FAIL || sid <= 0)
      {
!       semsg(_(is_autoload && sid <= 0
!                   ? e_autoload_import_cannot_use_absolute_or_relative_path
!                   : e_could_not_import_str), tv.vval.v_string);
        goto erret;
      }
  
***************
*** 451,457 ****
        {
            if (import->imp_flags & IMP_FLAGS_RELOAD)
            {
!               // encountering same script first ime on a reload is OK
                import->imp_flags &= ~IMP_FLAGS_RELOAD;
                break;
            }
--- 516,522 ----
        {
            if (import->imp_flags & IMP_FLAGS_RELOAD)
            {
!               // encountering same script first time on a reload is OK
                import->imp_flags &= ~IMP_FLAGS_RELOAD;
                break;
            }
***************
*** 513,519 ****
      {
        imported_T  *imported;
  
!       imported = find_imported(as_name, STRLEN(as_name), cctx);
        if (imported != NULL && imported->imp_sid != sid)
        {
            semsg(_(e_name_already_defined_str), as_name);
--- 578,584 ----
      {
        imported_T  *imported;
  
!       imported = find_imported(as_name, FALSE, STRLEN(as_name), cctx);
        if (imported != NULL && imported->imp_sid != sid)
        {
            semsg(_(e_name_already_defined_str), as_name);
***************
*** 529,534 ****
--- 594,601 ----
        imported->imp_name = as_name;
        as_name = NULL;
        imported->imp_sid = sid;
+       if (is_autoload)
+           imported->imp_flags = IMP_FLAGS_AUTOLOAD;
      }
  
  erret:
*** ../vim-8.2.4049/src/scriptfile.c    2022-01-08 16:19:18.505639885 +0000
--- src/scriptfile.c    2022-01-09 20:36:52.041830557 +0000
***************
*** 239,244 ****
--- 239,340 ----
      (void)do_source(fname, FALSE, DOSO_NONE, cookie);
  }
  
+ #ifdef FEAT_EVAL
+ /*
+  * Find an already loaded script "name".
+  * If found returns its script ID.  If not found returns -1.
+  */
+     static int
+ find_script_by_name(char_u *name)
+ {
+     int                   sid;
+     scriptitem_T    *si;
+ 
+     for (sid = script_items.ga_len; sid > 0; --sid)
+     {
+       // We used to check inode here, but that doesn't work:
+       // - If a script is edited and written, it may get a different
+       //   inode number, even though to the user it is the same script.
+       // - If a script is deleted and another script is written, with a
+       //   different name, the inode may be re-used.
+       si = SCRIPT_ITEM(sid);
+       if (si->sn_name != NULL && fnamecmp(si->sn_name, name) == 0)
+           return sid;
+     }
+     return -1;
+ }
+ 
+ /*
+  * Add a new scriptitem with all items initialized.
+  * When running out of memory "error" is set to FAIL.
+  * Returns the script ID.
+  */
+     static int
+ get_new_scriptitem(int *error)
+ {
+     static scid_T   last_current_SID = 0;
+     int                   sid = ++last_current_SID;
+     scriptitem_T    *si;
+ 
+     if (ga_grow(&script_items, (int)(sid - script_items.ga_len)) == FAIL)
+     {
+       *error = FAIL;
+       return sid;
+     }
+     while (script_items.ga_len < sid)
+     {
+       si = ALLOC_CLEAR_ONE(scriptitem_T);
+       if (si == NULL)
+       {
+           *error = FAIL;
+           return sid;
+       }
+       ++script_items.ga_len;
+       SCRIPT_ITEM(script_items.ga_len) = si;
+       si->sn_name = NULL;
+       si->sn_version = 1;
+ 
+       // Allocate the local script variables to use for this script.
+       new_script_vars(script_items.ga_len);
+       ga_init2(&si->sn_var_vals, sizeof(svar_T), 10);
+       hash_init(&si->sn_all_vars.dv_hashtab);
+       ga_init2(&si->sn_imports, sizeof(imported_T), 10);
+       ga_init2(&si->sn_type_list, sizeof(type_T), 10);
+ # ifdef FEAT_PROFILE
+       si->sn_prof_on = FALSE;
+ # endif
+     }
+ 
+     // Used to check script variable index is still valid.
+     si->sn_script_seq = current_sctx.sc_seq;
+ 
+     return sid;
+ }
+ 
+     static void
+ find_script_callback(char_u *fname, void *cookie)
+ {
+     int sid;
+     int error = OK;
+     int *ret_sid = cookie;
+ 
+     sid = find_script_by_name(fname);
+     if (sid < 0)
+     {
+       // script does not exist yet, create a new scriptitem
+       sid = get_new_scriptitem(&error);
+       if (error == OK)
+       {
+           scriptitem_T *si = SCRIPT_ITEM(sid);
+ 
+           si->sn_name = vim_strsave(fname);
+           si->sn_state = SN_STATE_NOT_LOADED;
+       }
+     }
+     *ret_sid = sid;
+ }
+ #endif
+ 
  /*
   * Find the file "name" in all directories in "path" and invoke
   * "callback(fname, cookie)".
***************
*** 455,461 ****
  }
  
  /*
!  * Just like source_runtime(), but use "path" instead of 'runtimepath'.
   */
      int
  source_in_path(char_u *path, char_u *name, int flags, int *ret_sid)
--- 551,558 ----
  }
  
  /*
!  * Just like source_runtime(), but use "path" instead of 'runtimepath'
!  * and return the script ID in "ret_sid".
   */
      int
  source_in_path(char_u *path, char_u *name, int flags, int *ret_sid)
***************
*** 463,472 ****
      return do_in_path_and_pp(path, name, flags, source_callback, ret_sid);
  }
  
- 
  #if defined(FEAT_EVAL) || defined(PROTO)
  
  /*
   * Expand wildcards in "pat" and invoke do_source() for each match.
   */
      static void
--- 560,583 ----
      return do_in_path_and_pp(path, name, flags, source_callback, ret_sid);
  }
  
  #if defined(FEAT_EVAL) || defined(PROTO)
  
  /*
+  * Find "name" in 'runtimepath'. If found a new scriptitem is created for it
+  * and it's script ID is returned.
+  * If not found returns -1.
+  */
+     int
+ find_script_in_rtp(char_u *name)
+ {
+     int sid = -1;
+ 
+     (void)do_in_path_and_pp(p_rtp, name, DIP_NOAFTER,
+                                                  find_script_callback, &sid);
+     return sid;
+ }
+ 
+ /*
   * Expand wildcards in "pat" and invoke do_source() for each match.
   */
      static void
***************
*** 1127,1133 ****
      int                           retval = FAIL;
      sctx_T                save_current_sctx;
  #ifdef FEAT_EVAL
-     static scid_T         last_current_SID = 0;
      static int                    last_current_SID_seq = 0;
      funccal_entry_T       funccalp_entry;
      int                           save_debug_break_level = debug_break_level;
--- 1238,1243 ----
***************
*** 1161,1178 ****
      estack_compiling = FALSE;
  
      // See if we loaded this script before.
!     for (sid = script_items.ga_len; sid > 0; --sid)
!     {
!       // We used to check inode here, but that doesn't work:
!       // - If a script is edited and written, it may get a different
!       //   inode number, even though to the user it is the same script.
!       // - If a script is deleted and another script is written, with a
!       //   different name, the inode may be re-used.
!       si = SCRIPT_ITEM(sid);
!       if (si->sn_name != NULL && fnamecmp(si->sn_name, fname_exp) == 0)
!               // Found it!
!               break;
!     }
      if (sid > 0 && ret_sid != NULL)
      {
        // Already loaded and no need to load again, return here.
--- 1271,1277 ----
      estack_compiling = FALSE;
  
      // See if we loaded this script before.
!     sid = find_script_by_name(fname_exp);
      if (sid > 0 && ret_sid != NULL)
      {
        // Already loaded and no need to load again, return here.
***************
*** 1318,1371 ****
        dictitem_T      *di;
  
        // loading the same script again
-       si->sn_state = SN_STATE_RELOAD;
        current_sctx.sc_sid = sid;
  
!       // Script-local variables remain but "const" can be set again.
!       // In Vim9 script variables will be cleared when "vim9script" is
!       // encountered without the "noclear" argument.
!       ht = &SCRIPT_VARS(sid);
!       todo = (int)ht->ht_used;
!       for (hi = ht->ht_array; todo > 0; ++hi)
!           if (!HASHITEM_EMPTY(hi))
!           {
!               --todo;
!               di = HI2DI(hi);
!               di->di_flags |= DI_FLAGS_RELOAD;
!           }
!       // imports can be redefined once
!       mark_imports_for_reload(sid);
  
!       // reset version, "vim9script" may have been added or removed.
!       si->sn_version = 1;
      }
      else
      {
!       // It's new, generate a new SID.
!       current_sctx.sc_sid = ++last_current_SID;
!       if (ga_grow(&script_items,
!                    (int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
!           goto almosttheend;
!       while (script_items.ga_len < current_sctx.sc_sid)
!       {
!           si = ALLOC_CLEAR_ONE(scriptitem_T);
!           if (si == NULL)
!               goto almosttheend;
!           ++script_items.ga_len;
!           SCRIPT_ITEM(script_items.ga_len) = si;
!           si->sn_name = NULL;
!           si->sn_version = 1;
  
!           // Allocate the local script variables to use for this script.
!           new_script_vars(script_items.ga_len);
!           ga_init2(&si->sn_var_vals, sizeof(svar_T), 10);
!           hash_init(&si->sn_all_vars.dv_hashtab);
!           ga_init2(&si->sn_imports, sizeof(imported_T), 10);
!           ga_init2(&si->sn_type_list, sizeof(type_T), 10);
! # ifdef FEAT_PROFILE
!           si->sn_prof_on = FALSE;
! # endif
!       }
        si = SCRIPT_ITEM(current_sctx.sc_sid);
        si->sn_name = fname_exp;
        fname_exp = vim_strsave(si->sn_name);  // used for autocmd
--- 1417,1460 ----
        dictitem_T      *di;
  
        // loading the same script again
        current_sctx.sc_sid = sid;
+       si = SCRIPT_ITEM(sid);
+       if (si->sn_state == SN_STATE_NOT_LOADED)
+       {
+           // this script was found but not loaded yet
+           si->sn_state = SN_STATE_NEW;
+       }
+       else
+       {
+           si->sn_state = SN_STATE_RELOAD;
  
!           // Script-local variables remain but "const" can be set again.
!           // In Vim9 script variables will be cleared when "vim9script" is
!           // encountered without the "noclear" argument.
!           ht = &SCRIPT_VARS(sid);
!           todo = (int)ht->ht_used;
!           for (hi = ht->ht_array; todo > 0; ++hi)
!               if (!HASHITEM_EMPTY(hi))
!               {
!                   --todo;
!                   di = HI2DI(hi);
!                   di->di_flags |= DI_FLAGS_RELOAD;
!               }
!           // imports can be redefined once
!           mark_imports_for_reload(sid);
  
!           // reset version, "vim9script" may have been added or removed.
!           si->sn_version = 1;
!       }
      }
      else
      {
!       int error = OK;
  
!       // It's new, generate a new SID and initialize the scriptitem.
!       current_sctx.sc_sid = get_new_scriptitem(&error);
!       if (error == FAIL)
!           goto almosttheend;
        si = SCRIPT_ITEM(current_sctx.sc_sid);
        si->sn_name = fname_exp;
        fname_exp = vim_strsave(si->sn_name);  // used for autocmd
***************
*** 1374,1382 ****
  
        // Remember the "is_vimrc" flag for when the file is sourced again.
        si->sn_is_vimrc = is_vimrc;
- 
-       // Used to check script variable index is still valid.
-       si->sn_script_seq = current_sctx.sc_seq;
      }
  
  # ifdef FEAT_PROFILE
--- 1463,1468 ----
***************
*** 2031,2036 ****
--- 2117,2194 ----
  }
  
  /*
+  * Find the path of a script below the "autoload" directory.
+  * Returns NULL if there is no "/autoload/" in the script name.
+  */
+     char_u *
+ script_name_after_autoload(scriptitem_T *si)
+ {
+     char_u    *p = si->sn_name;
+     char_u    *res = NULL;
+ 
+     for (;;)
+     {
+       char_u *n = (char_u *)strstr((char *)p, "autoload");
+ 
+       if (n == NULL)
+           break;
+       if (n > p && vim_ispathsep(n[-1]) && vim_ispathsep(n[8]))
+           res = n + 9;
+       p = n + 8;
+     }
+     return res;
+ }
+ 
+ /*
+  * If in a Vim9 autoload script return "name" with the autoload prefix for the
+  * script.  If successful "name" is freed, the returned name is allocated.
+  * Otherwise it returns "name" unmodified.
+  */
+     char_u *
+ may_prefix_autoload(char_u *name)
+ {
+     if (SCRIPT_ID_VALID(current_sctx.sc_sid))
+     {
+       scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
+ 
+       if (si->sn_is_autoload)
+       {
+           char_u *p = script_name_after_autoload(si);
+ 
+           if (p != NULL)
+           {
+               char_u *tail = vim_strsave(p);
+ 
+               if (tail != NULL)
+               {
+                   for (p = tail; *p != NUL; p += mb_ptr2len(p))
+                   {
+                       if (vim_ispathsep(*p))
+                           *p = '#';
+                       else if (STRCMP(p, ".vim"))
+                       {
+                           size_t  len = (p - tail) + STRLEN(name) + 2;
+                           char_u  *res = alloc(len);
+ 
+                           if (res == NULL)
+                               break;
+                           *p = NUL;
+                           vim_snprintf((char *)res, len, "%s#%s", tail, name);
+                           vim_free(name);
+                           vim_free(tail);
+                           return res;
+                       }
+                   }
+               }
+               // did not find ".vim" at the end
+               vim_free(tail);
+           }
+       }
+     }
+     return name;
+ }
+ 
+ /*
   * 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.
*** ../vim-8.2.4049/src/proto/scriptfile.pro    2020-09-10 18:25:01.612194701 
+0100
--- src/proto/scriptfile.pro    2022-01-09 19:05:13.911795307 +0000
***************
*** 10,15 ****
--- 10,16 ----
  int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u 
*fname, void *ck), void *cookie);
  int source_runtime(char_u *name, int flags);
  int source_in_path(char_u *path, char_u *name, int flags, int *ret_sid);
+ int find_script_in_rtp(char_u *name);
  void add_pack_start_dirs(void);
  void load_start_packages(void);
  void ex_packloadall(exarg_T *eap);
***************
*** 36,41 ****
--- 37,44 ----
  void ex_finish(exarg_T *eap);
  void do_finish(exarg_T *eap, int reanimate);
  int source_finished(char_u *(*fgetline)(int, void *, int, getline_opt_T), 
void *cookie);
+ char_u *script_name_after_autoload(scriptitem_T *si);
+ char_u *may_prefix_autoload(char_u *name);
  char_u *autoload_name(char_u *name);
  int script_autoload(char_u *name, int reload);
  /* vim: set ft=c : */
*** ../vim-8.2.4049/src/userfunc.c      2022-01-08 16:19:18.509639849 +0000
--- src/userfunc.c      2022-01-09 20:40:16.825423767 +0000
***************
*** 1608,1614 ****
            p = name + 2;
            len -= 2;
        }
!       import = find_imported(p, len, NULL);
  
        // imported function from another script
        if (import != NULL)
--- 1608,1614 ----
            p = name + 2;
            len -= 2;
        }
!       import = find_imported(p, len, FALSE, NULL);
  
        // imported function from another script
        if (import != NULL)
***************
*** 4079,4084 ****
--- 4079,4087 ----
            else
                eap->skip = TRUE;
        }
+ 
+ //    if (is_export)
+ //        name = may_prefix_autoload(name);
      }
  
      // An error in a function call during evaluation of an expression in magic
***************
*** 4363,4369 ****
        {
            char_u *uname = untrans_function_name(name);
  
!           import = find_imported(uname == NULL ? name : uname, 0, NULL);
        }
  
        if (fp != NULL || import != NULL)
--- 4366,4372 ----
        {
            char_u *uname = untrans_function_name(name);
  
!           import = find_imported(uname == NULL ? name : uname, 0, FALSE, 
NULL);
        }
  
        if (fp != NULL || import != NULL)
*** ../vim-8.2.4049/src/eval.c  2022-01-08 16:19:18.501639918 +0000
--- src/eval.c  2022-01-09 19:51:02.672126801 +0000
***************
*** 886,892 ****
  
      if (*p == '.' && in_vim9script())
      {
!       imported_T *import = find_imported(lp->ll_name, p - lp->ll_name, NULL);
        if (import != NULL)
        {
            ufunc_T *ufunc;
--- 886,894 ----
  
      if (*p == '.' && in_vim9script())
      {
!       imported_T *import = find_imported(lp->ll_name, p - lp->ll_name,
!                                                                  TRUE, NULL);
! 
        if (import != NULL)
        {
            ufunc_T *ufunc;
*** ../vim-8.2.4049/src/evalvars.c      2022-01-08 16:19:18.501639918 +0000
--- src/evalvars.c      2022-01-09 19:52:11.080080967 +0000
***************
*** 2683,2689 ****
        char_u      *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
  
        if (sid == 0)
!           import = find_imported(p, 0, NULL);
  
        // imported variable from another script
        if (import != NULL || sid != 0)
--- 2683,2689 ----
        char_u      *p = STRNCMP(name, "s:", 2) == 0 ? name + 2 : name;
  
        if (sid == 0)
!           import = find_imported(p, 0, TRUE, NULL);
  
        // imported variable from another script
        if (import != NULL || sid != 0)
***************
*** 3015,3021 ****
      res = HASHITEM_EMPTY(hi) ? FAIL : OK;
  
      // if not script-local, then perhaps imported
!     if (res == FAIL && find_imported(p, 0, NULL) != NULL)
        res = OK;
      if (p != buffer)
        vim_free(p);
--- 3015,3021 ----
      res = HASHITEM_EMPTY(hi) ? FAIL : OK;
  
      // if not script-local, then perhaps imported
!     if (res == FAIL && find_imported(p, 0, FALSE, NULL) != NULL)
        res = OK;
      if (p != buffer)
        vim_free(p);
***************
*** 3388,3394 ****
  
      if (di == NULL && var_in_vim9script)
      {
!       imported_T  *import = find_imported(varname, 0, NULL);
  
        if (import != NULL)
        {
--- 3388,3394 ----
  
      if (di == NULL && var_in_vim9script)
      {
!       imported_T  *import = find_imported(varname, 0, FALSE, NULL);
  
        if (import != NULL)
        {
*** ../vim-8.2.4049/src/vim9compile.c   2022-01-08 18:43:36.877446896 +0000
--- src/vim9compile.c   2022-01-09 20:31:53.506442778 +0000
***************
*** 268,274 ****
                && (lookup_local(name, len, NULL, cctx) == OK
                    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
            || script_var_exists(name, len, cctx) == OK
!           || find_imported(name, len, cctx) != NULL;
  }
  
  /*
--- 268,274 ----
                && (lookup_local(name, len, NULL, cctx) == OK
                    || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK))
            || script_var_exists(name, len, cctx) == OK
!           || find_imported(name, len, FALSE, cctx) != NULL;
  }
  
  /*
***************
*** 331,337 ****
      if ((cctx != NULL
                && (lookup_local(p, len, NULL, cctx) == OK
                    || arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
!           || find_imported(p, len, cctx) != NULL
            || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
      {
        // A local or script-local function can shadow a global function.
--- 331,337 ----
      if ((cctx != NULL
                && (lookup_local(p, len, NULL, cctx) == OK
                    || arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
!           || find_imported(p, len, FALSE, cctx) != NULL
            || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
      {
        // A local or script-local function can shadow a global function.
***************
*** 581,591 ****
  /*
   * Find "name" in imported items of the current script or in "cctx" if not
   * NULL.
   */
      imported_T *
! find_imported(char_u *name, size_t len, cctx_T *cctx)
  {
      int                   idx;
  
      if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
        return NULL;
--- 581,593 ----
  /*
   * Find "name" in imported items of the current script or in "cctx" if not
   * NULL.
+  * If "load" is TRUE and the script was not loaded yet, load it now.
   */
      imported_T *
! find_imported(char_u *name, size_t len, int load, cctx_T *cctx)
  {
      int                   idx;
+     imported_T            *ret = NULL;
  
      if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
        return NULL;
***************
*** 598,607 ****
            if (len == 0 ? STRCMP(name, import->imp_name) == 0
                         : STRLEN(import->imp_name) == len
                                  && STRNCMP(name, import->imp_name, len) == 0)
!               return import;
        }
  
!     return find_imported_in_script(name, len, current_sctx.sc_sid);
  }
  
  /*
--- 600,622 ----
            if (len == 0 ? STRCMP(name, import->imp_name) == 0
                         : STRLEN(import->imp_name) == len
                                  && STRNCMP(name, import->imp_name, len) == 0)
!           {
!               ret = import;
!               break;
!           }
        }
  
!     if (ret == NULL)
!       ret = find_imported_in_script(name, len, current_sctx.sc_sid);
! 
!     if (ret != NULL && load && ret->imp_flags == IMP_FLAGS_AUTOLOAD)
!     {
!       // script found before but not loaded yet
!       ret->imp_flags = 0;
!       (void)do_source(SCRIPT_ITEM(ret->imp_sid)->sn_name, FALSE,
!                                                             DOSO_NONE, NULL);
!     }
!     return ret;
  }
  
  /*
***************
*** 1326,1332 ****
                          : script_var_exists(var_start, lhs->lhs_varlen,
                                                                  cctx)) == OK;
                imported_T  *import =
!                              find_imported(var_start, lhs->lhs_varlen, cctx);
  
                if (script_namespace || script_var || import != NULL)
                {
--- 1341,1347 ----
                          : script_var_exists(var_start, lhs->lhs_varlen,
                                                                  cctx)) == OK;
                imported_T  *import =
!                       find_imported(var_start, lhs->lhs_varlen, FALSE, cctx);
  
                if (script_namespace || script_var || import != NULL)
                {
*** ../vim-8.2.4049/src/proto/vim9compile.pro   2022-01-08 18:43:36.877446896 
+0000
--- src/proto/vim9compile.pro   2022-01-09 19:50:12.916155722 +0000
***************
*** 7,13 ****
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
  lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, 
type_T *type);
  int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T 
*cctx);
! imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx);
  char_u *may_peek_next_line(cctx_T *cctx, char_u *arg, char_u **nextp);
  char_u *peek_next_line_from_context(cctx_T *cctx);
  char_u *next_line_from_context(cctx_T *cctx, int skip_comment);
--- 7,13 ----
  int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, 
cctx_T *cctx, int silent, int actual_is_const);
  lvar_T *reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, 
type_T *type);
  int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T 
*cctx);
! imported_T *find_imported(char_u *name, size_t len, int load, cctx_T *cctx);
  char_u *may_peek_next_line(cctx_T *cctx, char_u *arg, char_u **nextp);
  char_u *peek_next_line_from_context(cctx_T *cctx);
  char_u *next_line_from_context(cctx_T *cctx, int skip_comment);
*** ../vim-8.2.4049/src/vim9expr.c      2022-01-09 13:36:20.351866599 +0000
--- src/vim9expr.c      2022-01-09 19:56:21.231865382 +0000
***************
*** 266,272 ****
        return OK;
      }
  
!     import = end == NULL ? NULL : find_imported(name, 0, cctx);
      if (import != NULL)
      {
        char_u  *p = skipwhite(*end);
--- 266,272 ----
        return OK;
      }
  
!     import = end == NULL ? NULL : find_imported(name, 0, FALSE, cctx);
      if (import != NULL)
      {
        char_u  *p = skipwhite(*end);
***************
*** 275,280 ****
--- 275,281 ----
        ufunc_T *ufunc;
        type_T  *type;
  
+       // TODO: if this is an autoload import do something else.
        // Need to lookup the member.
        if (*p != '.')
        {
***************
*** 474,480 ****
                // "var" can be script-local even without using "s:" if it
                // already exists in a Vim9 script or when it's imported.
                if (script_var_exists(*arg, len, cctx) == OK
!                       || find_imported(name, 0, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
                // When evaluating an expression and the name starts with an
--- 475,481 ----
                // "var" can be script-local even without using "s:" if it
                // already exists in a Vim9 script or when it's imported.
                if (script_var_exists(*arg, len, cctx) == OK
!                       || find_imported(name, 0, FALSE, cctx) != NULL)
                   res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
  
                // When evaluating an expression and the name starts with an
*** ../vim-8.2.4049/src/testdir/test_vim9_script.vim    2022-01-07 
21:38:43.171435890 +0000
--- src/testdir/test_vim9_script.vim    2022-01-09 20:43:06.881446211 +0000
***************
*** 3032,3037 ****
--- 3032,3057 ----
    writefile(lines, 'Xdir/autoload/Other.vim')
    assert_equal('other', g:Other#getOther())
  
+   # using "vim9script autoload" prefix is not needed
+   lines =<< trim END
+      vim9script autoload
+      g:prefixed_loaded = 'yes'
+      export def Gettest(): string
+        return 'test'
+      enddef
+      export var name = 'name'
+   END
+   writefile(lines, 'Xdir/autoload/prefixed.vim')
+ 
+   lines =<< trim END
+       vim9script
+       import autoload 'prefixed.vim'
+       assert_false(exists('g:prefixed_loaded'))
+       assert_equal('test', prefixed.Gettest())
+       assert_equal('yes', g:prefixed_loaded)
+   END
+   CheckScriptSuccess(lines)
+ 
    delete('Xdir', 'rf')
    &rtp = save_rtp
  enddef
*** ../vim-8.2.4049/src/version.c       2022-01-09 13:36:20.351866599 +0000
--- src/version.c       2022-01-09 21:29:00.618164671 +0000
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     4050,
  /**/

-- 
ARTHUR: This new learning amazes me, Sir Bedevere.  Explain again how sheep's
        bladders may be employed to prevent earthquakes.
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            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/20220109213729.2D6811C042A%40moolenaar.net.

Raspunde prin e-mail lui