Commit Graph
6061 Commits
Author SHA1 Message Date
Barrett Ruth 4ceb92cd76 feat(dir): open entries in splits with a, o mappings #41834 2026-09-11 19:01:41 -04:00
Justin M. Keyes a6d91a8d7c feat(multicursor): {Visual}[count]Q matches in Visual selection #41863
Problem:
`[count]Q` cannot be limited to a Visual selection.

Solution:
`{Visual}[count]Q` places cursors on matches within a Visual selection
(linewise).

TODO:
This works linewise, even if the visual selection is charwise/block. If
we really want to limit by charwise/block selection, then we should add
that feature to `seachpos()` or similar. Every caller of `seachpos()`
should not have to cobble together bespoke support thereof.
2026-09-11 10:30:53 -04:00
Justin M. Keyes fbe3a6131e fix(multicursor): {Visual}Q should not move primary cursor #41862
Problem:
`{Visual}Q` moves the primary to the top of the selection, for no
particular reason. And it's inconsistent with `[count]Q`.

Solution:
Keep the primary on the line where the selection ended, aligned to the
shared screen column so it still coincides with that line's cursor.
2026-09-11 09:22:46 -04:00
glepnir 2a344d8c84 fix(lsp): snippet is not expanded when resolve races the user #41774
Problem:
on_complete_done() defers clear_word() and the snippet expansion until
completionItem/resolve answers, and drops both when 'changedtick' moved
meanwhile. Typing right after accepting leaves the plain word in the
buffer.

Solution:
Expand before requesting, and anchor the resolved edits with an extmark
instead of gating them on 'changedtick'.
2026-09-11 07:49:57 -04:00
Barrett Ruth f5c4ef5c25 feat(lsp): support timeout_ms for async formatting #41850
Problem:
`vim.lsp.buf.format()` does not support a timeout for asynchronous
requests.

Solution:
Honor an explicit timeouts per client so formatting can continue.
Do not permit a default value for async format requests.
2026-09-11 05:25:33 -04:00
Justin M. Keyes 8c292c96dd fix(autocmd): dot-repeat triggers InsertCharPre #41806
Problem:
InsertCharPre is triggered for stuffed text (".", i_CTRL-R, i_CTRL-A).
But that text was already transformed when it was typed: the `v:char`
result is appended to the redo buffer literally (`redo_append_lit()`).
So "." transforms it again, e.g. an autopair handler turns "()" into
"())".

Solution:
Skip InsertCharPre for stuffed text.

Precedent: `vgetorpeek()` disables abbreviations for stuffed text for
the same reason (it is post-expansion).

Macros are unaffected.
2026-09-10 05:57:03 -04:00
Lewis Russell d039f19af5 build: enable more EmmyLua checks
Enable checks for unused code, deprecated calls, return types, and
annotations.

Fix the warnings and replace the deprecated highlight function. Keep
exceptions where old APIs are still needed or the checker gets it wrong.

AI-assisted
2026-09-09 22:31:58 +01:00
glepnir 08dd3adffb feat(api): add ev.win to autocmd callback args #39826
Problem: Autocmd callbacks currently have to rely on curwin, which may
already have changed by the time they run. This is especially noticeable
for WinNew, WinClosed, WinResized and WinScrolled.

Solution: Track the window in the autocmd context and expose it as ev.win.
Pass it explicitly for the window events that need it.
2026-09-09 15:42:20 -04:00
Justin M. Keyes ac167f943a fix(terminal): check file timestamps on terminal-job exit #41814
Problem:
When a `:!` command runs, file timestamps are checked and W12 or
`FileChangedShell` is triggered. But not when a `:terminal` job exits.

Only `enter_buffer()` checks, so whether you get the W12 warning depends
on how you happen to return to the file: `:term` works, `:tabnew | term`
does not.

    echo foo > testfile
    nvim --clean testfile
    " Edit the buffer, don't save it.
    :!mv testfile testfile2
    :tabnew | term sh
    touch testfile2 && mv testfile2 testfile
    exit

'autoread' is defeated because `:!mv` deletes the file, so
`should_watch()` fails and the watcher stops. `ensure_watcher()` only
re-runs on `BufReadPost`/`BufWritePost`/`OptionSet`, so nothing watches
the file when the terminal moves it back.

Solution:
Set `need_check_timestamps` on terminal-job exit, same as `:!cmd`
(`os_shell`).
2026-09-09 15:14:26 -04:00
Justin M. Keyes d24cafc06a fix(multicursor): failed motion at primary is still cascaded #41812
Problem:
In follow-mode, a motion that fails at the primary cursor (e.g. "j" at
EOB) still cascades to other cursors, so they move while the primary
does not, which causes them to be deduplicated...

Also affects Visual sessions: "Vjd" at EOB deletes 1 line at the primary
but (potentially) 2 lines at every multicursor.

Solution:
If a motion "beeps", don't replay it.

"3w" near the end still replays (it moved), as does "0" at column
0 (does not beep). This feels like a usable and intuitive compromise.
2026-09-09 12:10:01 -04:00
Olivia Kinnear ec2c58ed26 docs: add help tag for vim.async 2026-09-09 15:50:38 +01:00
Volodymyr Chernetskyi 8e0045f43a feat(lsp): support workspace/foldingRange/refresh #41780
Problem:
Servers cannot request refreshing stale LSP folding ranges after a
project-wide change.

Solution:
Advertise `workspace.foldingRange.refreshSupport` and re-request folding
ranges for active buffers when handling `workspace/foldingRange/refresh`.

AI-assisted
2026-09-09 08:45:10 -04:00
Justin M. Keyes cb2e9cdfd3 fix(multicursor): clipboard=unnamed, explicit "+yy #41804
Problem:
- With `clipboard=unnamed[plus]`, per-cursor yanks are joined into '"'
  on exit, but not the clipboard.
- Multicursor `"+yy` calls the clipboard provider per-cursor, behaving
  as "last wins".

Solution:
- Never cascade to/from the clipboard provider.
- Implicit clipboard (`clipboard=unnamed[plus]`) uses the cursor-local
  unnamed register, so the cascade needs no `start_batch_changes()`. On
  exit, the clipboard gets the same joined result as the `"` register.
- Operations that reference the explicit clipboard registers `"+` / `"*`
  while multicursor is active, use the cached (primary) clipboard value.
2026-09-09 07:25:32 -04:00
Lewis Russell 6a54396db4 build: enable more EmmyLua checks
- call-non-callable
- missing-fields
- redefined-label
- redefined-local
- undefined-field
- unreachable-code

Promote redefined-local and unreachable-code to warnings.

Fix DOS line-ending handling for multiline semantic tokens, and support
intersection types in the help parser.

AI-assisted
2026-09-08 16:50:53 +01:00
zeertzjqandVrushali-Z e66fdc1eac vim-patch:9.2.1038: CursorLineFold/Sign highlighting depends on 'cursorlineopt' (#41785)
Problem:  CursorLineFold and CursorLineSign are only applied when
          'cursorlineopt' contains "number" or is "both"
          (Evgeni Chasnovski).
Solution: Apply those groups whenever 'cursorline' is set, independent
          of 'cursorlineopt' (Vrushali Zampalkar).

fixes:  vim/vim#20480
closes: vim/vim#21112

https://github.com/vim/vim/commit/1f8d3c44c5bd5a3d5032b3fc53e9d3aa1052583c

Co-authored-by: Vrushali-Z <zampalkarvasu@gmail.com>
2026-09-08 15:24:45 +00:00
glepnir b3bd442c5c fix(lsp): completion dynamicRegistration breaks capability readers #41771
Problem:
A server that supports dynamic registration must not also declare
completionProvider at initialize, so server_capabilities.completionProvider
is nil for anything reading it directly.

Solution:
Do not advertise it by default. A client that follows a registration can
declare it itself.
2026-09-08 05:48:38 -04:00
Lewis Russell 65ef6fdaee build: replace LuaLS with EmmyLua
Problem: LuaLS struggles with the generics used in Nvim's runtime,
requiring broad diagnostic suppressions. Indexing is also slow.

Solution: Use EmmyLua for type checks in the build and CI. It offers
more sophisticated type checking, substantially better support for
generics, and much better flow analysis.

Correct the affected annotations. Use `@internal`, supported directly by
EmmyLua, instead of `@nodoc` for shared internal declarations, and
support it in the help parser.

AI-assisted
2026-09-07 15:33:22 +01:00
Lewis Russell cd52c77cd5 fix(help): resolve generic and nullable type references
Problem: K on generic and nullable type annotations can jump to the
wrong help tag. Generated See references repeat the type names.

Solution: Strip generic arguments and nullable suffixes when resolving
help tags. Remove the redundant generated See references.

AI-assisted
2026-09-07 15:33:22 +01:00
b222398553 vim-patch:57d6d00: runtime(doc): Add documentation style
closes: vim/vim#17627

https://github.com/vim/vim/commit/57d6d004331f1770b5f04ba28ac242c0e0c8a005

Co-authored-by: Damien Lejay <damien@lejay.be>
Co-authored-by: Phạm Bình An <111893501+brianhuster@users.noreply.github.com>
2026-09-06 23:57:11 -04:00
Jan Edmund LazoandHirohito Higashi 594381d758 vim-patch:0ed11ba: runtime(doc): Tweak documentation style a bit
https://github.com/vim/vim/commit/0ed11ba223ec69dfefc8cc5800fb3e0d610fd9f8

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-09-06 23:56:32 -04:00
zeertzjqandYegappan Lakshmanan 797171f45f vim-patch:ca2e65a: runtime(doc): Update quickfix help text with missing information
closes: vim/vim#21229

Supported by AI.

https://github.com/vim/vim/commit/ca2e65a842d93bd6e3f433ce36b55ec450a2bb1a

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
2026-09-07 08:05:09 +08:00
Justin M. Keyes bd43394d4e fix(multicursor): skip insert live-mirror on conflicting edits #41730
Problem:
Cursors placed same-line before the primary, or producing multiline
edits on lines above the primary, shift the text in a way that breaks
the insert-mode live-mirroring.

Solution:
Skip live-mirroring under those conditions.

TODO (future): we could support live-mirroring if ins-completion's
internal bookkeeping tracked its regions more precisely.
2026-09-06 10:04:47 -04:00
Volodymyr Chernetskyi 06bff27929 feat(ui2): highlight the [+x] spill indicator with MoreMsg #41679
Problem:
The "spill" indicator that ui2 appends when messages overflow the
available height is drawn with whatever highlight the message tail
happens to have, so it is indistinguishable from the message text.

Solution:
Give the [+x] chunks an explicit `MoreMsg` highlight, and only fall back
to the message tail highlight for chunks that don't carry one of their
own.

AI-assisted
2026-09-04 14:28:22 -04:00
Volodymyr Chernetskyi b21f2094ba feat(ui2): scroll the dialog window with the mouse wheel #41682
Problem:
The ui2 dialog implements paging for the arrow keys, Home/End and the
page keys, but not for the mouse wheel. When `mouse` contains `"c"`,
turning the wheel does nothing at all.

Solution:
Handle <ScrollWheelUp>/<ScrollWheelDown>, scrolling by the `mousescroll`
`"ver"` amount.

AI-assisted
2026-09-04 11:33:53 -04:00
Justin M. Keyes 2124f968a6 feat(multicursor): "]C"/"[C" leave a cursor at old position #41681
Problem:
`]C` jumps the primary onto another cursor, which dedupes at the next
edit. Every `]C` consumes a cursor.

Solution:
`]C` adds a cursor at the current position before jumping. This
effectively "rotates" the primary cursor.
2026-09-04 06:28:42 -04:00
Lewis Russell ce8a897f98 feat(lua): add vim.async
Problem: Nvim has many Lua APIs that start callback-driven work: timers,
jobs, libuv handles, and other event-loop tasks. Callers that need to
sequence or cancel that work have to build their own coroutine wrappers,
task bookkeeping, and cleanup rules. This makes async control flow hard
to share, test, and document.

Solution: Add `vim.async`, a structured-concurrency module vendored from
async.nvim. It provides task handles, await/pawait helpers,
sleep/timeout helpers, completion-order iteration, and semaphores on top
of Nvim's event loop.

The API follows the same broad model as Trio: async work has an owner,
tasks are awaited explicitly, and cancellation is cooperative. Include
generated vimdoc with an introductory overview and examples, a news
entry, and functional tests for the new module.

AI-assisted
2026-09-03 19:17:25 +01:00
Justin M. Keyes 80e9708afa fix(multicursor): atom may cascade in another buffer #41624
Problem:
An atom queued in buffer A cascades on B's cursors if the mapping ends
in B ("nnoremap X x:bnext<CR>").

Solution:
Check the atom's origin buffer (`CmdAtom.origin.buf`).

Note: This does not preclude mappings etc from doing work in temporary
throwaway buffers, as long as they return to the origin buffer.
2026-09-02 10:38:27 -04:00
Justin M. Keyes 350fa5ad7c fix(multicursor): act on fold contents, not the fold itself #41622
Problem:
If an edit cascades to cursor(s) that happen to be within a closed fold,
the edit acts on the fold itself (`:h fold-behavior`). E.g. "dd" deletes
the entire fold, not the cursor's line within the fold.

Solution:
Check `mc_replaying()` in `hasAnyFolding()`, so folds are ignored during
a multicursor cascade. This means multicursor always replays relative to
text *within* the fold.
2026-09-02 09:42:40 -04:00
Justin M. Keyes 7168e0d12f fix(mcursor): drop q= "follow motion" message 2026-09-02 13:09:30 +02:00
zeertzjqandEisuke Kawashima 90fc8946e8 vim-patch:fac9e33: runtime(doc): fix example output of cosh (#41609)
closes: vim/vim#21197

https://github.com/vim/vim/commit/fac9e333a8d38e7049e6628e0f5157f4b7c44d2c

Co-authored-by: Eisuke Kawashima <e-kwsm@users.noreply.github.com>
2026-09-02 13:52:12 +08:00
Justin M. Keyes 9a29622b54 feat(multicursor): MC HAMMER #41587
Other (squashed) commits:

fix(tui): emit ui_send output atomically with the frame

Problem:
tui_ui_send() writes directly to the TTY, bypassing the output buffer.
Sequences sent via nvim_ui_send() (e.g. kitty multiple-cursors, or
visual-dot-repeat) always arrive in a separate TTY write from the frame
they were computed for. This manifests as "tearing", or e.g. in the case
of multicursor the terminal renders text with stale cursor overlays.

Solution:
- tui_ui_send(): while a frame is being assembled (pending invalid
  regions or buffered output), buffer instead of writing directly.
  - Out-of-frame sends (tty queries, clear-on-disable) still write
    immediately.
- mcursor.lua: emit the terminal-cursor update at the end of the redraw
  cycle (`on_end`, when screen positions are final) instead of
  vim.schedule().
2026-09-01 15:17:22 +00:00
Justin M. Keyes b542f3a8f8 fix(cmdatom): edit-repeat mapping #41564
Problem:
The "." example mapping at `:h edit-repeat` doesn't work well with
`nvim_feedkeys(…, 'mt', false)`.

Solution:
Use `vim.b[ev.buf].maxseq` instead of `undotree()`.
2026-08-30 23:38:34 +00:00
Justin M. Keyes 25f7c87a70 fix(mappings): replaying a deleted Lua mapping is UB
Problem:
Replaying a deleted Lua mapping, may call an arbitrary function.

RHS of a Lua mapping embeds its LuaRef (`<K_LUA><ref><CR>`). The raw
keys may outlive the ref (redobuff ".", CmdAtom `keys`). If the mapping
is deleted, replaying it either (1) dereferences a freed registry slot,
or (2) calls whatever callback reused the slot (autocmd, timer, other
mapping).

Solution:
Assign a monotonic (never recycled) id to Lua mappings and encode the
mapping keys as `<K_LUA><id><CR>`.

Note: in the case of Vimscript, a deleted function raises E117, but if
the function is redefined with the same name, the mapping will find it.

Alternatives?:
- Globally ensure `LuaRef` ids are not recycled.
  - Problem: could exhaust `int` in a long-lived Nvim session? Also,
    difficult to impl bc the "recycling" is done by `luaL_ref` itself.

ref: 5ac2e47acc
2026-08-31 00:16:01 +02:00
Justin M. Keyes 2514256d95 refactor(input): exec stuffed keys eagerly
Problem:
The Vim "stuff" concept breaks the ability to reason about the call
stack and thus the boundaries of a `CmdAtom`: a stuffed translation ("x"
=> "dl") defers to the main loop. This "continuation" must be modeled in
`CmdAtom`, by checking global flags at undefined times, during undefined
circumstances.

Solution:
- After a stuffed "translation", eagerly execute the stuff buffer
  (`exec_stuffed()`).
- Delete the CmdAtom "continuation" junk.

Note:
- op_colon runs its cmdline "nested", but that's fine because operators
  already nest interactive sessions there (op_change runs edit()), and
  the cmdline is frameless so the operator's frame can own/capture it.
2026-08-29 01:06:26 +02:00
Rob Pilling 61958f2335 fix(cmdwin): allow a user to switch to other buffers #41199 2026-08-28 13:34:31 -04:00
Justin M. Keyes 7e2e3f8c25 feat(editor): undo restores cursor position #41520
Problem:
Undo places the cursor wherever the cursor happened to sit at "save
time" (`uh_cursor` is sampled lazily on the first change).
Examples:
- `i` preserves, but `a` does not
- `diw`, `atest<Esc>`, `d^` abandon the original position
- `D`, `o` restore it (by accident).

Solution:
`composite` tracks the pending atom (and its `origin`) across frames.
A `stuffed` continuation frame inherits the `origin` + prepped redo.
Store `origin` info in the undo header, so undo can restore it.

- Not for a mid-command undo break (i_CTRL-G_u).
- Undoing a mapping restores where the mapping started (which
  technically may be different than where the "edit" started).
2026-08-27 16:12:11 -04:00
zeertzjqandHirohito Higashi ec982dfb93 vim-patch:9.2.1004: a completion function cannot tell why it was called (#41500)
Problem:  A function used through 'omnifunc' or 'complete' is called the
          same way whether 'autocomplete' started the completion or a
          key asked for one, so it cannot answer differently.
Solution: Report which of the two it is in complete_info() as "auto". It
          is returned only when asked for in {what}, so what
          complete_info() says by itself does not change
          (Hirohito Higashi).

closes: vim/vim#21143

https://github.com/vim/vim/commit/1f56c351dedad288f79c89b6b6f64be762ec3b9b

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-08-26 07:21:22 +00:00
Justin M. Keyes 3d6c4555a7 build: don't require the "vimdoc" parser to build Nvim
Problem:
The runs ":helptags", which needs the tree-sitter-vimdoc parser.
This may cause problems for package maintainers / distros?

Solution:
Use running to generate the tags, like the zig build already does.
It also errors on duplicate tags, which is good.

The `:helptags` command still uses treesitter.
2026-08-25 13:36:01 +02:00
Justin M. Keyes 1ef030f162 fix(help): :helptags regressions
Problem:
Parent commit regressed some behavior of the old C helptags-gen impl:
- helpfiles in sub-directories are named by basename, so :help fails
- "help-tags" always names "tags", never "tags-nl"
- E150 E151 E152 E153 are never reported
- existing tags file is not overwritten if no tags were found
- a duplicate tag aborts the run, skipping the remaining directories
- `*.TXT` and `*.FRX` (uppercase) are not recognized as helpfiles
- tree-sitter-vimdoc accepts tags that the C parser rejected: `*a|b*`
  (breaks |links|) and unterminated `*tag`
- PUC Lua "<" compares with (localized) `strcoll()`, so the tags file is
  not sorted by byte value (E432)
- requiring `vim.treesitter` at load time breaks :help itself, not just
  :helptags, where the module is unavailable
- `vim.pack` runs :helptags for plugins that have no "doc/" directory,
  so every install/update emits E150

Solution:
- Fail the build if generating helptags reports any `v:errmsg`.
- Restore old behavior: tags generated for runtime/doc are now identical
  to those from the C implementation. Errors are non-fatal messages
  instead of exceptions, so all directories are still processed.
- Load treesitter lazily, report a plain error if parser is missing.
2026-08-25 13:32:25 +02:00
Yochem van Rosmalen b36b3d7f3a feat(help): generate :helptags using Treesitter
Problem:
Tags are manually parsed in C which is not flexible and prone to errors.
Extending the help system to allow for other formats (e.g. Markdown)
would require a large rewrite in the C core, while with Treesitter it
only needs a query update.

Solution:
Use the power of treesitter to extract the tags from helpfiles.

- build: set `$VIMRUNTIME` when generating helptags, like
  `cmake/Util.cmake` already does for other generators.
- fix(help): only accept tags delimited by whitespace. The old C parser
  only accepted a `*tag*` preceded by start-of-line or whitespace and
  followed by whitespace or end-of-line. The vimdoc parser also captures
  tags followed by other text, e.g. `*$XDG_STATE_HOME*/.../logs` in
  starting.txt, which caused an E154 duplicate tag error for docs that
  were previously fine.
2026-08-25 10:52:12 +02:00
Justin M. Keyes a1de07418b feat(ui2): lift ui2 options into 'messagesopt' (part 1) #41474
Problem:
In order for ui2 to graduate to the main "messages ui" its configuration
needs to graduate into actual options.

Solution:
Migrate some of its config to 'messagesopt':
- "maxheight" (note: currently this is an integer treated as
  a "percentage"; if we want to support a row count we could allow
  values with units, like `"42%"`)
- "pager"
- "timeout"

Also improves error messages:

    messagesopt=hit-enter,history:500,bogus       E474: Unknown item 'bogus'
    messagesopt=hit-enter,history:500,progress:x  E474: 'progress' must be one of: , c
    messagesopt=hit-enter,history:abc             E474: 'history' requires a number
2026-08-25 03:58:17 -04:00
Justin M. Keyes 510f61555b fix(ui2): pager_char does not match keycode aliases #41468
Problem:
`pager_char` compares the `keytrans()` result exactly. E.g. `pager_char
= "<cr>"` does not work, it expects `<CR>` (uppercase).

Solution:
Normalize `pager_char` in enable().
2026-08-24 15:01:50 -04:00
Justin M. Keyes 8c440c469b fix(ui2): ui2 misinterprets getchar() input as pager_char (CR) #41465
Problem:
`vim.on_key()` callbacks are invoked for keys that `getchar()` consumes,
which never reach the main loop, and there is no way to tell such a key
apart.  With ui2 the `on_key` handler activated after interactive
cmdline, handles it as `pager_char` (thus enters the ui2 pager).

Solution:
Skip `vim.on_key()` callbacks during `getchar()`/`getcharstr()`.
2026-08-24 10:18:47 -04:00
glepnir 92d5531f96 vim-patch:9.2.1001: complete_info() does not report the item highlight groups (#41461)
Problem:  complete_info() omits "abbr_hlgroup" and "kind_hlgroup".
Solution: Keep the highlight group ID with the match instead of the
          resolved attribute and add both entries to the returned items
          (glepnir).

closes: vim/vim#21105

https://github.com/vim/vim/commit/1c32cede0afdc9351d5887e2f25977d4fb964d9f
2026-08-24 14:35:25 +08:00
zeertzjqandJosep Puigdemont cbe513fca6 vim-patch:63d08d4: runtime(doc): update :h write-plugin and readdir() example
1) The complete example plugin at :h write-plugin the end of the
   documentation didn't reflect the snippets provided during the
   tutorial. In most of the Add() function, interpolated strings are
   used, but the final result used concatenated strings.

2) The example provided in readdir() to get a list of files ending in
   ".txt" didn't properly escape the dot in the regular expression:
      readdir(dirname, {n -> n =~ '.txt$'})
   This would match any file ending with "txt" that is at least 4
   characters long, instead it should be:
      readdir(dirname, {n -> n =~ '\.txt$'})

closes: vim/vim#21123

https://github.com/vim/vim/commit/63d08d43862ed195da78cfb1bebe2c0ed02f80b7

Co-authored-by: Josep Puigdemont <josep.puigdemont@gmail.com>
2026-08-24 08:17:27 +08:00
zeertzjqandChristian Brabandt 15beb0f7ce vim-patch:ef461d1: runtime(doc): fix typo in :h substitute-repeat
fixes: vim/vim#21136

https://github.com/vim/vim/commit/ef461d18e3729f6ef71e2d69e320fbcdf13acda2

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-24 08:15:10 +08:00
Justin M. Keyes 69bf8c7792 fix(cmdatom): terminal-mode keys leak into mapping lhs #41455
Problem:
A mapping that enters terminal-mode (`:FzfLua files` via `:startinsert`)
never reaches a composite-end: terminal-mode runs no "normal" CmdFrames.
The composite collects the entire terminal session (and more) into `lhs`.

E.g. if I have `<M-/>` mapped to open `:FzfLua files`, then interact
with fzf-lua UI, the emitted CmdAtom looks like:

    <M-/>… => { type='mapping', lhs='<M-/><C-N><C-N><CR>', keys=nil }

Solution:
End the composite when terminal-mode is entered, which emits a more
meaningful and repeatable atom:

    <M-/>… => { type='mapping', lhs='<M-/>', keys=nil }
2026-08-23 15:04:11 -04:00
Justin M. Keyes bb82f9612c fix(cmdatom): "!" operator hardcodes its range #41451
Problem:
The "!" operator stuffs its cmdline continuation (`:.,.+1!`), so its
frame ends before capture (stuff pending) and the redo-prep disappears
with it.

    !ipsort<CR> => { type='excmd', lhs=':.,.+1!sort<NL>', keys=':.,.+1!sort<NL>' }

Compare to builtin "." which works bc `do_bang()` completes the redo
(`!ip` + `sort<NL>`).

Solution:
Appoint the stuffed continuation frame as the "redo-prep" frame.

    !ipsort<CR> => { type='operator', operator='!', lhs='!ipsort<NL>', keys='!ipsort<NL>' }

Notes:
- atom_cmd_end(): a frame ending with stuff pending re-points its
  redo-prep to the next frame.
- atom_cmd_start(): a stuffed continuation frame (`KeyStuffed`) keeps
  the redo-prep; flushed stuff discards it.
2026-08-23 13:58:45 -04:00
354ea3bf2a docs: misc #41452
Co-authored-by: darkdi <rantovov5@gmail.com>
Co-authored-by: Qiaoxi Guo <28090444+breadtitor@users.noreply.github.com>
Co-authored-by: zaveshaa <zaveshaa@gmail.com>
2026-08-23 12:38:07 -04:00
Barrett Ruth 211bef2315 docs(dir): how to decorate a listing #41315 2026-08-23 11:34:44 -04:00