mirror of
https://github.com/neovim/neovim.git
synced 2026-08-30 19:11:52 +00:00
fix(cmdatom): insert-session entered by feedkeys() ignores typed input #41518
Problem:
An insert-session entered by a scheduled `feedkeys('i','n')` is
classified on entry (as "not typed"), and not reevaluated after that,
thus user input following it is not captured.
Repro: an `:imap` that does `feedkeys('<esc>','n')` and schedules
re-entering insert, emits one CmdAtom for the first press, then nothing
else.
Solution:
Sample `maptick` (ticked by `gotchars()` on typed input, including
mappings) at session start; if it advanced by session end, the session
is user input.
This commit is contained in:
@@ -194,7 +194,7 @@ CmdSpec atom_cmd_spec(const cmdarg_T *cap)
|
||||
static CmdOrigin atom_origin(void)
|
||||
{
|
||||
CmdOrigin origin = { .win = curwin, .pos = curwin->w_cursor,
|
||||
.tick = buf_get_changedtick(curbuf) };
|
||||
.tick = buf_get_changedtick(curbuf), .maptick = maptick };
|
||||
set_bufref(&origin.buf, curbuf);
|
||||
return origin;
|
||||
}
|
||||
@@ -1167,9 +1167,12 @@ InsSession atom_ins_start(int cmd, long count, VisualIns vis, bool vblock)
|
||||
void atom_ins_end(const InsSession *session, bool busy)
|
||||
{
|
||||
bool visual = session->vis != kVInsNone;
|
||||
if (!session->typed || busy || restart_edit != 0 || !atom_buf_has_consumers()
|
||||
bool user_input = session->typed
|
||||
// A session is user input, if user input occurred during it. #41516
|
||||
|| maptick != session->origin.maptick;
|
||||
if (!user_input || busy || restart_edit != 0 || !atom_buf_has_consumers()
|
||||
|| (visual && session->vis != kVInsKeys)) {
|
||||
if (session->typed && (busy || restart_edit != 0) && atom_composite_active()) {
|
||||
if (user_input && (busy || restart_edit != 0) && atom_composite_active()) {
|
||||
// Incomplete session (i_CTRL-O): its resolution is never captured.
|
||||
composite.lossy = true;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ typedef struct {
|
||||
const win_T *win; ///< Window.
|
||||
pos_T pos; ///< Cursor position. Stored here bc the window might be closed.
|
||||
varnumber_T tick; ///< b:changedtick.
|
||||
int maptick; ///< Advances on typed input (globals.h:maptick).
|
||||
} CmdOrigin;
|
||||
|
||||
/// How an insert-session was entered from Visual mode.
|
||||
|
||||
@@ -939,7 +939,7 @@ describe('CmdAtom', function()
|
||||
)
|
||||
end)
|
||||
|
||||
it('an insert session atom captures its text', function()
|
||||
it('insert-session atom captures its text', function()
|
||||
fn.setline(1, { 'aaa' })
|
||||
feed('gg0')
|
||||
atoms_start()
|
||||
@@ -966,6 +966,38 @@ describe('CmdAtom', function()
|
||||
eq({ type = 'insert', count = 3, text = 'Z' }, pick(atom_last(), 'type', 'count', 'text'))
|
||||
end)
|
||||
|
||||
it('insert-session entered programmatically, still captures *user* input #41516', function()
|
||||
atoms_start()
|
||||
n.exec_lua([[
|
||||
vim.keymap.set('i', '<C-j>', function()
|
||||
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Esc>', true, false, true), 'n', false)
|
||||
vim.schedule(function()
|
||||
vim.api.nvim_feedkeys('i', 'n', false)
|
||||
end)
|
||||
end)
|
||||
]])
|
||||
local before = #atoms()
|
||||
feed('i')
|
||||
n.exec_lua('vim.wait(50)')
|
||||
feed('<C-j>')
|
||||
n.exec_lua('vim.wait(50)')
|
||||
feed('<Esc>')
|
||||
local evs = atoms()
|
||||
eq(before + 2, #evs)
|
||||
eq({ k('1i<Esc>'), k('1i<Esc>') }, { evs[#evs - 1].keys, evs[#evs].keys })
|
||||
-- Typed text within such a session lands in its atom...
|
||||
n.exec_lua([[vim.schedule(function() vim.api.nvim_feedkeys('i', 'n', false) end)]])
|
||||
n.exec_lua('vim.wait(50)')
|
||||
feed('hi<Esc>')
|
||||
eq({ text = 'hi', keys = k('1ihi<Esc>') }, pick(atom_last(), 'text', 'keys'))
|
||||
-- ...but with NO typed input within it, the session emits nothing.
|
||||
before = #atoms()
|
||||
n.exec_lua([[vim.schedule(function() vim.api.nvim_feedkeys('i', 'n', false) end)]])
|
||||
n.exec_lua('vim.wait(50)')
|
||||
n.exec_lua([[vim.api.nvim_feedkeys('\27', 'n', false)]])
|
||||
eq(before, #atoms())
|
||||
end)
|
||||
|
||||
it("operatorfunc atom includes the getchar()'d payload", function()
|
||||
n.exec(t_atom.minisurround_vim)
|
||||
fn.setline(1, { 'alpha beta' })
|
||||
|
||||
Reference in New Issue
Block a user