]> granicus.if.org Git - vim/commitdiff
patch 8.2.4059: Vim9: an expression of a map cannot access script-local items v8.2.4059
authorBram Moolenaar <Bram@vim.org>
Tue, 11 Jan 2022 11:58:19 +0000 (11:58 +0000)
committerBram Moolenaar <Bram@vim.org>
Tue, 11 Jan 2022 11:58:19 +0000 (11:58 +0000)
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.

src/getchar.c
src/map.c
src/proto/map.pro
src/testdir/test_vim9_import.vim
src/version.c

index 6fecc1a2897e28be7a3ba1946e68ba0b1d289055..08c1a955781600cff414e032178ef3d237c545dd 100644 (file)
@@ -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 <expr>": 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)
index 336425afe9a55ee12da40ef78ee0c692f624ab80..181aa654b6ff0410f2843674cb0316b4ede38b5e 100644 (file)
--- 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);
 
index 3592623543b47aba205fed5419299a46da0d6e0d..42ebd4b61331d738bcadcc0528a0f0a315c7179c 100644 (file)
@@ -10,7 +10,7 @@ int map_to_exists_mode(char_u *rhs, int mode, int abbr);
 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);
index 395265bbd36bc0ecd08afac4f2859dbb902a7701..ddf5b82b66aed55135310e08e3bb639cd5e0ded2 100644 (file)
@@ -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'\<CR>"
+      enddef
+  END
+  writefile(lines, 'Xdir/autoload/toggle.vim')
+
+  lines =<< trim END
+      vim9script
+
+      import autoload 'toggle.vim'
+
+      nnoremap <silent> <expr> 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
index f5e2ee0c252c2fbfe6636c9b633373366cef5f21..27f63212a97133f4dbbcee504f0935ad5b2c97e7 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    4059,
 /**/
     4058,
 /**/