summaryrefslogtreecommitdiffstatshomepage
path: root/runtime/lua/vim/treesitter/highlighter.lua
AgeCommit message (Collapse)AuthorFiles
2026-04-08feat(api): rename buffer to buf #35330Jordan1
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>
2026-03-12refactor: integer functions, optimize asserts #34112Lewis Russell1
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
2026-01-15fix(treesitter): fix spell navigation on first line (#37361)ashab-k1
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>
2025-12-14fix(treesitter): no injection highlighting on last line #36951Jaehwang Jung1
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.
2025-11-18perf(treesitter): parse multiple ranges in languagetree, eliminate ↵Riley Bruins1
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>
2025-11-06fix(treesitter): reset next_col when performing intermediate highlightsRiley Bruins1
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.
2025-09-26fix(highlight): ensure extmark range is within buffer bounds #35928skewb1k1
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.
2025-09-09fix(treesitter): use subpriorities for tree orderingbfredl1
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.
2025-09-09perf(highlight): allow decoration providers to skip ranges without databfredl1
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.
2025-08-28perf: add on_range in treesitter highlightingvanaigr1
2025-08-19fix(treesitter): run FileType autocmds in the context of `<abuf>`Sean Dewar1
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.
2025-07-06fix(treesitter): inconsistent highlight of multiline combined injection #32619Artem1
Problem: Combined injections not entirely highlighted. Solution: Reapply layer highlights on each line.
2025-06-08fix(treesitter): ensure window is valid in async parsing #34385notomo1
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) ```
2025-06-07fix(treesitter): scope highlight state per window #34347Riley Bruins1
**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.
2025-05-06fix(treesitter): invalidate conceal_lines cache earlier #33875luukvbaal1
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.
2025-05-05fix(treesitter): eliminate flicker for single windows #33842Riley Bruins1
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`.
2025-05-03fix(treesitter): invalidate conceal_lines marks #33828luukvbaal1
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.
2025-04-13fix(treesitter): injected lang ranges may cross capture boundaries #32549Riley Bruins1
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>
2025-04-07fix(treesitter): not refreshing virtualtext contents #33361Dmitry Zolotukhin1
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.
2025-02-28fix(marks): ineffective conceal_line callback optimization (#32662)luukvbaal1
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'.
2025-02-25fix(treesitter): nil check query for has_conceal_lineLuuk van Baal1
2025-02-25feat(treesitter): vertical conceal support for highlighterLuuk van Baal1
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.
2025-02-19fix(treesitter): don't spam query errors in the highlighterRiley Bruins1
**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).
2025-01-29fix(treesitter) Set modeline=false in TSHighlighter:destroy (#32234)Daniel Petrovic1
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>
2025-01-14refactor: use nvim.foo.bar format for namespacesMaria José Solano1
2025-01-12feat(treesitter)!: don't parse tree in get_parser() or start()Riley Bruins1
**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.
2025-01-12feat(treesitter): async parsingRiley Bruins1
**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>
2025-01-06refactor: split predicates and directivesvanaigr1
2024-11-18fix(api): only flush nvim__redraw when necessary #31250luukvbaal1
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.
2024-11-17fix(api): update "range" windows in nvim__redraw #31042luukvbaal1
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.
2024-11-16fix(treesitter): remove redundant on_bytes callback #31041luukvbaal1
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.
2024-10-21refactor: rename vim.highlight => vim.hlJustin M. Keyes1
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).
2024-07-03fix(treesitter): ensure syntaxset augroup exists (#29542)zeertzjq1
Problem: Error when calling vim.treesitter.start() and vim.treesitter.stop() in init.lua. Solution: Ensure syntaxset augroup exists after loading synload.vim.
2024-06-28refactor: use `vim._with` where possibledundargoc1
This mostly means replacing `nvim_buf_call` and `nvim_win_call` with `vim._with`.
2024-06-24fix(treesitter): do not modify highlight state for _on_spell_navLuuk van Baal1
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.
2024-06-11refactor(lua): improve type annotationsLewis Russell1
2024-05-02feat(api): add nvim__redraw for more granular redrawingLuuk van Baal1
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'.
2024-03-27fix(treesitter): return correct match table in iter_captures()Lewis Russell1
2024-03-17fix(treesitter): revert to using iter_captures in highlighterLewis Russell1
Fixes #27895
2024-03-14refactor(treesitter): move some logic into functionsLewis Russell1
2024-03-14fix(treesitter): highlight injections properlyLewis Russell1
`on_line_impl` doesn't highlight single lines, so using pattern indexes to offset priority doesn't work.
2024-03-12fix(treesitter): use 0 as initial value for computing maximum (#27837)Gregory Anders1
Using -1 as the initial value can cause the pattern offset to become negative, which in turn results in a negative subpriority, which fails validation in nvim_buf_set_extmark.
2024-03-12feat(treesitter): support URLs (#27132)Gregory Anders1
Tree-sitter queries can add URLs to a capture using the `#set!` directive, e.g. (inline_link (link_text) @text.reference (link_destination) @text.uri (#set! @text.reference "url" @text.uri)) The pattern above is included by default in the `markdown_inline` highlight query so that users with supporting terminals will see hyperlinks. For now, this creates a hyperlink for *all* Markdown URLs of the pattern [link text](link url), even if `link url` does not contain a valid protocol (e.g. if `link url` is a path to a file). We may wish to change this in the future to only linkify when the URL has a valid protocol scheme, but for now we delegate handling this to the terminal emulator. In order to support directives which reference other nodes, the highlighter must be updated to use `iter_matches` rather than `iter_captures`. The former provides the `match` table which maps capture IDs to nodes. However, this has its own challenges: - `iter_matches` does not guarantee the order in which patterns are iterated matches the order in the query file. So we must enforce ordering manually using "subpriorities" (#27131). The pattern index of each match dictates the extmark's subpriority. - When injections are used, the highlighter contains multiple trees. The pattern indices of each tree must be offset relative to the maximum pattern index from all previous trees to ensure that extmarks appear in the correct order. - The `iter_captures` implementation currently has a bug where the "match" table is only returned for the first capture within a pattern (see #27274). This bug means that `#set!` directives in a query apply only to the first capture within a pattern. Unfortunately, many queries in the wild have come to depend on this behavior. `iter_matches` does not share this flaw, so switching to `iter_matches` exposed bugs in existing highlight queries. These queries have been updated in this repo, but may still need to be updated by users. The `#set!` directive applies to the _entire_ query pattern when used without a capture argument. To make `#set!` apply only to a single capture, the capture must be given as an argument.
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-25refactor(types): fix miscellaneous type warningsMaria José Solano1
2024-02-08refactor(treesitter): typing for Query, TSQuery, and TSQueryInfoJongwook Choi1
- `TSQuery`: userdata object for parsed query. - `vim.treesitter.Query`: renamed from `Query`. - Add a new field `lang`. - `TSQueryInfo`: - Move to `vim/treesitter/_meta.lua`, because C code owns it. - Correct typing for `patterns`, should be a map from `integer` (pattern_id) to `(integer|string)[][]` (list of predicates or directives). - `vim.treesitter.QueryInfo` is added. - This currently has the same structure as `TSQueryInfo` (exported from C code). - Document the fields (see `TSQuery:inspect`). - Add typing for `vim._ts_parse_query()`.
2024-01-24fix(treesitter): prefix treesitter types with vimPhạm Huy Hoàng1
2023-12-20refactor(treesitter): cleanup highlighterLewis Russell1
- Remove some unused fields - Prefix classes with `vim.` - Move around some functions so the query stuff is at the top. - Improve type hints - Rework how hl_cache is implemented
2023-12-19fix(treesitter): prepare highlight states for [s, ]sJaehwang Jung1