Mercurial > vim
changeset 30102:539fb427124d v9.0.0387
patch 9.0.0387: repeat <ScriptCmd> mapping doesn't use right script context
Commit: https://github.com/vim/vim/commit/ddf7dba96e05a41c7a228b153146237e0a21b146
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Sep 5 16:53:21 2022 +0100
patch 9.0.0387: repeat <ScriptCmd> mapping doesn't use right script context
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)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 05 Sep 2022 18:00:05 +0200 |
parents | 50cb1d7be810 |
children | ec4ce9c64e2b |
files | src/getchar.c src/keymap.h src/normal.c src/proto/getchar.pro src/testdir/test_mapping.vim src/version.c |
diffstat | 6 files changed, 113 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- 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>{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>{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 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
--- a/src/keymap.h +++ b/src/keymap.h @@ -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
--- 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('"');
--- 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 : */
--- 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 <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