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 -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///