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;
|
||||
cmdmod_T save_cmdmod;
|
||||
const int save_reg_executing = reg_executing;
|
||||
const bool save_pending_end_reg_executing = pending_end_reg_executing;
|
||||
char_u *cmd;
|
||||
|
||||
memset(&ea, 0, sizeof(ea));
|
||||
@ -2018,6 +2019,7 @@ doend:
|
||||
undo_cmdmod(&ea, save_msg_scroll);
|
||||
cmdmod = save_cmdmod;
|
||||
reg_executing = save_reg_executing;
|
||||
pending_end_reg_executing = save_pending_end_reg_executing;
|
||||
|
||||
if (ea.did_sandbox) {
|
||||
sandbox--;
|
||||
@ -8529,6 +8531,7 @@ bool save_current_state(save_state_T *sst)
|
||||
sst->save_finish_op = finish_op;
|
||||
sst->save_opcount = opcount;
|
||||
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
|
||||
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;
|
||||
opcount = sst->save_opcount;
|
||||
reg_executing = sst->save_reg_executing;
|
||||
pending_end_reg_executing = sst->save_pending_end_reg_executing;
|
||||
|
||||
// don't reset msg_didout now
|
||||
msg_didout |= sst->save_msg_didout;
|
||||
|
@ -29,6 +29,7 @@ typedef struct {
|
||||
bool save_finish_op;
|
||||
long save_opcount;
|
||||
int save_reg_executing;
|
||||
bool save_pending_end_reg_executing;
|
||||
tasave_T tabuf;
|
||||
} 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!)
|
||||
/// 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.
|
||||
void vungetc(int c)
|
||||
{
|
||||
@ -2072,6 +2072,20 @@ void vungetc(int c)
|
||||
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:
|
||||
/// 1. from the stuffbuffer
|
||||
/// This is used for abbreviated commands like "D" -> "d$".
|
||||
@ -2126,9 +2140,7 @@ static int vgetorpeek(bool advance)
|
||||
|
||||
init_typebuf();
|
||||
start_stuff();
|
||||
if (advance && typebuf.tb_maplen == 0) {
|
||||
reg_executing = 0;
|
||||
}
|
||||
check_end_reg_executing(advance);
|
||||
do {
|
||||
// get a character: 1. from the stuffbuffer
|
||||
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
|
||||
// try re-mapping.
|
||||
for (;;) {
|
||||
check_end_reg_executing(advance);
|
||||
// os_breakcheck() is slow, don't use it too often when
|
||||
// inside a mapping. But call it each time for typed
|
||||
// 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_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 no_mapping INIT(= false); // currently no mapping allowed
|
||||
|
@ -690,5 +690,23 @@ func Test_record_in_select_mode()
|
||||
bwipe!
|
||||
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
|
||||
|
@ -6,11 +6,13 @@ local feed = helpers.feed
|
||||
local clear = helpers.clear
|
||||
local expect = helpers.expect
|
||||
local command = helpers.command
|
||||
local meths = helpers.meths
|
||||
local insert = helpers.insert
|
||||
local curbufmeths = helpers.curbufmeths
|
||||
|
||||
before_each(clear)
|
||||
|
||||
describe('macros', function()
|
||||
before_each(clear)
|
||||
it('can be recorded and replayed', function()
|
||||
feed('qiahello<esc>q')
|
||||
expect('hello')
|
||||
@ -47,9 +49,34 @@ hello]]
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('reg_recorded()', function()
|
||||
before_each(clear)
|
||||
describe('immediately after a macro has finished executing,', function()
|
||||
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()
|
||||
feed [[qqyyq]]
|
||||
eq('q', eval('reg_recorded()'))
|
||||
|
Loading…
Reference in New Issue
Block a user