Skip to content

Commit ddf7dba

Browse files
committed
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)
1 parent b1f471e commit ddf7dba

6 files changed

Lines changed: 113 additions & 4 deletions

File tree

src/getchar.c

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ static int last_recorded_len = 0; // number of last recorded chars
8585

8686
#ifdef FEAT_EVAL
8787
mapblock_T *last_used_map = NULL;
88+
int last_used_sid = -1;
8889
#endif
8990

9091
static int read_readbuf(buffheader_T *buf, int advance);
@@ -837,6 +838,22 @@ start_redo(long count, int old_redo)
837838

838839
c = read_redo(FALSE, old_redo);
839840

841+
#ifdef FEAT_EVAL
842+
if (c == K_SID)
843+
{
844+
// Copy the <SID>{sid}; sequence
845+
add_char_buff(&readbuf2, c);
846+
for (;;)
847+
{
848+
c = read_redo(FALSE, old_redo);
849+
add_char_buff(&readbuf2, c);
850+
if (!isdigit(c))
851+
break;
852+
}
853+
c = read_redo(FALSE, old_redo);
854+
}
855+
#endif
856+
840857
// copy the buffer name, if present
841858
if (c == '"')
842859
{
@@ -876,7 +893,7 @@ start_redo(long count, int old_redo)
876893
add_num_buff(&readbuf2, count);
877894
}
878895

879-
// copy from the redo buffer into the stuff buffer
896+
// copy the rest from the redo buffer into the stuff buffer
880897
add_char_buff(&readbuf2, c);
881898
copy_redo(old_redo);
882899
return OK;
@@ -1795,8 +1812,22 @@ vgetc(void)
17951812
// avoid it being recognized as the start of a special key.
17961813
if (c == K_CSI)
17971814
c = CSI;
1815+
#endif
1816+
#ifdef FEAT_EVAL
1817+
if (c == K_SID)
1818+
{
1819+
int j;
1820+
1821+
// Handle <SID>{sid}; Do up to 20 digits for safety.
1822+
last_used_sid = 0;
1823+
for (j = 0; j < 20 && isdigit(c = vgetorpeek(TRUE)); ++j)
1824+
last_used_sid = last_used_sid * 10 + (c - '0');
1825+
last_used_map = NULL;
1826+
continue;
1827+
}
17981828
#endif
17991829
}
1830+
18001831
// a keypad or special function key was not mapped, use it like
18011832
// its ASCII equivalent
18021833
switch (c)
@@ -2922,6 +2953,10 @@ handle_mapping(
29222953
{
29232954
int noremap;
29242955

2956+
#ifdef FEAT_EVAL
2957+
last_used_map = mp;
2958+
last_used_sid = -1;
2959+
#endif
29252960
if (save_m_noremap != REMAP_YES)
29262961
noremap = save_m_noremap;
29272962
else if (
@@ -2940,7 +2975,6 @@ handle_mapping(
29402975
#ifdef FEAT_EVAL
29412976
if (save_m_expr)
29422977
vim_free(map_str);
2943-
last_used_map = mp;
29442978
#endif
29452979
}
29462980
#ifdef FEAT_EVAL
@@ -3896,17 +3930,48 @@ getcmdkeycmd(
38963930
return (char_u *)line_ga.ga_data;
38973931
}
38983932

3933+
#if defined(FEAT_EVAL) || defined(PROTO)
3934+
/*
3935+
* If there was a mapping put info about it in the redo buffer, so that "."
3936+
* will use the same script context. We only need the SID.
3937+
*/
3938+
void
3939+
may_add_last_used_map_to_redobuff(void)
3940+
{
3941+
char_u buf[3 + 20];
3942+
3943+
if (last_used_map == NULL || last_used_map->m_script_ctx.sc_sid < 0)
3944+
return;
3945+
3946+
// <K_SID>{nr};
3947+
buf[0] = K_SPECIAL;
3948+
buf[1] = KS_EXTRA;
3949+
buf[2] = KE_SID;
3950+
vim_snprintf((char *)buf + 3, 20, "%d;",
3951+
last_used_map->m_script_ctx.sc_sid);
3952+
add_buff(&redobuff, buf, -1L);
3953+
}
3954+
#endif
3955+
38993956
int
39003957
do_cmdkey_command(int key UNUSED, int flags)
39013958
{
39023959
int res;
39033960
#ifdef FEAT_EVAL
39043961
sctx_T save_current_sctx = {-1, 0, 0, 0};
39053962

3906-
if (key == K_SCRIPT_COMMAND && last_used_map != NULL)
3963+
if (key == K_SCRIPT_COMMAND
3964+
&& (last_used_map != NULL || SCRIPT_ID_VALID(last_used_sid)))
39073965
{
39083966
save_current_sctx = current_sctx;
3909-
current_sctx = last_used_map->m_script_ctx;
3967+
if (last_used_map != NULL)
3968+
current_sctx = last_used_map->m_script_ctx;
3969+
else
3970+
{
3971+
current_sctx.sc_sid = last_used_sid;
3972+
current_sctx.sc_lnum = 0;
3973+
current_sctx.sc_version = SCRIPT_ITEM(last_used_sid)->sn_version;
3974+
}
39103975
}
39113976
#endif
39123977

@@ -3925,6 +3990,9 @@ do_cmdkey_command(int key UNUSED, int flags)
39253990
reset_last_used_map(mapblock_T *mp)
39263991
{
39273992
if (last_used_map == mp)
3993+
{
39283994
last_used_map = NULL;
3995+
last_used_sid = -1;
3996+
}
39293997
}
39303998
#endif

src/keymap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ enum key_extra
277277
, KE_COMMAND = 103 // <Cmd> special key
278278
, KE_SCRIPT_COMMAND = 104 // <ScriptCmd> special key
279279
, KE_S_BS = 105 // shift + <BS>
280+
, KE_SID = 106 // <SID> special key, followed by {nr};
280281
};
281282

282283
/*
@@ -483,6 +484,7 @@ enum key_extra
483484

484485
#define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND)
485486
#define K_SCRIPT_COMMAND TERMCAP2KEY(KS_EXTRA, KE_SCRIPT_COMMAND)
487+
#define K_SID TERMCAP2KEY(KS_EXTRA, KE_SID)
486488

487489
// Bits for modifier mask
488490
// 0x01 cannot be used, because the modifier must be 0x02 or higher

src/normal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,13 @@ prep_redo_num2(
14661466
int cmd5)
14671467
{
14681468
ResetRedobuff();
1469+
1470+
#ifdef FEAT_EVAL
1471+
// Put info about a mapping in the redo buffer, so that "." will use the
1472+
// same script context.
1473+
may_add_last_used_map_to_redobuff();
1474+
#endif
1475+
14691476
if (regname != 0) // yank from specified buffer
14701477
{
14711478
AppendCharToRedobuff('"');

src/proto/getchar.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void parse_queued_messages(void);
5252
void vungetc(int c);
5353
int fix_input_buffer(char_u *buf, int len);
5454
int input_available(void);
55+
void may_add_last_used_map_to_redobuff(void);
5556
int do_cmdkey_command(int key, int flags);
5657
void reset_last_used_map(mapblock_T *mp);
5758
/* vim: set ft=c : */

src/testdir/test_mapping.vim

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,35 @@ func Test_map_script_cmd_survives_unmap()
15291529
autocmd! CmdlineEnter
15301530
endfunc
15311531

1532+
func Test_map_script_cmd_redo()
1533+
call mkdir('Xmapcmd')
1534+
let lines =<< trim END
1535+
vim9script
1536+
import autoload './script.vim'
1537+
onoremap <F3> <ScriptCmd>script.Func()<CR>
1538+
END
1539+
call writefile(lines, 'Xmapcmd/plugin.vim')
1540+
1541+
let lines =<< trim END
1542+
vim9script
1543+
export def Func()
1544+
normal! dd
1545+
enddef
1546+
END
1547+
call writefile(lines, 'Xmapcmd/script.vim')
1548+
new
1549+
call setline(1, ['one', 'two', 'three', 'four'])
1550+
nnoremap j j
1551+
source Xmapcmd/plugin.vim
1552+
call feedkeys("d\<F3>j.", 'xt')
1553+
call assert_equal(['two', 'four'], getline(1, '$'))
1554+
1555+
ounmap <F3>
1556+
nunmap j
1557+
call delete('Xmapcmd', 'rf')
1558+
bwipe!
1559+
endfunc
1560+
15321561
" Test for using <script> with a map to remap characters in rhs
15331562
func Test_script_local_remap()
15341563
new

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ static char *(features[]) =
703703

704704
static int included_patches[] =
705705
{ /* Add new patch number below this line */
706+
/**/
707+
387,
706708
/**/
707709
386,
708710
/**/

0 commit comments

Comments
 (0)