mirror of
https://github.com/vim/vim.git
synced 2025-09-27 04:14:06 -04:00
patch 9.0.0253: a symlink to an autoload script results in two entries
Problem: A symlink to an autoload script results in two entries in the list of scripts, items expected in one are actually in the other. Solution: Have one script item refer to the actually sourced one. (closes #10960)
This commit is contained in:
@@ -4091,15 +4091,18 @@ getregtype([{regname}]) *getregtype()*
|
|||||||
|
|
||||||
getscriptinfo() *getscriptinfo()*
|
getscriptinfo() *getscriptinfo()*
|
||||||
Returns a |List| with information about all the sourced Vim
|
Returns a |List| with information about all the sourced Vim
|
||||||
scripts in the order they were sourced. (|:scriptinfo|)
|
scripts in the order they were sourced, like what
|
||||||
|
`:scriptnames` shows.
|
||||||
|
|
||||||
Each item in the returned List is a |Dict| with the following
|
Each item in the returned List is a |Dict| with the following
|
||||||
items:
|
items:
|
||||||
autoload set to TRUE for a script that was used with
|
autoload set to TRUE for a script that was used with
|
||||||
|import autoload| but was not actually sourced
|
`import autoload` but was not actually sourced
|
||||||
yet.
|
yet (see |import-autoload|).
|
||||||
name vim script file name.
|
name vim script file name.
|
||||||
sid script ID |<SID>|.
|
sid script ID |<SID>|.
|
||||||
|
sourced if this script is an alias this is the script
|
||||||
|
ID of the actually sourced script, otherwise zero
|
||||||
|
|
||||||
gettabinfo([{tabnr}]) *gettabinfo()*
|
gettabinfo([{tabnr}]) *gettabinfo()*
|
||||||
If {tabnr} is not specified, then information about all the
|
If {tabnr} is not specified, then information about all the
|
||||||
|
@@ -417,6 +417,10 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|.
|
|||||||
For a script that was used with `import autoload` but
|
For a script that was used with `import autoload` but
|
||||||
was not actually sourced yet an "A" is shown after the
|
was not actually sourced yet an "A" is shown after the
|
||||||
script ID.
|
script ID.
|
||||||
|
For a script that was referred to by one name but
|
||||||
|
after resolving symbolic links got sourced with
|
||||||
|
another name the other script is after "->". E.g.
|
||||||
|
"20->22" means script 20 was sourced as script 22.
|
||||||
{not available when compiled without the |+eval|
|
{not available when compiled without the |+eval|
|
||||||
feature}
|
feature}
|
||||||
|
|
||||||
|
@@ -1039,6 +1039,7 @@ get_lval(
|
|||||||
ufunc_T *ufunc;
|
ufunc_T *ufunc;
|
||||||
type_T *type;
|
type_T *type;
|
||||||
|
|
||||||
|
import_check_sourced_sid(&import->imp_sid);
|
||||||
lp->ll_sid = import->imp_sid;
|
lp->ll_sid = import->imp_sid;
|
||||||
lp->ll_name = skipwhite(p + 1);
|
lp->ll_name = skipwhite(p + 1);
|
||||||
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
|
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
|
||||||
|
@@ -2953,6 +2953,7 @@ eval_variable(
|
|||||||
{
|
{
|
||||||
if (rettv != NULL)
|
if (rettv != NULL)
|
||||||
{
|
{
|
||||||
|
// special value that is used in handle_subscript()
|
||||||
rettv->v_type = VAR_ANY;
|
rettv->v_type = VAR_ANY;
|
||||||
rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
|
rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ void ex_export(exarg_T *eap);
|
|||||||
void free_imports_and_script_vars(int sid);
|
void free_imports_and_script_vars(int sid);
|
||||||
void mark_imports_for_reload(int sid);
|
void mark_imports_for_reload(int sid);
|
||||||
void ex_import(exarg_T *eap);
|
void ex_import(exarg_T *eap);
|
||||||
|
void import_check_sourced_sid(int *sid);
|
||||||
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, cstack_T *cstack, int verbose);
|
int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, cstack_T *cstack, 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, char_u *name, 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);
|
||||||
|
@@ -1357,6 +1357,7 @@ do_source_ext(
|
|||||||
{
|
{
|
||||||
source_cookie_T cookie;
|
source_cookie_T cookie;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
char_u *fname_not_fixed = NULL;
|
||||||
char_u *fname_exp;
|
char_u *fname_exp;
|
||||||
char_u *firstline = NULL;
|
char_u *firstline = NULL;
|
||||||
int retval = FAIL;
|
int retval = FAIL;
|
||||||
@@ -1389,13 +1390,12 @@ do_source_ext(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = expand_env_save(fname);
|
fname_not_fixed = expand_env_save(fname);
|
||||||
if (p == NULL)
|
if (fname_not_fixed == NULL)
|
||||||
return retval;
|
goto theend;
|
||||||
fname_exp = fix_fname(p);
|
fname_exp = fix_fname(fname_not_fixed);
|
||||||
vim_free(p);
|
|
||||||
if (fname_exp == NULL)
|
if (fname_exp == NULL)
|
||||||
return retval;
|
goto theend;
|
||||||
if (mch_isdir(fname_exp))
|
if (mch_isdir(fname_exp))
|
||||||
{
|
{
|
||||||
smsg(_("Cannot source a directory: \"%s\""), fname);
|
smsg(_("Cannot source a directory: \"%s\""), fname);
|
||||||
@@ -1602,14 +1602,15 @@ do_source_ext(
|
|||||||
int error = OK;
|
int error = OK;
|
||||||
|
|
||||||
// It's new, generate a new SID and initialize the scriptitem.
|
// It's new, generate a new SID and initialize the scriptitem.
|
||||||
current_sctx.sc_sid = get_new_scriptitem(&error);
|
sid = get_new_scriptitem(&error);
|
||||||
|
current_sctx.sc_sid = sid;
|
||||||
if (error == FAIL)
|
if (error == FAIL)
|
||||||
goto almosttheend;
|
goto almosttheend;
|
||||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
si = SCRIPT_ITEM(sid);
|
||||||
si->sn_name = fname_exp;
|
si->sn_name = fname_exp;
|
||||||
fname_exp = vim_strsave(si->sn_name); // used for autocmd
|
fname_exp = vim_strsave(si->sn_name); // used for autocmd
|
||||||
if (ret_sid != NULL)
|
if (ret_sid != NULL)
|
||||||
*ret_sid = current_sctx.sc_sid;
|
*ret_sid = sid;
|
||||||
|
|
||||||
// Remember the "is_vimrc" flag for when the file is sourced again.
|
// Remember the "is_vimrc" flag for when the file is sourced again.
|
||||||
si->sn_is_vimrc = is_vimrc;
|
si->sn_is_vimrc = is_vimrc;
|
||||||
@@ -1668,7 +1669,7 @@ do_source_ext(
|
|||||||
if (do_profiling == PROF_YES)
|
if (do_profiling == PROF_YES)
|
||||||
{
|
{
|
||||||
// Get "si" again, "script_items" may have been reallocated.
|
// Get "si" again, "script_items" may have been reallocated.
|
||||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
si = SCRIPT_ITEM(sid);
|
||||||
if (si->sn_prof_on)
|
if (si->sn_prof_on)
|
||||||
{
|
{
|
||||||
profile_end(&si->sn_pr_start);
|
profile_end(&si->sn_pr_start);
|
||||||
@@ -1719,7 +1720,7 @@ almosttheend:
|
|||||||
// If "sn_save_cpo" is set that means we encountered "vim9script": restore
|
// If "sn_save_cpo" is set that means we encountered "vim9script": restore
|
||||||
// 'cpoptions', unless in the main .vimrc file.
|
// 'cpoptions', unless in the main .vimrc file.
|
||||||
// Get "si" again, "script_items" may have been reallocated.
|
// Get "si" again, "script_items" may have been reallocated.
|
||||||
si = SCRIPT_ITEM(current_sctx.sc_sid);
|
si = SCRIPT_ITEM(sid);
|
||||||
if (si->sn_save_cpo != NULL && si->sn_is_vimrc == DOSO_NONE)
|
if (si->sn_save_cpo != NULL && si->sn_is_vimrc == DOSO_NONE)
|
||||||
{
|
{
|
||||||
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
if (STRCMP(p_cpo, CPO_VIM) != 0)
|
||||||
@@ -1774,6 +1775,19 @@ almosttheend:
|
|||||||
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
|
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
|
||||||
|
|
||||||
theend:
|
theend:
|
||||||
|
if (sid > 0 && ret_sid != NULL
|
||||||
|
&& fname_not_fixed != NULL && fname_exp != NULL)
|
||||||
|
{
|
||||||
|
int not_fixed_sid = find_script_by_name(fname_not_fixed);
|
||||||
|
|
||||||
|
// If "fname_not_fixed" is a symlink then we source the linked file.
|
||||||
|
// If the original name is in the script list we add the ID of the
|
||||||
|
// script that was actually sourced.
|
||||||
|
if (SCRIPT_ID_VALID(not_fixed_sid) && not_fixed_sid != sid)
|
||||||
|
SCRIPT_ITEM(not_fixed_sid)->sn_sourced_sid = sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
vim_free(fname_not_fixed);
|
||||||
vim_free(fname_exp);
|
vim_free(fname_exp);
|
||||||
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
|
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
@@ -1787,7 +1801,7 @@ do_source(
|
|||||||
char_u *fname,
|
char_u *fname,
|
||||||
int check_other, // check for .vimrc and _vimrc
|
int check_other, // check for .vimrc and _vimrc
|
||||||
int is_vimrc, // DOSO_ value
|
int is_vimrc, // DOSO_ value
|
||||||
int *ret_sid UNUSED)
|
int *ret_sid)
|
||||||
{
|
{
|
||||||
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
|
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
|
||||||
}
|
}
|
||||||
@@ -1828,9 +1842,16 @@ ex_scriptnames(exarg_T *eap)
|
|||||||
|
|
||||||
if (si->sn_name != NULL)
|
if (si->sn_name != NULL)
|
||||||
{
|
{
|
||||||
|
char sourced_buf[20];
|
||||||
|
|
||||||
home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE);
|
home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE);
|
||||||
vim_snprintf((char *)IObuff, IOSIZE, "%3d%s: %s",
|
if (si->sn_sourced_sid > 0)
|
||||||
|
vim_snprintf(sourced_buf, 20, "->%d", si->sn_sourced_sid);
|
||||||
|
else
|
||||||
|
sourced_buf[0] = NUL;
|
||||||
|
vim_snprintf((char *)IObuff, IOSIZE, "%3d%s%s: %s",
|
||||||
i,
|
i,
|
||||||
|
sourced_buf,
|
||||||
si->sn_state == SN_STATE_NOT_LOADED ? " A" : "",
|
si->sn_state == SN_STATE_NOT_LOADED ? " A" : "",
|
||||||
NameBuff);
|
NameBuff);
|
||||||
if (!message_filtered(IObuff))
|
if (!message_filtered(IObuff))
|
||||||
@@ -1946,6 +1967,7 @@ f_getscriptinfo(typval_T *argvars UNUSED, typval_T *rettv)
|
|||||||
|| list_append_dict(l, d) == FAIL
|
|| list_append_dict(l, d) == FAIL
|
||||||
|| dict_add_string(d, "name", si->sn_name) == FAIL
|
|| dict_add_string(d, "name", si->sn_name) == FAIL
|
||||||
|| dict_add_number(d, "sid", i) == FAIL
|
|| dict_add_number(d, "sid", i) == FAIL
|
||||||
|
|| dict_add_number(d, "sourced", si->sn_sourced_sid) == FAIL
|
||||||
|| dict_add_bool(d, "autoload",
|
|| dict_add_bool(d, "autoload",
|
||||||
si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
|
si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
|
||||||
return;
|
return;
|
||||||
|
@@ -1850,13 +1850,19 @@ typedef struct {
|
|||||||
#define IMP_FLAGS_AUTOLOAD 4 // script still needs to be loaded
|
#define IMP_FLAGS_AUTOLOAD 4 // script still needs to be loaded
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Info about an already sourced scripts.
|
* Info about an encoutered script.
|
||||||
|
* When sn_state has the SN_STATE_NOT_LOADED is has not been sourced yet.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char_u *sn_name; // full path of script file
|
char_u *sn_name; // full path of script file
|
||||||
int sn_script_seq; // latest sctx_T sc_seq value
|
int sn_script_seq; // latest sctx_T sc_seq value
|
||||||
|
|
||||||
|
// When non-zero the script ID of the actually sourced script. Used if a
|
||||||
|
// script is used by a name which has a symlink, we list both names, but
|
||||||
|
// only the linked-to script is actually sourced.
|
||||||
|
int sn_sourced_sid;
|
||||||
|
|
||||||
// "sn_vars" stores the s: variables currently valid. When leaving a block
|
// "sn_vars" stores the s: variables currently valid. When leaving a block
|
||||||
// variables local to that block are removed.
|
// variables local to that block are removed.
|
||||||
scriptvar_T *sn_vars;
|
scriptvar_T *sn_vars;
|
||||||
|
@@ -2906,5 +2906,50 @@ def Test_vim9_autoload_error()
|
|||||||
v9.CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
|
v9.CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
def Test_vim9_import_symlink()
|
||||||
|
if !has('unix')
|
||||||
|
CheckUnix
|
||||||
|
else
|
||||||
|
mkdir('Xto/plugin', 'p')
|
||||||
|
var lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
import autoload 'bar.vim'
|
||||||
|
g:resultFunc = bar.Func()
|
||||||
|
g:resultValue = bar.value
|
||||||
|
END
|
||||||
|
writefile(lines, 'Xto/plugin/foo.vim')
|
||||||
|
|
||||||
|
mkdir('Xto/autoload', 'p')
|
||||||
|
lines =<< trim END
|
||||||
|
vim9script
|
||||||
|
export def Func(): string
|
||||||
|
return 'func'
|
||||||
|
enddef
|
||||||
|
export var value = 'val'
|
||||||
|
END
|
||||||
|
writefile(lines, 'Xto/autoload/bar.vim')
|
||||||
|
|
||||||
|
var save_rtp = &rtp
|
||||||
|
&rtp = getcwd() .. '/Xfrom'
|
||||||
|
system('ln -s ' .. getcwd() .. '/Xto Xfrom')
|
||||||
|
|
||||||
|
source Xfrom/plugin/foo.vim
|
||||||
|
assert_equal('func', g:resultFunc)
|
||||||
|
assert_equal('val', g:resultValue)
|
||||||
|
|
||||||
|
var infoTo = getscriptinfo()->filter((_, v) => v.name =~ 'Xto/autoload/bar')
|
||||||
|
var infoFrom = getscriptinfo()->filter((_, v) => v.name =~ 'Xfrom/autoload/bar')
|
||||||
|
assert_equal(1, len(infoTo))
|
||||||
|
assert_equal(1, len(infoFrom))
|
||||||
|
assert_equal(infoTo[0].sid, infoFrom[0].sourced)
|
||||||
|
|
||||||
|
unlet g:resultFunc
|
||||||
|
unlet g:resultValue
|
||||||
|
&rtp = save_rtp
|
||||||
|
delete('Xto', 'rf')
|
||||||
|
delete('Xfrom', 'rf')
|
||||||
|
endif
|
||||||
|
enddef
|
||||||
|
|
||||||
|
|
||||||
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
|
||||||
|
@@ -731,6 +731,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 */
|
||||||
|
/**/
|
||||||
|
253,
|
||||||
/**/
|
/**/
|
||||||
252,
|
252,
|
||||||
/**/
|
/**/
|
||||||
|
@@ -610,7 +610,7 @@ find_imported(char_u *name, size_t len, int load)
|
|||||||
ret = find_imported_in_script(name, len, current_sctx.sc_sid);
|
ret = find_imported_in_script(name, len, current_sctx.sc_sid);
|
||||||
if (ret != NULL && load && (ret->imp_flags & IMP_FLAGS_AUTOLOAD))
|
if (ret != NULL && load && (ret->imp_flags & IMP_FLAGS_AUTOLOAD))
|
||||||
{
|
{
|
||||||
scid_T dummy;
|
scid_T actual_sid = 0;
|
||||||
int save_emsg_off = emsg_off;
|
int save_emsg_off = emsg_off;
|
||||||
|
|
||||||
// "emsg_off" will be set when evaluating an expression silently, but
|
// "emsg_off" will be set when evaluating an expression silently, but
|
||||||
@@ -621,7 +621,11 @@ find_imported(char_u *name, size_t len, int load)
|
|||||||
// script found before but not loaded yet
|
// script found before but not loaded yet
|
||||||
ret->imp_flags &= ~IMP_FLAGS_AUTOLOAD;
|
ret->imp_flags &= ~IMP_FLAGS_AUTOLOAD;
|
||||||
(void)do_source(SCRIPT_ITEM(ret->imp_sid)->sn_name, FALSE,
|
(void)do_source(SCRIPT_ITEM(ret->imp_sid)->sn_name, FALSE,
|
||||||
DOSO_NONE, &dummy);
|
DOSO_NONE, &actual_sid);
|
||||||
|
// If the script is a symlink it may be sourced with another name, may
|
||||||
|
// need to adjust the script ID for that.
|
||||||
|
if (actual_sid != 0)
|
||||||
|
ret->imp_sid = actual_sid;
|
||||||
|
|
||||||
emsg_off = save_emsg_off;
|
emsg_off = save_emsg_off;
|
||||||
}
|
}
|
||||||
|
@@ -696,6 +696,20 @@ ex_import(exarg_T *eap)
|
|||||||
clear_evalarg(&evalarg, eap);
|
clear_evalarg(&evalarg, eap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a script is a symlink it may be imported with one name and sourced
|
||||||
|
* under another name. Adjust the import script ID if needed.
|
||||||
|
* "*sid" must be a valid script ID.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
import_check_sourced_sid(int *sid)
|
||||||
|
{
|
||||||
|
scriptitem_T *script = SCRIPT_ITEM(*sid);
|
||||||
|
|
||||||
|
if (script->sn_sourced_sid > 0)
|
||||||
|
*sid = script->sn_sourced_sid;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find an exported item in "sid" matching "name".
|
* Find an exported item in "sid" matching "name".
|
||||||
* Either "cctx" or "cstack" is NULL.
|
* Either "cctx" or "cstack" is NULL.
|
||||||
|
Reference in New Issue
Block a user