aboutsummaryrefslogtreecommitdiff
path: root/test/functional/editor
Commit message (Collapse)AuthorAge
* [extregs] implement tab completion for ~ menu.extregsJosh Rahm21 hours
|
* [extregs] update the register statusmsg to show the full extreg name.Josh Rahm22 hours
| | | | Now it shows something like `5 lines yanked into "~my.extreg`
* [extregs] implement dot redo functionality for extregs.Josh Rahm23 hours
|
* [extregs] fixed rebase.Josh Rahm39 hours
|
* [feat] comprehensive alias tests and fixes.Josh Rahm39 hours
| | | | Alias semantis are identical to using the full extreg name.
* [extregs] Add support for :registers with extregs and aliases.Josh Rahm39 hours
|
* [extregs] implemented aliases.Josh Rahm39 hours
|
* [extregs] tests are passing (at least all those that pass in upstream/master)Josh Rahm39 hours
| | | | Added a big test suite for extregs
* fix(search): crash on "//e" with only a substitute pattern (#42345)Jonas Örnfelt5 days
| | | | | | | | | | | | | | | vim-patch:9.2.1191: crash with "//e" when only a substitute pattern exists Problem: Crash when using "//e" or "//" while there is a substitute pattern but no previous search pattern (after v9.2.0374). Solution: Use the previous pattern selected for an empty pattern (Jonas Ornfelt). related: vim/vim#19998 closes: vim/vim#21533 AI-assisted https://github.com/vim/vim/commit/c58607c9a0579de0da909fc46f68144a01378af1
* feat(multicursor): ]C [C use previous cursors if mc inactive #42267IOCRYPOSTO6 days
| | | | | | | | | | | | Problem: After clearing cursors, "]C" "[C" do nothing, although the previous cursor positions ("gQ") may still be useful as marks. Solution: If multicursor is not active, "]C" "[C" iterate the "nvim.multicursor.last" extmarks. They also work as an operator motion ("d]C"), since there is no cascade. AI-assisted
* fix(ops): '] and yank width of forced-blockwise motion #42321IcyJerry6 days
| | | | | | | | | | | | | | | Problem: `g@<C-v>j` and `y<C-v>j` set '] one char short of the block corner, so 'operatorfunc' cannot get the block. With 'virtualedit' "block", "y" also yanks a short last line one column narrow. Solution: - Decide `inclusive` from the motion's own type, before get_op_vcol() makes it blockwise (like Vim). - Never exclude the end of a block from '] (`g@<C-v>l`): a block includes its corner. Co-authored-by: IcyJerry <263879414+Icyjerry@users.noreply.github.com> Co-authored-by: Nagato Yuzuru <nagato@yuzuru.me>
* fix(multicursor): Visual-mode mapping drops getchar() payload #42324Justin M. Keyes7 days
| | | | | | | | | | Problem: A Visual-mode mapping that reads input (`getchar()`) does not include that input when cascading to other cursors (they only see ESC). OTOH, Normal-mode mappings do replay the input. Solution: Append the payload to the Visual session's Lua-mapping subatom, and to the session-ending command (`:<C-u>…` mapping).
* fix(multicursor): v:cascading during on_key, insert-preview #42319Justin M. Keyes7 days
| | | | | | | | | | | Problem: - `v:cascading` is false during the Insert-mode live-preview. - `vim.on_key()` sees the internal keys of the Visual-selection preview and "zq" steps. Solution: - Set `v:cascading` during the Insert-mode preview. - Don't send internal keys to `on_key` callbacks. - Use `v:cascading` as the source of truth for `mc_replaying()`.
* fix(multicursor): "zqn" places no cursors after "/\%V" search #42313Justin M. Keyes7 days
| | | | | | | | Problem: After `/\%Vfoo<CR>`, `zqn` places no cursors. `mc_zq_target()` clears `'< '>` before `gn` (to detect a failed match), so `\%V` never matches. Solution: Keep the user's `'< '>` during `gn`; detect failure by its beep.
* multicursor: v:cascading #42289Evgeni Chasnovski7 days
| | | | | Problem: No way to check if cascade is in action. Solution: Add `v:cascading` variable.
* fix(multicursor): insert-mode Lua/API edit dropped on ESC #42312Justin M. Keyes7 days
| | | | | | | | | | | | | | | | | | | | | | | | Problem: With multicursors, an Insert-mode edit by a Lua/`<Cmd>` mapping or API (nvim_put(), …) is live-previewed at the other cursors, but dropped at ESC: the cascade replays _redo_, which does not contain such edits. Solution: When `<Cmd>`/Lua/RPC changes the buffer during Insert-mode, sync the previews and restart the capture (like a non-captured cursor-move). The edit stays as text. - The mapping runs only at the primary. Its text is mirrored as-is (similar to insert-completion). Re-running it per cursor would require a "partial-remap" span replay, and breaks single-session plugins (vim.snippet). - Not during completion; redo already captures the pre-inserted candidate on accept. - Text typed before the edit is kept as mirrored, not replayed, so per-cursor effects ('textwidth' wrapping, …) don't apply to it. Known issues: - "o"/"O"/"cc" with 'autoindent' followed by the mapping: the per-cursor insert-entry replay is still pending, so the edit is lost.
* test: simplify functional test expectationsLewis Russell2026-10-05
| | | | | | | | | | | | Problem: Repeated default fields and field-by-field assertions obscure the values that each functional test is meant to check. Solution: Add eq_partial() to check selected record fields while preserving list length and order. Use local helpers to fill fixed expected defaults where tests need full equality. Keep explicit absence checks and test-specific values at the call sites. AI-assisted
* fix(multicursor): session-end clobbers '< '>; zqgj skips rows #42221Justin M. Keyes2026-10-03
| | | | | | | | | | | | Problem: - At session end, `'< '>` revert to the session-start snapshot, which drops a selection made during the session. And the snapshot may be from another buffer. - `zqgj` skips screen rows: `zq` tries the motion before the steps, and those trial runs advance `w_curswant`. Solution: - Keep the primary's `'< '>` at session-end. - Restore `w_curswant` after the trial runs and after each run of steps.
* fix(input): aborted dot-repeat causes ModeChanged during emsg() #42181Justin M. Keyes2026-09-30
| | | | | | | | | | Problem: When a flush discards dot-repeat keys mid-selection, flush_buffers() ends Visual-mode immediately, triggering `ModeChanged` autocmds from `emsg()` (before the error is shown) or `vgetorpeek()`. Solution: End Visual-mode from `normal_finish_command()` by checking a flag, similar to `Visual.restart_select`.
* fix(multicursor): zq failed motions, "t", first stepJustin M. Keyes2026-09-30
| | | | | | | | | | | | | | | | Problem: - "Vjzqfx" (on a line without "x") places a cursor at the selection start. - 'nowrapscan': `zqN` places a cursor on a non-match; `zq#` mid-word places it mid-word. - `zqfa` places at primary even if not on an "a". - `zqti` stops after one step (bc "ti" before an "i" does not move). Solution: - `did_beep_silent`: counts beeps silenced by `emsg_silent`, so `zq` steps can detect failed motions. - If a `zq` step does not move the cursor, retry it from the next char. - Decide the first `zq` step the same way as `{Visual}zq` already does: the primary is considered a step only if the motion lands on it.
* fix(multicursor): zq edge cases; cascade perf #42165Justin M. Keyes2026-09-30
| | | | | | | | | | | - `{Visual}Q` / `{Visual}zqj`: for linewise motion ("j"), every line gets a cursor. - `zq`: handle 3-key motions (`g'a`), don't scroll the view, preserve the search direction, update existing cursors `gv` target. - Disallow `zq` in macros. - Abort `zq` on non-motion ("zqx"). - Classify `g'x` classify like `'x`. - Classify `'(` `'{` etc. as `type=motion` (they are cursor-relative). - Perf: skip save/restore of marks when cascading motions ('follow').
* fix(input): end Visual mode when aborting redo #42151Qiming zhao2026-09-30
| | | | | | | | | | | Problem: Skipping buffer flushing in Visual mode breaks map-error and leaves failed redo motions that raise errors stuck in Visual mode. Solution: Keep flushing on errors and exit Visual mode when pending redo is discarded. Cover failed motions, unset marks, macros, and mappings. AI-assisted
* refactor(multicursor)!: drop nvim_mcursor #42156Justin M. Keyes2026-09-30
| | | | | | | | | | | | | | Problem: `nvim_mcursor` is not fully baked, and not strongly motivated, currently. The main programmatic interface for cursors is the "nvim.multicursor" extmarks namespace. Solution: Drop `nvim_mcursor`. Add an internal hook so that multicursor can react when extmarks are added to the "nvim.multicursor" namespace. TODO: If extmarks/namespaces are clumsy to work with, we should _fix that_ rather than adding wrappers.
* feat(multicursor): zq operator; cursor-local marks #42148Justin M. Keyes2026-09-29
| | | | | | | | | | | | | | | | | | Problem: - `[count]Q` and `{Visual}Q` are implemented as ad hoc utils, because `Q` is not an "operator". - `Q` always "toggles", it is not "idempotent". - Various *cursor-relative* marks (`'.`, `'[`) are not saved/restored per-cursor, so they don't work during cascade. - Insert cascade clobbers the primary's `'^` and changelist. Solution: - Introduce the `zq{motion}` operator, which places cursors at every reachable `{motion}`. - `{Visual}Q` is now an alias to `{Visual}zqj`. - Introduce `1Q` and `2Q` for idempotent cursor placement. - Drop `[count]Q`, it's redundant with `zqgn`. - Classify cursor-relative marks as `type=motion` instead of `type=jump`. Save/restore per-cursor during cascade.
* fix(editor)!: operator target/cgn modifies Visual marks #42119Justin M. Keyes2026-09-27
| | | | | | | | | | | | | | | | | | Problem: An operator on a target that creates a Visual selection (`cgn`, `d<C-v>j`, an omap text object like `:<C-U>normal! viw`) sets `'< '>`, `gv` and `visualmode()` to the operator target. This causes at least the following problems: - clobbers the user's previous `'< '>` (annoying and usually unwanted) - E.g. after a custom textobj, `:help text-object-define`. - "cgn" with a `\%V` pattern can't be dot-repeated (".") Solution: Don't save the Visual area if the operator target created it (operator was pending). Also fix `an`/`in` with `'selection'=exclusive` starting from an empty range.
* feat(multicursor): 'follow' option #42095Justin M. Keyes2026-09-27
| | | | | | | | Problem: - gQ does not restore follow-mode (q=). - Users/plugins have no way to check if follow-mode is enabled. Solution: Introduce buffer-local 'follow' option.
* vim-patch:9.2.1114: Visual selection is not highlighted at the cursor ↵Takumi Katase2026-09-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | position #42105 vim-patch:9.2.1114: Visual selection is not highlighted at the cursor position Problem: In a terminal the character under the cursor is normally not shown as part of the visual selection. Solution: Don't set "noinvcur" in win_line() (Shane Harper). The problem did not occur in the GUI, only in a terminal. The name "noinvcur" ("don't invert the cursor") was misleading: the variable did not affect the cursor, but whether the character under the cursor could be displayed as part of the visual selection. The "noinvcur" handling may have been meant to help during a visual selection when Visual is shown in reverse video and the terminal draws the cursor by inverting the character under it, as otherwise the character under the cursor would not look highlighted like the rest of the selection. But Vim cannot know in general how a terminal draws the cursor, and when either the cursor is not drawn by inverting the character under it or Visual is not shown in reverse video, the handling just left a character of the visual selection unhighlighted. closes: vim/vim#21317 https://github.com/vim/vim/commit/d10aab4ba6602f8f2f2576d2d62ceb63869db6fb Co-authored-by: Shane Harper <shane@shaneharper.net> AI-assisted
* fix(multicursor): "gv" + Insert-entering cmd #42110Justin M. Keyes2026-09-27
| | | | | | | | | | | | | | | | | | | | | Problem: - Multicursor does not cascade a `gv`-entered insert-session (`gvc`). - CmdAtom of a `gv`-entered insert-session (e.g. `gvcX<Esc>`) has `keys="1vcX<Esc>"` (redo's fallback), not the typed keys. And is not emitted at all if multicursor is inactive. Analysis: Redo can't contain "gv", so it does the "1v" fallback, and the insert-cascade replays redo. Solution: Replay "gv" + op at each cursor: store the typed selection in `InsSession.vsel`; it supplants redo's "1v" in the emitted atom and in the insert-cascade replay. A cursor without a Visual area skips a "gv"-based replay (else its keys would run as Normal-mode: "gvrx" => "rx"). Redo behavior is unchanged ("1v" fallback): "gv" is absolute, "." acts at the cursor.
* fix(multicursor): flicker with ui2 #42090Justin M. Keyes2026-09-25
| | | | | | | | | | | | | Problem: UI clients (such as the builtin "ui2") redraw on 'showcmd' updates. When multicursor is active this flushes a frame per-cursor during cascade, which causes: - flicker - slow performance - renders half-applied edits, displaced cursors, Visual selections without highlights Solution: Skip 'showcmd' updates during cascade.
* fix(multicursor): unsynced primary-overlapping cursor #42089Justin M. Keyes2026-09-25
| | | | | | | | | | | | | | | | | | Problem: - The primary-overlapping cursor is synced to primary only after cascade, so it may display at a shifted position (e.g. after "rx") during cascade. - LHS-replay edits apply twice if there is a primary-overlapping cursor. Solution: - Sync the primary-overlapping cursor _before_ replay. This ensures the mark is correct _during_ the cascade. - Drop the post-cascade sync; this is safe because the overlapping mark and the primary-tracking mark are both right-gravity, so they get shifted the same way. - Set `origin` on LHS-replay atoms, so the cascade can compare it. Bonus: a buffer-switching mapping no longer LHS-replays if it ends up in a different buffer.
* fix(multicursor): insert-mode <c-r>x per-cursor registers #42076Justin M. Keyes2026-09-24
| | | | | | | | | | | | Problem: Insert-mode `<c-r>x` stuffs the literal text, so multicursor cascade puts the same (primary) text at each cursor. Note: `<c-r>-` happens to work because `insert_reg()` special-cases it. Solution: Update `insert_reg` so that it preps redo with `<c-r>x` instead of the literal text. Update `atom_key_class` so that CTRL-R flushes the insert-span.
* feat(multicursor): gQ restores primary-cursor position #42071Justin M. Keyes2026-09-24
| | | | | | | | | | | | | | | | | | | | | Problem: Unlike "gv", "gQ" does not restore the primary-cursor position. This is inconvenient for workflows where you temporarily clear the cursors, navigate somewhere, then want to return to the multicursor session. Solution: Store the primary-cursor position at extmark-id 1 of the `'nvim.multicursor.last'` namespace. Note: users that *don't* want to restore the primary-cursor position can delete extmark-id 1 from the `'nvim.multicursor.last'` namespace just before `gQ`. (Intentionally undocumented because this interface is not final, and should not block Nvim 0.13 release.) vim.keymap.set('n', 'gQ', function() local ns = vim.api.nvim_create_namespace('nvim.multicursor.last') pcall(vim.api.nvim_buf_del_extmark, 0, ns, 1) return 'gQ' end, { expr = true })
* fix(multicursor): skip gQ during an active session #42068Justin M. Keyes2026-09-24
| | | | | | | Problem: gQ is nonsense during an active multicursor session. Solution: Make it a no-op.
* fix(multicursor): mapped jump merges cursors in follow-mode #42063Justin M. Keyes2026-09-24
| | | | | | | | | | | | Problem: Jumps (intentionally) don't cascade, thus they don't queue atoms. But in follow-mode, a mapping that moves the cursor but queues no atoms, LHS-cascades (this is a general fallback for the case where `keys` cannot be resolved). Thus `nnoremap <Down> ]C` replays `]C` at each cursor, which causes overlapping cursors, which are then merged/deduped. Solution: If a composite contains a "jump", set `composite.queued` to disable LHS-replay.
* fix(multicursor): don't dedupe primary-overlapping cursor #42060Justin M. Keyes2026-09-24
| | | | | | | | | | | | | | Problem: A primary-overlapping cursor is deduped before an edit. But if a Visual/Insert action moves the primary first, the cursor is not skipped (e.g. `vipQva)c` replays at the primary-overlapping cursor). Solution: Skip _replay_ of a primary-overlapping cursor, but don't _dedupe_ it. Keep its position synced with the primary. Sample the primary-overlapping cursor (`CmdOrigin.mcursor`) at the action start (first root frame, or Visual session-start), instead of current frame start.
* feat(multicursor): cgn, failed insert-entry #42054Justin M. Keyes2026-09-23
| | | | | | | | | | | | | | | | | | Problem: - A failed motion in a replay (`vt;` where there is no `;`) flushes the rest of the replay, so `vt;cX` inserts `X` without changing the selection. - If the Insert-entering cmd fails at a cursor (`ct;`, `cgn` with no match), the text is still inserted at the failed cursor. Solution: - `beep_flush()`: Don't flush typeahead (i.e. keys following the failed cmd) during mc-replay. - Aligns with interactively-typed behavior. - Remove a cursor if its Insert-entering command aborts (`beep && !changedtick`). - This is particular to Insert-entering commands (`c{motion}`), because they are tricky. We don't usually remove cursors if a replayed cmd happens to fail at some cursors.
* feat(multicursor): jump vs motion #42052Justin M. Keyes2026-09-23
| | | | | | | | | | | | | | | | | | | | Problem: Incoherent classification of motions vs jumps. Solution: Define "motion" as cursor-relative, and "jump" as "absolute". - Classify G/gg/H/L/M/go/N% as `CmdAtom.type=jump`. - Classify `*`/`#` as motions. Behavior changes: - `*` in follow-mode now moves each cursor to the next occurrence of its own word. - Note: the "last search pattern" is not stored per-cursor, so `n` still searches for the primary's search pattern. - G/gg/H/M/L in follow-mode do not cascade (would converge/dedupe all cursors). - If you want to force cursors to converge for some reason, use `9999j`. - Also affects mappings that mix an absolute move with an edit. E.g. mapping `nnoremap X ggdd` only replays `dd` per-cursor now. This is how marks already behaved.
* fix(multicursor): undo/redo mapping in follow-mode #42051Justin M. Keyes2026-09-23
| | | | | | | | | | Problem: In follow-mode, a mapping that moves the cursor but doesn't queue an atom, cascades LHS. Undo moves the cursor and (intentionally) does not queue an atom, so `nnoremap u u` replays undo per-cursor. Solution: - Set `composite.queued`, to skip LHS-cascade. - Also treat "U" (line-undo) as a "global op".
* fix(multicursor): edit applied twice at cursor overlapping the primary #42050Justin M. Keyes2026-09-23
| | | | | | | | | | | Problem: A cursor overlapping the primary is deduped by comparing positions at the clock edge, i.e. after the primary edit executed. A "replace" at the cursor cell ("rx", "~", "g~iw") shifts the overlapping extmark, so it no longer matches and gets its own replay. E.g. "vipQg~~" applies twice to the 2nd line, which inverts the effect. Solution: Decide "overlaps the primary" at cmd start, before the edit.
* fix(multicursor): revert "]C"/"[C" cursor-plopping behavior #42034Justin M. Keyes2026-09-22
| | | | | | | | | | | | | Problem: Jumping to a cursor adds one at the old position, so navigation has a side-effect. "]CQ" no longer deletes a cursor, and returning with "[C" after wandering off adds a cursor wherever you were. This is useful in some cases, but as a default it is surprising. The default behavior should be simple and composable. Solution: Revert the "]C"/"[C" cursor-plopping behavior. Document a mapping for the "rotate" behavior.
* fix(multicursor): cascade mapping-edit during Visual selection #42027Justin M. Keyes2026-09-21
| | | | | | | | | | | | | | | | Problem: - A mapping that edits the buffer during a Visual selection applies only at the primary cursor. The edit "voids" the pending Visual-session, because `mc_vsel_refresh` only previews the selection per-cursor and must not edit. - A cursor overlapping the primary applies an edit twice, if the command moves the primary before cascade ("yiwp"). Solution: Cascade a Visual session's edits span-by-span, like an insert-session. - Each span is prefixed with "gv" so per-cursor reselect works. - Void only if no subatom was captured. - Dedupe cursors against the primary's anchor at cmd start, not its position after.
* fix(cmdatom): capture <Cmd>, not its subatoms #42020Justin M. Keyes2026-09-21
| | | | | | | | | | | | | | | | | | | Problem: A command's `:norm` children are captured as Visual subatoms: `v<Cmd>normal! e<CR>d` is "decomposed" to `ved`. That is a cosmetic, nice-to-have feature, which greatly complicates the cmdatom logic: it must detect "lossy" cases (API moves, "gv" on marks the command set, a session ended and restarted). Solution: Drop the nice-to-have. - A command is captured as itself, never its `:norm` children. - While a child frame runs, a pending Visual session is kept open until the enclosing frame resolves. - `:`/`<Cmd>` no longer decline to be a Visual subatom. - Stuffed keys ("." replay, "x" => "dl") and K_EVENT children (RPC, timer), are still captured as their translation. - `mc_add()` discards any pending Visual session, so `{Visual}Q` does not cascade recursively to the cursors it just created.
* fix(multicursor): replay of Lua mapping-id ending in "0" #42011Justin M. Keyes2026-09-20
| | | | | | | | | | | | | | | | Problem: - A captured Lua mapping (`K_LUA`+id) whose id ends in "0" replays the wrong mapping: `atom_from_cmdline()` escapes the id like a typed cmdline (trailing "0" => CTRL-V "048"), but the id is read raw. E.g. treesitter `an` (id 60) replays `gc` (id 6), so `van` does not preview/cascade at mcursors. - Same for `<Cmd>…` ending in "0" or "^" (`<Cmd>normal! 0<CR>`). - `c` + Lua/":" textobj (`canX`) does not insert-cascade. Solution: - Only CTRL-V-escape ":", "/" cmdline; append `<Cmd>` and Lua mapping-ids "raw" (`sb_add_spec()`). - `kVInsMotion`: an insert entered by Ex/Lua motion re-executes the motion, unless it read input.
* fix(multicursor): selection by API/Lua from mapping #41999Justin M. Keyes2026-09-19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: A Visual selection produced by a Lua mapping is captured as the keys it fed (`:norm!`), so non-primary cursors get the wrong selection. Examples: - API cursor-moves around a fed "o" are lost. - `setpos("'<")` + "gv" reselects the primary's marks (treesitter `an`). - A mapping that feeds an absolute selection (`:norm! <Esc>`, then `norm! 3GV6G`). Solution: Classify fed keys as `lossy` if their produced selection differs from the selection at mapping-end, or fed-key-start: the mapping moved it by other means (API). Same idea as `composite.lossy` LHS-replay. Now the captured Visual session contains the mapping's own cmd (`<Cmd>…`, `:…`, or a Lua mapping-id) as one subatom, instead of the keys it fed. E.g. `v…<K_LUA id>` instead of `v…V…G`. Also affects dot-repeat ("."). A `:norm!` that ends a typed selection keeps the Visual session (`vatom`) open (instead of the usual `atom_visual_reset()` plus emit/stage), so the enclosing user frame (the mapping's `<Cmd>`/Lua, or a typed `:norm!`) can complete or replace it. - A child frame re-entering Visual does not restart it, so a later `norm! V` continues that session instead of a new `kVatomFed` one. - At end of the user (toplevel) frame, the fed subatoms are dropped in favor of the mapping's own atom: as a subatom if Visual is active, else as the session's closing suffix.
* fix(cmdatom): feedkeys() without "t" emits CmdAtom #41996Justin M. Keyes2026-09-19
| | | | | | | | | | | | | Problem: `nvim_feedkeys('gj', 'm')` (remap, but not "t"=typed) emits a CmdAtom for the mapping's insert session. Same for `feedkeys('ihello<Esc>', '')`. Keys fed without "t" land in `tb_maplen` ("mapped prefix"), just like a mapping's expansion, and `atom_is_user_input()` treats that as user input. Solution: Narrow the `atom_is_user_input` condition. A mapping resolved from typed keys always has a composite by the time its commands run, so `KeyTyped || (user cmd && composite active)` is sufficient.
* fix(multicursor): visual "gv", change-marks '[,'] #41988Justin M. Keyes2026-09-18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: - `gv` reselects only primary's region, it doesn't have per-cursor behavior. '< '> are buffer-global and the sandbox restores the primary's marks. The Visual atom containing `gv` was voided anyway, so it never cascaded. - Same for change-marks (`'[ '] '.`): they are stale after edits from other cursors, not managed per-cursor. - `McSandbox` saves "editor state", which should be owned by the `Context` module. Solution: Lift more state from `McSandbox` into `Context`. `kCtxCursor` (position, curswant) and `kCtxMarks` (Visual area, change-marks), are owned by `Context` now, as an "in-memory" special-case (TODO: support it for the "serialized" case?). - Classify a `gv` selection as replayable. Manage its state per-cursor. Dot-repeat "." after `gv` behaves like Vim (the "1v" fallback). - Save/restore change-marks per-cursor. The primary's change-marks are shifted by edits from other cursors during the cascade. `McSandbox` still contains (for now) the view and replay isolation (typeahead/mode, redobuff, search patterns, the active selection). Bonus: - `visualmode()` is per cursor. - A cursor's `curswant` follows its column when other cursors' edits shift it, instead of the column captured after its own replay.
* fix(cmdatom)!: diff-mode "do"/"dp" not captured properly #41982Justin M. Keyes2026-09-18