To: vim_dev@googlegroups.com Subject: Patch 9.0.0253 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 ||. 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 ||. + 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 -- Bram@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 ///