To: vim_dev@googlegroups.com Subject: Patch 9.0.0387 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0387 Problem: repeating a mapping does not use the right script context. Solution: When using a mapping put {sid}; in the redo buffer. (closes #11049) Files: src/getchar.c, src/proto/getchar.pro, src/keymap.h, src/normal.c, src/testdir/test_mapping.vim *** ../vim-9.0.0386/src/getchar.c 2022-09-05 13:05:26.034229996 +0100 --- src/getchar.c 2022-09-05 16:50:04.679709793 +0100 *************** *** 85,90 **** --- 85,91 ---- #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,842 **** --- 838,859 ---- 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,882 **** add_num_buff(&readbuf2, count); } ! // copy from the redo buffer into the stuff buffer add_char_buff(&readbuf2, c); copy_redo(old_redo); return OK; --- 893,899 ---- add_num_buff(&readbuf2, count); } ! // copy the rest from the redo buffer into the stuff buffer add_char_buff(&readbuf2, c); copy_redo(old_redo); return OK; *************** *** 1796,1802 **** --- 1813,1833 ---- 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,2927 **** --- 2953,2962 ---- { 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,2946 **** #ifdef FEAT_EVAL if (save_m_expr) vim_free(map_str); - last_used_map = mp; #endif } #ifdef FEAT_EVAL --- 2975,2980 ---- *************** *** 3896,3901 **** --- 3930,3958 ---- 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,3912 **** #ifdef FEAT_EVAL sctx_T save_current_sctx = {-1, 0, 0, 0}; ! if (key == K_SCRIPT_COMMAND && last_used_map != NULL) { save_current_sctx = current_sctx; ! current_sctx = last_used_map->m_script_ctx; } #endif --- 3960,3977 ---- #ifdef FEAT_EVAL sctx_T save_current_sctx = {-1, 0, 0, 0}; ! if (key == K_SCRIPT_COMMAND ! && (last_used_map != NULL || SCRIPT_ID_VALID(last_used_sid))) { save_current_sctx = current_sctx; ! 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,3930 **** --- 3990,3998 ---- reset_last_used_map(mapblock_T *mp) { if (last_used_map == mp) + { last_used_map = NULL; + last_used_sid = -1; + } } #endif *** ../vim-9.0.0386/src/proto/getchar.pro 2022-06-27 23:15:07.000000000 +0100 --- src/proto/getchar.pro 2022-09-05 15:48:38.243636493 +0100 *************** *** 52,57 **** --- 52,58 ---- 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 : */ *** ../vim-9.0.0386/src/keymap.h 2022-05-09 19:16:21.000000000 +0100 --- src/keymap.h 2022-09-05 15:11:28.574604295 +0100 *************** *** 277,282 **** --- 277,283 ---- , 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,488 **** --- 484,490 ---- #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 *** ../vim-9.0.0386/src/normal.c 2022-08-31 14:46:07.907016957 +0100 --- src/normal.c 2022-09-05 15:48:22.403657169 +0100 *************** *** 1466,1471 **** --- 1466,1478 ---- 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('"'); *** ../vim-9.0.0386/src/testdir/test_mapping.vim 2022-07-01 16:35:38.406031649 +0100 --- src/testdir/test_mapping.vim 2022-09-05 16:39:55.404396060 +0100 *************** *** 1529,1534 **** --- 1529,1563 ---- 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