aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
Commit message (Collapse)AuthorAge
* [extregs] implement tab completion for ~ menu.extregsJosh Rahm19 hours
|
* [feat] extregistersJosh Rahm37 hours
| | | | | | | | | | | | | | | | | | | | | 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. Keyes2 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(snippet): preserve the full TM_DIRECTORY path (#42408)Volodymyr Chernetskyi3 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 Russell3 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
* docs: flow layoutJustin M. Keyes3 days
| | | | | | | | | | Work towards enabling "flow" layout in most `:help` files. Since [tables are supported in help](https://github.com/neovim/tree-sitter-vimdoc#tables), it's now possible to render most help files as ["flow" layout](https://github.com/neovim/neovim/blob/9244da12e400ec0291450a5e9400d995e7a29b83/src/gen/gen_help_html.lua#L86-L88) instead of the legacy fixed-width layout. Besides [improved HTML rendering](https://github.com/neovim/neovim/pull/42381#discussion_r4285705739), flow layout will allow `:help` presentation-mode to un-hardwrap text blocks.
* docs: cleanup invalid help sourceJustin M. Keyes3 days
| | | | | | | | | | Work towards enabling "flow" layout in most `:help` files. Since [tables are supported in help](https://github.com/neovim/tree-sitter-vimdoc#tables), it's now possible to render most help files as ["flow" layout](https://github.com/neovim/neovim/blob/9244da12e400ec0291450a5e9400d995e7a29b83/src/gen/gen_help_html.lua#L86-L88) instead of the legacy fixed-width layout. Besides [improved HTML rendering](https://github.com/neovim/neovim/pull/42381#discussion_r4285705739), flow layout will allow `:help` presentation-mode to un-hardwrap text blocks.
* fix(diagnostic): use logical positions for counted jumps #42394Volodymyr Chernetskyi3 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 Chernetskyi3 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 Chernetskyi3 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 Chernetskyi3 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 Chernetskyi3 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
* docs: cleanup #42395Justin M. Keyes3 days
| | | | | | | | | | Work towards enabling "flow" layout in most `:help` files. Since [tables are supported in help](https://github.com/neovim/tree-sitter-vimdoc#tables), it's now possible to render most help files as ["flow" layout](https://github.com/neovim/neovim/blob/9244da12e400ec0291450a5e9400d995e7a29b83/src/gen/gen_help_html.lua#L86-L88) instead of the legacy fixed-width layout. Besides [improved HTML rendering](https://github.com/neovim/neovim/pull/42381#discussion_r4285705739), flow layout will allow `:help` presentation-mode to un-hardwrap text blocks. https://github.com/neovim/neovim/issues/31825
* fix(health): handle percent signs in LSP reports #42396Volodymyr Chernetskyi3 days
| | | | | | | | | | | Problem: Active-feature report text is passed to string.format() without arguments. Percent signs in buffer or client names can raise an error or change the displayed text. Solution: Report the concatenated text without formatting it again. AI-assisted
* fix(ui2): use global value of 'fillchars' #42397Evgeni Chasnovski3 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 Russell3 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(health): stop timed-out provider probe jobs #42390Volodymyr Chernetskyi3 days
| | | | | | | | | | Problem: The timeout handler raises an error before jobstop(), leaving the provider probe running after the healthcheck fails. Solution: Stop the job before raising the timeout error. AI-assisted
* fix(health): run provider probes only once #42391Volodymyr Chernetskyi3 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(health): report when 'paste' is enabled #42389Volodymyr Chernetskyi3 days
| | | | | | | | | | Problem: The configuration check compares the boolean 'paste' option to 1, so it never reports that the option is enabled. Solution: Check the boolean value directly and cover enabled and disabled states. AI-assisted
* docs: cleanup tables, highlights.scm #42381Justin M. Keyes3 days
| | | highlights.scm: `#match` is slow, prefer `#lua-match`.
* feat(diagnostic): add source option to virtual_lines handler (#42371)Aradhya Jain4 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(docs): listitems with codeblocks #42367Justin M. Keyes4 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: - `<` before a listitem (`< - foo`) is not concealed. - Codeblock HTML has extra blank lines. - Codeblock in a listitem ends the listitem, so HTML docs drop the rest of the item and its nesting. Example from `:h nvim_open_win()`: ``` • border: … the double-box style can be specified as: > [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. < If fewer than eight chars are given, they will be repeated. • bufpos: … tree-sitter-vimdoc v4.1.0: (block (line_li (prefix) (line) (codeblock (code (line))))) (block (line) ; "If fewer…" (line_li (prefix) (line) (line))) ; "bufpos" tree-sitter-vimdoc v4.2.0: (block (line_li (prefix) (line) (codeblock (code (line))) (line)) ; "If fewer…" (line_li (prefix) (line) (line))) ; "bufpos" ``` Solution: - Bump tree-sitter-vimdoc to v4.2.0. https://github.com/neovim/tree-sitter-vimdoc/pull/174 - gen_help_html: get listitem indent from its first line - gen_help_html: don't double codeblock newlines. - highlight query: conceal `<` in `line_li`. - docs: fix doc sources where a blank line was missing after listitems followed by non-listitem text.
* docs: fix invalid vimdoc #42353Justin M. Keyes5 days
|
* fix(api): nvim_set_option_value() "remove" ignores non-adjacent items #42351Justin M. Keyes5 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.
* 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(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()`.
* multicursor: v:cascading #42289Evgeni Chasnovski7 days
| | | | | Problem: No way to check if cascade is in action. Solution: Add `v:cascading` variable.
* fix(diagnostic): "Failed to delete autocmd" after noautocmd bwipeout #42303Justin M. Keyes7 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.
* feat(api): nvim_chan_set()Justin M. Keyes10 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 #42198 from lewis6991/watch-pruningLewis Russell13 days
|\ | | | | perf(watch): skip directories outside include glob prefixes
| * perf(watch): skip directories outside include glob prefixesLewis Russell2026-10-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: watchdirs() scans and watches every directory that is not excluded, even when a glob only matches files in one subtree. Some language servers register absolute dependency filenames separately. Neovim uses the workspace root for these string globs, so each extra registration can scan and allocate libuv handles across the whole tree. Solution: Keep each glob's literal directory prefix with its compiled matcher. A directory must be allowed by both the include filter and at least one watch rule. Skip unrelated subtrees, including new directories created later. Keep ancestors watched so matching directories can still be found. Report events only when they match the full patterns. For example, watching /project for /project/src/**/*.lua only needs the src tree and /project itself: /project/ watched |-- src/ watched | `-- lib/ watched |-- tests/ skipped | `-- fixtures/ skipped `-- vendor/ skipped `-- pkg/ skipped With no exclusions, this uses three watches instead of seven. The gain can be large, but depends on the server's patterns and the workspace layout. Separate watches for absolute dependency filenames can skip most directories. For example, a test workspace has 213 directories, including 201 under build/. The two dependency files in this example are under packages/ and styles/, so their watches can skip build/. Before this change, each watch starts at the workspace root, scans all 213 directories and creates 213 libuv handles. With this change: - Haskell Language Server: a separate watch for /project/packages/demo/demo.cabal watches four directories: the project root, packages/, demo/ and its src/ child. This cuts that watch's scans and handles by 98%. With one broad source watch and this dependency watch, the total falls by 49%. - Tailwind CSS v4: a separate watch for the imported /project/styles/themes/colors.css watches three directories: the project root, styles/ and themes/. This cuts that watch's scans and handles by 99%. With two broad watches and this dependency watch, the total falls by 33%. The broad watches still cover all 213 directories. The saving comes from avoiding repeated scans and extra handles for each dependency watch. Most servers with watch registrations in the survey do not benefit. Their patterns match throughout the watch root, or their watches already start at the relevant directory. In both cases, the glob prefix cannot exclude more directories. AI-assisted
| * fix(glob): match leading hash characters literallyLewis Russell2026-10-05
| | | | | | | | | | | | | | | | | | | | | | | | Problem: Globs such as '#generated/*.lua' fail to match their literal paths. The parser consumes a leading '#' as its internal in-segment flag. Solution: Pass the flag as an LPeg match argument instead of inserting it into the glob text. Cover literal and braced patterns with leading hashes. AI-assisted
* | feat(env)!: 'isident' does not affect $NAME parsingJustin M. Keyes2026-10-05
| | | | | | | | | | | | | | | | | | | | | | | | Problem: 'isident' decides how env var names are parsed, which is more "confusing" than "useful": - Changing 'isident' (for 'define' or "\i") can break `$NAME` expansion. - Its default byte ranges let multibyte names work on Windows (`$aあ`) but not Unix (`$é`). Solution: Ignore 'isident' when parsing env var names.
* | fix(vim.fs): find{follow=true} skips symlink targets of the given `type` #42246Justin M. Keyes2026-10-05
| | | | | | | | | | | | | | | | | | Problem: `vim.fs.find()` checks `type` against the symlink itself, so `{ type='file', follow=true }` skips symlinked files (e.g. `:helptags`). Solution: With `follow=true`, a symlink has the type of its target. Thus `type='link'` only matches broken symlinks (like `find -L -type l`).
* | fix(lua): vim._with({ buf, win }) assertion failure #42244Justin M. Keyes2026-10-05
|/ | | | | | | | | Problem: `vim._with({ buf = 0, win = 0 }, f)` fails an assert in ctx_switch(). vim._with() allows `buf` with `win` when `win` shows `buf`, but nlua_with() passes both, and ctx_switch() takes only one target. Solution: Ignore `buf` if `win` is given; the window implies its buffer.
* feat(lsp): support client_id in vim.lsp.completion.get() #42189glepnir2026-10-03
| | | | | | | | | Problem: vim.lsp.completion.get() always asks every client that has completion enabled in the buffer, so a mapping cannot ask just some of them. Solution: Add a "client_id" option that limits the request to the given client, or clients if it is a list.
* 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(display): pad virtual text after listchars eol #41292Langning Zhang2026-10-03
| | | | | | | | | Problem: End-of-line virtual text is drawn directly after a displayed listchars eol character. Solution: Preserve the normal one-cell separator after the eol character. AI-assisted
* fix(search): correct patlen calculation for semicolon search (#42150)Qiming zhao2026-09-30
| | | | | | | | | | | | | | | | | Problem: When repeating search using a semicolon (e.g. `/pat1/;/pat2`), `pat` advances past both the semicolon and the delimiter ('/' or '?'), consuming 2 characters, but `patlen` was only decremented by 1. Consequently, `patlen` in the subsequent search is 1 byte too long and includes the trailing NUL byte, corrupting `msgbuf` and causing ui2's search_count handler to fail with 'attempt to concatenate a nil value'. Solution: Decrement `patlen` by 2 when skipping ';' and delimiter. Also ensure ui2 safely guards search_count messages when extracting the search stat. Fixes #41929 AI-assisted
* fix(pack): ignore inherited GIT_INDEX_FILE #42114Jake Wang2026-09-30
| | | | | | | | | | | | Problem: An inherited Git index can leave a plugin checkout empty or prevent updates. Solution: Clear GIT_INDEX_FILE for plugin Git commands. Verify installs and updates preserve the caller environment and index. AI-assisted Signed-off-by: Jake Wang <jakezwang@users.noreply.github.com>
* Merge #41944 from epithet/stl-hl-scopesJustin M. Keyes2026-09-30
|\
| * fix(statusline): combine diagnostic highlights, use highlight scopesSébastien Hoffmann2026-09-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: when the highlighting surrounding the diagnostics section is not StatusLine[NC], the in-section highlights are not combined and not correctly reset afterwards. The spaces between the diagnostic items have the highlight of the item to the left, which looks bad when the Diagnostic* highlight groups are customised with background colour or underlines. Solution: use %$ to combine, and %#(...%#) to reset. ref #36685 ref #35806
| * feat(statusline): highlight scopesSébastien Hoffmann2026-09-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem 1: many status line sections are automatically hidden when they currently aren't relevant. When such a section contains highlights, the exact pre-section highlighting needs to be reset at the end, otherwise the highlighting of unrelated sections to the right depend on whether the section is hidden or not. And in case of auto-hiding item groups, it might even refuse to hide. Problem 2: when only a part in the middle of a section should deviate from the surrounding highlighting, the section needs knowledge of the highlighting outside in order to reset it, which makes it hard to create self-contained, reusable modules. Problem 3: with nested sections of progressively stacked highlighting changes, the last %$-modifications effectively have to be subtracted when ending a subsection. This can only be done by replaying all the pre-subsection changes from the last %#. Solution: Introduce highlight scopes %#(...%#) that automatically reset pre-scope highlighting at the end. ref #26037 ref #29976 ref #29980 ref #35806 ref #36685
* | ci(lua): enable annotation and style checksLewis Russell2026-09-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |