aboutsummaryrefslogtreecommitdiff
path: root/test/functional
Commit message (Collapse)AuthorAge
* [extregs] implement tab completion for ~ menu.extregsJosh Rahm41 hours
|
* [extregs] update the register statusmsg to show the full extreg name.Josh Rahm42 hours
| | | | Now it shows something like `5 lines yanked into "~my.extreg`
* [extregs] implement dot redo functionality for extregs.Josh Rahm43 hours
|
* [extregs] fixed rebase.Josh Rahm2 days
|
* [feat] comprehensive alias tests and fixes.Josh Rahm2 days
| | | | Alias semantis are identical to using the full extreg name.
* [extregs] Add support for :registers with extregs and aliases.Josh Rahm2 days
|
* [extregs] implemented aliases.Josh Rahm2 days
|
* [extregs] tests are passing (at least all those that pass in upstream/master)Josh Rahm2 days
| | | | Added a big test suite for extregs
* [feat] extregistersJosh Rahm2 days
| | | | | | | | | | | | | | | | | | | | | Implements "extended registers" Extended registers provide access to a separate namespace of registers backed by custom lua callback functions. A new special register ("~) is introduced, which prompts the user for the name of an extregistr to yank or paste from. This enables file-backed or cloud-synced or other arbitrary register behavior. One can now use: `"~file_extreg<cr>yy` to yank into the "file_extreg" register. AI-assisted: Qwen3-Coder
* feat(defaults): drop TAB from 'termpastefilter' #42433Justin M. Keyes3 days
| | | | | | | | Problem: By default, 'termpastefilter' removes TAB chars when pasting to a :terminal. Very annoying, and does not improve "security". Solution: Drop "HT" from the 'termpastefilter' default.
* fix(options): out-of-range number in 'iskeyword' aborts Nvim (#42410)ump45nose4 days
| | | | | | | | | | | | Problem: A number in 'iskeyword', 'isfname' or 'isident' that overflows (e.g. via a modeline) hits abort() or an assert in getdigits_int(). Solution: Parse the numbers non-strictly so an out-of-range value gives E474. Fixes #42409 AI-assisted
* fix(snippet): preserve the full TM_DIRECTORY path (#42408)Volodymyr Chernetskyi4 days
| | | | | | | | | | Problem: TM_DIRECTORY expands to the directory's basename, losing its parent path. Solution: Remove the tail modifier when expanding the current file's directory. Extend the existing known-variable test to check the full directory path. AI-assisted
* refactor(watch): extract watchdirs into a classLewis Russell4 days
| | | | | | | | | | | | Problem: watchdirs() keeps its state in large nested callbacks in _watch.lua, which makes its directory tracking logic harder to change. Solution: Move the backend into its own module and store its state in a WatchDirs instance. Split setup, event handling and cleanup into methods. Extend the existing test to cover cancellation while a directory stat is pending. AI-assisted
* fix(diagnostic): use logical positions for counted jumps #42394Volodymyr Chernetskyi4 days
| | | | | | | | | | | | | Problem: After edits move diagnostic ranges, counted jumps resume searching from their original positions. This can revisit the same diagnostic and hang the default first/last diagnostic mappings. Solution: Advance the search origin using the diagnostic's current logical position. Test forward and backward counted jumps after inserting or deleting a line, including jumps to the last or first diagnostic without wrapping. AI-assisted
* fix(lsp): ignore completion items without LSP metadata #42401Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: Accepting an item from another completion source raises an error when its user_data.nvim table does not contain LSP metadata. Solution: Retrieve and guard the nested LSP metadata before accessing its fields. Cover acceptance of a foreign completion item without LSP metadata. AI-assisted
* fix(lsp): keep label fallback for empty snippet insertText #42402Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: An empty snippet insertText falls back to the label during selection, but acceptance clears that label and expands an empty string. Solution: Require nonempty insertText before expanding a snippet without textEdit. Extend the omnifunc acceptance fixture with an empty snippet insertion. AI-assisted
* fix(lsp): preserve explicit completion edit ranges #42399Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: A completion list default edit range can replace the explicit range of an InsertReplaceEdit, filtering out valid items or changing their replacement. Solution: Only synthesize a default text edit when the completion item has none. Extend the existing itemDefaults test for explicit edits with both range variants. AI-assisted
* fix(lsp): prefer textEdit for snippet completion text #42400Volodymyr Chernetskyi4 days
| | | | | | | | | | | | Problem: Snippet completion words and previews prefer insertText even when textEdit is present, although the actual expansion uses textEdit.newText. Solution: Use the text edit before the fallback insertion text in both selectors. Extend the existing precedence test to check the snippet word and preview. AI-assisted
* fix(ui2): use global value of 'fillchars' #42397Evgeni Chasnovski4 days
| | | | | | | | Problem: Custom ui2 window tracks 'fillchars' option to adjust to the change of `msgsep` flag. However, 'fillchars' is `:h global-local` window option. If it is set locally to the window, ui2 reacts to its `msgsep` value and keeps using it afterwards even in other windows. Solution: Use and react to only global value of 'fillchars'.
* feat(inspector): support ranges in vim.inspect_posLewis Russell4 days
| | | | | | | | | | | | | | | | Problem: Highlight inspection is limited to a single position, and its result types do not document the fields shared by different highlight sources. Solution: Accept end_row/end_col in vim.inspect_pos to inspect a range. Keep range ends exclusive and retain the existing single-position behavior. Support Ex line ranges in :Inspect, including Visual selections. Document named result types, expose shared highlight fields, and keep the existing extmark details and buffer field for compatibility. AI-assisted
* fix(startup): respect --noplugin when used with --clean #42362Max Coplan4 days
| | | | | | | | | | | | | | | Problem: When starting Nvim with both `--clean` and `--noplugin` (in either order), `--noplugin` is silently ignored and built-in runtime plugins are loaded anyway. `command_line_scan()` sets `p_lpl = false` for `--noplugin`, and `--clean` sets `params.use_vimrc = "NONE"` and `params.clean = true`, which later overwrites `p_lpl` back to `true` via `p_lpl = vimrc_none ? params.clean : p_lpl`. Solution: Only reset `p_lpl = false` when `vimrc_none && !params.clean`, preserving `p_lpl = false` if `--noplugin` was passed. AI-assisted
* fix(health): run provider probes only once #42391Volodymyr Chernetskyi4 days
| | | | | | | | | | | | | Problem: Provider checks start and wait for a job, then execute the same command again to obtain its output. The returned output can disagree with the first process's exit status, and the second execution has no timeout. Solution: Return the first job's captured output. Bind the output callbacks to their state and preserve line breaks between callback data entries. Cover invocation count, multiline stdout, and merged stderr. AI-assisted
* fix(options): extend dry-run validationLewis Russell5 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: nvim_set_option_value() dry runs skip checks in did_set_* callbacks. This logic also prepares values needed to apply the option, such as tab widths or a compiled regexp. Moving the checks into validation callbacks needs a way to save that work for did_set_*. Solution: Store prepared values in optset_T so did_set_* can consume them after the option is stored. Dry runs perform the same validation, then free the prepared values without changing live state. This extends dry-run validation for: - 'cedit': reject invalid command-line window keys. - 'completeitemalign': require each completion column exactly once. - 'cursorlineopt': reject empty values and conflicting line modes. - 'encoding': accept only UTF-8 and its aliases. - 'fileencoding': reject lists and local changes with 'nomodifiable'. - 'messagesopt': require mandatory fields and enforce numeric limits. - 'spellcapcheck': return regexp errors, including under :silent!. - 'spellsuggest': reject conflicting suggestion modes. - 'varsofttabstop' and 'vartabstop': reject invalid tab widths. - 'wildmode': reject more than four completion stages. 'makeencoding' also uses the shared encoding preparation. Separating value preparation exposed a bug in 'vartabstop' and 'varsofttabstop': failed assignments could discard local tab widths, and global assignments could overwrite them. Fix this by preparing new widths separately and applying them only after a valid local assignment. AI-assisted
* feat(diagnostic): add source option to virtual_lines handler (#42371)Aradhya Jain5 days
| | | | | | | | | | | | vim.diagnostic.Opts.VirtualText has a `source` option to prefix diagnostic messages with their source (`'if_many'` or always), but the newer virtual_lines handler never got the same option, even though the shared helpers it needs (diagnostic_shared.prefix_source/count_sources) are already render-target-agnostic and used by virtual_text as-is. Add the same `source` field to vim.diagnostic.Opts.VirtualLines and apply it in the virtual_lines handler right after message formatting, mirroring virtual_text's own ordering (format first, then prefix the source onto the already-formatted message).
* fix(search): crash on "//e" with only a substitute pattern (#42345)Jonas Örnfelt6 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
* fix(api): nvim_buf_call() from expression for window in non-current tabpage ↵Justin M. Keyes6 days
| | | | | | | | | | | | | | | | #42352 Problem: - nvim_buf_call() aborts (assert) when called from an expression evaluated for a window in another tabpage ('foldexpr', 'statusline'), because `curwin` is not in `curtab`. - After it returns, `curwin` is wrong if it switched windows. - `vim._with{win=…, keepcwd=true}` does not undo `:lcd` if `win` is in another tabpage. Solution: - Allow `curwin` outside `curtab`, and restore if it was outside `curtab` at `ctx_switch()`. - Find the target window in any tabpage when restoring its dirs.
* fix(api): nvim_set_option_value() "remove" ignores non-adjacent items #42351Justin M. Keyes6 days
| | | | | | | | | | | | | Problem: `nvim_set_option_value('fo', {'c','r','o'}, {operation='remove'})` does nothing on "jcqrol": the items are joined into one `:set-=` value, which only matches a contiguous substring. Removing map keys, e.g. {'eol','space'} from 'listchars', never matches. `vim.opt:remove{…}` inherits this. (Regression from f34ee3da80e8; 429338e74bf4 fixed the case where the flags are adjacent and in order.) Solution: Remove each item separately.
* fix(terminal): [Process exited] msg hides last line of full screen #42349Justin M. Keyes6 days
| | | | | | | | | Problem: If a job exits with cursor at last row, the `[Process exited]` message covers the text of that row. Solution: Start a new line before showing the message, like the old `\r\n[Process exited]` did.
* feat(multicursor): ]C [C use previous cursors if mc inactive #42267IOCRYPOSTO7 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(channel): emit ChanInfo for :detach! #42295Sanzhar Kuandyk7 days
| | | | | | | | | Problem: :detach! changes the channel's detach property without emitting ChanInfo, so plugins watching channel updates cannot react to changes. Solution: Schedule ChanInfo after setting detach=true. Add a test covering emit on :detach!. AI-assisted
* fix(ops): '] and yank width of forced-blockwise motion #42321IcyJerry7 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>
* test(version): adapt to vim-patch updatesJustin M. Keyes7 days
|
* fix(api): crash on invalid :tab address #42328glepnir7 days
| | | | | | | | Problem: nvim_parse_cmd("'btab", {}) and typing ":'btab" crash, parse_cmdline() continues with a NULL eap->cmd after an invalid :tab address. Solution: Fail if parse_command_modifiers() set an error.
* fix(ui): ext_messages/ui2: stale 'rulerformat' "[+]" after :write #42315Justin M. Keyes8 days
| | | | | | | | | | | | | | Problem: With 'ruler' in the cmdline ('laststatus=0') and ext_messages (ui2), a 'rulerformat' "%m" does not update the "[+]" indicator after ":write", until a cursor-move. Analysis: `redraw_buf_status_later()` only marks windows with a statusline or winbar. The symptom is hidden by the legacy message grid because the write message overwrites the cmdline, which redraws the ruler. Solution: Also mark the cmdline 'ruler', like `status_redraw_buf()`.
* fix(multicursor): Visual-mode mapping drops getchar() payload #42324Justin M. Keyes8 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. Keyes8 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. Keyes8 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 Chasnovski8 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. Keyes8 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.
* fix(diagnostic): "Failed to delete autocmd" after noautocmd bwipeout #42303Justin M. Keyes8 days
| | | | | | | | | | | Problem: Handlers defer `show()` on unloaded buffers with a buffer-local BufRead autocmd whose id is stored per-namespace: - `noautocmd bwipeout` deletes the autocmd, so the next show/hide fails. - Showing another buffer in the same namespace cancels the pending show. Solution: Handlers skip unloaded buffers. The existing global BufRead autocmd shows cached diagnostics when the buffer loads.
* fix(setreg): use better estimate of register widthbfredl9 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | vim-patch:9.2.1175: setreg() block width wrong for unprintable chars When yanking, the width of a <c-v>{motion}y register is determined by the virtual colums of the text. However in setreg() in 'b' mode use an idosyncratic width measurement where C0 control chars (ASCII 0x00 - 0x19) and invalid UTF-8 bytes have width 1 instead of their display width (2 or 4 cells). Consider the following test case: let strings = ['"reference', '"Übel', "\"aa\x07bb", "\"qq\x82", "\"x\nbabbel"] for string in strings call append('$', string) exec "normal G0\<c-v>$\"ay" let one = getregtype('a') if string != strings[-1] call setreg("b", string, 'b') let two = getregtype('b') else let two = "na" endif call setreg("c", [string], 'b') let three = getregtype('c') call append('$', '"yank: '.one.", string: ".two.", list: ".three) endfor AFter this fix, all the three ways of measuring the width gives equal values (or two, in the case of not being able to use setreg() with a plain string in the first case)
* feat(startup): --embed --listen waits for UI if stdin is not a pipeJustin M. Keyes11 days
| | | | | | | | | | | | | | | | | | | | | | Problem: `nvim --embed --listen addr` always treats stdin as an RPC channel. If stdin is /dev/null (e.g. backgrounded over ssh), the channel closes before a UI can attach, so Nvim exits (detach=false behavior). If stdin is a tty, keystrokes are read as RPC. Solution: With `--embed --listen`, open the stdio RPC channel only if stdin is a pipe or socket. Else wait for a UI at the `--listen` address. $ nvim --embed --listen ./nvim.sock Nvim server (pid: 71984) waiting for UI, listening on: "./nvim.sock" Note: - No change when stdin is a pipe. So the test harness, TUI, and :restart all behave exactly as before. - The #29634 use-case of configuring a UI that attaches *after* startup (a second UI, or reattach) still requires #25377 (reliable UIEnter). Not affected by this change.
* feat(api): nvim_chan_set()Justin M. Keyes11 days
| | | | | | | | | | | | | | | | | | | Problem: Only the stdio channel can "own" a server (self-exit on close). After :restart the TUI reconnects over a socket, so the restarted server does not have "self-exit" behavior when the channel closes (e.g. by UI disconnect, host-terminal close, etc.), which leaves a dangling server. Solution: - Introduce `nvim_chan_set`. (`nvim_set_client_info` doesn't fit: exposing it to Lua would require a `channel` param, which is not backwards-compatible, plus it's awkward because it doesn't merge info.) - Broadcast per-channel properties in the "restart" UI event as an opaque dict (a potentially useful pattern for other UI-events in the future). - UIs are expected to restore the channel properties on restart. - `nvim_get_chan_info()` reports "detach". - Remove `nvim__chan_set_detach()`.
* Merge pull request #42217 from bfredl/redirectingbfredl2026-10-06
|\ | | | | fix(lua): regression with `print()` in headless mode when redirecting
| * fix(lua): regression with `print()` in headless modebfredl2026-10-06
| | | | | | | | | | | | | | | | | | This is a bunch of hacks so we can override msg_puts_printf specifically while still allowing redirecting and "normal" message flow to happen, as this still has observable side-effects (even with no screen attached, screenstring() is still valid..) fixes #42218
* | fix(terminal): nvim_open_term crash in zero-size window #42248Justin M. Keyes2026-10-06
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: nvim_open_term() sizes the terminal from the current window, which may have 0 rows (bordered float, 'cmdheight' taking all rows). libvterm aborts when resizing from 0 rows. Solution: In `terminal_alloc()`, treat zero width/height as the pty default (80x24), like jobstart(term=true). Open question: nvim_win_get_height() on such a float returns -1 (winheight() returns 0).
* | Merge pull request #42198 from lewis6991/watch-pruningLewis Russell2026-10-06
|\ \ | | | | | | perf(watch): skip directories outside include glob prefixes
| * | perf(watch): skip directories outside include glob prefixesLewis Russell2026-10-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |