<feed xmlns='http://www.w3.org/2005/Atom'>
<title>rneovim.git/test/functional/editor/cmdatom_spec.lua, branch master</title>
<subtitle>Neovim fork with Rahm's personal hacks.</subtitle>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/'/>
<entry>
<title>test: simplify functional test expectations</title>
<updated>2026-10-05T16:33:44+00:00</updated>
<author>
<name>Lewis Russell</name>
<email>lewis6991@gmail.com</email>
</author>
<published>2026-10-05T14:37:06+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=483815ab45cf8fc08804e0cfa95b126493a5dd1f'/>
<id>483815ab45cf8fc08804e0cfa95b126493a5dd1f</id>
<content type='text'>
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
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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
</pre>
</div>
</content>
</entry>
<entry>
<title>fix(input): aborted dot-repeat causes ModeChanged during emsg() #42181</title>
<updated>2026-09-30T22:37:00+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-30T22:37:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=c3874b3fb50788bc74d135686657f5a48beeb02d'/>
<id>c3874b3fb50788bc74d135686657f5a48beeb02d</id>
<content type='text'>
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`.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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`.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(multicursor): zq edge cases; cascade perf #42165</title>
<updated>2026-09-30T16:22:29+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-30T16:22:29+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=9f7fb8b27dc03daf21ff4524b982e1d6e982ca5e'/>
<id>9f7fb8b27dc03daf21ff4524b982e1d6e982ca5e</id>
<content type='text'>
- `{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').</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- `{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').</pre>
</div>
</content>
</entry>
<entry>
<title>fix(input): end Visual mode when aborting redo #42151</title>
<updated>2026-09-30T14:16:27+00:00</updated>
<author>
<name>Qiming zhao</name>
<email>chemzqm@gmail.com</email>
</author>
<published>2026-09-30T14:16:27+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=cc4e0c8d60ede60d2a48efe322a9bd1f71198b8a'/>
<id>cc4e0c8d60ede60d2a48efe322a9bd1f71198b8a</id>
<content type='text'>
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</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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</pre>
</div>
</content>
</entry>
<entry>
<title>feat(multicursor): zq operator; cursor-local marks #42148</title>
<updated>2026-09-29T23:51:43+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-29T23:51:43+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=ac9ddec6b855a54193899f95da2d94d8224b31af'/>
<id>ac9ddec6b855a54193899f95da2d94d8224b31af</id>
<content type='text'>
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.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(multicursor): "gv" + Insert-entering cmd #42110</title>
<updated>2026-09-27T11:24:28+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-27T11:24:28+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=a835a3f1a09653a6b201dc08413b33a2b7c0db0a'/>
<id>a835a3f1a09653a6b201dc08413b33a2b7c0db0a</id>
<content type='text'>
Problem:
- Multicursor does not cascade a `gv`-entered insert-session (`gvc`).
- CmdAtom of a `gv`-entered insert-session (e.g. `gvcX&lt;Esc&gt;`) has
  `keys="1vcX&lt;Esc&gt;"` (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" =&gt;
"rx").

Redo behavior is unchanged ("1v" fallback): "gv" is absolute, "." acts
at the cursor.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
- Multicursor does not cascade a `gv`-entered insert-session (`gvc`).
- CmdAtom of a `gv`-entered insert-session (e.g. `gvcX&lt;Esc&gt;`) has
  `keys="1vcX&lt;Esc&gt;"` (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" =&gt;
"rx").

Redo behavior is unchanged ("1v" fallback): "gv" is absolute, "." acts
at the cursor.</pre>
</div>
</content>
</entry>
<entry>
<title>feat(multicursor): jump vs motion #42052</title>
<updated>2026-09-23T16:11:00+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-23T16:11:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=1088dffe8203095744bc899d1687d5e1e7e983c6'/>
<id>1088dffe8203095744bc899d1687d5e1e7e983c6</id>
<content type='text'>
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.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(multicursor): cascade mapping-edit during Visual selection #42027</title>
<updated>2026-09-21T19:54:57+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-21T19:54:57+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=32665c454979ee137f4a3db16baec350205b73ee'/>
<id>32665c454979ee137f4a3db16baec350205b73ee</id>
<content type='text'>
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.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(cmdatom): capture &lt;Cmd&gt;, not its subatoms #42020</title>
<updated>2026-09-21T12:04:55+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-21T12:04:55+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=8894b96ec8ea893bc0f9620c99b06070bca4efdb'/>
<id>8894b96ec8ea893bc0f9620c99b06070bca4efdb</id>
<content type='text'>
Problem:
A command's `:norm` children are captured as Visual subatoms:
`v&lt;Cmd&gt;normal! e&lt;CR&gt;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.
- `:`/`&lt;Cmd&gt;` no longer decline to be a Visual subatom.
- Stuffed keys ("." replay, "x" =&gt; "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.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Problem:
A command's `:norm` children are captured as Visual subatoms:
`v&lt;Cmd&gt;normal! e&lt;CR&gt;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.
- `:`/`&lt;Cmd&gt;` no longer decline to be a Visual subatom.
- Stuffed keys ("." replay, "x" =&gt; "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.</pre>
</div>
</content>
</entry>
<entry>
<title>fix(multicursor): replay of Lua mapping-id ending in "0" #42011</title>
<updated>2026-09-20T14:19:50+00:00</updated>
<author>
<name>Justin M. Keyes</name>
<email>justinkz@gmail.com</email>
</author>
<published>2026-09-20T14:19:50+00:00</published>
<link rel='alternate' type='text/html' href='http://git.josher.dev/rneovim.git/commit/?id=0ea627cfb7713dd77dab00fff1073e5e407f263e'/>
<id>0ea627cfb7713dd77dab00fff1073e5e407f263e</id>
<content type='text'>
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" =&gt; 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 `&lt;Cmd&gt;…` ending in "0" or "^" (`&lt;Cmd&gt;normal! 0&lt;CR&gt;`).
- `c` + Lua/":" textobj (`canX`) does not insert-cascade.

Solution:
- Only CTRL-V-escape ":", "/" cmdline; append `&lt;Cmd&gt;` and Lua
  mapping-ids "raw" (`sb_add_spec()`).
- `kVInsMotion`: an insert entered by Ex/Lua motion re-executes the
  motion, unless it read input.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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" =&gt; 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 `&lt;Cmd&gt;…` ending in "0" or "^" (`&lt;Cmd&gt;normal! 0&lt;CR&gt;`).
- `c` + Lua/":" textobj (`canX`) does not insert-cascade.

Solution:
- Only CTRL-V-escape ":", "/" cmdline; append `&lt;Cmd&gt;` and Lua
  mapping-ids "raw" (`sb_add_spec()`).
- `kVInsMotion`: an insert entered by Ex/Lua motion re-executes the
  motion, unless it read input.</pre>
</div>
</content>
</entry>
</feed>
