mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.4053: Vim9: autoload mechanism doesn't fully work yet
Problem: Vim9: autoload mechanism doesn't fully work yet. Solution: Define functions and variables with their autoload name, add the prefix when calling a function, find the variable in the table of script variables.
This commit is contained in:
parent
ee63031b57
commit
fe2ef0b2cd
@ -3339,10 +3339,12 @@ set_var_const(
|
|||||||
dictitem_T *di;
|
dictitem_T *di;
|
||||||
typval_T *dest_tv = NULL;
|
typval_T *dest_tv = NULL;
|
||||||
char_u *varname;
|
char_u *varname;
|
||||||
|
char_u *name_tofree = NULL;
|
||||||
hashtab_T *ht = NULL;
|
hashtab_T *ht = NULL;
|
||||||
int is_script_local;
|
int is_script_local;
|
||||||
int vim9script = in_vim9script();
|
int vim9script = in_vim9script();
|
||||||
int var_in_vim9script;
|
int var_in_vim9script;
|
||||||
|
int var_in_autoload = FALSE;
|
||||||
int flags = flags_arg;
|
int flags = flags_arg;
|
||||||
int free_tv_arg = !copy; // free tv_arg if not used
|
int free_tv_arg = !copy; // free tv_arg if not used
|
||||||
|
|
||||||
@ -3352,14 +3354,35 @@ set_var_const(
|
|||||||
ht = &SCRIPT_VARS(sid);
|
ht = &SCRIPT_VARS(sid);
|
||||||
varname = name;
|
varname = name;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (in_vim9script() && SCRIPT_ID_VALID(current_sctx.sc_sid)
|
||||||
|
&& SCRIPT_ITEM(current_sctx.sc_sid)->sn_autoload_prefix != NULL
|
||||||
|
&& is_export)
|
||||||
|
{
|
||||||
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
size_t len = STRLEN(name) + STRLEN(si->sn_autoload_prefix) + 1;
|
||||||
|
|
||||||
|
// In a vim9 autoload script an exported variable is put in the
|
||||||
|
// global namespace with the autoload prefix.
|
||||||
|
var_in_autoload = TRUE;
|
||||||
|
varname = alloc(len);
|
||||||
|
if (varname == NULL)
|
||||||
|
goto failed;
|
||||||
|
name_tofree = varname;
|
||||||
|
vim_snprintf((char *)varname, len, "%s%s",
|
||||||
|
si->sn_autoload_prefix, name);
|
||||||
|
ht = &globvarht;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
ht = find_var_ht(name, &varname);
|
ht = find_var_ht(name, &varname);
|
||||||
|
}
|
||||||
if (ht == NULL || *varname == NUL)
|
if (ht == NULL || *varname == NUL)
|
||||||
{
|
{
|
||||||
semsg(_(e_illegal_variable_name_str), name);
|
semsg(_(e_illegal_variable_name_str), name);
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
is_script_local = ht == get_script_local_ht() || sid != 0;
|
is_script_local = ht == get_script_local_ht() || sid != 0 || var_in_autoload;
|
||||||
|
|
||||||
if (vim9script
|
if (vim9script
|
||||||
&& !is_script_local
|
&& !is_script_local
|
||||||
@ -3470,9 +3493,10 @@ set_var_const(
|
|||||||
|
|
||||||
// A Vim9 script-local variable is also present in sn_all_vars
|
// A Vim9 script-local variable is also present in sn_all_vars
|
||||||
// and sn_var_vals. It may set "type" from "tv".
|
// and sn_var_vals. It may set "type" from "tv".
|
||||||
if (var_in_vim9script)
|
if (var_in_vim9script || var_in_autoload)
|
||||||
update_vim9_script_var(FALSE, di, flags, tv, &type,
|
update_vim9_script_var(FALSE, di,
|
||||||
(flags & ASSIGN_NO_MEMBER_TYPE) == 0);
|
var_in_autoload ? name : di->di_key, flags,
|
||||||
|
tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// existing variable, need to clear the value
|
// existing variable, need to clear the value
|
||||||
@ -3550,10 +3574,11 @@ set_var_const(
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the variable name is valid. In Vim9 script an autoload
|
// Make sure the variable name is valid. In Vim9 script an
|
||||||
// variable must be prefixed with "g:".
|
// autoload variable must be prefixed with "g:" unless in an
|
||||||
|
// autoload script.
|
||||||
if (!valid_varname(varname, -1, !vim9script
|
if (!valid_varname(varname, -1, !vim9script
|
||||||
|| STRNCMP(name, "g:", 2) == 0))
|
|| STRNCMP(name, "g:", 2) == 0 || var_in_autoload))
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
di = alloc(sizeof(dictitem_T) + STRLEN(varname));
|
di = alloc(sizeof(dictitem_T) + STRLEN(varname));
|
||||||
@ -3571,9 +3596,10 @@ set_var_const(
|
|||||||
|
|
||||||
// A Vim9 script-local variable is also added to sn_all_vars and
|
// A Vim9 script-local variable is also added to sn_all_vars and
|
||||||
// sn_var_vals. It may set "type" from "tv".
|
// sn_var_vals. It may set "type" from "tv".
|
||||||
if (var_in_vim9script)
|
if (var_in_vim9script || var_in_autoload)
|
||||||
update_vim9_script_var(TRUE, di, flags, tv, &type,
|
update_vim9_script_var(TRUE, di,
|
||||||
(flags & ASSIGN_NO_MEMBER_TYPE) == 0);
|
var_in_autoload ? name : di->di_key, flags,
|
||||||
|
tv, &type, (flags & ASSIGN_NO_MEMBER_TYPE) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
dest_tv = &di->di_tv;
|
dest_tv = &di->di_tv;
|
||||||
@ -3618,6 +3644,7 @@ set_var_const(
|
|||||||
item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
|
item_lock(dest_tv, DICT_MAXNEST, TRUE, TRUE);
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
vim_free(name_tofree);
|
||||||
if (free_tv_arg)
|
if (free_tv_arg)
|
||||||
clear_tv(tv_arg);
|
clear_tv(tv_arg);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ void ex_finish(exarg_T *eap);
|
|||||||
void do_finish(exarg_T *eap, int reanimate);
|
void do_finish(exarg_T *eap, int reanimate);
|
||||||
int source_finished(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
|
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 *script_name_after_autoload(scriptitem_T *si);
|
||||||
|
char_u *get_autoload_prefix(scriptitem_T *si);
|
||||||
char_u *may_prefix_autoload(char_u *name);
|
char_u *may_prefix_autoload(char_u *name);
|
||||||
char_u *autoload_name(char_u *name);
|
char_u *autoload_name(char_u *name);
|
||||||
int script_autoload(char_u *name, int reload);
|
int script_autoload(char_u *name, int reload);
|
||||||
|
@ -13,7 +13,7 @@ void mark_imports_for_reload(int sid);
|
|||||||
void ex_import(exarg_T *eap);
|
void ex_import(exarg_T *eap);
|
||||||
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose);
|
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose);
|
||||||
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
|
char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg);
|
||||||
void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type, int do_member);
|
void update_vim9_script_var(int create, dictitem_T *di, char_u *name, int flags, typval_T *tv, type_T **type, int do_member);
|
||||||
void hide_script_var(scriptitem_T *si, int idx, int func_defined);
|
void hide_script_var(scriptitem_T *si, int idx, int func_defined);
|
||||||
svar_T *find_typval_in_script(typval_T *dest, scid_T sid);
|
svar_T *find_typval_in_script(typval_T *dest, scid_T sid);
|
||||||
int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where);
|
int check_script_var_type(svar_T *sv, typval_T *value, char_u *name, where_T where);
|
||||||
|
@ -1711,6 +1711,7 @@ free_scriptnames(void)
|
|||||||
# ifdef FEAT_PROFILE
|
# ifdef FEAT_PROFILE
|
||||||
ga_clear(&si->sn_prl_ga);
|
ga_clear(&si->sn_prl_ga);
|
||||||
# endif
|
# endif
|
||||||
|
vim_free(si->sn_autoload_prefix);
|
||||||
vim_free(si);
|
vim_free(si);
|
||||||
}
|
}
|
||||||
ga_clear(&script_items);
|
ga_clear(&script_items);
|
||||||
@ -2141,6 +2142,41 @@ script_name_after_autoload(scriptitem_T *si)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For an autoload script "autoload/dir/script.vim" return the prefix
|
||||||
|
* "dir#script#" in allocated memory.
|
||||||
|
* Returns NULL if anything is wrong.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
get_autoload_prefix(scriptitem_T *si)
|
||||||
|
{
|
||||||
|
char_u *p = script_name_after_autoload(si);
|
||||||
|
char_u *prefix;
|
||||||
|
|
||||||
|
if (p == NULL)
|
||||||
|
return NULL;
|
||||||
|
prefix = vim_strsave(p);
|
||||||
|
if (prefix == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// replace all '/' with '#' and locate ".vim" at the end
|
||||||
|
for (p = prefix; *p != NUL; p += mb_ptr2len(p))
|
||||||
|
{
|
||||||
|
if (vim_ispathsep(*p))
|
||||||
|
*p = '#';
|
||||||
|
else if (STRCMP(p, ".vim") == 0)
|
||||||
|
{
|
||||||
|
p[0] = '#';
|
||||||
|
p[1] = NUL;
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// did not find ".vim" at the end
|
||||||
|
vim_free(prefix);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If in a Vim9 autoload script return "name" with the autoload prefix for the
|
* 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.
|
* script. If successful "name" is freed, the returned name is allocated.
|
||||||
@ -2153,40 +2189,31 @@ may_prefix_autoload(char_u *name)
|
|||||||
{
|
{
|
||||||
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
|
||||||
|
|
||||||
if (si->sn_is_autoload)
|
if (si->sn_autoload_prefix != NULL)
|
||||||
{
|
{
|
||||||
char_u *p = script_name_after_autoload(si);
|
char_u *basename = name;
|
||||||
|
size_t len;
|
||||||
|
char_u *res;
|
||||||
|
|
||||||
|
if (*name == K_SPECIAL)
|
||||||
|
{
|
||||||
|
char_u *p = vim_strchr(name, '_');
|
||||||
|
|
||||||
|
// skip over "<SNR>99_"
|
||||||
if (p != NULL)
|
if (p != NULL)
|
||||||
{
|
basename = p + 1;
|
||||||
char_u *tail = vim_strsave(p);
|
}
|
||||||
|
|
||||||
if (tail != NULL)
|
len = STRLEN(si->sn_autoload_prefix) + STRLEN(basename) + 2;
|
||||||
|
res = alloc(len);
|
||||||
|
if (res != NULL)
|
||||||
{
|
{
|
||||||
for (p = tail; *p != NUL; p += mb_ptr2len(p))
|
vim_snprintf((char *)res, len, "%s%s",
|
||||||
{
|
si->sn_autoload_prefix, basename);
|
||||||
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;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// did not find ".vim" at the end
|
|
||||||
vim_free(tail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1864,7 +1864,9 @@ typedef struct
|
|||||||
int sn_state; // SN_STATE_ values
|
int sn_state; // SN_STATE_ values
|
||||||
char_u *sn_save_cpo; // 'cpo' value when :vim9script found
|
char_u *sn_save_cpo; // 'cpo' value when :vim9script found
|
||||||
char sn_is_vimrc; // .vimrc file, do not restore 'cpo'
|
char sn_is_vimrc; // .vimrc file, do not restore 'cpo'
|
||||||
char sn_is_autoload; // "vim9script autoload"
|
|
||||||
|
// for "vim9script autoload" this is "dir#scriptname#"
|
||||||
|
char_u *sn_autoload_prefix;
|
||||||
|
|
||||||
# ifdef FEAT_PROFILE
|
# ifdef FEAT_PROFILE
|
||||||
int sn_prof_on; // TRUE when script is/was profiled
|
int sn_prof_on; // TRUE when script is/was profiled
|
||||||
|
@ -3049,6 +3049,14 @@ def Test_vim9_autoload()
|
|||||||
assert_false(exists('g:prefixed_loaded'))
|
assert_false(exists('g:prefixed_loaded'))
|
||||||
assert_equal('test', prefixed.Gettest())
|
assert_equal('test', prefixed.Gettest())
|
||||||
assert_equal('yes', g:prefixed_loaded)
|
assert_equal('yes', g:prefixed_loaded)
|
||||||
|
assert_equal('name', prefixed.name)
|
||||||
|
END
|
||||||
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
# can also get the items by autoload name
|
||||||
|
lines =<< trim END
|
||||||
|
call assert_equal('test', prefixed#Gettest())
|
||||||
|
call assert_equal('name', prefixed#name)
|
||||||
END
|
END
|
||||||
CheckScriptSuccess(lines)
|
CheckScriptSuccess(lines)
|
||||||
|
|
||||||
|
@ -4080,8 +4080,11 @@ define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free)
|
|||||||
eap->skip = TRUE;
|
eap->skip = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (is_export)
|
// For "export def FuncName()" in an autoload script the function name
|
||||||
// name = may_prefix_autoload(name);
|
// is stored with the legacy autoload name "dir#script#FuncName" so
|
||||||
|
// that it can also be found in legacy script.
|
||||||
|
if (is_export)
|
||||||
|
name = may_prefix_autoload(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// An error in a function call during evaluation of an expression in magic
|
// An error in a function call during evaluation of an expression in magic
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
4053,
|
||||||
/**/
|
/**/
|
||||||
4052,
|
4052,
|
||||||
/**/
|
/**/
|
||||||
|
@ -132,7 +132,8 @@ ex_vim9script(exarg_T *eap UNUSED)
|
|||||||
}
|
}
|
||||||
si->sn_state = SN_STATE_HAD_COMMAND;
|
si->sn_state = SN_STATE_HAD_COMMAND;
|
||||||
|
|
||||||
si->sn_is_autoload = found_autoload;
|
// Store the prefix with the script. It isused to find exported functions.
|
||||||
|
si->sn_autoload_prefix = get_autoload_prefix(si);
|
||||||
|
|
||||||
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
|
||||||
si->sn_version = SCRIPT_VERSION_VIM9;
|
si->sn_version = SCRIPT_VERSION_VIM9;
|
||||||
@ -663,22 +664,37 @@ find_exported(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
size_t len = STRLEN(name);
|
||||||
char_u buffer[200];
|
char_u buffer[200];
|
||||||
char_u *funcname;
|
char_u *funcname;
|
||||||
|
|
||||||
// it could be a user function.
|
// It could be a user function. Normally this is stored as
|
||||||
if (STRLEN(name) < sizeof(buffer) - 15)
|
// "<SNR>99_name". For an autoload script a function is stored with
|
||||||
|
// the autoload prefix: "dir#script#name".
|
||||||
|
if (script->sn_autoload_prefix != NULL)
|
||||||
|
len += STRLEN(script->sn_autoload_prefix) + 2;
|
||||||
|
else
|
||||||
|
len += 15;
|
||||||
|
|
||||||
|
if (len < sizeof(buffer))
|
||||||
funcname = buffer;
|
funcname = buffer;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
funcname = alloc(STRLEN(name) + 15);
|
funcname = alloc(len);
|
||||||
if (funcname == NULL)
|
if (funcname == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (script->sn_autoload_prefix != NULL)
|
||||||
|
{
|
||||||
|
sprintf((char *)funcname, "%s%s", script->sn_autoload_prefix, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
funcname[0] = K_SPECIAL;
|
funcname[0] = K_SPECIAL;
|
||||||
funcname[1] = KS_EXTRA;
|
funcname[1] = KS_EXTRA;
|
||||||
funcname[2] = (int)KE_SNR;
|
funcname[2] = (int)KE_SNR;
|
||||||
sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
|
sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name);
|
||||||
|
}
|
||||||
*ufunc = find_func(funcname, FALSE, NULL);
|
*ufunc = find_func(funcname, FALSE, NULL);
|
||||||
if (funcname != buffer)
|
if (funcname != buffer)
|
||||||
vim_free(funcname);
|
vim_free(funcname);
|
||||||
@ -782,6 +798,7 @@ vim9_declare_scriptvar(exarg_T *eap, char_u *arg)
|
|||||||
update_vim9_script_var(
|
update_vim9_script_var(
|
||||||
int create,
|
int create,
|
||||||
dictitem_T *di,
|
dictitem_T *di,
|
||||||
|
char_u *name,
|
||||||
int flags,
|
int flags,
|
||||||
typval_T *tv,
|
typval_T *tv,
|
||||||
type_T **type,
|
type_T **type,
|
||||||
@ -801,7 +818,7 @@ update_vim9_script_var(
|
|||||||
if (ga_grow(&si->sn_var_vals, 1) == FAIL)
|
if (ga_grow(&si->sn_var_vals, 1) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hi = hash_find(&si->sn_all_vars.dv_hashtab, di->di_key);
|
hi = hash_find(&si->sn_all_vars.dv_hashtab, name);
|
||||||
if (!HASHITEM_EMPTY(hi))
|
if (!HASHITEM_EMPTY(hi))
|
||||||
{
|
{
|
||||||
// Variable with this name exists, either in this block or in
|
// Variable with this name exists, either in this block or in
|
||||||
@ -833,7 +850,7 @@ update_vim9_script_var(
|
|||||||
// svar_T and create a new sallvar_T.
|
// svar_T and create a new sallvar_T.
|
||||||
sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
|
sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len;
|
||||||
newsav = (sallvar_T *)alloc_clear(
|
newsav = (sallvar_T *)alloc_clear(
|
||||||
sizeof(sallvar_T) + STRLEN(di->di_key));
|
sizeof(sallvar_T) + STRLEN(name));
|
||||||
if (newsav == NULL)
|
if (newsav == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -843,7 +860,7 @@ update_vim9_script_var(
|
|||||||
sv->sv_export = is_export;
|
sv->sv_export = is_export;
|
||||||
newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
|
newsav->sav_var_vals_idx = si->sn_var_vals.ga_len;
|
||||||
++si->sn_var_vals.ga_len;
|
++si->sn_var_vals.ga_len;
|
||||||
STRCPY(&newsav->sav_key, di->di_key);
|
STRCPY(&newsav->sav_key, name);
|
||||||
sv->sv_name = newsav->sav_key;
|
sv->sv_name = newsav->sav_key;
|
||||||
newsav->sav_di = di;
|
newsav->sav_di = di;
|
||||||
newsav->sav_block_id = si->sn_current_block_id;
|
newsav->sav_block_id = si->sn_current_block_id;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user