aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/treesitter/highlighter.lua
Commit message (Collapse)AuthorAge
* 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 assignment type checking in runtime codeLewis Russell2026-09-25
| | | | | | | | | | | Enable EmmyLua's assign-type-mismatch diagnostic after correcting the runtime annotations and assignments it flags. Correct option, tuple, and return types, and use separate locals when a value changes representation. Add guards and narrow casts where needed so the runtime passes the stricter check. Regenerate the affected docs. 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-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
* 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(treesitter): make TSHighlighter.new() idempotent for an active buffer #41090Freddie Haddad2026-08-02
| | | | | | | | | | | | | | | | | | | Problem: Calling vim.treesitter.start() a second time on a buffer that already has an active TSHighlighter creates a brand new instance instead of reusing it, whether the parser tree is unchanged (e.g. calling start() twice) or different (e.g. switching languages). Either way the old instance is silently discarded without calling :destroy() on it, so its on_bytes/on_changedtree/on_detach callbacks stay registered and its buffer-local state (spelloptions, decoration namespace) is never restored, both leaking indefinitely for an orphaned instance that nothing references anymore. Solution: Return the existing instance when TSHighlighter.active[source] is already set for the same parser tree, instead of unconditionally constructing a new one. When the tree differs instead (e.g. a language switch), destroy() the old instance first, matching stop() semantics, before constructing the new one.
* refactor(api): omit optional paramJustin M. Keyes2026-07-13
|
* fix(api): nvim_exec_autocmds({buf=x}) runs in buffer context #39061Barrett Ruth2026-05-20
| | | | | Problem: `nvim_exec_autocmds({ buf = ... })` matches the target buffer, but callbacks and modelines run with the caller buffer current rather than the target buffer. Solution: Execute the buffered path in prepared target-buffer context and restore the caller afterward.
* feat(treesitter/extmark): support removing a conceal highlight #35087Peter Cardenas2026-04-25
| | | | | | | | | Problem: Cannot remove a `@conceal` highlight when defined in highlights.scm. Solution: Support a `@noconceal` highlight that works similarly to `@nospell` where it overrides the conceal set on the range to remove it. Additionally, can set the conceal metadata field to false for the same behavior.
* feat(api): rename buffer to buf #35330Jordan2026-04-08
| | | | | | | | | | | | Problem: `:help dev-name-common` states that "buf" should be used instead of "buffer" but there are cases where buffer is mentioned in the lua API. Solution: - Rename occurrences of "buffer" to "buf" for consistency with the documentation. - Support (but deprecate) "buffer" for backwards compatibility. Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
* refactor: integer functions, optimize asserts #34112Lewis Russell2026-03-12
| | | | | | | | | | | | refactor(lua): add integer coercion helpers Add vim._tointeger() and vim._ensure_integer(), including optional base support, and switch integer-only tonumber()/assert call sites in the Lua runtime to use them. This also cleans up related integer parsing in LSP, health, loader, URI, tohtml, and Treesitter code. supported by AI
* fix(treesitter): fix spell navigation on first line (#37361)ashab-k2026-01-15
| | | | | | | | Problem: Spell navigation skips words on the first line because _on_spell_nav passes an empty range (0,0) to the highlighter. Solution: Use math.max(erow, srow + 1) to ensure a valid search window. Signed-off-by: ashab-k <ashabkhan2000@gmail.com>
* fix(treesitter): no injection highlighting on last line #36951Jaehwang Jung2025-12-14
| | | | | | | | | | | | | Problem: If the last visible line in a window is not fully displayed, this line may not get injection highlighting. This happens because line('w$') actually means the last *completely displayed* line. Solution: Use line('w$') + 1 for the botline. This reverts 4244a967746a1476831d990153d4de85450e54d4 "test: fix failing lsp/utils_spec #36609", which changed the test based on the wrong behavior.
* perf(treesitter): parse multiple ranges in languagetree, eliminate ↵Riley Bruins2025-11-18
| | | | | | | | | | | flickering #36503 **Problem:** Whenever `LanguageTree:parse()` is called, injection trees from previously parsed ranges are dropped. **Solution:** Allow the function to accept a list of ranges, so it can return injection trees for all the given ranges. Co-authored-by: Jaehwang Jung <tomtomjhj@gmail.com>
* fix(treesitter): reset next_col when performing intermediate highlightsRiley Bruins2025-11-06
| | | | | | The iterator is meant to be fully reset in this code path, but only the `next_row` state was being reset. This would only cause highlight artifacts for very brief periods of time, though.
* fix(highlight): ensure extmark range is within buffer bounds #35928skewb1k2025-09-26
| | | | | | Adds an additional check for the case when end_col = 0, addressing https://github.com/neovim/neovim/issues/35814#issuecomment-3340709532. Validation is now localized to the highlighter without affecting the C API.
* fix(treesitter): use subpriorities for tree orderingbfredl2025-09-09
| | | | | | | | | | | | | | | This partially reverts 0b8a72b73934d33a05e20c255298e88cd921df32, that is unreverts 15e77a56b711102fdc123e15b3f37d49bc0b1df1 "priority" is an internal neovim concept which does not occur in shared queries. Ideally a single priority space should eventually be enough for our needs. But as we don't want to poke at the usages of priorities right now in the wider ecosystem, introduce the "subpriorities" so that treesitter code can distinguish highlights of the same priorities with different tree nesting depth. This mainly affects `injection.combined` as parent-tree nodes might appear in the middle of child-tree nodes which otherwise is not possible.
* perf(highlight): allow decoration providers to skip ranges without databfredl2025-09-09
| | | | | | | | | | | | | | | | Continuing the work of #31400 That PR allowed the provider to be invoked multiple times per line. We want only to do that when there actually is more data later on the line. Additionally, we want to skip over lines which contain no new highlight items. The TS query cursor already tells us what the next position with more data is, so there is no need to reinvoke the range callback before that. NB: this removes the double buffering introduced in #32619 which is funtamentally incompatible with this (nvim core is supposed to keep track of long ranges by itself, without requiring a callback reinvoke blitz). Need to adjust the priorities some other way to fix the same issue.
* perf: add on_range in treesitter highlightingvanaigr2025-08-28
|
* fix(treesitter): run FileType autocmds in the context of `<abuf>`Sean Dewar2025-08-19
| | | | | | | | | Problem: many FileType autocommands assume curbuf is the same as the target buffer; this can cause &syntax to be restored for the wrong buffer in some cases when TSHighlighter:destroy is called. Solution: run nvim_exec_autocmds in the context of the target buffer via nvim_buf_call.
* fix(treesitter): inconsistent highlight of multiline combined injection #32619Artem2025-07-06
| | | | | | | Problem: Combined injections not entirely highlighted. Solution: Reapply layer highlights on each line.
* fix(treesitter): ensure window is valid in async parsing #34385notomo2025-06-08
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Error occurs if window is invalid in the middle of parsing. Solution: Check if window is valid in parsing. - Error ``` vim.schedule callback: ...im/share/nvim/runtime/lua/vim/treesitter/highlighter.lua:485: Invalid window id: 1037 stack traceback: [C]: in function 'nvim__redraw' ...im/share/nvim/runtime/lua/vim/treesitter/highlighter.lua:485: in function 'cb' ...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:494: in function '_run_async_callbacks' ...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:550: in function <...m/share/nvim/runtime/lua/vim/treesitter/languagetree.lua:529> ``` - Reproduce script ```lua local bufnr = vim.api.nvim_create_buf(false, true) local many_lines = vim.fn["repeat"]({ "local test = 'a'" }, 100000) vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, many_lines) local window = vim.api.nvim_open_win(bufnr, true, { relative = "editor", row = 0, col = 0, width = 10, height = 10, }) vim.bo.filetype = "lua" vim.schedule(function() vim.api.nvim_win_close(window, true) end) ```
* fix(treesitter): scope highlight state per window #34347Riley Bruins2025-06-07
| | | | | | | | | **Problem:** There is a lot of distracting highlight flickering when editing a buffer with multiple open windows. This is because the parsing/highlighting state is shared across all windows. **Solution:** Greatly reduce flicker in window splits by scoping the highlighter state object and the `parsing` state object to each individual window, so there is no cross-window interference.
* fix(treesitter): invalidate conceal_lines cache earlier #33875luukvbaal2025-05-06
| | | | | | | | Problem: conceal_lines cache is invalidated in `on_buf` which is too late for code calculating text height after a buffer change but before a redraw (like `lsp/util.lua`). Solution: Replace `on_buf` with `on_bytes` handler that invalidates the cache and clears the marks.
* fix(treesitter): eliminate flicker for single windows #33842Riley Bruins2025-05-05
| | | | | | | | | | This commit will eliminate flicker while editing one open window. It works by querying previously calculated trees for highlight marks, in the case that we are still asynchronously parsing in `on_win`. It will not fully solve the case of flicker when there are multiple open windows, since the parser will drop previously parsed injection trees whenever it receives a call to parse a different region of the buffer. This will require a refactor of `languagetree.lua`.
* fix(treesitter): invalidate conceal_lines marks #33828luukvbaal2025-05-03
| | | | | | Problem: Spliced conceal_lines marks after changing the buffer text are left valid, concealing lines that shouldn't be. Solution: Set the `invalidate` extmark property.
* fix(treesitter): injected lang ranges may cross capture boundaries #32549Riley Bruins2025-04-13
| | | | | | | | | | | | | Problem: treesitter injected language ranges sometimes cross over the capture boundaries when `@combined`. Solution: Clip child regions to not spill out of parent regions within languagetree.lua, and only apply highlights within those regions in highlighter.lua. Co-authored-by: Cormac Relf <web@cormacrelf.net>
* fix(treesitter): not refreshing virtualtext contents #33361Dmitry Zolotukhin2025-04-07
| | | | | | | | Problem: In some cases, when treesitter is enabled, deleting a line below virtualtext will not refresh all updated lines. https://github.com/neovim/neovim/issues/33358 Solution: Revert a part of https://github.com/neovim/neovim/pull/31324 to ensure that the full range (with virtual lines) is refreshed.
* fix(marks): ineffective conceal_line callback optimization (#32662)luukvbaal2025-02-28
| | | | | | | Problem: _on_conceal_line callbacks are not invoked if callback has not let Nvim know it wants to receive them. But this may change on factors other than what is currently checked (changed buffer). Solution: Forego this optimization, callback is still guarded behind 'conceallevel'.
* fix(treesitter): nil check query for has_conceal_lineLuuk van Baal2025-02-25
|
* feat(treesitter): vertical conceal support for highlighterLuuk van Baal2025-02-25
| | | | | | | | TSHighlighter now places marks for conceal_lines metadata. A new internal decor provider callback _on_conceal_line was added that instructs the highlighter to place conceal_lines marks whenever the editor needs to know whether a line is concealed. The bundled markdown queries use conceal_lines metadata to conceal code block fence lines.
* fix(treesitter): don't spam query errors in the highlighterRiley Bruins2025-02-19
| | | | | | | | **Problem:** An erroneous query in the treesitter highlighter gives a deluge of errors that makes the editor almost unusable. **Solution:** Detach the highlighter after an error is detected, so that it only gets displayed once (per highlighter instance).
* fix(treesitter) Set modeline=false in TSHighlighter:destroy (#32234)Daniel Petrovic2025-01-29
| | | | | | | | | | Problem: `TSHighlighter:destroy()` causes double-processing of the modeline and failure of `b:undo_ftplugin`. Solution: Disable modeline in `TSHighlighter:destroy()` by setting `modeline=false` if executing `syntaxset` autocommands for the `FileType` event. Co-authored-by: Daniel Petrovic <daniel.petrovic@ebcont.com>
* refactor: use nvim.foo.bar format for namespacesMaria José Solano2025-01-14
|
* feat(treesitter)!: don't parse tree in get_parser() or start()Riley Bruins2025-01-12
| | | | | | | | | | **Problem:** `vim.treesitter.get_parser()` and `vim.treesitter.start()` both parse the tree before returning it. This is problematic because if this is a sync parse, it will stall the editor on large files. If it is an async parse, the functions return stale trees. **Solution:** Remove this parsing side effect and leave it to the user to parse the returned trees, either synchronously or asynchronously.
* feat(treesitter): async parsingRiley Bruins2025-01-12
| | | | | | | | | | | | **Problem:** Parsing can be slow for large files, and it is a blocking operation which can be disruptive and annoying. **Solution:** Provide a function for asynchronous parsing, which accepts a callback to be run after parsing completes. Co-authored-by: Lewis Russell <lewis6991@gmail.com> Co-authored-by: Luuk van Baal <luukvbaal@gmail.com> Co-authored-by: VanaIgr <vanaigranov@gmail.com>
* refactor: split predicates and directivesvanaigr2025-01-06
|
* fix(api): only flush nvim__redraw when necessary #31250luukvbaal2024-11-18
| | | | | | | | Problem: Not possible to only set a "redraw later" type with nvim__redraw, which seems to be desired for the treesitter highlighter. Solution: Do not update the screen when "flush" is explicitly set to false and only redraw later types are present. In that case, do not call ui_flush() either.
* fix(api): update "range" windows in nvim__redraw #31042luukvbaal2024-11-17
| | | | | | | Problem: nvim__redraw's "range" marks a buffer range for redraw, and subsequently flushes the UI without updating the windows containing that buffer. Solution: Implicitly update the screen, unless specified otherwise. Only update the screen with the last call of the treesitter on_changedtree() callback.
* fix(treesitter): remove redundant on_bytes callback #31041luukvbaal2024-11-16
| | | | | | | Problem: Treesitter highlighter implements an on_bytes callback that just re-marks a buffer range for redraw. The edit that prompted the callback will already have done that. Solution: Remove redundant on_bytes callback from the treesitter highlighter module.
* refactor: rename vim.highlight => vim.hlJustin M. Keyes2024-10-21
| | | | | | | | | | | | Problem: - `vim.highlight` module does not follow `:help dev-name-common`, which documents the name for "highlight" as "hl". - Shorter names are usually preferred. Solution: Rename `vim.highlight` to `vim.hl`. This is not a breaking change until 2.0 (or maybe never).
* fix(treesitter): ensure syntaxset augroup exists (#29542)zeertzjq2024-07-03
| | | | | | | | Problem: Error when calling vim.treesitter.start() and vim.treesitter.stop() in init.lua. Solution: Ensure syntaxset augroup exists after loading synload.vim.
* refactor: use `vim._with` where possibledundargoc2024-06-28
| | | | | This mostly means replacing `nvim_buf_call` and `nvim_win_call` with `vim._with`.
* fix(treesitter): do not modify highlight state for _on_spell_navLuuk van Baal2024-06-24
| | | | | | | | Problem: Treesitter highlighter clears the already populated highlight state when performing spell checking while drawing a smoothscrolled topline. Solution: Save and restore the highlight state in the highlighter's _on_spell_nav callback.
* refactor(lua): improve type annotationsLewis Russell2024-06-11
|
* feat(api): add nvim__redraw for more granular redrawingLuuk van Baal2024-05-02
| | | | | | | | | | | Experimental and subject to future changes. Add a way to redraw certain elements that are not redrawn while Nvim is waiting for input, or currently have no API to do so. This API covers all that can be done with the :redraw* commands, in addition to the following new features: - Immediately move the cursor to a (non-current) window. - Target a specific window or buffer to mark for redraw. - Mark a buffer range for redraw (replaces nvim__buf_redraw_range()). - Redraw the 'statuscolumn'.
* fix(treesitter): return correct match table in iter_captures()Lewis Russell2024-03-27
|
* fix(treesitter): revert to using iter_captures in highlighterLewis Russell2024-03-17
| | | | Fixes #27895
* refactor(treesitter): move some logic into functionsLewis Russell2024-03-14
|