summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2024-04-21 14:45:48 +0200
committerChristian Brabandt <cb@256bit.org>2024-04-21 14:45:48 +0200
commit84f6dc7ed29d52b1034bfb27bdcd3154a01ee2b1 (patch)
tree4f67c1ed39bcb9db0a66ab9ea12d8ba90cc3a3c7
parent158673680f5ad87591d05dfa7f6a3c0b0eb7061c (diff)
patch 9.1.0360: Vim9: does not handle autoloaded variables wellv9.1.0360
Problem: Vim9: does not handle autoloaded variables well Solution: Better handle script-level exported variable references from autoload files (Ernie Rael). fixes: #14591 closes: #14607 Signed-off-by: Ernie Rael <errael@raelity.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--src/evalvars.c74
-rw-r--r--src/proto/evalvars.pro1
-rw-r--r--src/testdir/test_vim9_import.vim65
-rw-r--r--src/version.c2
4 files changed, 128 insertions, 14 deletions
diff --git a/src/evalvars.c b/src/evalvars.c
index 70bb6da2ce..b70a3cd394 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3340,12 +3340,31 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
}
}
+ // and finally try
+ return find_var_autoload_prefix(name, 0, htp, NULL);
+}
+
+/*
+ * Find variable "name" with sn_autoload_prefix.
+ * Return a pointer to it if found, NULL if not found.
+ * When "sid" > 0, use it otherwise use "current_sctx.sc_sid".
+ * When "htp" is not NULL set "htp" to the hashtab_T used.
+ * When "namep" is not NULL set "namep" to the generated name, and
+ * then the caller gets ownership and is responsible for freeing the name.
+ */
+ dictitem_T *
+find_var_autoload_prefix(char_u *name, int sid, hashtab_T **htp,
+ char_u **namep)
+{
+ hashtab_T *ht;
+ dictitem_T *ret = NULL;
// When using "vim9script autoload" script-local items are prefixed but can
// be used with s:name.
- if (SCRIPT_ID_VALID(current_sctx.sc_sid)
+ int check_sid = sid > 0 ? sid : current_sctx.sc_sid;
+ if (SCRIPT_ID_VALID(check_sid)
&& (in_vim9script() || (name[0] == 's' && name[1] == ':')))
{
- scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
+ scriptitem_T *si = SCRIPT_ITEM(check_sid);
if (si->sn_autoload_prefix != NULL)
{
@@ -3355,20 +3374,26 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
if (auto_name != NULL)
{
+ int free_auto_name = TRUE;
ht = &globvarht;
ret = find_var_in_ht(ht, 'g', auto_name, TRUE);
- vim_free(auto_name);
if (ret != NULL)
{
if (htp != NULL)
*htp = ht;
- return ret;
+ if (namep != NULL)
+ {
+ free_auto_name = FALSE;
+ *namep = auto_name;
+ }
}
+ if (free_auto_name)
+ vim_free(auto_name);
}
}
}
- return NULL;
+ return ret;
}
/*
@@ -3508,7 +3533,11 @@ lookup_scriptitem(
hi = hash_find(ht, p);
res = HASHITEM_EMPTY(hi) ? FAIL : OK;
- // if not script-local, then perhaps imported
+ // if not script-local, then perhaps autoload-exported
+ if (res == FAIL && find_var_autoload_prefix(p, 0, NULL, NULL) != NULL)
+ res = OK;
+
+ // if not script-local or autoload, then perhaps imported
if (res == FAIL && find_imported(p, 0, FALSE) != NULL)
res = OK;
if (p != buffer)
@@ -3904,23 +3933,40 @@ set_var_const(
if (sid != 0)
{
+ varname = NULL;
if (SCRIPT_ID_VALID(sid))
- ht = &SCRIPT_VARS(sid);
- varname = name;
+ {
+ char_u *auto_name = NULL;
+ if (find_var_autoload_prefix(name, sid, &ht, &auto_name) != NULL)
+ {
+ var_in_autoload = TRUE;
+ varname = auto_name;
+ name_tofree = varname;
+ }
+ else
+ ht = &SCRIPT_VARS(sid);
+ }
+ if (varname == NULL)
+ varname = name;
}
else
{
- scriptitem_T *si;
+ scriptitem_T *si;
+ char_u *auto_name = NULL;
- if (in_vim9script() && is_export
- && SCRIPT_ID_VALID(current_sctx.sc_sid)
- && (si = SCRIPT_ITEM(current_sctx.sc_sid))
- ->sn_autoload_prefix != NULL)
+ if (in_vim9script()
+ && SCRIPT_ID_VALID(current_sctx.sc_sid)
+ && (si = SCRIPT_ITEM(current_sctx.sc_sid))
+ ->sn_autoload_prefix != NULL
+ && (is_export
+ || find_var_autoload_prefix(name, 0, NULL, &auto_name)
+ != NULL))
{
// In a vim9 autoload script an exported variable is put in the
// global namespace with the autoload prefix.
var_in_autoload = TRUE;
- varname = concat_str(si->sn_autoload_prefix, name);
+ varname = auto_name != NULL ? auto_name
+ : concat_str(si->sn_autoload_prefix, name);
if (varname == NULL)
goto failed;
name_tofree = varname;
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index ea14fe5cef..a0e0100016 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -63,6 +63,7 @@ int eval_variable(char_u *name, int len, scid_T sid, typval_T *rettv, dictitem_T
int eval_variable_import(char_u *name, typval_T *rettv);
void check_vars(char_u *name, int len);
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
+dictitem_T *find_var_autoload_prefix(char_u *name, int sid, hashtab_T **htp, char_u **namep);
dictitem_T *find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload);
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
hashtab_T *get_script_local_ht(void);
diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim
index 78383ee79b..cfab50d584 100644
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -1201,6 +1201,71 @@ def Test_autoload_import_relative_from_buffer_in_dir()
:bw!
enddef
+" Test modifying exported autoload variable. Github issue: #14591
+def Test_autoload_export_variables()
+ mkdir('Xautoload_vars/autoload', 'pR')
+ var lines =<< trim END
+ vim9script
+ export var val = 11
+ val = 42
+ END
+
+ # Test that the imported script, above, can modify the exported variable;
+ # and test that the importing script, below, can modify the variable.
+ writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f2.vim', 'D')
+ lines =<< trim END
+ vim9script
+
+ import autoload './Xautoload_vars/autoload/Xauto_vars_f2.vim' as f2
+
+ def F(): number
+ return f2.val
+ enddef
+ assert_equal(42, F())
+ assert_equal(42, f2.val)
+ f2.val = 17
+ assert_equal(17, f2.val)
+
+ def G()
+ f2.val = 19
+ enddef
+ G()
+ assert_equal(19, f2.val)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ # Test const var is not modifiable.
+ lines =<< trim END
+ vim9script
+ export const val = 11
+ val = 42
+ END
+ writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f3.vim', 'D')
+ lines =<< trim END
+ vim9script
+
+ import autoload './Xautoload_vars/autoload/Xauto_vars_f3.vim' as f3
+
+ var x = f3.val
+ END
+ v9.CheckScriptFailure(lines, 'E46:')
+
+ # Test const var is not modifiable from importing script.
+ lines =<< trim END
+ vim9script
+ export const val = 11
+ END
+ writefile(lines, 'Xautoload_vars/autoload/Xauto_vars_f4.vim', 'D')
+ lines =<< trim END
+ vim9script
+
+ import autoload './Xautoload_vars/autoload/Xauto_vars_f4.vim' as f4
+
+ f4.val = 13
+ END
+ v9.CheckScriptFailure(lines, 'E46:')
+enddef
+
def Test_autoload_import_relative_autoload_dir()
mkdir('autoload', 'pR')
var lines =<< trim END
diff --git a/src/version.c b/src/version.c
index 9e2acb87e2..d418b602b2 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 360,
+/**/
359,
/**/
358,