Mercurial > vim
changeset 28447:6f753a8125f0 v8.2.4748
patch 8.2.4748: cannot use an imported function in a mapping
Commit: https://github.com/vim/vim/commit/8944551534b311a2d25acf6e8db235c6d906256c
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Apr 14 12:58:23 2022 +0100
patch 8.2.4748: cannot use an imported function in a mapping
Problem: Cannot use an imported function in a mapping.
Solution: Recognize <SID>name.Func.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 14 Apr 2022 14:00:05 +0200 |
parents | 224455817fac |
children | 68c4651c8dfc |
files | runtime/doc/vim9.txt src/proto/vim9execute.pro src/scriptfile.c src/term.c src/testdir/test_vim9_import.vim src/version.c src/vim9execute.c |
diffstat | 7 files changed, 105 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1720,7 +1720,15 @@ line, there can be no line break: > name # Error! echo that .name # Error! -< *:import-cycle* + +To refer to a function in an imported script in a mapping, |<SID>| can be +used: > + noremap <silent> ,a :call <SID>name.Function()<CR> + +When the mapping is defined "<SID>name." will be replaced with <SNR> and the +script ID of the imported script. + + *:import-cycle* The `import` commands are executed when encountered. If script A imports script B, and B (directly or indirectly) imports A, this will be skipped over. At this point items in A after "import B" will not have been processed and
--- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -6,6 +6,7 @@ int set_ref_in_funcstacks(int copyID); char_u *char_from_string(char_u *str, varnumber_T index); char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive); int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx); +int may_load_script(int sid, int *loaded); typval_T *lookup_debug_var(char_u *name); int may_break_in_function(ufunc_T *ufunc); int exe_typval_instr(typval_T *tv, typval_T *rettv);
--- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -117,7 +117,7 @@ estack_pop(void) } /* - * Get the current value for <sfile> in allocated memory. + * Get the current value for "which" in allocated memory. * "which" is ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or * ESTACK_SCRIPT for <script>. */ @@ -2468,6 +2468,18 @@ script_autoload( int i; int ret_sid; + // If the name starts with "<SNR>123_" then "123" is the script ID. + if (name[0] == K_SPECIAL && name[1] == KS_EXTRA && name[2] == KE_SNR) + { + p = name + 3; + ret_sid = (int)getdigits(&p); + if (*p == '_' && SCRIPT_ID_VALID(ret_sid)) + { + may_load_script(ret_sid, &ret); + return ret; + } + } + // If there is no '#' after name[0] there is no package name. p = vim_strchr(name, AUTOLOAD_CHAR); if (p == NULL || p == name)
--- a/src/term.c +++ b/src/term.c @@ -6010,8 +6010,11 @@ replace_termcodes( { #ifdef FEAT_EVAL /* - * Replace <SID> by K_SNR <script-nr> _. + * Change <SID>Func to K_SNR <script-nr> _Func. This name is used + * for script-locla user functions. * (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14) + * Also change <SID>name.Func to K_SNR <import-script-nr> _Func. + * Only if "name" is recognized as an import. */ if (STRNICMP(src, "<SID>", 5) == 0) { @@ -6019,12 +6022,26 @@ replace_termcodes( emsg(_(e_using_sid_not_in_script_context)); else { + char_u *dot; + long sid = current_sctx.sc_sid; + src += 5; + if (in_vim9script() + && (dot = vim_strchr(src, '.')) != NULL) + { + imported_T *imp = find_imported(src, dot - src, FALSE); + + if (imp != NULL) + { + sid = imp->imp_sid; + src = dot + 1; + } + } + result[dlen++] = K_SPECIAL; result[dlen++] = (int)KS_EXTRA; result[dlen++] = (int)KE_SNR; - sprintf((char *)result + dlen, "%ld", - (long)current_sctx.sc_sid); + sprintf((char *)result + dlen, "%ld", sid); dlen += (int)STRLEN(result + dlen); result[dlen++] = '_'; continue;
--- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -642,8 +642,8 @@ enddef def Test_use_import_in_mapping() var lines =<< trim END vim9script - export def Funcx() - g:result = 42 + export def Funcx(nr: number) + g:result = nr enddef END writefile(lines, 'XsomeExport.vim') @@ -651,18 +651,48 @@ def Test_use_import_in_mapping() vim9script import './XsomeExport.vim' as some var Funcy = some.Funcx - nnoremap <F3> :call <sid>Funcy()<cr> + nnoremap <F3> :call <sid>Funcy(42)<cr> + nnoremap <F4> :call <sid>some.Funcx(44)<cr> END writefile(lines, 'Xmapscript.vim') source Xmapscript.vim feedkeys("\<F3>", "xt") assert_equal(42, g:result) + feedkeys("\<F4>", "xt") + assert_equal(44, g:result) unlet g:result delete('XsomeExport.vim') delete('Xmapscript.vim') nunmap <F3> + nunmap <F4> +enddef + +def Test_use_autoload_import_in_mapping() + var lines =<< trim END + vim9script + export def Func() + g:result = 42 + enddef + END + writefile(lines, 'XautoloadExport.vim') + lines =<< trim END + vim9script + import autoload './XautoloadExport.vim' as some + nnoremap <F3> :call <SID>some.Func()<CR> + END + writefile(lines, 'Xmapscript.vim') + + source Xmapscript.vim + assert_match('\d\+ A: .*XautoloadExport.vim', execute('scriptnames')->split("\n")[-1]) + feedkeys("\<F3>", "xt") + assert_equal(42, g:result) + + unlet g:result + delete('XautoloadExport.vim') + delete('Xmapscript.vim') + nunmap <F3> enddef def Test_use_import_in_command_completion()
--- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4748, +/**/ 4747, /**/ 4746,
--- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1658,6 +1658,29 @@ exec_command(isn_T *iptr) return OK; } +/* + * If script "sid" is not loaded yet then load it now. + * Caller must make sure "sid" is a valid script ID. + * "loaded" is set to TRUE if the script had to be loaded. + * Returns FAIL if loading fails, OK if already loaded or loaded now. + */ + int +may_load_script(int sid, int *loaded) +{ + scriptitem_T *si = SCRIPT_ITEM(sid); + + if (si->sn_state == SN_STATE_NOT_LOADED) + { + *loaded = TRUE; + if (do_source(si->sn_name, FALSE, DOSO_NONE, NULL) == FAIL) + { + semsg(_(e_cant_open_file_str), si->sn_name); + return FAIL; + } + } + return OK; +} + // used for v_instr of typval of VAR_INSTR struct instr_S { ectx_T *instr_ectx; @@ -2632,18 +2655,11 @@ exec_instructions(ectx_T *ectx) case ISN_SOURCE: { - scriptitem_T *si = SCRIPT_ITEM(iptr->isn_arg.number); - - if (si->sn_state == SN_STATE_NOT_LOADED) - { - SOURCING_LNUM = iptr->isn_lnum; - if (do_source(si->sn_name, FALSE, DOSO_NONE, NULL) + int notused; + SOURCING_LNUM = iptr->isn_lnum; + if (may_load_script((int)iptr->isn_arg.number, ¬used) == FAIL) - { - semsg(_(e_cant_open_file_str), si->sn_name); - goto on_error; - } - } + goto on_error; } break;