Patch 8.2.4748
Problem: Cannot use an imported function in a mapping.
Solution: Recognize <SID>name.Func.
Files: runtime/doc/vim9.txt, src/term.c, src/vim9execute.c,
src/proto/
vim9execute.pro, src/scriptfile.c,
src/testdir/test_vim9_import.vim
*** ../vim-8.2.4747/runtime/doc/vim9.txt 2022-04-10 11:26:00.941539608 +0100
--- runtime/doc/vim9.txt 2022-04-14 12:55:06.633007990 +0100
***************
*** 1542,1548 ****
name # Error!
echo that
.name # Error!
! < *: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
--- 1720,1734 ----
name # Error!
echo that
.name # Error!
!
! 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
*** ../vim-8.2.4747/src/term.c 2022-03-09 13:00:50.776824777 +0000
--- src/term.c 2022-04-14 12:07:46.058053594 +0100
***************
*** 6010,6017 ****
{
#ifdef FEAT_EVAL
/*
! * Replace <SID> by K_SNR <script-nr> _.
* (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
*/
if (STRNICMP(src, "<SID>", 5) == 0)
{
--- 6010,6020 ----
{
#ifdef FEAT_EVAL
/*
! * 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,6030 ****
emsg(_(e_using_sid_not_in_script_context));
else
{
src += 5;
result[dlen++] = K_SPECIAL;
result[dlen++] = (int)KS_EXTRA;
result[dlen++] = (int)KE_SNR;
! sprintf((char *)result + dlen, "%ld",
! (long)current_sctx.sc_sid);
dlen += (int)STRLEN(result + dlen);
result[dlen++] = '_';
continue;
--- 6022,6047 ----
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", sid);
dlen += (int)STRLEN(result + dlen);
result[dlen++] = '_';
continue;
*** ../vim-8.2.4747/src/vim9execute.c 2022-04-05 21:40:32.107458262 +0100
--- src/vim9execute.c 2022-04-14 12:39:01.904659075 +0100
***************
*** 1658,1663 ****
--- 1658,1686 ----
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,2649 ****
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)
== FAIL)
! {
! semsg(_(e_cant_open_file_str), si->sn_name);
! goto on_error;
! }
! }
}
break;
--- 2655,2665 ----
case ISN_SOURCE:
{
! int notused;
! SOURCING_LNUM = iptr->isn_lnum;
! if (may_load_script((int)iptr->isn_arg.number, ¬used)
== FAIL)
! goto on_error;
}
break;
*** ../vim-8.2.4747/src/proto/
vim9execute.pro 2022-03-15 15:57:00.426428445 +0000
--- src/proto/
vim9execute.pro 2022-04-14 12:38:23.248578404 +0100
***************
*** 6,11 ****
--- 6,12 ----
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);
*** ../vim-8.2.4747/src/scriptfile.c 2022-04-09 21:41:22.266689586 +0100
--- src/scriptfile.c 2022-04-14 12:39:08.148671284 +0100
***************
*** 117,123 ****
}
/*
! * Get the current value for <sfile> in allocated memory.
* "which" is ESTACK_SFILE for <sfile>, ESTACK_STACK for <stack> or
* ESTACK_SCRIPT for <script>.
*/
--- 117,123 ----
}
/*
! * 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,2473 ****
--- 2468,2485 ----
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)
*** ../vim-8.2.4747/src/testdir/test_vim9_import.vim 2022-04-03 21:52:47.770067812 +0100
--- src/testdir/test_vim9_import.vim 2022-04-14 12:49:06.077119932 +0100
***************
*** 642,649 ****
def Test_use_import_in_mapping()
var lines =<< trim END
vim9script
! export def Funcx()
! g:result = 42
enddef
END
writefile(lines, 'XsomeExport.vim')
--- 642,649 ----
def Test_use_import_in_mapping()
var lines =<< trim END
vim9script
! export def Funcx(nr: number)
! g:result = nr
enddef
END
writefile(lines, 'XsomeExport.vim')
***************
*** 651,668 ****
vim9script
import './XsomeExport.vim' as some
var Funcy = some.Funcx
! nnoremap <F3> :call <sid>Funcy()<cr>
END
writefile(lines, 'Xmapscript.vim')
source Xmapscript.vim
feedkeys("\<F3>", "xt")
assert_equal(42, g:result)
unlet g:result
delete('XsomeExport.vim')
delete('Xmapscript.vim')
nunmap <F3>
enddef
def Test_use_import_in_command_completion()
--- 651,698 ----
vim9script
import './XsomeExport.vim' as some
var Funcy = some.Funcx
! 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()
*** ../vim-8.2.4747/src/version.c 2022-04-13 20:45:33.343510618 +0100
--- src/version.c 2022-04-14 12:06:20.474252051 +0100
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 4748,
/**/
--
The only way the average employee can speak to an executive is by taking a
second job as a golf caddie.
(Scott Adams - The Dilbert principle)
/// Bram Moolenaar -- Br...@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 ///