summaryrefslogtreecommitdiffstatshomepage
path: root/runtime/lua/vim/lsp/codelens.lua
AgeCommit message (Collapse)AuthorFiles
2026-04-22perf(lsp): clear table by table.clear() #39222Yi Ming1
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.
2026-04-18fix(lsp): stale codelens after external file change (#39203)Jaehwang Jung1
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.
2026-04-18fix(lsp): skip codelens refresh redraw for deleted buffer #39193Jaehwang Jung1
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>
2026-04-11fix(lsp): codelens text flickers #38782Jaehwang Jung1
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
2026-04-06feat(vim.pos)!: require `buf` param on vim.pos, vim.range #38665Luis Calle1
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
2026-04-05fix(lsp): do not respond to codelens refresh if a request is already ↵Yi Ming1
scheduled (#38801)
2026-03-31fix(lsp): use `winresetview()` to avoid switching to normal mode (#38641)Yi Ming1
2026-03-29feat: extend vim.Pos, vim.Range #36397Luis Calle1
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.
2026-03-18fix(lsp): redraw codelens after request completed #38352Yi Ming1
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.
2026-03-10fix(lsp): do not clear the codelens on the last line #38226Yi Ming1
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.
2026-03-09Merge #37985 fix(lsp): adjust codelens position by range, ensure first-line ↵Justin M. Keyes1
visibility
2026-03-09fix(lsp): stop and close timer when `Capability` is destroyedYi Ming1
2026-03-08fix(lsp): ensure the codelens on the first line is visibleYi Ming1
2026-03-08fix(lsp): adjust codelens position based on the server-provided rangeYi Ming1
2026-03-04fix(lsp): ignore stale codelens resolve responses (#38153)Lewis Russell1
2026-02-08feat(lsp): display codelens as virtual lines, not virtual text #36469Mike J McGuirk1
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>
2026-02-06refactor(lsp): always fetch lenses again in codelens.run (#37720)Mathias Fußenegger1
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.
2026-02-03feat(lsp): support `workspace/codeLens/refresh`Yi Ming1
2026-02-03feat(lsp)!: reimplement `textDocument/codeLens` as decoration providerYi Ming1
2025-10-04fix(lsp): deprecate `vim.lsp.protocol.Methods` (#35998)Maria Solano1
2025-08-11fix(lsp): check for lens range in `vim.lsp.codelens.run()` (#35294)Maria José Solano1
2025-08-03fix(lsp): check if buffer is valid when resolving code lenses (#35092)Maria José Solano1
2025-07-26fix(lsp): codelens extmark line out of range (#35070)Jaehwang Jung1
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.
2025-07-12fix(lsp): prevent flicker in codelens virtual text #34888Jaehwang Jung1
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.
2025-06-06fix: type fixesLewis Russell1
Type fixes caught by emmylua
2025-01-14refactor: use nvim.foo.bar format for autocommand groupsMaria José Solano1
2025-01-14refactor: use nvim.foo.bar format for namespacesMaria José Solano1
2024-12-07refactor: add vim._resolve_bufnrLewis Russell1
2024-11-20feat(lsp): deprecate non-method client functionsLewis Russell1
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.
2024-11-01feat(lsp)!: remove client-server handlers from vim.lsp.handlersLewis Russell1
- 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).
2024-10-24feat(lsp): deprecate execute_command with client:exec_cmdLewis Russell1
2024-07-16fix(lsp): don't show codelens for buffers that don't support it (#29690)Riley Bruins1
2024-05-21fix(lsp): hide layout in codelenses in virtual text (#28794) (#28807)Mango The Fourth1
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
2024-04-10fix(lsp): prevent code-lens refresh from becoming a permanent no-op (#28228)Yi Ming1
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.
2024-04-10fix(lsp): empty commands should not be considered executable (#28216)Yi Ming1
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.
2024-03-17fix(lsp): create codelens request parameters for each buffer (#27699)Takuya Tokuda1
2024-03-01docs: improve/add documentation of Lua typesLewis Russell1
- 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.
2024-02-27feat(docs): replace lua2dox.luaLewis Russell1
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).
2024-02-13refactor(lsp): resolve the config-client entanglementLewis Russell1
Previously the LSP-Client object contained some fields that are also in the client config, but for a lot of other fields, the config was used directly making the two objects vaguely entangled with either not having a clear role. Now the config object is treated purely as config (read-only) from the client, and any fields the client needs from the config are now copied in as additional fields. This means: - the config object is no longet normalised and is left as the user provided it. - the client only reads the config on creation of the client and all other implementations now read the clients version of the fields. In addition, internal support for multiple callbacks has been added to the client so the client tracking logic (done in lua.lsp) can be done more robustly instead of wrapping the user callbacks which may error.
2024-02-08feat(lsp): add opts paramater to vim.lsp.codelens.refreshMaria José Solano1
2024-02-08refactor(lsp): tidy up loggingLewis Russell1
2024-02-07refactor(lsp): move client code to a regular Lua classLewis Russell1
Problem: The LSP client code is implemented as a complicated closure-class (class defined in a single function). Solution: Move LSP client code to a more conventional Lua class and move to a separate file.
2023-12-14feat(lsp): more annotationsLewis Russell1
2023-09-21fix(lsp): clear codelens on LspDetach (#24903)Jaehwang Jung1
Also fix incorrect parameters in on_detach callback.
2023-09-14docs: replace <pre> with ``` (#25136)Gregory Anders1
2023-08-03refactor(lsp): use protocol.Methods instead of strings #24537Raphael1
2023-07-18docs(lua): more improvements (#24387)Lewis Russell1
* docs(lua): teach lua2dox how to table * docs(lua): teach gen_vimdoc.py about local functions No more need to mark local functions with @private * docs(lua): mention @nodoc and @meta in dev-lua-doc * fixup! Co-authored-by: Justin M. Keyes <justinkz@gmail.com> --------- Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2023-07-01fix(lsp): lint warnings, default offset_encoding #24046Raphael1
- fix lint / analysis warnings - locations_to_items(): get default offset_encoding from active client - character_offset(): get default offset_encoding from active client
2023-06-20refactor(lsp): extract common execute command functionality (#24065)Mathias Fußenegger1
2023-06-13fix(codelens): add buffer and line checks before displaying codelens (#23887)Rohit Sukumaran1
Co-authored-by: Rohit Sukumaran <rohit.sukumaran@kredx.com>