# HG changeset patch # User Bram Moolenaar # Date 1662393605 -7200 # Node ID 539fb427124dd419460fa70dff358284ca9292a3 # Parent 50cb1d7be81063569eb9cf91b28119cca90c822e patch 9.0.0387: repeat mapping doesn't use right script context Commit: https://github.com/vim/vim/commit/ddf7dba96e05a41c7a228b153146237e0a21b146 Author: Bram Moolenaar Date: Mon Sep 5 16:53:21 2022 +0100 patch 9.0.0387: repeat mapping doesn't use right script context Problem: repeating a mapping does not use the right script context. Solution: When using a mapping put {sid}; in the redo buffer. (closes #11049) diff --git a/src/getchar.c b/src/getchar.c --- a/src/getchar.c +++ b/src/getchar.c @@ -85,6 +85,7 @@ static int last_recorded_len = 0; // num #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}; 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; @@ -1796,7 +1813,21 @@ vgetc(void) if (c == K_CSI) c = CSI; #endif +#ifdef FEAT_EVAL + if (c == K_SID) + { + int j; + + // Handle {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; + + // {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 fl #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 fl reset_last_used_map(mapblock_T *mp) { if (last_used_map == mp) + { last_used_map = NULL; + last_used_sid = -1; + } } #endif diff --git a/src/keymap.h b/src/keymap.h --- a/src/keymap.h +++ b/src/keymap.h @@ -277,6 +277,7 @@ enum key_extra , KE_COMMAND = 103 // special key , KE_SCRIPT_COMMAND = 104 // special key , KE_S_BS = 105 // shift + + , KE_SID = 106 // 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 diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -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('"'); diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -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 : */ diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim --- a/src/testdir/test_mapping.vim +++ b/src/testdir/test_mapping.vim @@ -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 script.Func() + 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\j.", 'xt') + call assert_equal(['two', 'four'], getline(1, '$')) + + ounmap + nunmap j + call delete('Xmapcmd', 'rf') + bwipe! +endfunc + " Test for using