aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua
Commit message (Collapse)AuthorAge
...
* feat(health): async healthchecks #41673Barrett Ruth2026-09-11
| | | | | | | | | Problem: :checkhealth blocks as healthchecks perform slow work. Solution: Partially fix it: run Lua healthchecks in vim.async tasks and await vim.health subprocesses. Existing synchronous checks still block until they leverage the new apis.
* fix(ui2): dialog messages offset by the pager line count #41839Justin M. Keyes2026-09-11
| | | | | | | | | | | | | | | | Problem: expand_msg() derives its start row from the pager buffer even when the target is the cmd or dialog buffer, so the copied lines are appended instead of replacing, and the copied extmarks are placed at pager rows in a smaller buffer: "Invalid 'end_col': out of range", thrown inside a UI event handler. Solution: Offset only when appending to a visible pager, and read the line count after msg_clear(), whose autocmds may write to the pager. Copy marks with `strict = false`, since the rows and columns are recomputed for a different buffer and should clamp rather than raise. AI-assisted
* refactor(help): reuse help.lua to generate build tagsLewis Russell2026-09-10
| | | | | | | | | | Make gen_helptags.lua call help.lua instead of keeping its own tag parser. Builds and :helptags now use the same code. Allow the shared code to run without Neovim, and fail the build when tag generation reports an error. AI-assisted
* perf(fs): defer path joining in find()Lewis Russell2026-09-10
| | | | | | | | Only join paths for matches and entries needed for traversal. This avoids string processing for rejected files and improves selective searches across the Neovim tree by about 19-25%. AI-assisted
* perf(help): generate helptags with LPegLewis Russell2026-09-10
| | | | | | | | | | | | | | | | Problem: Generating helptags builds and queries a full vimdoc syntax tree. This is much slower than the previous scanner and also happens before discovering that the tags file cannot be written. Solution: Extract tags with an LPeg grammar, reading each file once and skipping example blocks and ordinary text. Open the output first so unwritable directories can return immediately. This restores legacy handling of tags inside inline code spans. On an arm64 Mac, the 5.36 MB runtime corpus takes 24 ms instead of 604 ms, with identical generated tags. AI-assisted
* vim-patch:9.2.1052: filetype: evcxr history files are not recognized (#41797)zeertzjq2026-09-10
| | | | | | | | | | | | | Problem: filetype: evcxr history files are not recognized Solution: Detect evcxr/history.txt as rust filetype (Wu, Zhenyu). Reference: https://github.com/evcxr/evcxr/blob/main/evcxr_repl/README.md closes: vim/vim#21164 https://github.com/vim/vim/commit/e6bc60ce1b24954ebead198ba0afe41f94bbcf89 Co-authored-by: Wu, Zhenyu <wuzhenyu@ustc.edu>
* build: enable more EmmyLua checksLewis Russell2026-09-09
| | | | | | | | | | 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
* feat(api): add ev.win to autocmd callback args #39826glepnir2026-09-09
| | | | | | | | 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.
* fix(lsp): stale client when rpc.connect fails #41792stenja2026-09-09
| | | | | | | | | | | | | | | | Problem: When vim.lsp.rpc.connect is used for an LSP and the connection fails (due to ECONNREFUSED, for example), the LSP client is left uninitialized. Subsequent calls to vim.lsp.start will reuse the uninitialized client, but no new connection will be attempted. Solution: When vim.lsp.rpc.connect encounters a connection error, terminate the client. This allows the user to do something in response to the failed connection in the on_exit callback, and also makes it so subsequent attempts to start the LSP will try to establish a new connection rather than using the previous uninitialized client. Co-authored-by: Jason Stenftenagel <jasonstenftenagel@gmail.com>
* feat(lsp): support `workspace/foldingRange/refresh` #41780Volodymyr Chernetskyi2026-09-09
| | | | | | | | | | | 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
* fix(lsp): newlines in the completion word from insertText #41801glepnir2026-09-09
| | | | | | | | Problem: A textEdit is cut to its first line but an insertText is not, so its newlines reach the |complete-items| word. Solution: Cut it the same way.
* feat(watch): add on_error callbackLewis Russell2026-09-09
| | | | | | | | | | | | | | Problem: Watcher failures are reported inconsistently, and callers cannot detect when a watcher is no longer usable. Solution: Route startup and event failures and unexpected inotifywait exits through an optional on_error callback. Log to nvim-watch.log by default. Ignore disappearing child directories and exits caused by cancellation. Let LSP log failures and notify once per message, using INFO for missing roots and ERROR otherwise, without interrupting registration. AI-assisted
* build: enable more EmmyLua checksLewis Russell2026-09-08
| | | | | | | | | | | | | | | | - 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
* vim-patch:9.2.1038: CursorLineFold/Sign highlighting depends on ↵zeertzjq2026-09-08
| | | | | | | | | | | | | | | | '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>
* fix(lsp): completion dynamicRegistration breaks capability readers #41771glepnir2026-09-08
| | | | | | | | | | 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.
* fix(lsp): announce typeHierarchy and executeCommand capabilities #41762Volodymyr Chernetskyi2026-09-07
| | | | | | | | | | | Problem: Type hierarchy (#28388, #28467) and `workspace/executeCommand` (#11607) are implemented, but `textDocument.typeHierarchy` and `workspace.executeCommand` are missing from `make_client_capabilities()`. Solution: Declare both capabilities. AI-assisted
* fix(lsp): semantic tokens ignore 'fileformat' when sizing line endings #41733Volodymyr Chernetskyi2026-09-07
| | | | | | | | | | | | | | | | | | | | Problem: The eol_offset used to decode multiline semantic tokens is computed as vim.bo.fileformat[bufnr] == 'dos' and 2 or 1 which indexes the option value rather than the buffer, so it is never "dos" and the offset is always 1. A token that crosses a line boundary in a 'fileformat' of "dos" is then decoded one code unit short per line ending, and the highlight extends past the end of the token. Solution: Read the option with the buffer-scoped form, vim.bo[bufnr].fileformat. The existing multiline test covers both formats now. Its token length of 82 counts the line endings it spans, so the same token reaches four characters less far once the buffer is "dos". AI-assisted
* fix(lsp): show_document() reports a failed buffer load #41731Volodymyr Chernetskyi2026-09-07
| | | | | | | | | | | | | | Problem: vim.lsp.util.show_document() can fail to load the target buffer, most visibly with E325 when another process owns the file's swapfile and the user declines to open it. The Vim error escapes show_document() and surfaces inside whichever LSP handler called it, instead of being reported as a failure to show the document. Solution: Load the buffer up front with vim.fn.bufload(), before any of that state is touched, and report the error instead of raising. AI-assisted
* build: replace LuaLS with EmmyLuaLewis Russell2026-09-07
| | | | | | | | | | | | | | | 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
* fix(help): resolve generic and nullable type referencesLewis Russell2026-09-07
| | | | | | | | | | 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
* feat(lsp): support dynamic registration of completionProvider #41748glepnir2026-09-07
| | | | | | | | Problem: dynamicRegistration is declared false, and completionProvider is read from server_capabilities only. Solution: Declare it, and prefer registerOptions per field.
* perf(watch): prune excluded subtrees during setupLewis Russell2026-09-07
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: The LSP client excludes paths such as Git objects and installed dependencies from file watching. However, watchdirs() still traverses these subtrees before filtering which directories receive watchers, paying the filesystem and Lua traversal cost for excluded content. Solution: Prune excluded subdirectories during the initial walk, and document that excluding a directory also excludes its descendants. Using the LSP client's existing **/node_modules/*/** exclusion on a synthetic macOS tree with 100 installed packages and 4,000 files: Before After Directory scans 503 103 Entries inspected 4502 202 Directory watchers 103 103 The measurements use real filesystem calls and watcher handles, with identical watcher paths for this exclusion. Ref: #23291 AI-assisted
* Merge pull request #41717 from janlazo/vim-0ed11bazeertzjq2026-09-07
|\ | | | | vim-patch:9.1.1429,{0ed11ba,57d6d00}
| * vim-patch:0ed11ba: runtime(doc): Tweak documentation style a bitJan Edmund Lazo2026-09-06
| | | | | | | | | | | | https://github.com/vim/vim/commit/0ed11ba223ec69dfefc8cc5800fb3e0d610fd9f8 Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
* | refactor(pack): use vim.asyncLewis Russell2026-09-07
|/ | | | | | | | | | | Problem: vim.pack uses a private async implementation even though vim.async is now available. Solution: Remove the private implementation and run plugin operations in structured task scopes. Bound parallel work with semaphores and use protected awaits so cancellation still propagates. AI-assisted
* vim-patch:ca2e65a: runtime(doc): Update quickfix help text with missing ↵zeertzjq2026-09-07
| | | | | | | | | | | | information closes: vim/vim#21229 Supported by AI. https://github.com/vim/vim/commit/ca2e65a842d93bd6e3f433ce36b55ec450a2bb1a Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
* fix(treesitter): conceal_lines is not applied to injected treesVolodymyr Chernetskyi2026-09-06
| | | | | | | | | | | | | | | | | | | | | Problem: TSHighlighter._on_conceal_line() parses with the range { row, row }. A Range2 has an exclusive end, so that is the empty range, and no injected region ever intercepts it. The root tree is parsed regardless, because its region is empty, so only injections are affected: conceal_lines metadata coming from an injected language's highlights query is dropped. on_range_impl() then records the row in _conceal_checked, so the miss persists until the buffer changes. For a markdown code block nested in a markdown code block, the inner fence delimiters stay visible and nvim_win_text_height() reports 5 rows where 3 are displayed. Solution: Pass the one-row range, as the on_range_impl() call below already does. AI-assisted
* fix(ui2): mouse movement dismisses expanded messages #41732Volodymyr Chernetskyi2026-09-06
| | | | | | | | | | | | | Problem: cmd_on_key() tests the key it was handed against the literal string '<MouseMove>', but at that point "typed" still holds raw key bytes. Thus the comparison never holds and the branch its own comment describes is dead. Moving the mouse over an expanded cmdline collapses it. Solution: Translate the key once, up front, so every comparison in the function sees the same form. AI-assisted
* fix(treesitter): #has-parent? errors on a node with no parentVolodymyr Chernetskyi2026-09-06
| | | | | | | | | | | | | | | | | Problem: The #has-parent? predicate indexes the result of node:parent() without checking it, so a capture that matches a tree's root node raises query.lua:600: attempt to index a nil value instead of simply not matching. In a highlights query that breaks highlighting for the whole buffer. The sibling #has-ancestor? predicate handles the same situation. Solution: Treat a missing parent as "does not match". AI-assisted
* feat(ui2): highlight the [+x] spill indicator with MoreMsg #41679Volodymyr Chernetskyi2026-09-04
| | | | | | | | | | | | | 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
* feat(ui2): scroll the dialog window with the mouse wheel #41682Volodymyr Chernetskyi2026-09-04
| | | | | | | | | | | | 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
* feat(multicursor): "]C"/"[C" leave a cursor at old position #41681Justin M. Keyes2026-09-04
| | | | | | | | | 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.
* feat(lua): add vim.asyncLewis Russell2026-09-03
| | | | | | | | | | | | | | | | | | | | 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
* fix(statusline): default 'statusline' improvements #41597Sébastien Hoffmann2026-09-03
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: there should be exactly one cell of padding between sections, and exactly one cell of minimum padding between the left and the right. - Spaces between sections waste space when a section is empty. According to a comment in #33036, this was the reason to avoid `%k` and implement the keymap section with a vim expression, but other sections still have this problem. - The diagnostics section wastes space because it is not entirely empty when there are diagnostics in another buffer. - The terminal exit code section can touch the right side, e.g. the ruler, even though it belongs to the left side. Solution: - Use auto-hiding item groups (`%(` without width fields) to get rid of unneeded spaces when a section shows no information. This simplifies the 'showcmd' and 'keymap' sections in particular. - As a slight simplification, `term_exitcode` is moved into the flags section since it is formatted with square brackets like a flag. - Count the diagnostics for the current buffer specifically. - Ensure at least one cell of padding between the left and the right side by adding a space next to the separator `%=`. Problem: some sections are implemented with `%{%`, even though reevaluation of the expression result is not needed. This leads to otherwise needless %-escaping in `progress_status`. Solution: use `%{` instead. Problem: `%{` and `%{%` (without items) replace spaces with fillchars. This looks out-of-place inside the terminal exit code section, and in contrast to all other sections, the 'busy' section is surrounded by fillchars, which looks inconsistent, and with some terminal-font combinations, ◐ overlaps the fillchar, e.g. Alacritty & JetBrains Mono. Solution: use non-breaking spaces U+202F to avoid fillchar substitution. Problem: sections that appear/disappear frequently can make otherwise more stable sections jump around a lot. Solution: sort the sections on the right roughly by volatility: 'showcmd' in first place, 'keymap' next to the ruler.
* fix(ssh): compare table length in the SSH config #41637Volodymyr Chernetskyi2026-09-03
| | | | | | | | | | | | | | | | | | Problem: `parse_ssh_config()` compares tables against a freshly allocated empty table. - In `parse_multiple_values()`, the guard which avoids flushing an empty accumulator never applies. Runs of separators and trailing whitespace push empty strings into the results, and `is_valid()` does not filter them. `Host alpha beta ` parses as `{ 'alpha', '', 'beta' }`. - In `parse_value()`, the condition reduces to `chr == '"' and quoted`. `quoted` starts false and only that branch sets it, so it can never become true: quotes are never recognised and are inserted literally, and the unterminated-quote check is unreachable. Solution: Compare `#val` instead. Add a test for repeated and trailing separators. AI-assisted
* fix(filetype): report documented parameter name #41649Volodymyr Chernetskyi2026-09-03
| | | | | | | | Problem: Invalid `args` parameter for `vim.filetype.match()` reports wrong parameter name `"arg"`. Solution: Report correct parameter name `"args"` instead.
* fix(iter): keep take() predicate within bounds #41635Volodymyr Chernetskyi2026-09-03
| | | | | | | | | | | | | Problem: `IterArray:take()` iterates up to `self._tail`, but `_tail` is exclusive. When no element fails the predicate, the loop reads one index past the last element and calls the predicate with `nil`. Solution: Stop at `self._tail - inc`, which is the last in-range index for both iteration directions. Add tests using a predicate which dereferences its argument and matches every element, forward and reversed. AI-assisted
* vim-patch:9.2.1035: filetype: Github citation files are not recognized (#41643)zeertzjq2026-09-03
| | | | | | | | | | | | | Problem: filetype: Github citation files are not recognized Solution: Detect *.cff files as yaml filetype (Wu Zhenyu). Reference: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-citation-files closes: vim/vim#21163 https://github.com/vim/vim/commit/05de89440166f045535ebf06fb7aeec962f3fbd2 Co-authored-by: Wu, Zhenyu <wuzhenyu@ustc.edu>
* fix(treesitter): accept a string title in inspect_tree() #41639Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | Problem: `inspect_tree()` documents `title` as `string|fun(bufnr:integer):string|nil`, but the implementation handles only `nil` and function values. A string title leaves `title` unset and fails the assertion below. Solution: Use the string as the title.
* fix(lsp): respect range in linewise visual mode #41636Volodymyr Chernetskyi2026-09-02
| | | | | | | | Problem: An explicitly passed `range` to `vim.lsp.buf.format()` in linewise visual mode is silently replaced by the selection. Solution: Parenthesise the mode check.
* fix(pack): read document links from the request buffer #41638Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | | | Problem: The `textDocument/documentLink` handler resolves the confirmation buffer from the request URI and checks it for `nil`, then reads lines from buffer `0`. When the confirmation buffer is not current, links are computed from unrelated text and returned against the confirmation buffer's line numbers, producing missing or misplaced links. Solution: Read lines from the resolved `bufnr`. AI-assisted
* fix(keymap): report the documented parameter name #41633Volodymyr Chernetskyi2026-09-02
| | | | | | | | Problem: Invalid `modes` parameter for `vim.keymap.del()` reports wrong parameter name `"mode"`. Solution: Report correct parameter name `"mode"` instead.
* fix(health): correct reporting messages #41632Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | | | Problems: - Slow shell check measures time in nanoseconds, but reports seconds. - `kdch1` check incorrectly tests `kbs_entry` instead. - curl version is passed as an advice, so it is never reported. Solutions: - Scale the elapsed time to seconds before reporting. - Test `kdch1_entry` for `kdch1` check. - Format curl warning with `string.format()`. AI-assisted
* fix(vim.version): fix metatable for intersections #41615Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | Problem: `vim.version.intersect()` returns tables with `VersionRange` (method table) as their metatable. Although the calculated bounds are correct, the results do not expose `VersionRange` methods. Solution: Construct intersection tables with `range_mt`, matching `vim.version.range()`. Add assertions covering method access and repeated intersection.
* fix(trust): hash fileformat=mac buffers correctly #41616Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | Problem: `compute_hash()` reconstructs buffer contents with `fileformat` set to `mac` using CRLF (`dos`) line endings. The resulting hash does not match the file's bytes. Solution: Define the line ending for every supported file format. Use that mapping when reconstructing buffer contents for hashing.
* fix(loader): remove all cached loaders on disable #41613Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | | Problem: When disabling, the loader list is traversed forwards while entries are removed. As a result, some entries are skipped and remain active. Thus, disabling `vim.loader` restores `_G.loadfile`, but does not fully restore the original package loader chain. Solution: Traverse `package.loaders` in reverse when removing cached loaders. Capture the original `package.loaders` list in the test, and assert that the list is restored properly.
* fix(health): restore pynvim version lookup #41619Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | | | | | | | | Problem: Fallback pynvim version lookup is broken since Vimscript-to-Lua rewrite. - `vim.fs.basename()` returns the module filename instead of the directory needed to discover adjacent metadata. This produces an empty metadata list, hiding the remaining issues. - `table.sort()` requires a Boolean comparator, while `vim.version.cmp()` returns a number. - `table.sort()` sorts in place and returns no value, so assigning its result discards the metadata list. Solution: - Use `vim.fs.dirname()` to discover adjacent package metadata. - Use `vim.version.gt()` as the descending Boolean comparator. - Sort the metadata list in place. This restores fallback version detection when `neovim.VERSION` is unavailable.
* fix(vim.hl): convert finish column independently #41618Volodymyr Chernetskyi2026-09-02
| | | | | | | | | | | Problem: Coordinates-to-position conversion for the finish column in `vim.hl.range()` checks the start column. This results in an incorrect finish column when only one of the column coordinates is `vim.v.maxcol`. Solution: Check the finish column when converting the finish position. Update the existing screen test so that a `vim.v.maxcol` finish highlights the end-of-line marker, matching the existing `-1` behavior.
* vim-patch:fac9e33