Patch 8.2.4650
Problem: "import autoload" only works with using 'runtimepath'.
Solution: Also support a relative and absolute file name.
Files: runtime/doc/vim9.txt, src/structs.h, src/scriptfile.c,
src/proto/
scriptfile.pro, src/vim9script.c, src/vim9expr.c,
src/vim9.h, src/vim9execute.c, src/vim9instr.c,
src/proto/
vim9instr.pro, src/vim.h, src/userfunc.c,
src/proto/
userfunc.pro, src/testdir/test_vim9_import.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.4649/runtime/doc/vim9.txt 2022-03-08 13:18:10.805020790 +0000
--- runtime/doc/vim9.txt 2022-03-30 19:57:51.472168649 +0100
***************
*** 1529,1545 ****
echo that
.name # Error!
< *:import-cycle*
! The `import` commands are executed when encountered. If that script (directly
! or indirectly) imports the current script, then items defined after the
! `import` won't be processed yet. Therefore cyclic imports can exist, but may
! result in undefined items.
Importing 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'
--- 1721,1739 ----
echo that
.name # Error!
< *:import-cycle*
! The `import` commands are executed when encountered. If script A imports
! script B, and B (directly or indirectly) imports A, this will be skipped over.
! At this point items in A after "import B" will not have been processed and
! defined yet. Therefore cyclic imports can exist and not result in an error
! directly, but may result in an error for items in A after "import B" not being
! defined. This does not apply to autoload imports, see the next section.
Importing 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:
! *E1264*
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'
***************
*** 1551,1557 ****
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
--- 1745,1752 ----
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. Alternatively a relative or absolute name can be used, see
! below.
2. In the autoload script put the bulk of the code. >
vim9script
***************
*** 1565,1575 ****
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
! use 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.
For defining a mapping that uses the imported autoload script the special key
|<ScriptCmd>| is useful. It allows for a command in a mapping to use the
script context of where the mapping was defined.
--- 1760,1779 ----
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
! use the prefix (which has the side effect of loading the autoload script
! when compiling a function that encounters this name).
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.
+ Searching for the autoload script in all entries in 'runtimepath' can be a bit
+ slow. If the plugin knows where the script is located, quite often a relative
+ path can be used. This avoids the search and should be quite a bit faster.
+ Another advantage is that the script name does not need to be unique. An
+ absolute path is also possible. Examples: >
+ import autoload '../lib/implement.vim'
+ import autoload MyScriptsDir .. '/lib/implement.vim'
+
For defining a mapping that uses the imported autoload script the special key
|<ScriptCmd>| is useful. It allows for a command in a mapping to use the
script context of where the mapping was defined.
***************
*** 1577,1583 ****
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.
For testing the |test_override()| function can be used to have the
`import autoload` load the script right away, so that the items and types can
--- 1781,1797 ----
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. If you would use the name with '#' characters
! then the autoload script IS loaded.
!
! Be careful to not refer to an item in an autoload script that does trigger
! loading it unintentionally. For example, when setting an option that takes a
! function name, make sure to use a string, not a function reference: >
! import autoload 'qftf.vim'
! &quickfixtextfunc = 'qftf.Func' # autoload script NOT loaded
! &quickfixtextfunc = qftf.Func # autoload script IS loaded
! On the other hand, it can be useful to load the script early, at a time when
! any errors should be given.
For testing the |test_override()| function can be used to have the
`import autoload` load the script right away, so that the items and types can
*** ../vim-8.2.4649/src/structs.h 2022-03-30 10:14:41.485657271 +0100
--- src/structs.h 2022-03-30 14:21:51.012324633 +0100
***************
*** 1833,1839 ****
*/
typedef struct
{
! char_u *sn_name;
int sn_script_seq; // latest sctx_T sc_seq value
// "sn_vars" stores the s: variables currently valid. When leaving a block
--- 1833,1839 ----
*/
typedef struct
{
! char_u *sn_name; // full path of script file
int sn_script_seq; // latest sctx_T sc_seq value
// "sn_vars" stores the s: variables currently valid. When leaving a block
***************
*** 1864,1872 ****
char_u *sn_save_cpo; // 'cpo' value when :vim9script found
char sn_is_vimrc; // .vimrc file, do not restore 'cpo'
! // for "vim9script autoload" this is "dir#scriptname#"
char_u *sn_autoload_prefix;
# ifdef FEAT_PROFILE
int sn_prof_on; // TRUE when script is/was profiled
int sn_pr_force; // forceit: profile functions in this script
--- 1864,1875 ----
char_u *sn_save_cpo; // 'cpo' value when :vim9script found
char sn_is_vimrc; // .vimrc file, do not restore 'cpo'
! // for a Vim9 script under "rtp/autoload/" this is "dir#scriptname#"
char_u *sn_autoload_prefix;
+ // TRUE for a script used with "import autoload './dirname/script.vim'"
+ int sn_import_autoload;
+
# ifdef FEAT_PROFILE
int sn_prof_on; // TRUE when script is/was profiled
int sn_pr_force; // forceit: profile functions in this script
*** ../vim-8.2.4649/src/scriptfile.c 2022-03-29 19:52:08.787653549 +0100
--- src/scriptfile.c 2022-03-30 14:55:27.953493854 +0100
***************
*** 251,257 ****
* 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;
--- 251,257 ----
* Find an already loaded script "name".
* If found returns its script ID. If not found returns -1.
*/
! int
find_script_by_name(char_u *name)
{
int sid;
***************
*** 320,325 ****
--- 320,340 ----
return sid;
}
+ int
+ get_new_scriptitem_for_fname(int *error, char_u *fname)
+ {
+ int 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;
+ }
+ return sid;
+ }
+
static void
find_script_callback(char_u *fname, void *cookie)
{
***************
*** 329,345 ****
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
--- 344,351 ----
sid = find_script_by_name(fname);
if (sid < 0)
// script does not exist yet, create a new scriptitem
! sid = get_new_scriptitem_for_fname(&error, fname);
*ret_sid = sid;
}
#endif
*** ../vim-8.2.4649/src/proto/
scriptfile.pro 2022-03-21 19:45:13.200420997 +0000
--- src/proto/
scriptfile.pro 2022-03-30 14:55:31.673487843 +0100
***************
*** 6,11 ****
--- 6,13 ----
estack_T *estack_pop(void);
char_u *estack_sfile(estack_arg_T which);
void ex_runtime(exarg_T *eap);
+ int find_script_by_name(char_u *name);
+ int get_new_scriptitem_for_fname(int *error, char_u *fname);
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
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);
*** ../vim-8.2.4649/src/vim9script.c 2022-03-28 15:22:31.490443719 +0100
--- src/vim9script.c 2022-03-30 15:02:11.104833760 +0100
***************
*** 384,389 ****
--- 384,421 ----
}
/*
+ * Part of "import" that handles a relative or absolute file name/
+ * Returns OK or FAIL.
+ */
+ static int
+ handle_import_fname(char_u *fname, int is_autoload, int *sid)
+ {
+ if (is_autoload)
+ {
+ scriptitem_T *si;
+
+ *sid = find_script_by_name(fname);
+ if (*sid < 0)
+ {
+ int error = OK;
+
+ // script does not exist yet, create a new scriptitem
+ *sid = get_new_scriptitem_for_fname(&error, fname);
+ if (error == FAIL)
+ return FAIL;
+ }
+
+ si = SCRIPT_ITEM(*sid);
+ si->sn_import_autoload = TRUE;
+
+ // with testing override: load autoload script right away
+ if (!override_autoload || si->sn_state != SN_STATE_NOT_LOADED)
+ return OK;
+ }
+ return do_source(fname, FALSE, DOSO_NONE, sid);
+ }
+
+ /*
* Handle an ":import" command and add the resulting imported_T to "gap", when
* not NULL, or script "import_sid" sn_imports.
* "cctx" is NULL at the script level.
***************
*** 442,466 ****
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)
#ifdef BACKSLASH_IN_FILENAME
--- 474,491 ----
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 = handle_import_fname(from_name, is_autoload, &sid);
! vim_free(from_name);
}
else if (mch_isFullName(tv.vval.v_string)
#ifdef BACKSLASH_IN_FILENAME
***************
*** 471,480 ****
)
{
// 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)
{
--- 496,502 ----
)
{
// Absolute path: "/tmp/name.vim"
! res = handle_import_fname(tv.vval.v_string, is_autoload, &sid);
}
else if (is_autoload)
{
***************
*** 677,682 ****
--- 699,710 ----
svar_T *sv;
scriptitem_T *script = SCRIPT_ITEM(sid);
+ if (script->sn_import_autoload && script->sn_state == SN_STATE_NOT_LOADED)
+ {
+ if (do_source(script->sn_name, FALSE, DOSO_NONE, NULL) == FAIL)
+ return -1;
+ }
+
// Find name in "script".
idx = get_script_item_idx(sid, name, 0, cctx, cstack);
if (idx >= 0)
*** ../vim-8.2.4649/src/vim9expr.c 2022-03-27 16:29:49.880153368 +0100
--- src/vim9expr.c 2022-03-30 16:49:42.100316230 +0100
***************
*** 313,318 ****
--- 313,339 ----
vim_free(auto_name);
done = TRUE;
}
+ else if (si->sn_import_autoload && si->sn_state == SN_STATE_NOT_LOADED)
+ {
+ // "import autoload './dir/script.vim'" - load script first
+ res = generate_SOURCE(cctx, import->imp_sid);
+ if (res == OK)
+ {
+ // If a '(' follows it must be a function. Otherwise we don't
+ // know, it can be "script.Func".
+ if (cc == '(' || paren_follows_after_expr)
+ {
+ char_u sid_name[MAX_FUNC_NAME_LEN];
+
+ func_name_with_sid(exp_name, import->imp_sid, sid_name);
+ res = generate_PUSHFUNC(cctx, sid_name, &t_func_any);
+ }
+ else
+ res = generate_OLDSCRIPT(cctx, ISN_LOADEXPORT, exp_name,
+ import->imp_sid, &t_any);
+ }
+ done = TRUE;
+ }
else
{
idx = find_exported(import->imp_sid, exp_name, &ufunc, &type,
*** ../vim-8.2.4649/src/vim9.h 2022-03-27 20:04:16.029188564 +0100
--- src/vim9.h 2022-03-30 17:10:56.817448503 +0100
***************
*** 28,33 ****
--- 28,35 ----
ISN_ECHOERR, // :echoerr with isn_arg.number items on top of stack
ISN_RANGE, // compute range from isn_arg.string, push to stack
ISN_SUBSTITUTE, // :s command with expression
+
+ ISN_SOURCE, // source autoload script, isn_arg.number is the script ID
ISN_INSTR, // instructions compiled from expression
// get and set variables
***************
*** 43,48 ****
--- 45,51 ----
ISN_LOADWDICT, // push w: dict
ISN_LOADTDICT, // push t: dict
ISN_LOADS, // push s: variable isn_arg.loadstore
+ ISN_LOADEXPORT, // push exported variable isn_arg.loadstore
ISN_LOADOUTER, // push variable from outer scope isn_arg.outer
ISN_LOADSCRIPT, // push script-local variable isn_arg.script.
ISN_LOADOPT, // push option isn_arg.string
***************
*** 57,62 ****
--- 60,66 ----
ISN_STOREW, // pop into window-local variable isn_arg.string
ISN_STORET, // pop into tab-local variable isn_arg.string
ISN_STORES, // pop into script variable isn_arg.loadstore
+ ISN_STOREEXPORT, // pop into exported script variable isn_arg.loadstore
ISN_STOREOUTER, // pop variable into outer scope isn_arg.outer
ISN_STORESCRIPT, // pop into script variable isn_arg.script
ISN_STOREOPT, // pop into option isn_arg.storeopt
*** ../vim-8.2.4649/src/vim9execute.c 2022-03-28 18:16:43.619673423 +0100
--- src/vim9execute.c 2022-03-30 20:27:54.479338636 +0100
***************
*** 1510,1515 ****
--- 1510,1522 ----
emsg(_(e_script_variable_type_changed));
return NULL;
}
+
+ if (!sv->sv_export && sref->sref_sid != current_sctx.sc_sid)
+ {
+ if (dfunc != NULL)
+ semsg(_(e_item_not_exported_in_script_str), sv->sv_name);
+ return NULL;
+ }
return sv;
}
***************
*** 2623,2628 ****
--- 2630,2649 ----
}
break;
+ case ISN_SOURCE:
+ {
+ scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.number);
+
+ if (si->sn_state == SN_STATE_NOT_LOADED)
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ if (do_source(si->sn_name, FALSE, DOSO_NONE, NULL)
+ == FAIL)
+ goto on_error;
+ }
+ }
+ break;
+
// execute :substitute with an expression
case ISN_SUBSTITUTE:
{
***************
*** 2902,2912 ****
}
break;
! // load s: variable in old script
case ISN_LOADS:
{
! hashtab_T *ht = &SCRIPT_VARS(
! iptr->isn_arg.loadstore.ls_sid);
char_u *name = iptr->isn_arg.loadstore.ls_name;
dictitem_T *di = find_var_in_ht(ht, 0, name, TRUE);
--- 2923,2934 ----
}
break;
! // load s: variable in old script or autoload import
case ISN_LOADS:
+ case ISN_LOADEXPORT:
{
! int sid = iptr->isn_arg.loadstore.ls_sid;
! hashtab_T *ht = &SCRIPT_VARS(sid);
char_u *name = iptr->isn_arg.loadstore.ls_name;
dictitem_T *di = find_var_in_ht(ht, 0, name, TRUE);
***************
*** 2918,2923 ****
--- 2940,2964 ----
}
else
{
+ if (iptr->isn_type == ISN_LOADEXPORT)
+ {
+ int idx = get_script_item_idx(sid, name, 0,
+ NULL, NULL);
+ svar_T *sv;
+
+ if (idx >= 0)
+ {
+ sv = ((svar_T *)SCRIPT_ITEM(sid)
+ ->sn_var_vals.ga_data) + idx;
+ if (!sv->sv_export)
+ {
+ SOURCING_LNUM = iptr->isn_lnum;
+ semsg(_(e_item_not_exported_in_script_str),
+ name);
+ goto on_error;
+ }
+ }
+ }
if (GA_GROW_FAILS(&ectx->ec_stack, 1))
goto theend;
copy_tv(&di->di_tv, STACK_TV_BOT(0));
***************
*** 3039,3058 ****
*tv = *STACK_TV_BOT(0);
break;
! // store s: variable in old script
case ISN_STORES:
{
! hashtab_T *ht = &SCRIPT_VARS(
! iptr->isn_arg.loadstore.ls_sid);
char_u *name = iptr->isn_arg.loadstore.ls_name;
! dictitem_T *di = find_var_in_ht(ht, 0, name + 2, TRUE);
--ectx->ec_stack.ga_len;
if (di == NULL)
store_var(name, STACK_TV_BOT(0));
else
{
! SOURCING_LNUM = iptr->isn_lnum;
if (var_check_permission(di, name) == FAIL)
{
clear_tv(STACK_TV_BOT(0));
--- 3080,3127 ----
*tv = *STACK_TV_BOT(0);
break;
! // store s: variable in old script or autoload import
case ISN_STORES:
+ case ISN_STOREEXPORT:
{
! int sid = iptr->isn_arg.loadstore.ls_sid;
! hashtab_T *ht = &SCRIPT_VARS(sid);
char_u *name = iptr->isn_arg.loadstore.ls_name;
! dictitem_T *di = find_var_in_ht(ht, 0,
! iptr->isn_type == ISN_STORES
! ? name + 2 : name, TRUE);
--ectx->ec_stack.ga_len;
+ SOURCING_LNUM = iptr->isn_lnum;
if (di == NULL)
+ {
+ if (iptr->isn_type == ISN_STOREEXPORT)
+ {
+ semsg(_(e_undefined_variable_str), name);
+ goto on_error;
+ }
store_var(name, STACK_TV_BOT(0));
+ }
else
{
! if (iptr->isn_type == ISN_STOREEXPORT)
! {
! int idx = get_script_item_idx(sid, name, 0,
! NULL, NULL);
!
! if (idx >= 0)
! {
! svar_T *sv = ((svar_T *)SCRIPT_ITEM(sid)
! ->sn_var_vals.ga_data) + idx;
!
! if (!sv->sv_export)
! {
! semsg(_(e_item_not_exported_in_script_str),
! name);
! goto on_error;
! }
! }
! }
if (var_check_permission(di, name) == FAIL)
{
clear_tv(STACK_TV_BOT(0));
***************
*** 5409,5419 ****
#endif
break;
case ISN_INSTR:
{
! smsg("%s%4d INSTR", pfx, current);
! list_instructions(" ", iptr->isn_arg.instr,
! INT_MAX, NULL);
! msg(" -------------");
}
break;
case ISN_SUBSTITUTE:
--- 5478,5492 ----
#endif
break;
case ISN_INSTR:
+ smsg("%s%4d INSTR", pfx, current);
+ list_instructions(" ", iptr->isn_arg.instr, INT_MAX, NULL);
+ msg(" -------------");
+ break;
+ case ISN_SOURCE:
{
! scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.number);
!
! smsg("%s%4d SOURCE %s", pfx, current, si->sn_name);
}
break;
case ISN_SUBSTITUTE:
***************
*** 5500,5511 ****
}
break;
case ISN_LOADS:
{
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
! smsg("%s%4d LOADS s:%s from %s", pfx, current,
! iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
case ISN_LOADAUTO:
--- 5573,5587 ----
}
break;
case ISN_LOADS:
+ case ISN_LOADEXPORT:
{
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
! smsg("%s%4d %s s:%s from %s", pfx, current,
! iptr->isn_type == ISN_LOADS ? "LOADS"
! : "LOADEXPORT",
! iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
case ISN_LOADAUTO:
***************
*** 5586,5596 ****
smsg("%s%4d STORET %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STORES:
{
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
! smsg("%s%4d STORES %s in %s", pfx, current,
iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
--- 5662,5675 ----
smsg("%s%4d STORET %s", pfx, current, iptr->isn_arg.string);
break;
case ISN_STORES:
+ case ISN_STOREEXPORT:
{
scriptitem_T *si = SCRIPT_ITEM(
iptr->isn_arg.loadstore.ls_sid);
! smsg("%s%4d %s %s in %s", pfx, current,
! iptr->isn_type == ISN_STORES
! ? "STORES" : "STOREEXPORT",
iptr->isn_arg.loadstore.ls_name, si->sn_name);
}
break;
*** ../vim-8.2.4649/src/vim9instr.c 2022-03-27 16:29:49.876153380 +0100
--- src/vim9instr.c 2022-03-30 20:40:15.387219798 +0100
***************
*** 1066,1072 ****
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
! if (isn_type == ISN_LOADS)
isn = generate_instr_type(cctx, isn_type, type);
else
isn = generate_instr_drop(cctx, isn_type, 1);
--- 1066,1072 ----
isn_T *isn;
RETURN_OK_IF_SKIP(cctx);
! if (isn_type == ISN_LOADS || isn_type == ISN_LOADEXPORT)
isn = generate_instr_type(cctx, isn_type, type);
else
isn = generate_instr_drop(cctx, isn_type, 1);
***************
*** 1728,1733 ****
--- 1728,1748 ----
}
/*
+ * Generate an ISN_SOURCE instruction.
+ */
+ int
+ generate_SOURCE(cctx_T *cctx, int sid)
+ {
+ isn_T *isn;
+
+ if ((isn = generate_instr(cctx, ISN_SOURCE)) == NULL)
+ return FAIL;
+ isn->isn_arg.number = sid;
+
+ return OK;
+ }
+
+ /*
* Generate an ISN_PUT instruction.
*/
int
***************
*** 1913,1921 ****
return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
case dest_script:
if (scriptvar_idx < 0)
// "s:" may be included in the name.
! return generate_OLDSCRIPT(cctx, ISN_STORES, name,
! scriptvar_sid, type);
return generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
scriptvar_sid, scriptvar_idx, type);
case dest_local:
--- 1928,1949 ----
return generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL);
case dest_script:
if (scriptvar_idx < 0)
+ {
+ isntype_T isn_type = ISN_STORES;
+
+ if (SCRIPT_ID_VALID(scriptvar_sid)
+ && SCRIPT_ITEM(scriptvar_sid)->sn_import_autoload)
+ {
+ // "import autoload './dir/script.vim'" - load script first
+ if (generate_SOURCE(cctx, scriptvar_sid) == FAIL)
+ return FAIL;
+ isn_type = ISN_STOREEXPORT;
+ }
+
// "s:" may be included in the name.
! return generate_OLDSCRIPT(cctx, isn_type, name,
! scriptvar_sid, type);
! }
return generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT,
scriptvar_sid, scriptvar_idx, type);
case dest_local:
***************
*** 2062,2068 ****
--- 2090,2098 ----
break;
case ISN_LOADS:
+ case ISN_LOADEXPORT:
case ISN_STORES:
+ case ISN_STOREEXPORT:
vim_free(isn->isn_arg.loadstore.ls_name);
break;
***************
*** 2089,2095 ****
if (isn->isn_arg.funcref.fr_func_name == NULL)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.funcref.fr_dfunc_idx;
ufunc_T *ufunc = dfunc->df_ufunc;
if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
--- 2119,2125 ----
if (isn->isn_arg.funcref.fr_func_name == NULL)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.funcref.fr_dfunc_idx;
ufunc_T *ufunc = dfunc->df_ufunc;
if (ufunc != NULL && func_name_refcount(ufunc->uf_name))
***************
*** 2109,2118 ****
case ISN_DCALL:
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.dfunc.cdf_idx;
if (dfunc->df_ufunc != NULL
! && func_name_refcount(dfunc->df_ufunc->uf_name))
func_ptr_unref(dfunc->df_ufunc);
}
break;
--- 2139,2148 ----
case ISN_DCALL:
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
! + isn->isn_arg.dfunc.cdf_idx;
if (dfunc->df_ufunc != NULL
! && func_name_refcount(dfunc->df_ufunc->uf_name))
func_ptr_unref(dfunc->df_ufunc);
}
break;
***************
*** 2140,2146 ****
case ISN_CMDMOD:
vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
! ->cmod_filter_regmatch.regprog);
vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
break;
--- 2170,2176 ----
case ISN_CMDMOD:
vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod
! ->cmod_filter_regmatch.regprog);
vim_free(isn->isn_arg.cmdmod.cf_cmdmod);
break;
***************
*** 2243,2263 ****
case ISN_STORE:
case ISN_STOREINDEX:
case ISN_STORENR:
! case ISN_STOREOUTER:
! case ISN_STORERANGE:
! case ISN_STOREREG:
! case ISN_STOREV:
! case ISN_STRINDEX:
! case ISN_STRSLICE:
! case ISN_THROW:
! case ISN_TRYCONT:
! case ISN_UNLETINDEX:
! case ISN_UNLETRANGE:
! case ISN_UNPACK:
! case ISN_USEDICT:
! // nothing allocated
! break;
! }
}
void
--- 2273,2294 ----
case ISN_STORE:
case ISN_STOREINDEX:
case ISN_STORENR:
! case ISN_SOURCE:
! case ISN_STOREOUTER:
! case ISN_STORERANGE:
! case ISN_STOREREG:
! case ISN_STOREV:
! case ISN_STRINDEX:
! case ISN_STRSLICE:
! case ISN_THROW:
! case ISN_TRYCONT:
! case ISN_UNLETINDEX:
! case ISN_UNLETRANGE:
! case ISN_UNPACK:
! case ISN_USEDICT:
! // nothing allocated
! break;
! }
}
void
*** ../vim-8.2.4649/src/proto/
vim9instr.pro 2022-03-27 16:29:49.876153380 +0100
--- src/proto/
vim9instr.pro 2022-03-30 15:26:07.158733162 +0100
***************
*** 54,59 ****
--- 54,60 ----
int generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len);
int generate_ECHO(cctx_T *cctx, int with_white, int count);
int generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count);
+ int generate_SOURCE(cctx_T *cctx, int sid);
int generate_PUT(cctx_T *cctx, int regname, linenr_T lnum);
int generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line);
int generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str);
*** ../vim-8.2.4649/src/vim.h 2022-03-28 15:22:31.490443719 +0100
--- src/vim.h 2022-03-30 15:36:18.057768667 +0100
***************
*** 1571,1576 ****
--- 1571,1579 ----
*/
#define MAXMAPLEN 50
+ // maximum length of a function name, including SID and NUL
+ #define MAX_FUNC_NAME_LEN 200
+
// Size in bytes of the hash used in the undo file.
#define UNDO_HASH_SIZE 32
*** ../vim-8.2.4649/src/userfunc.c 2022-03-17 16:30:00.174908142 +0000
--- src/userfunc.c 2022-03-30 15:58:23.858836587 +0100
***************
*** 1884,1906 ****
}
/*
* Find a function "name" in script "sid".
*/
static ufunc_T *
find_func_with_sid(char_u *name, int sid)
{
hashitem_T *hi;
! char_u buffer[200];
if (!SCRIPT_ID_VALID(sid))
return NULL; // not in a script
! // A script-local function is stored as "<SNR>99_name".
! buffer[0] = K_SPECIAL;
! buffer[1] = KS_EXTRA;
! buffer[2] = (int)KE_SNR;
! vim_snprintf((char *)buffer + 3, sizeof(buffer) - 3, "%ld_%s",
! (long)sid, name);
hi = hash_find(&func_hashtab, buffer);
if (!HASHITEM_EMPTY(hi))
return HI2UF(hi);
--- 1884,1916 ----
}
/*
+ * Concatenate the script ID and function name into "<SNR>99_name".
+ * "buffer" must have size MAX_FUNC_NAME_LEN.
+ */
+ void
+ func_name_with_sid(char_u *name, int sid, char_u *buffer)
+ {
+ // A script-local function is stored as "<SNR>99_name".
+ buffer[0] = K_SPECIAL;
+ buffer[1] = KS_EXTRA;
+ buffer[2] = (int)KE_SNR;
+ vim_snprintf((char *)buffer + 3, MAX_FUNC_NAME_LEN - 3, "%ld_%s",
+ (long)sid, name);
+ }
+
+ /*
* Find a function "name" in script "sid".
*/
static ufunc_T *
find_func_with_sid(char_u *name, int sid)
{
hashitem_T *hi;
! char_u buffer[MAX_FUNC_NAME_LEN];
if (!SCRIPT_ID_VALID(sid))
return NULL; // not in a script
! func_name_with_sid(name, sid, buffer);
hi = hash_find(&func_hashtab, buffer);
if (!HASHITEM_EMPTY(hi))
return HI2UF(hi);
***************
*** 1914,1920 ****
find_func_with_prefix(char_u *name, int sid)
{
hashitem_T *hi;
! char_u buffer[200];
scriptitem_T *si;
if (vim_strchr(name, AUTOLOAD_CHAR) != NULL)
--- 1924,1930 ----
find_func_with_prefix(char_u *name, int sid)
{
hashitem_T *hi;
! char_u buffer[MAX_FUNC_NAME_LEN];
scriptitem_T *si;
if (vim_strchr(name, AUTOLOAD_CHAR) != NULL)
*** ../vim-8.2.4649/src/proto/
userfunc.pro 2022-02-21 13:13:44.919693176 +0000
--- src/proto/
userfunc.pro 2022-03-30 15:41:26.061275045 +0100
***************
*** 8,13 ****
--- 8,14 ----
void emsg_funcname(char *ermsg, char_u *name);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, evalarg_T *evalarg, funcexe_T *funcexe);
char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error);
+ void func_name_with_sid(char_u *name, int sid, char_u *buffer);
ufunc_T *find_func_even_dead(char_u *name, int flags);
ufunc_T *find_func(char_u *name, int is_global);
int func_is_global(ufunc_T *ufunc);
*** ../vim-8.2.4649/src/testdir/test_vim9_import.vim 2022-03-21 20:40:32.408367357 +0000
--- src/testdir/test_vim9_import.vim 2022-03-30 20:57:56.315691134 +0100
***************
*** 840,845 ****
--- 840,974 ----
&rtp = save_rtp
enddef
+ def Test_autoload_import_relative()
+ var lines =<< trim END
+ vim9script
+
+ g:loaded = 'yes'
+ export def RelFunc(): string
+ return 'relfunc'
+ enddef
+ def NotExported()
+ echo 'not'
+ enddef
+
+ export var someText = 'some text'
+ var notexp = 'bad'
+ END
+ writefile(lines, 'XimportRel.vim')
+ writefile(lines, 'XimportRel2.vim')
+ writefile(lines, 'XimportRel3.vim')
+
+ lines =<< trim END
+ vim9script
+ g:loaded = 'no'
+ import autoload './XimportRel.vim'
+ assert_equal('no', g:loaded)
+
+ def AFunc(): string
+ var res = ''
+ res ..= XimportRel.RelFunc()
+ res ..= '/'
+ res ..= XimportRel.someText
+ XimportRel.someText = 'from AFunc'
+ return res
+ enddef
+ # script not loaded when compiling
+ defcompile
+ assert_equal('no', g:loaded)
+
+ assert_equal('relfunc/some text', AFunc())
+ assert_equal('yes', g:loaded)
+ unlet g:loaded
+
+ assert_equal('from AFunc', XimportRel.someText)
+ XimportRel.someText = 'from script'
+ assert_equal('from script', XimportRel.someText)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ echo XimportRel.NotExported()
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 3)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ echo XimportRel.notexp
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ XimportRel.notexp = 'bad'
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 3)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ def Func()
+ echo XimportRel.NotExported()
+ enddef
+ Func()
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: NotExported', 1)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ def Func()
+ echo XimportRel.notexp
+ enddef
+ Func()
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
+
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel.vim'
+ def Func()
+ XimportRel.notexp = 'bad'
+ enddef
+ Func()
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
+
+ # does not fail if the script wasn't loaded yet
+ g:loaded = 'no'
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel2.vim'
+ def Func()
+ echo XimportRel2.notexp
+ enddef
+ defcompile
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_equal('no', g:loaded)
+
+ # fails with a not loaded import
+ lines =<< trim END
+ vim9script
+ import autoload './XimportRel3.vim'
+ def Func()
+ XimportRel3.notexp = 'bad'
+ enddef
+ Func()
+ END
+ v9.CheckScriptFailure(lines, 'E1049: Item not exported in script: notexp', 1)
+ assert_equal('yes', g:loaded)
+ unlet g:loaded
+
+ delete('XimportRel.vim')
+ delete('XimportRel2.vim')
+ delete('XimportRel3.vim')
+ enddef
+
func Test_import_in_diffexpr()
CheckExecutable diff
***************
*** 2379,2391 ****
vim9script
import autoload './doesNotExist.vim'
END
! v9.CheckScriptFailure(lines, 'E1264:')
lines =<< trim END
vim9script
import autoload '/dir/doesNotExist.vim'
END
! v9.CheckScriptFailure(lines, 'E1264:')
lines =<< trim END
vim9script
--- 2508,2520 ----
vim9script
import autoload './doesNotExist.vim'
END
! v9.CheckScriptSuccess(lines)
lines =<< trim END
vim9script
import autoload '/dir/doesNotExist.vim'
END
! v9.CheckScriptSuccess(lines)
lines =<< trim END
vim9script
*** ../vim-8.2.4649/src/testdir/test_vim9_disassemble.vim 2022-03-27 16:29:49.880153368 +0100
--- src/testdir/test_vim9_disassemble.vim 2022-03-30 21:07:59.595912515 +0100
***************
*** 318,323 ****
--- 318,363 ----
&rtp = save_rtp
enddef
+ def Test_disassemble_import_autoload()
+ writefile(['vim9script'], 'XimportAL.vim')
+
+ var lines =<< trim END
+ vim9script
+ import autoload './XimportAL.vim'
+
+ def AutoloadFunc()
+ echo XimportAL.SomeFunc()
+ echo XimportAL.someVar
+ XimportAL.someVar = "yes"
+ enddef
+
+ var res = execute('disass AutoloadFunc')
+ assert_match('<SNR>\d*_AutoloadFunc.*' ..
+ 'echo XimportAL.SomeFunc()\_s*' ..
+ '\d SOURCE /home/mool/vim/vim82/src/testdir/XimportAL.vim\_s*' ..
+ '\d PUSHFUNC "<80><fd>R\d\+_SomeFunc"\_s*' ..
+ '\d PCALL top (argc 0)\_s*' ..
+ '\d PCALL end\_s*' ..
+ '\d ECHO 1\_s*' ..
+
+ 'echo XimportAL.someVar\_s*' ..
+ '\d SOURCE .*/testdir/XimportAL.vim\_s*' ..
+ '\d LOADEXPORT s:someVar from .*/testdir/XimportAL.vim\_s*' ..
+ '\d ECHO 1\_s*' ..
+
+ 'XimportAL.someVar = "yes"\_s*' ..
+ '\d\+ PUSHS "yes"\_s*' ..
+ '\d\+ SOURCE .*/testdir/XimportAL.vim\_s*' ..
+ '\d\+ STOREEXPORT someVar in .*/testdir/XimportAL.vim\_s*' ..
+
+ '\d\+ RETURN void',
+ res)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ delete('XimportAL.vim')
+ enddef
+
def s:ScriptFuncStore()
var localnr = 1
localnr = 2
*** ../vim-8.2.4649/src/version.c 2022-03-30 10:57:36.739346189 +0100
--- src/version.c 2022-03-30 14:20:17.028426263 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 4650,
/**/
--
Two cows are standing together in a field. One asks the other:
"So what do you think about this Mad Cow Disease?"
The other replies: "That doesn't concern me. I'm a helicopter."
/// 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 ///