mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
fix(input): fix clearing of reg_executing
vim-patch:8.2.4705
This commit is contained in:
parent
dc9e436986
commit
2a574f7aaa
@ -1248,6 +1248,7 @@ static char_u *do_one_cmd(char_u **cmdlinep, int flags, cstack_T *cstack, LineGe
|
|||||||
const int save_msg_scroll = msg_scroll;
|
const int save_msg_scroll = msg_scroll;
|
||||||
cmdmod_T save_cmdmod;
|
cmdmod_T save_cmdmod;
|
||||||
const int save_reg_executing = reg_executing;
|
const int save_reg_executing = reg_executing;
|
||||||
|
const bool save_pending_end_reg_executing = pending_end_reg_executing;
|
||||||
char_u *cmd;
|
char_u *cmd;
|
||||||
|
|
||||||
memset(&ea, 0, sizeof(ea));
|
memset(&ea, 0, sizeof(ea));
|
||||||
@ -2018,6 +2019,7 @@ doend:
|
|||||||
undo_cmdmod(&ea, save_msg_scroll);
|
undo_cmdmod(&ea, save_msg_scroll);
|
||||||
cmdmod = save_cmdmod;
|
cmdmod = save_cmdmod;
|
||||||
reg_executing = save_reg_executing;
|
reg_executing = save_reg_executing;
|
||||||
|
pending_end_reg_executing = save_pending_end_reg_executing;
|
||||||
|
|
||||||
if (ea.did_sandbox) {
|
if (ea.did_sandbox) {
|
||||||
sandbox--;
|
sandbox--;
|
||||||
@ -8529,6 +8531,7 @@ bool save_current_state(save_state_T *sst)
|
|||||||
sst->save_finish_op = finish_op;
|
sst->save_finish_op = finish_op;
|
||||||
sst->save_opcount = opcount;
|
sst->save_opcount = opcount;
|
||||||
sst->save_reg_executing = reg_executing;
|
sst->save_reg_executing = reg_executing;
|
||||||
|
sst->save_pending_end_reg_executing = pending_end_reg_executing;
|
||||||
|
|
||||||
msg_scroll = false; // no msg scrolling in Normal mode
|
msg_scroll = false; // no msg scrolling in Normal mode
|
||||||
restart_edit = 0; // don't go to Insert mode
|
restart_edit = 0; // don't go to Insert mode
|
||||||
@ -8559,6 +8562,7 @@ void restore_current_state(save_state_T *sst)
|
|||||||
finish_op = sst->save_finish_op;
|
finish_op = sst->save_finish_op;
|
||||||
opcount = sst->save_opcount;
|
opcount = sst->save_opcount;
|
||||||
reg_executing = sst->save_reg_executing;
|
reg_executing = sst->save_reg_executing;
|
||||||
|
pending_end_reg_executing = sst->save_pending_end_reg_executing;
|
||||||
|
|
||||||
// don't reset msg_didout now
|
// don't reset msg_didout now
|
||||||
msg_didout |= sst->save_msg_didout;
|
msg_didout |= sst->save_msg_didout;
|
||||||
|
@ -29,6 +29,7 @@ typedef struct {
|
|||||||
bool save_finish_op;
|
bool save_finish_op;
|
||||||
long save_opcount;
|
long save_opcount;
|
||||||
int save_reg_executing;
|
int save_reg_executing;
|
||||||
|
bool save_pending_end_reg_executing;
|
||||||
tasave_T tabuf;
|
tasave_T tabuf;
|
||||||
} save_state_T;
|
} save_state_T;
|
||||||
|
|
||||||
|
@ -2060,7 +2060,7 @@ static int handle_mapping(int *keylenp, bool *timedout, int *mapdepth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// unget one character (can only be done once!)
|
/// unget one character (can only be done once!)
|
||||||
/// If the character was stuffed, vgetc() will get it next time it was called.
|
/// If the character was stuffed, vgetc() will get it next time it is called.
|
||||||
/// Otherwise vgetc() will only get it when the stuff buffer is empty.
|
/// Otherwise vgetc() will only get it when the stuff buffer is empty.
|
||||||
void vungetc(int c)
|
void vungetc(int c)
|
||||||
{
|
{
|
||||||
@ -2072,6 +2072,20 @@ void vungetc(int c)
|
|||||||
old_KeyStuffed = KeyStuffed;
|
old_KeyStuffed = KeyStuffed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// When peeking and not getting a character, reg_executing cannot be cleared
|
||||||
|
/// yet, so set a flag to clear it later.
|
||||||
|
static void check_end_reg_executing(bool advance)
|
||||||
|
{
|
||||||
|
if (reg_executing != 0 && (typebuf.tb_maplen == 0 || pending_end_reg_executing)) {
|
||||||
|
if (advance) {
|
||||||
|
reg_executing = 0;
|
||||||
|
pending_end_reg_executing = false;
|
||||||
|
} else {
|
||||||
|
pending_end_reg_executing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets a byte:
|
/// Gets a byte:
|
||||||
/// 1. from the stuffbuffer
|
/// 1. from the stuffbuffer
|
||||||
/// This is used for abbreviated commands like "D" -> "d$".
|
/// This is used for abbreviated commands like "D" -> "d$".
|
||||||
@ -2126,9 +2140,7 @@ static int vgetorpeek(bool advance)
|
|||||||
|
|
||||||
init_typebuf();
|
init_typebuf();
|
||||||
start_stuff();
|
start_stuff();
|
||||||
if (advance && typebuf.tb_maplen == 0) {
|
check_end_reg_executing(advance);
|
||||||
reg_executing = 0;
|
|
||||||
}
|
|
||||||
do {
|
do {
|
||||||
// get a character: 1. from the stuffbuffer
|
// get a character: 1. from the stuffbuffer
|
||||||
if (typeahead_char != 0) {
|
if (typeahead_char != 0) {
|
||||||
@ -2155,6 +2167,7 @@ static int vgetorpeek(bool advance)
|
|||||||
// If a mapped key sequence is found we go back to the start to
|
// If a mapped key sequence is found we go back to the start to
|
||||||
// try re-mapping.
|
// try re-mapping.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
check_end_reg_executing(advance);
|
||||||
// os_breakcheck() is slow, don't use it too often when
|
// os_breakcheck() is slow, don't use it too often when
|
||||||
// inside a mapping. But call it each time for typed
|
// inside a mapping. But call it each time for typed
|
||||||
// characters.
|
// characters.
|
||||||
|
@ -643,6 +643,8 @@ EXTERN bool ex_no_reprint INIT(=false); // No need to print after z or p.
|
|||||||
|
|
||||||
EXTERN int reg_recording INIT(= 0); // register for recording or zero
|
EXTERN int reg_recording INIT(= 0); // register for recording or zero
|
||||||
EXTERN int reg_executing INIT(= 0); // register being executed or zero
|
EXTERN int reg_executing INIT(= 0); // register being executed or zero
|
||||||
|
// Flag set when peeking a character and found the end of executed register
|
||||||
|
EXTERN bool pending_end_reg_executing INIT(= false);
|
||||||
EXTERN int reg_recorded INIT(= 0); // last recorded register or zero
|
EXTERN int reg_recorded INIT(= 0); // last recorded register or zero
|
||||||
|
|
||||||
EXTERN int no_mapping INIT(= false); // currently no mapping allowed
|
EXTERN int no_mapping INIT(= false); // currently no mapping allowed
|
||||||
|
@ -690,5 +690,23 @@ func Test_record_in_select_mode()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_end_reg_executing()
|
||||||
|
nnoremap s <Nop>
|
||||||
|
let @a = 's'
|
||||||
|
call feedkeys("@aqaq\<Esc>", 'tx')
|
||||||
|
call assert_equal('', @a)
|
||||||
|
call assert_equal('', getline(1))
|
||||||
|
|
||||||
|
call setline(1, 'aaa')
|
||||||
|
nnoremap s qa
|
||||||
|
let @a = 'fa'
|
||||||
|
call feedkeys("@asq\<Esc>", 'tx')
|
||||||
|
call assert_equal('', @a)
|
||||||
|
call assert_equal('aaa', getline(1))
|
||||||
|
|
||||||
|
nunmap s
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -6,11 +6,13 @@ local feed = helpers.feed
|
|||||||
local clear = helpers.clear
|
local clear = helpers.clear
|
||||||
local expect = helpers.expect
|
local expect = helpers.expect
|
||||||
local command = helpers.command
|
local command = helpers.command
|
||||||
|
local meths = helpers.meths
|
||||||
local insert = helpers.insert
|
local insert = helpers.insert
|
||||||
local curbufmeths = helpers.curbufmeths
|
local curbufmeths = helpers.curbufmeths
|
||||||
|
|
||||||
|
before_each(clear)
|
||||||
|
|
||||||
describe('macros', function()
|
describe('macros', function()
|
||||||
before_each(clear)
|
|
||||||
it('can be recorded and replayed', function()
|
it('can be recorded and replayed', function()
|
||||||
feed('qiahello<esc>q')
|
feed('qiahello<esc>q')
|
||||||
expect('hello')
|
expect('hello')
|
||||||
@ -47,9 +49,34 @@ hello]]
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('reg_recorded()', function()
|
describe('immediately after a macro has finished executing,', function()
|
||||||
before_each(clear)
|
before_each(function()
|
||||||
|
command([[let @a = 'gg0']])
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('characters from a mapping are not treated as a part of the macro #18015', function()
|
||||||
|
before_each(function()
|
||||||
|
command('nnoremap s qa')
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('if the macro does not end with a <Nop> mapping', function()
|
||||||
|
feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
|
||||||
|
eq({mode = 'n', blocking = false}, meths.get_mode())
|
||||||
|
expect('')
|
||||||
|
eq('', eval('@a'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('if the macro ends with a <Nop> mapping', function()
|
||||||
|
command('nnoremap 0 <Nop>')
|
||||||
|
feed('@asq') -- "q" from "s" mapping should start recording a macro instead of being no-op
|
||||||
|
eq({mode = 'n', blocking = false}, meths.get_mode())
|
||||||
|
expect('')
|
||||||
|
eq('', eval('@a'))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('reg_recorded()', function()
|
||||||
it('returns the correct value', function()
|
it('returns the correct value', function()
|
||||||
feed [[qqyyq]]
|
feed [[qqyyq]]
|
||||||
eq('q', eval('reg_recorded()'))
|
eq('q', eval('reg_recorded()'))
|
||||||
|
Loading…
Reference in New Issue
Block a user