]> granicus.if.org Git - vim/commitdiff
patch 9.0.0387: repeat <ScriptCmd> mapping doesn't use right script context v9.0.0387
authorBram Moolenaar <Bram@vim.org>
Mon, 5 Sep 2022 15:53:21 +0000 (16:53 +0100)
committerBram Moolenaar <Bram@vim.org>
Mon, 5 Sep 2022 15:53:21 +0000 (16:53 +0100)
Problem:    repeating a <ScriptCmd> mapping does not use the right script
            context.
Solution:   When using a mapping put <SID>{sid}; in the redo buffer.
            (closes #11049)

src/getchar.c
src/keymap.h
src/normal.c
src/proto/getchar.pro
src/testdir/test_mapping.vim
src/version.c

index 51faa2382cf69a1ce58dbad246d0cbcc621bb6eb..d49c02635b4e05b8656dc8df85256810d7292260 100644 (file)
@@ -85,6 +85,7 @@ static int    last_recorded_len = 0;  // number of last recorded chars
 
 #ifdef FEAT_EVAL
 mapblock_T     *last_used_map = NULL;
+int            last_used_sid = -1;
 #endif
 
 static int     read_readbuf(buffheader_T *buf, int advance);
@@ -837,6 +838,22 @@ start_redo(long count, int old_redo)
 
     c = read_redo(FALSE, old_redo);
 
+#ifdef FEAT_EVAL
+    if (c == K_SID)
+    {
+       // Copy the <SID>{sid}; sequence
+       add_char_buff(&readbuf2, c);
+       for (;;)
+       {
+           c = read_redo(FALSE, old_redo);
+           add_char_buff(&readbuf2, c);
+           if (!isdigit(c))
+               break;
+       }
+       c = read_redo(FALSE, old_redo);
+    }
+#endif
+
     // copy the buffer name, if present
     if (c == '"')
     {
@@ -876,7 +893,7 @@ start_redo(long count, int old_redo)
        add_num_buff(&readbuf2, count);
     }
 
-    // copy from the redo buffer into the stuff buffer
+    // copy the rest from the redo buffer into the stuff buffer
     add_char_buff(&readbuf2, c);
     copy_redo(old_redo);
     return OK;
@@ -1795,8 +1812,22 @@ vgetc(void)
                // avoid it being recognized as the start of a special key.
                if (c == K_CSI)
                    c = CSI;
+#endif
+#ifdef FEAT_EVAL
+               if (c == K_SID)
+               {
+                   int     j;
+
+                   // Handle <SID>{sid};  Do up to 20 digits for safety.
+                   last_used_sid = 0;
+                   for (j = 0; j < 20 && isdigit(c = vgetorpeek(TRUE)); ++j)
+                       last_used_sid = last_used_sid * 10 + (c - '0');
+                   last_used_map = NULL;
+                   continue;
+               }
 #endif
            }
+
            // a keypad or special function key was not mapped, use it like
            // its ASCII equivalent
            switch (c)
@@ -2922,6 +2953,10 @@ handle_mapping(
        {
            int noremap;
 
+#ifdef FEAT_EVAL
+           last_used_map = mp;
+           last_used_sid = -1;
+#endif
            if (save_m_noremap != REMAP_YES)
                noremap = save_m_noremap;
            else if (
@@ -2940,7 +2975,6 @@ handle_mapping(
 #ifdef FEAT_EVAL
            if (save_m_expr)
                vim_free(map_str);
-           last_used_map = mp;
 #endif
        }
 #ifdef FEAT_EVAL
@@ -3896,6 +3930,29 @@ getcmdkeycmd(
     return (char_u *)line_ga.ga_data;
 }
 
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * If there was a mapping put info about it in the redo buffer, so that "."
+ * will use the same script context.  We only need the SID.
+ */
+    void
+may_add_last_used_map_to_redobuff(void)
+{
+    char_u buf[3 + 20];
+
+    if (last_used_map == NULL || last_used_map->m_script_ctx.sc_sid < 0)
+       return;
+
+    // <K_SID>{nr};
+    buf[0] = K_SPECIAL;
+    buf[1] = KS_EXTRA;
+    buf[2] = KE_SID;
+    vim_snprintf((char *)buf + 3, 20, "%d;",
+                                          last_used_map->m_script_ctx.sc_sid);
+    add_buff(&redobuff, buf, -1L);
+}
+#endif
+
     int
 do_cmdkey_command(int key UNUSED, int flags)
 {
@@ -3903,10 +3960,18 @@ do_cmdkey_command(int key UNUSED, int flags)
 #ifdef FEAT_EVAL
     sctx_T  save_current_sctx = {-1, 0, 0, 0};
 
-    if (key == K_SCRIPT_COMMAND && last_used_map != NULL)
+    if (key == K_SCRIPT_COMMAND
+                 && (last_used_map != NULL || SCRIPT_ID_VALID(last_used_sid)))
     {
        save_current_sctx = current_sctx;
-       current_sctx = last_used_map->m_script_ctx;
+       if (last_used_map != NULL)
+           current_sctx = last_used_map->m_script_ctx;
+       else
+       {
+           current_sctx.sc_sid = last_used_sid;
+           current_sctx.sc_lnum = 0;
+           current_sctx.sc_version = SCRIPT_ITEM(last_used_sid)->sn_version;
+       }
     }
 #endif
 
@@ -3925,6 +3990,9 @@ do_cmdkey_command(int key UNUSED, int flags)
 reset_last_used_map(mapblock_T *mp)
 {
     if (last_used_map == mp)
+    {
        last_used_map = NULL;
+       last_used_sid = -1;
+    }
 }
 #endif
index 6350772c7294e1ab414a1b2a861aa1e7af849e75..910df7d025503184154d4fb2e9c03cdf14f88e7f 100644 (file)
@@ -277,6 +277,7 @@ enum key_extra
     , KE_COMMAND = 103         // <Cmd> special key
     , KE_SCRIPT_COMMAND = 104  // <ScriptCmd> special key
     , KE_S_BS = 105            // shift + <BS>
+    , KE_SID = 106             // <SID> special key, followed by {nr};
 };
 
 /*
@@ -483,6 +484,7 @@ enum key_extra
 
 #define K_COMMAND      TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
 #define K_SCRIPT_COMMAND TERMCAP2KEY(KS_EXTRA, KE_SCRIPT_COMMAND)
+#define K_SID          TERMCAP2KEY(KS_EXTRA, KE_SID)
 
 // Bits for modifier mask
 // 0x01 cannot be used, because the modifier must be 0x02 or higher
index fb2bced04ac84bd3dd1d7a64d825945e4223ef02..8351685d1d4ef7393f999c8c7bbadc140be93880 100644 (file)
@@ -1466,6 +1466,13 @@ prep_redo_num2(
     int            cmd5)
 {
     ResetRedobuff();
+
+#ifdef FEAT_EVAL
+    // Put info about a mapping in the redo buffer, so that "." will use the
+    // same script context.
+    may_add_last_used_map_to_redobuff();
+#endif
+
     if (regname != 0)  // yank from specified buffer
     {
        AppendCharToRedobuff('"');
index 47af0bb32b56b4294f0e74d5afd2f3f3c2ca1a32..66c1e9b72dec32f6ec642da7a7cca47b13835a3b 100644 (file)
@@ -52,6 +52,7 @@ void parse_queued_messages(void);
 void vungetc(int c);
 int fix_input_buffer(char_u *buf, int len);
 int input_available(void);
+void may_add_last_used_map_to_redobuff(void);
 int do_cmdkey_command(int key, int flags);
 void reset_last_used_map(mapblock_T *mp);
 /* vim: set ft=c : */
index 2927ba718b02757f2aa1a5edc5f6dda37b0a7206..bc5b487f2f17c5f8584bf2d608c396449e27e15e 100644 (file)
@@ -1529,6 +1529,35 @@ func Test_map_script_cmd_survives_unmap()
   autocmd! CmdlineEnter
 endfunc
 
+func Test_map_script_cmd_redo()
+  call mkdir('Xmapcmd')
+  let lines =<< trim END
+      vim9script
+      import autoload './script.vim'
+      onoremap <F3> <ScriptCmd>script.Func()<CR>
+  END
+  call writefile(lines, 'Xmapcmd/plugin.vim')
+
+  let lines =<< trim END
+      vim9script
+      export def Func()
+        normal! dd
+      enddef
+  END
+  call writefile(lines, 'Xmapcmd/script.vim')
+  new
+  call setline(1, ['one', 'two', 'three', 'four'])
+  nnoremap j j
+  source Xmapcmd/plugin.vim
+  call feedkeys("d\<F3>j.", 'xt')
+  call assert_equal(['two', 'four'], getline(1, '$'))
+
+  ounmap <F3>
+  nunmap j
+  call delete('Xmapcmd', 'rf')
+  bwipe!
+endfunc
+
 " Test for using <script> with a map to remap characters in rhs
 func Test_script_local_remap()
   new
index fc8850161a2c1313cfe8608c6746523b49bba77f..5ab26b1021b784cc7db9cf48151d95ce3aec5a35 100644 (file)
@@ -703,6 +703,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    387,
 /**/
     386,
 /**/