Patch 9.0.0253
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)
Files: runtime/doc/builtin.txt, runtime/doc/repeat.txt, src/structs.h,
src/eval.c, src/evalvars.c, src/vim9script.c,
src/proto/vim9script.pro, src/vim9compile.c, src/scriptfile.c,
src/testdir/test_vim9_import.vim
*** ../vim-9.0.0252/runtime/doc/builtin.txt 2022-08-22 13:14:31.892769316
+0100
--- runtime/doc/builtin.txt 2022-08-24 14:27:57.354222156 +0100
***************
*** 253,259 ****
String or List contents of a register
getreginfo([{regname}]) Dict information about a register
getregtype([{regname}]) String type of a register
! getscriptinfo() List list of sourced scripts
gettabinfo([{expr}]) List list of tab pages
gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def}
--- 253,259 ----
String or List contents of a register
getreginfo([{regname}]) Dict information about a register
getregtype([{regname}]) String type of a register
! getscriptinfo() List list of sourced scripts
gettabinfo([{expr}]) List list of tab pages
gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def}
***************
*** 4083,4099 ****
Can also be used as a |method|: >
GetRegname()->getregtype()
! getscriptinfo() *getscriptinfo()*
Returns a |List| with information about all the sourced Vim
! scripts in the order they were sourced. (|:scriptinfo|)
Each item in the returned List is a |Dict| with the following
items:
autoload set to TRUE for a script that was used with
! |import autoload| but was not actually sourced
! yet.
name vim script file name.
sid script ID |<SID>|.
gettabinfo([{tabnr}]) *gettabinfo()*
If {tabnr} is not specified, then information about all the
--- 4089,4108 ----
Can also be used as a |method|: >
GetRegname()->getregtype()
! getscriptinfo()
*getscriptinfo()*
Returns a |List| with information about all the sourced Vim
! scripts in the order they were sourced, like what
! `:scriptnames` shows.
Each item in the returned List is a |Dict| with the following
items:
autoload set to TRUE for a script that was used with
! `import autoload` but was not actually sourced
! yet (see |import-autoload|).
name vim script file name.
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()*
If {tabnr} is not specified, then information about all the
*** ../vim-9.0.0252/runtime/doc/repeat.txt 2022-06-28 11:21:06.000000000
+0100
--- runtime/doc/repeat.txt 2022-08-24 16:27:02.026973284 +0100
***************
*** 417,422 ****
--- 417,426 ----
For a script that was used with `import autoload` but
was not actually sourced yet an "A" is shown after the
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|
feature}
*** ../vim-9.0.0252/src/structs.h 2022-08-23 18:39:14.756797669 +0100
--- src/structs.h 2022-08-24 13:42:39.564173558 +0100
***************
*** 1850,1862 ****
#define IMP_FLAGS_AUTOLOAD 4 // script still needs to be loaded
/*
! * Info about an already sourced scripts.
*/
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
// variables local to that block are removed.
scriptvar_T *sn_vars;
--- 1850,1868 ----
#define IMP_FLAGS_AUTOLOAD 4 // script still needs to be loaded
/*
! * Info about an encoutered script.
! * When sn_state has the SN_STATE_NOT_LOADED is has not been sourced yet.
*/
typedef struct
{
char_u *sn_name; // full path of script file
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
// variables local to that block are removed.
scriptvar_T *sn_vars;
*** ../vim-9.0.0252/src/eval.c 2022-08-18 13:28:27.720128098 +0100
--- src/eval.c 2022-08-24 13:54:43.834196244 +0100
***************
*** 1039,1044 ****
--- 1039,1045 ----
ufunc_T *ufunc;
type_T *type;
+ import_check_sourced_sid(&import->imp_sid);
lp->ll_sid = import->imp_sid;
lp->ll_name = skipwhite(p + 1);
p = find_name_end(lp->ll_name, NULL, NULL, fne_flags);
*** ../vim-9.0.0252/src/evalvars.c 2022-08-14 14:16:07.987582278 +0100
--- src/evalvars.c 2022-08-24 15:01:11.324428918 +0100
***************
*** 2953,2958 ****
--- 2953,2959 ----
{
if (rettv != NULL)
{
+ // special value that is used in handle_subscript()
rettv->v_type = VAR_ANY;
rettv->vval.v_number = sid != 0 ? sid : import->imp_sid;
}
*** ../vim-9.0.0252/src/vim9script.c 2022-08-06 22:12:59.994474165 +0100
--- src/vim9script.c 2022-08-24 14:00:27.856809188 +0100
***************
*** 697,702 ****
--- 697,716 ----
}
/*
+ * 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".
* Either "cctx" or "cstack" is NULL.
* When it is a variable return the index.
*** ../vim-9.0.0252/src/proto/vim9script.pro 2022-06-27 23:15:30.000000000
+0100
--- src/proto/vim9script.pro 2022-08-24 14:24:27.406358201 +0100
***************
*** 12,17 ****
--- 12,18 ----
void free_imports_and_script_vars(int sid);
void mark_imports_for_reload(int sid);
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);
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);
*** ../vim-9.0.0252/src/vim9compile.c 2022-08-17 15:55:47.864544955 +0100
--- src/vim9compile.c 2022-08-24 15:13:46.113786819 +0100
***************
*** 610,616 ****
ret = find_imported_in_script(name, len, current_sctx.sc_sid);
if (ret != NULL && load && (ret->imp_flags & IMP_FLAGS_AUTOLOAD))
{
! scid_T dummy;
int save_emsg_off = emsg_off;
// "emsg_off" will be set when evaluating an expression silently, but
--- 610,616 ----
ret = find_imported_in_script(name, len, current_sctx.sc_sid);
if (ret != NULL && load && (ret->imp_flags & IMP_FLAGS_AUTOLOAD))
{
! scid_T actual_sid = 0;
int save_emsg_off = emsg_off;
// "emsg_off" will be set when evaluating an expression silently, but
***************
*** 621,627 ****
// script found before but not loaded yet
ret->imp_flags &= ~IMP_FLAGS_AUTOLOAD;
(void)do_source(SCRIPT_ITEM(ret->imp_sid)->sn_name, FALSE,
! DOSO_NONE, &dummy);
emsg_off = save_emsg_off;
}
--- 621,631 ----
// script found before but not loaded yet
ret->imp_flags &= ~IMP_FLAGS_AUTOLOAD;
(void)do_source(SCRIPT_ITEM(ret->imp_sid)->sn_name, FALSE,
! 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;
}
*** ../vim-9.0.0252/src/scriptfile.c 2022-08-23 19:26:00.954972237 +0100
--- src/scriptfile.c 2022-08-24 16:20:33.251259001 +0100
***************
*** 1357,1362 ****
--- 1357,1363 ----
{
source_cookie_T cookie;
char_u *p;
+ char_u *fname_not_fixed = NULL;
char_u *fname_exp;
char_u *firstline = NULL;
int retval = FAIL;
***************
*** 1389,1401 ****
}
else
{
! p = expand_env_save(fname);
! if (p == NULL)
! return retval;
! fname_exp = fix_fname(p);
! vim_free(p);
if (fname_exp == NULL)
! return retval;
if (mch_isdir(fname_exp))
{
smsg(_("Cannot source a directory: \"%s\""), fname);
--- 1390,1401 ----
}
else
{
! fname_not_fixed = expand_env_save(fname);
! if (fname_not_fixed == NULL)
! goto theend;
! fname_exp = fix_fname(fname_not_fixed);
if (fname_exp == NULL)
! goto theend;
if (mch_isdir(fname_exp))
{
smsg(_("Cannot source a directory: \"%s\""), fname);
***************
*** 1602,1615 ****
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
if (ret_sid != NULL)
! *ret_sid = current_sctx.sc_sid;
// Remember the "is_vimrc" flag for when the file is sourced again.
si->sn_is_vimrc = is_vimrc;
--- 1602,1616 ----
int error = OK;
// It's new, generate a new SID and initialize the scriptitem.
! sid = get_new_scriptitem(&error);
! current_sctx.sc_sid = sid;
if (error == FAIL)
goto almosttheend;
! si = SCRIPT_ITEM(sid);
si->sn_name = fname_exp;
fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (ret_sid != NULL)
! *ret_sid = sid;
// Remember the "is_vimrc" flag for when the file is sourced again.
si->sn_is_vimrc = is_vimrc;
***************
*** 1668,1674 ****
if (do_profiling == PROF_YES)
{
// Get "si" again, "script_items" may have been reallocated.
! si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on)
{
profile_end(&si->sn_pr_start);
--- 1669,1675 ----
if (do_profiling == PROF_YES)
{
// Get "si" again, "script_items" may have been reallocated.
! si = SCRIPT_ITEM(sid);
if (si->sn_prof_on)
{
profile_end(&si->sn_pr_start);
***************
*** 1719,1725 ****
// If "sn_save_cpo" is set that means we encountered "vim9script": restore
// 'cpoptions', unless in the main .vimrc file.
// Get "si" again, "script_items" may have been reallocated.
! si = SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_save_cpo != NULL && si->sn_is_vimrc == DOSO_NONE)
{
if (STRCMP(p_cpo, CPO_VIM) != 0)
--- 1720,1726 ----
// If "sn_save_cpo" is set that means we encountered "vim9script": restore
// 'cpoptions', unless in the main .vimrc file.
// Get "si" again, "script_items" may have been reallocated.
! si = SCRIPT_ITEM(sid);
if (si->sn_save_cpo != NULL && si->sn_is_vimrc == DOSO_NONE)
{
if (STRCMP(p_cpo, CPO_VIM) != 0)
***************
*** 1774,1779 ****
--- 1775,1793 ----
apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf);
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);
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
#ifdef FEAT_EVAL
***************
*** 1787,1793 ****
char_u *fname,
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
! int *ret_sid UNUSED)
{
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
}
--- 1801,1807 ----
char_u *fname,
int check_other, // check for .vimrc and _vimrc
int is_vimrc, // DOSO_ value
! int *ret_sid)
{
return do_source_ext(fname, check_other, is_vimrc, ret_sid, NULL, FALSE);
}
***************
*** 1828,1836 ****
if (si->sn_name != NULL)
{
home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE);
! vim_snprintf((char *)IObuff, IOSIZE, "%3d%s: %s",
i,
si->sn_state == SN_STATE_NOT_LOADED ? " A" : "",
NameBuff);
if (!message_filtered(IObuff))
--- 1842,1857 ----
if (si->sn_name != NULL)
{
+ char sourced_buf[20];
+
home_replace(NULL, si->sn_name, NameBuff, MAXPATHL, TRUE);
! 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,
+ sourced_buf,
si->sn_state == SN_STATE_NOT_LOADED ? " A" : "",
NameBuff);
if (!message_filtered(IObuff))
***************
*** 1946,1951 ****
--- 1967,1973 ----
|| list_append_dict(l, d) == FAIL
|| dict_add_string(d, "name", si->sn_name) == FAIL
|| dict_add_number(d, "sid", i) == FAIL
+ || dict_add_number(d, "sourced", si->sn_sourced_sid) == FAIL
|| dict_add_bool(d, "autoload",
si->sn_state == SN_STATE_NOT_LOADED) == FAIL)
return;
*** ../vim-9.0.0252/src/testdir/test_vim9_import.vim 2022-08-22
13:14:31.896769307 +0100
--- src/testdir/test_vim9_import.vim 2022-08-24 16:22:52.723181428 +0100
***************
*** 2906,2910 ****
--- 2906,2955 ----
v9.CheckScriptFailure(lines, 'E461: Illegal variable name: foo#bar', 2)
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-9.0.0252/src/version.c 2022-08-24 12:24:04.299387716 +0100
--- src/version.c 2022-08-24 13:38:00.432376921 +0100
***************
*** 733,734 ****
--- 733,736 ----
{ /* Add new patch number below this line */
+ /**/
+ 253,
/**/
--
BEDEVERE: Oooooh!
LAUNCELOT: No "Aaaaarrrrrrggghhh ... " at the back of the throat.
BEDEVERE: No! "Oooooh!" in surprise and alarm!
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/20220824153122.F35EA1C0D30%40moolenaar.net.