diff --git a/src/nvim/context.c b/src/nvim/context.c index fbb0c3598b..a85bc030fd 100644 --- a/src/nvim/context.c +++ b/src/nvim/context.c @@ -1,9 +1,10 @@ -// Context = "full app state" abstraction. (Note: it's named "Context" to disambiguate with state.c -// which is about the event-loop state-machine, not "total program state".) +// Context = "full app state" abstraction. So named to disambiguate state.c, which is about the +// event-loop state-machine, not "total program state". // // Unified interface of: // + shada // + CtxSwitch/ctx_switch (FKA: aucmd_prepbuf, switch_win, win_execute_T) +// + TODO: save_state_T/save_current_state // + TODO: sessions // + TODO: undo save/restore (for cmdpreview, multicursor) // + TODO: TRY_WRAP ? @@ -11,7 +12,7 @@ // Related: // - vim.with() // - switch_option_context(), restore_option_context() -// - McSandbox: input-replay guard. Sibling axis to ctx_switch() and ctx_save(). +// - McSandbox/mc_sandbox_enter: input-replay guard. Sibling axis to ctx_switch() and ctx_save(). #include #include diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index ae8cf74d3c..6bf91447e0 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7092,7 +7092,7 @@ void update_topline_cursor(void) update_curswant(); } -/// Save the current State and go to Normal mode. +/// Save the current State (editor-mode) and go to Normal mode. void save_current_state(save_state_T *sst) FUNC_ATTR_NONNULL_ALL { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 9467340a85..e4f9e3ed60 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -493,7 +493,7 @@ EXTERN int inhibit_delete_count INIT( = 0); /// Encoding used when 'fencs' is set to "default" EXTERN char *fenc_default INIT( = NULL); -/// "State" is the main state of Vim. +/// "State" is the main state (editor-mode) of Vim. /// There are other variables that modify the state: /// Visual_mode: When State is MODE_NORMAL or MODE_INSERT. /// finish_op : When State is MODE_NORMAL, after typing the operator and diff --git a/src/nvim/mcursor.c b/src/nvim/mcursor.c index c0cffb683b..c66814e8ae 100644 --- a/src/nvim/mcursor.c +++ b/src/nvim/mcursor.c @@ -595,10 +595,6 @@ void mc_ins_cascade_start(bool cascade, varnumber_T tick) return; } mc_ins_joined = false; - if (cascade && mc_buf_has_cursors(curbuf) && kv_size(g_atoms) > 0) { - // Cascade now if a mapping queued atoms before entering Insert ("nnoremap i ^i"). - mc_cascade(); - } mc_ins_span.active = cascade && mc_buf_has_cursors(curbuf); mc_ins_span.first = true; mc_ins_span.done_len = 0; @@ -640,11 +636,13 @@ static void mc_ins_restore_state(const McInsSaved *saved) curbuf->b_last_changedtick_i = saved->last_changedtick_i; } -/// Pushes one span and immediately cascades it. Takes ownership of `keys` and `text`. +/// Pushes one span and immediately cascades it, plus any pending mapping atoms. +/// Takes ownership of `keys` and `text`. static void mc_ins_span_push(char *keys, char *text) { mc_ins_span.first = false; - // If all cursors disappear mid-session (e.g. by dedupe), emit but don't cascade. + + // If all cursors disappear mid-session (e.g. dedupe), emit but don't cascade. bool cascade = mc_buf_has_cursors(curbuf); atom_push_raw(cascade, &(CmdAtom){ .type = kAInsertSpan, @@ -655,6 +653,7 @@ static void mc_ins_span_push(char *keys, char *text) if (!cascade) { return; } + McInsSaved saved = mc_ins_save_state(); block_autocmds(); // The span replay would fire InsertEnter/InsertLeave on every key. mc_cascade(); @@ -823,7 +822,7 @@ void mc_ins_cascade_restart(void) void mc_ins_cascade(void) { if (!mc_ins_span.active || mc_replaying() || !(State & MODE_INSERT) - || !mc_buf_has_cursors(curbuf) || kv_size(g_atoms) != 0) { + || !mc_buf_has_cursors(curbuf)) { return; } String ins = redo_keys(NULL); diff --git a/test/functional/editor/mcursor_spec.lua b/test/functional/editor/mcursor_spec.lua index 9e540f113c..f8488ed6be 100644 --- a/test/functional/editor/mcursor_spec.lua +++ b/test/functional/editor/mcursor_spec.lua @@ -1215,14 +1215,10 @@ describe('multicursor', function() -- Also when a Normal-mode mapping moves before entering Insert. #41605 clear_cursors() cursors({ 'aaaa', 'bbbb', 'cccc' }, 'llQjQj') + eq({ { 0, 2 }, { 1, 2 } }, anchors()) + eq({ 3, 2 }, api.nvim_win_get_cursor(0)) command('nnoremap i ^i') - screen:expect([[ - aa{17:a}a | - bb{17:b}b | - cc^cc | - {1:~ }|*2 - | - ]]) + atoms_start() feed('iX') screen:expect([[ X{17:a}aaa | @@ -1233,6 +1229,16 @@ describe('multicursor', function() ]]) feed('') eq({ 'Xaaaa', 'Xbbbb', 'Xcccc' }, get_lines()) + local ev = atom_last() + eq( + { type = 'mapping', lhs = k('iX'), changed = true }, + t_atom.pick(atom_last(), 'type', 'lhs', 'changed') + ) + local children = {} + for _, child in ipairs(ev.atoms) do + children[#children + 1] = { child.type, child.keys } + end + eq({ { 'motion', '^' }, { 'insert', k('1i') }, { 'insert', k('iX') } }, children) end) end)