aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/lsp/codelens.lua
Commit message (Collapse)AuthorAge
* ci(lua): enable annotation and style checksLewis Russell2026-09-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: - annotation-usage-error and code-style-check are disabled. - vim.inspect relies on a dummy self-assignment for docgen, and its help omits parameter and option details. - LuaLS fallback types obscure iterator inference. - Docgen hardcodes public function names and appends separately sorted files, leaving shared helpers under the inspector heading. Solution: - Enable annotation-usage-error and code-style-check, and fix misplaced annotations. - Document vim.inspect's callable module directly, removing the dummy assignment. Describe its parameters, option defaults and process callback. - Remove LuaLS iterator fallbacks, correct iterator signatures and check values that the improved inference identifies as optional. - Parse callable modules, require bindings and parent module references. Derive public names and inherited function docs from these links, including missing help for vim.async.semaphore() and vim.version(). - Export vim.lsp.tagfunc directly with lazy loading and document its implementation instead of maintaining a wrapper. - Group files in section_order, replacing append_only and merge_files. Merge declarations before sorting each section, placing shared helpers in the main vim section and keeping vim.inspect in alphabetical order. - Add basic parser coverage for callable modules and module links. AI-assisted
* fix(lua): enable param-type-mismatch diagnosticLewis Russell2026-09-28
| | | | | | | | | Problem: Argument type mismatches are excluded from EmmyLua checks. Solution: Correct runtime annotations and calls, document local checker workarounds, and enable the diagnostic. AI-assisted
* fix(lua): enable nil-safety diagnostics in runtime codeLewis Russell2026-09-25
| | | | | | | | | | | | Enable EmmyLua's need-check-nil diagnostic and resolve nullable values through more precise types, explicit invariants, and guards for missing runtime state. Keep analyzer-specific workarounds local and update the affected API documentation. Exclude the bundled re.lua from analysis so its nil-check warnings do not fail CI. AI-assisted
* fix(lua): add missing param annotations (#41911)Lewis Russell2026-09-15
|
* 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
* 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
* 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
* refactor(lsp): unify LspNotify, decor provider for capabilities #40691jdrouhard2026-07-15
| | | | | | | | | | | | | | | | | | | | | | | | | Problem: Every LSP capability that sends a request on a document change to update its state was using its own buffer-local autocmd to do so. That means there is a separate autocmd per buffer per active capability/feature, and the actual code inside the autocmd callback was virtually identical. The same problem occurred for capabilities that had components to draw on the screen that had their own decoration providers. Solution: Introduce a central `LspNotify` autocmd and decoration provider in the capability module itself. New base class methods `on_close` and `on_change` that take a client_id have been provided, for `didClose` and `didOpen`/`didChange` notifications respectively. New base class method `on_win` that takes topline and botline has been provided to add extmarks or perform other work when lines of a buffer are being drawn. The autocmd callback loops through each active capability instance for the buffer and calls a corresponding method with the triggering client_id if it is currently attached to the buffer that triggered the autocmd. The decoration provider just calls on_win for all active capabilities on the buffer. This slightly tweaks folding range to make use of these new client-id specific callbacks.
* refactor(lsp): use LspNotify for codelens #40604jdrouhard2026-07-07
| | | | | | | | | | | | | | | | | | | | | Problem: The codelens LSP module was using its own raw buffer events and its own debounce mechanism for refreshing code lens in attached buffers. Solution: Switch the module to using the LspNotify autocmd events. LspNotify fires just after document versions are synced with the server and provides a built in debounce mechanism for changes. Additionally, this fixes some bugs with the previous implementation: 1. The workspace/codeLens/refresh handler re-requested codelens for all buffers but when the response came back, it forced an extra redraw after clearing the work the handler had just done. 2. Document synchronization was reworked to be more resilient to multiple clients providing codelens for a single buffer. The latest document version is now separately tracked per client (and per client's lenses per row) instead of for the buffer as a whole. This allows the on_win() function to properly redraw all codelens even when different clients' responses for a particular document version come back at different times.
* Merge #40087 from ofseed/pos-util-follow-upJustin M. Keyes2026-06-14
|\ | | | | feat(pos): create a cursor position by using the current of a window
| * feat(pos): create a cursor position by using the current of a windowYi Ming2026-06-08
| | | | | | | | | | | | | | | | | | | | Problem: `vim.pos.cursor(vim.api.nvim_get_current_buf(win), vim.api.nvim_win_get_cursor(win))` is too verbose to create a cursor position of a window, but it is a common use case. Solution: Overload `vim.pos.cursor()`, so that it accepts `win` as an argument when `pos` is omitted.
* | fix(lsp): refresh codelens despite pending debounce #40154Tristan Knight2026-06-10
|/ | | | | | | | | | | Problem: When a server sends workspace/codeLens/refresh while an automatic codelens request is already scheduled, Nvim ignores the server refresh. This can leave rendered codelens text stale until another buffer edit triggers a new request. Solution: Cancel the pending automatic request and send the server-requested refresh immediately. This preserves request coalescing while giving explicit server refreshes priority.
* perf(lsp): clear table by table.clear() #39222Yi Ming2026-04-22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | benchmark: https://gist.github.com/ofseed/6224529d77c016c36f7ab2f977059848 local rounds = tonumber(arg[1]) or 1000 local count = tonumber(arg[2]) or 1000 -- Load the table.clear function. local clear = require("table.clear") local function fill(t, n) for i = 1, n do t[i] = i end end local function bench_reassign(n_rounds, n_items) local t = {} local start = os.clock() for _ = 1, n_rounds do t = {} collectgarbage("collect") fill(t, n_items) end return os.clock() - start end local function bench_reassign_no_gc(n_rounds, n_items) local t = {} local start = os.clock() for _ = 1, n_rounds do t = {} fill(t, n_items) end return os.clock() - start end local function bench_clear(n_rounds, n_items) local t = {} local start = os.clock() for _ = 1, n_rounds do clear(t) fill(t, n_items) end return os.clock() - start end -- Warm up LuaJIT before the real benchmark. do local t = {} for _ = 1, 2000 do clear(t) fill(t, count) end end collectgarbage("collect") local reassign_time = bench_reassign(rounds, count) collectgarbage("collect") local reassign_no_gc_time = bench_reassign_no_gc(rounds, count) collectgarbage("collect") local clear_time = bench_clear(rounds, count) print(string.format("rounds=%d count=%d", rounds, count)) print(string.format("t = {} + GC : %.6f s", reassign_time)) print(string.format("t = {} : %.6f s", reassign_no_gc_time)) print(string.format("table.clear : %.6f s", clear_time)) print(string.format("vs + GC : %.2fx", reassign_time / clear_time)) print(string.format("vs no GC : %.2fx", reassign_no_gc_time / clear_time)) benchmark result: rounds=1000 count=1000 t = {} + GC : 0.022469 s t = {} : 0.002570 s table.clear : 0.000387 s vs + GC : 58.06x vs no GC : 6.64x `count` is how many items the table has, and `round` is how many rounds we fill the table, clear, and then refill it. `table = {}` is clear the table by resigning a new empty one, because this script does not run persistently like nvim so GC is not triggered, so I added another extreme control group that manually triggers GC.
* fix(lsp): stale codelens after external file change (#39203)Jaehwang Jung2026-04-18
| | | | | | | | | Problem: Codelens virtual lines remain on stale rows after an external file change and buffer reload. Solution: Clear codelens extmarks and cached row/version state in `on_reload` before requesting fresh code lenses.
* fix(lsp): skip codelens refresh redraw for deleted buffer #39193Jaehwang Jung2026-04-18
| | | | | | | | | | | | Problem: After on_refresh() sends a textDocument/codeLens request, the buffer may be deleted before the response arrives. The response callback then tries to redraw that deleted buffer and raises Invalid buffer id error. Solution: Check buffer validity before redrawing. AI-assisted: Codex Co-authored-by: Yi Ming <ofseed@foxmail.com>
* fix(lsp): codelens text flickers #38782Jaehwang Jung2026-04-11
| | | | | | | | | | | | | | | | | Problem: When a new textDocument/codeLens response arrives with unresolved lenses, on_win clears the existing codelens row before codeLens/resolve completes. This causes the displayed codelens text to flicker while typing. Solution: Keep the current virtual lines if any of the refreshed lenses are still unresolved. Clear the old virtual lines only when the line no longer has lenses or all its lenses are resolved. A trade-off is that the user may temporarily see outdated codelenses. However, that's preferable to spamming updates on every refresh. AI-assisted: Codex
* feat(vim.pos)!: require `buf` param on vim.pos, vim.range #38665Luis Calle2026-04-06
| | | | | | | Problem: `buf` is optional even though its needed to perform conversions and the ordering of `(buf, row, col)` is not consistent. Solution: make `buf` mandatory on `vim.range` and `vim.pos` and enforce the `buf, row, col` ordering
* fix(lsp): do not respond to codelens refresh if a request is already ↵Yi Ming2026-04-05
| | | | scheduled (#38801)
* fix(lsp): use `winresetview()` to avoid switching to normal mode (#38641)Yi Ming2026-03-31
|
* feat: extend vim.Pos, vim.Range #36397Luis Calle2026-03-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Using nested `vim.Pos` objects to represent each `vim.Range` object requires 3 tables for each `vim.Range`, which may be undesirable in performance critical code. Using key-value tables performs worse than using array-like tables (lists). Solution: Use array-like indices for the internal fields of both `vim.Pos` and `vim.Range` objects. Use a metatable to allow users to access them like if they were key-value tables. --- Problem: The `vim.Pos` conversion interface for `extmark` indexing does not take into account the difference in how a position on top of a newline is represented in `vim.Pos` and `extmark`. - `vim.Pos`: for a newline at the end of row `n`, `row` takes the value `n + 1` and `col` takes the value `0`. - `extmark`: for a newline at the end of for `n`, `row` takes the value `n` and `col` takes the value `#row_text`. Solution: Handle this in the `extmark` interface. --- Problem: Not all `to_xxx` interfaces have wrapping objects like `to_lsp`. Solution: Return unwrapped values in `to_xxx` interfaces where it makes sense. Accept unwrapped values in "from" interfaces where it makes sense. --- Problem: `start` and `end` positions have different semantics, so they can't be compared. `vim.Range` relies on comparing the `end` and `start` of two ranges to decide which one is greater, which doesn't work as expected because this of the different semantics. For example, for the ranges: local a = { start = { row = 0, col = 22, }, end_ = { row = 0, col = 24, }, } local b = { start = { row = 0, col = 17, }, end_ = { row = 0, col = 22, }, } in this code: local foo, bar = "foo", "bar" -- |---||-| -- b a The range `b` is smaller than the range `a`, but the current implementation compares `b._end` (`col = 22`) and `a.start` (`col = 22`) and concludes that, since `b.col` is not smaller than `a.col`, `b` should be greater than `a`. Solution: - Use a `to_inclusive_pos` to normalize end positions inside of `vim.Range` whenever a comparison between a start and an end position is necessary.
* fix(lsp): redraw codelens after request completed #38352Yi Ming2026-03-18
| | | | | | | Problem: When code lens is enabled, `on_attach` is executed, but it does not trigger a redraw. Another event, eg, moving the cursor, is required to trigger a redraw and execute the decoration provider's `on_win`. Solution: Trigger a `redraw` after each request is completed.
* fix(lsp): do not clear the codelens on the last line #38226Yi Ming2026-03-10
| | | | | | | Problem The logic that clears codelenses beyond the buffer also removes the codelenses on the last line. Solution Do not clear the codelens on the last line.
* Merge #37985 fix(lsp): adjust codelens position by range, ensure first-line ↵Justin M. Keyes2026-03-09
|\ | | | | | | visibility
| * fix(lsp): ensure the codelens on the first line is visibleYi Ming2026-03-08
| |
| * fix(lsp): adjust codelens position based on the server-provided rangeYi Ming2026-03-08
| |
* | fix(lsp): stop and close timer when `Capability` is destroyedYi Ming2026-03-09
|/
* fix(lsp): ignore stale codelens resolve responses (#38153)Lewis Russell2026-03-04
|
* feat(lsp): display codelens as virtual lines, not virtual text #36469Mike J McGuirk2026-02-08
| | | | | | | | | | | | Problem: Code lenses currently display as virtual text on the same line and after the relevant item. While the spec does not say how lenses should be rendered, above the line is most typical. For longer lines, lenses rendered as virtual text can run off the side of the screen. Solution: Display lenses as virtual lines above the text. Closes https://github.com/neovim/neovim/issues/33923 Co-authored-by: Yi Ming <ofseed@foxmail.com>
* refactor(lsp): always fetch lenses again in codelens.run (#37720)Mathias Fußenegger2026-02-06
| | | | | | | | | | | | | | | | | | | The auto-refresh has a bit of a delay so it can happen that when a user runs `codelens.run` it operates on an outdated state and either does nothing, or fails. This changes the logic for `.run` to always fetch the current lenses before (optional) prompt and execution. See discussion in https://github.com/neovim/neovim/pull/37689#discussion_r2764235931 This could potentially be optimized to first check if there's local state with a version that matches the current buf-version, but in my testing re-fetching them always was quickly enough that `run` still feels instant and doing it this way simplifies the logic. Side effect of the change is that `.run` also works if codelens aren't enabled - for power users who know what the codelens would show that can be useful.
* feat(lsp): support `workspace/codeLens/refresh`Yi Ming2026-02-03
|
* feat(lsp)!: reimplement `textDocument/codeLens` as decoration providerYi Ming2026-02-03
|
* fix(lsp): deprecate `vim.lsp.protocol.Methods` (#35998)Maria Solano2025-10-04
|
* fix(lsp): check for lens range in `vim.lsp.codelens.run()` (#35294)Maria José Solano2025-08-11
|
* fix(lsp): check if buffer is valid when resolving code lenses (#35092)Maria José Solano2025-08-03
|
* fix(lsp): codelens extmark line out of range (#35070)Jaehwang Jung2025-07-26
| | | | | | | | | Problem: When setting extmark for a codelens after it's asynchronously resolved, the line may have been removed, raising "invalid 'line': out of range" error. This is a regression from #34888. Solution: Re-introduce the line count check.
* fix(lsp): prevent flicker in codelens virtual text #34888Jaehwang Jung2025-07-12
| | | | | | | | | | | | | | | Problem: Calling lsp.codelens.refresh() causes transient visual flicker because codelens virtual texts are briefly replaced with "Unresolved lens ..." before being resolved and redrawn. Since refresh() is triggered frequently (e.g., on CursorHold or InsertLeave), this leads to redundant and noisy virtual text updates, even when the final text hasn't changed. Solution: Do not update virtual text for a line if some lenses for that line are not resolved yet. A trade-off is that the user may temporarily see outdated virtual text. However, that's preferable to spamming updates on every refresh.
* fix: type fixesLewis Russell2025-06-06
| | | | Type fixes caught by emmylua
* refactor: use nvim.foo.bar format for autocommand groupsMaria José Solano2025-01-14
|
* refactor: use nvim.foo.bar format for namespacesMaria José Solano2025-01-14
|
* refactor: add vim._resolve_bufnrLewis Russell2024-12-07
|
* feat(lsp): deprecate non-method client functionsLewis Russell2024-11-20
| | | | | | | | | | | | | | Deprecated: - `client.request()` -> `client:request()` - `client.request_sync()` -> `client:request_sync()` - `client.notify()` -> `client:notify()` - `client.cancel_request()` -> `client:cancel_request()` - `client.stop()` -> `client:stop()` - `client.is_stopped()` `client:is_stopped()` - `client.supports_method()` -> `client:supports_method()` - `client.on_attach()` -> `client:on_attach()` Fixed docgen to link class fields to the full function doc.
* feat(lsp)!: remove client-server handlers from vim.lsp.handlersLewis Russell2024-11-01
| | | | | | | | | | - Partition the handlers in vim.lsp.handlers as: - client to server response handlers (RCS) - server to client request handlers (RSC) - server to client notification handlers (NSC) Note use string indexes instead of protocol.methods for improved typing in LuaLS (tip: use hover on RCS, RSC or NSC).
* feat(lsp): deprecate execute_command with client:exec_cmdLewis Russell2024-10-24
|
* fix(lsp): don't show codelens for buffers that don't support it (#29690)Riley Bruins2024-07-16
|
* fix(lsp): hide layout in codelenses in virtual text (#28794) (#28807)Mango The Fourth2024-05-21
| | | | | | | Problem: layout i.e. whitespace that is part of codelenses is currently displayed as weird symbols and large amounts of spaces Solution: replace all consecutive whitespace symbols with a single space character when trying to display codelenses as virtual text
* fix(lsp): prevent code-lens refresh from becoming a permanent no-op (#28228)Yi Ming2024-04-10
| | | | | | To avoid repeatedly requesting a buffer multiple times before a request is completed, the current implementation puts the requested buffer into the active_refreshes table before requesting. But since we only remove the buffer from active_refreshes in the lsp-handler of textDocument/codeLens, this will cause if the user sends a request that cannot trigger lsp-handler (for example, if there is an LSP server attached to the current buffer, and especially when the user creates an autocmd which performs vim.lsp.codelens.refresh after the BufEnter event is triggered like in the document example), this buffer will be put into active_refreshes, and there is no way to remove it, which will result in all subsequent vim.lsp.codelens.refresh not requesting textDocument/codeLens.
* fix(lsp): empty commands should not be considered executable (#28216)Yi Ming2024-04-10
| | | According to the LSP specification, the CodeLens.command is optional but the CodeLens.command.command is not optional, which means the correct representation of a display-only code lens is indeed one with a command with a title to display and an empty string as command.
* fix(lsp): create codelens request parameters for each buffer (#27699)Takuya Tokuda2024-03-17
|
* docs: improve/add documentation of Lua typesLewis Russell2024-03-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - Added `@inlinedoc` so single use Lua types can be inlined into the functions docs. E.g. ```lua --- @class myopts --- @inlinedoc --- --- Documentation for some field --- @field somefield integer --- @param opts myOpts function foo(opts) end ``` Will be rendered as ``` foo(opts) Parameters: - {opts} (table) Object with the fields: - somefield (integer) Documentation for some field ``` - Marked many classes with with `@nodoc` or `(private)`. We can eventually introduce these when we want to.
* feat(docs): replace lua2dox.luaLewis Russell2024-02-27
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: The documentation flow (`gen_vimdoc.py`) has several issues: - it's not very versatile - depends on doxygen - doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C. - The intermediate XML files and filters makes it too much like a rube goldberg machine. Solution: Re-implement the flow using Lua, LPEG and treesitter. - `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic. - `lua2dox.lua` is gone! - No more XML files. - Doxygen is now longer used and instead we now use: - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`). - LPEG for C parsing (see `scripts/cdoc_parser.lua`) - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`). - Treesitter for Markdown parsing (see `scripts/text_utils.lua`). - The generated `runtime/doc/*.mpack` files have been removed. - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly. - Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change).