# HG changeset patch # User Bram Moolenaar # Date 1641902406 -3600 # Node ID 1a56c0252772c6193b3919bcdebc92aae55b9780 # Parent 6f3ec6d0ef3320a27e539e6ef1ac487618cd3276 patch 8.2.4059: Vim9: an expression of a map cannot access script-local items Commit: https://github.com/vim/vim/commit/19db9e6ba710ca32f0f5e0c2ca2ba69f8228b833 Author: Bram Moolenaar Date: Tue Jan 11 11:58:19 2022 +0000 patch 8.2.4059: Vim9: an expression of a map cannot access script-local items Problem: Vim9: an expression of a map cannot access script-local items. (Maxim Kim) Solution: Use the script ID of where the map was defined. diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -2785,7 +2785,6 @@ handle_mapping( int save_m_noremap; int save_m_silent; char_u *save_m_keys; - char_u *save_m_str; #else # define save_m_noremap mp->m_noremap # define save_m_silent mp->m_silent @@ -2834,7 +2833,6 @@ handle_mapping( save_m_noremap = mp->m_noremap; save_m_silent = mp->m_silent; save_m_keys = NULL; // only saved when needed - save_m_str = NULL; // only saved when needed /* * Handle ":map ": evaluate the {rhs} as an expression. Also @@ -2851,8 +2849,7 @@ handle_mapping( may_garbage_collect = FALSE; save_m_keys = vim_strsave(mp->m_keys); - save_m_str = vim_strsave(mp->m_str); - map_str = eval_map_expr(save_m_str, NUL); + map_str = eval_map_expr(mp, NUL); // The mapping may do anything, but we expect it to take care of // redrawing. Do put the cursor back where it was. @@ -2900,7 +2897,6 @@ handle_mapping( } #ifdef FEAT_EVAL vim_free(save_m_keys); - vim_free(save_m_str); #endif *keylenp = keylen; if (i == FAIL) diff --git a/src/map.c b/src/map.c --- a/src/map.c +++ b/src/map.c @@ -260,6 +260,7 @@ map_add( { mp->m_script_ctx.sc_sid = sid; mp->m_script_ctx.sc_lnum = lnum; + mp->m_script_ctx.sc_version = in_vim9script() ? SCRIPT_VERSION_VIM9 : 0; } else { @@ -1565,7 +1566,7 @@ check_abbr( } #ifdef FEAT_EVAL if (mp->m_expr) - s = eval_map_expr(mp->m_str, c); + s = eval_map_expr(mp, c); else #endif s = mp->m_str; @@ -1600,7 +1601,7 @@ check_abbr( */ char_u * eval_map_expr( - char_u *str, + mapblock_T *mp, int c) // NUL or typed character for abbreviation { char_u *res; @@ -1609,10 +1610,12 @@ eval_map_expr( pos_T save_cursor; int save_msg_col; int save_msg_row; + scid_T save_sctx_sid = current_sctx.sc_sid; + int save_sctx_version = current_sctx.sc_version; // Remove escaping of CSI, because "str" is in a format to be used as // typeahead. - expr = vim_strsave(str); + expr = vim_strsave(mp->m_str); if (expr == NULL) return NULL; vim_unescape_csi(expr); @@ -1625,12 +1628,22 @@ eval_map_expr( save_cursor = curwin->w_cursor; save_msg_col = msg_col; save_msg_row = msg_row; + if (mp->m_script_ctx.sc_version == SCRIPT_VERSION_VIM9) + { + current_sctx.sc_sid = mp->m_script_ctx.sc_sid; + current_sctx.sc_version = SCRIPT_VERSION_VIM9; + } + + // Note: the evaluation may make "mp" invalid. p = eval_to_string(expr, FALSE); + --textwinlock; --ex_normal_lock; curwin->w_cursor = save_cursor; msg_col = save_msg_col; msg_row = save_msg_row; + current_sctx.sc_sid = save_sctx_sid; + current_sctx.sc_version = save_sctx_version; vim_free(expr); diff --git a/src/proto/map.pro b/src/proto/map.pro --- a/src/proto/map.pro +++ b/src/proto/map.pro @@ -10,7 +10,7 @@ int map_to_exists_mode(char_u *rhs, int char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx); int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file); int check_abbr(int c, char_u *ptr, int col, int mincol); -char_u *eval_map_expr(char_u *str, int c); +char_u *eval_map_expr(mapblock_T *mp, int c); char_u *vim_strsave_escape_csi(char_u *p); void vim_unescape_csi(char_u *p); int makemap(FILE *fd, buf_T *buf); diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim --- a/src/testdir/test_vim9_import.vim +++ b/src/testdir/test_vim9_import.vim @@ -1184,6 +1184,44 @@ def Test_vim9script_autoload() &rtp = save_rtp enddef +def Test_autoload_mapping() + mkdir('Xdir/autoload', 'p') + var save_rtp = &rtp + exe 'set rtp^=' .. getcwd() .. '/Xdir' + + var lines =<< trim END + vim9script autoload + + g:toggle_loaded = 'yes' + + export def Toggle(): string + return ":g:toggle_called = 'yes'\" + enddef + END + writefile(lines, 'Xdir/autoload/toggle.vim') + + lines =<< trim END + vim9script + + import autoload 'toggle.vim' + + nnoremap tt toggle.Toggle() + END + CheckScriptSuccess(lines) + assert_false(exists("g:toggle_loaded")) + assert_false(exists("g:toggle_called")) + + feedkeys("tt", 'xt') + assert_equal('yes', g:toggle_loaded) + assert_equal('yes', g:toggle_called) + + nunmap tt + unlet g:toggle_loaded + unlet g:toggle_called + delete('Xdir', 'rf') + &rtp = save_rtp +enddef + def Test_vim9script_autoload_fails() var lines =<< trim END vim9script autoload diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4059, +/**/ 4058, /**/ 4057,