From 9a5678463c96baf3b39cb3083ddf0da87d39aa23 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sat, 4 Feb 2023 14:58:38 +0000 Subject: fix(treesitter): fix most diagnostics --- runtime/lua/vim/treesitter/highlighter.lua | 50 ++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d77a0d0d03..8adaa4ef2f 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,13 +1,27 @@ local a = vim.api local query = require('vim.treesitter.query') --- support reload for quick experimentation +---@alias TSHlIter fun(): integer, TSNode, TSMetadata + +---@class TSHighlightState +---@field next_row integer +---@field iter TSHlIter|nil + ---@class TSHighlighter +---@field active table +---@field bufnr integer +---@field orig_spelloptions string +---@field _highlight_states table +---@field _queries table +---@field tree LanguageTree local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {} TSHighlighter.__index = TSHighlighter TSHighlighter.active = TSHighlighter.active or {} +---@class TSHighlighterQuery +---@field _query Query|nil +---@field hl_cache table local TSHighlighterQuery = {} TSHighlighterQuery.__index = TSHighlighterQuery @@ -46,7 +60,7 @@ end --- Creates a new highlighter using @param tree --- ----@param tree LanguageTree |LanguageTree| parser object to use for highlighting +---@param tree LanguageTree parser object to use for highlighting ---@param opts (table|nil) Configuration of the highlighter: --- - queries table overwrite queries used by the highlighter ---@return TSHighlighter Created highlighter object @@ -57,9 +71,10 @@ function TSHighlighter.new(tree, opts) error('TSHighlighter can not be used with a string parser source.') end - opts = opts or {} + opts = opts or {} ---@type { queries: table } self.tree = tree tree:register_cbs({ + ---@diagnostic disable:invisible on_changedtree = function(...) self:on_changedtree(...) end, @@ -67,17 +82,20 @@ function TSHighlighter.new(tree, opts) self:on_bytes(...) end, on_detach = function(...) + ---@diagnostic disable-next-line:redundant-parameter self:on_detach(...) end, }) - self.bufnr = tree:source() + self.bufnr = tree:source() --[[@as integer]] self.edit_count = 0 self.redraw_count = 0 self.line_count = {} -- A map of highlight states. -- This state is kept during rendering across each line update. self._highlight_states = {} + + ---@type table self._queries = {} -- Queries for a specific language can be overridden by a custom @@ -128,6 +146,8 @@ function TSHighlighter:destroy() end ---@private +---@param tstree TSTree +---@return TSHighlightState function TSHighlighter:get_highlight_state(tstree) if not self._highlight_states[tstree] then self._highlight_states[tstree] = { @@ -145,6 +165,8 @@ function TSHighlighter:reset_highlight_state() end ---@private +---@param start_row integer +---@param new_end integer function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end) a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1) end @@ -155,6 +177,7 @@ function TSHighlighter:on_detach() end ---@private +---@param changes integer[][]? function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes or {}) do a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) @@ -165,7 +188,7 @@ end -- ---@private ---@param lang string Language used by the highlighter. ----@return Query +---@return TSHighlighterQuery function TSHighlighter:get_query(lang) if not self._queries[lang] then self._queries[lang] = TSHighlighterQuery.new(lang) @@ -175,7 +198,12 @@ function TSHighlighter:get_query(lang) end ---@private +---@param self TSHighlighter +---@param buf integer +---@param line integer +---@param is_spell_nav boolean local function on_line_impl(self, buf, line, is_spell_nav) + ---@diagnostic disable:invisible self.tree:for_each_tree(function(tstree, tree) if not tstree then return @@ -213,7 +241,7 @@ local function on_line_impl(self, buf, line, is_spell_nav) local hl = highlighter_query.hl_cache[capture] local capture_name = highlighter_query:query().captures[capture] - local spell = nil + local spell = nil ---@type boolean? if capture_name == 'spell' then spell = true elseif capture_name == 'nospell' then @@ -242,6 +270,9 @@ local function on_line_impl(self, buf, line, is_spell_nav) end ---@private +---@param _win integer +---@param buf integer +---@param line integer function TSHighlighter._on_line(_, _win, buf, line, _) local self = TSHighlighter.active[buf] if not self then @@ -252,6 +283,9 @@ function TSHighlighter._on_line(_, _win, buf, line, _) end ---@private +---@param buf integer +---@param srow integer +---@param erow integer function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) local self = TSHighlighter.active[buf] if not self then @@ -266,6 +300,7 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) end ---@private +---@param buf integer function TSHighlighter._on_buf(_, buf) local self = TSHighlighter.active[buf] if self then @@ -274,6 +309,9 @@ function TSHighlighter._on_buf(_, buf) end ---@private +---@param _win integer +---@param buf integer +---@param _topline integer function TSHighlighter._on_win(_, _win, buf, _topline) local self = TSHighlighter.active[buf] if not self then -- cgit From 8414cfe7f4d8888698343cb54a3f373a28b365db Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Thu, 2 Mar 2023 20:46:59 +0100 Subject: docs: fix vim.treesitter tags Problem: Help tags like vim.treesitter.language.add() are confusing because `vim.treesitter.language` is (thankfully) not a user-facing module. Solution: Ignore the "fstem" when generating "treesitter" tags. --- runtime/lua/vim/treesitter/highlighter.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 8adaa4ef2f..e3deaf6ba6 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -58,7 +58,9 @@ function TSHighlighterQuery:query() return self._query end ---- Creates a new highlighter using @param tree +---@private +--- +--- Creates a highlighter for `tree`. --- ---@param tree LanguageTree parser object to use for highlighting ---@param opts (table|nil) Configuration of the highlighter: -- cgit From 4e4203f71b0b9bb2ca4ad9abd2fbf4ea1deaf9a6 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 23 Mar 2023 11:23:51 +0000 Subject: fix(treesitter): annotations - Begin using `@package` in place of `@private` for functions that are accessed internally but outside their defined class. - Rename Node -> TSP.Node --- runtime/lua/vim/treesitter/highlighter.lua | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index e3deaf6ba6..e24b3ba5df 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -53,12 +53,12 @@ function TSHighlighterQuery.new(lang, query_string) return self end ----@private +---@package function TSHighlighterQuery:query() return self._query end ----@private +---@package --- --- Creates a highlighter for `tree`. --- @@ -76,16 +76,14 @@ function TSHighlighter.new(tree, opts) opts = opts or {} ---@type { queries: table } self.tree = tree tree:register_cbs({ - ---@diagnostic disable:invisible on_changedtree = function(...) self:on_changedtree(...) end, on_bytes = function(...) self:on_bytes(...) end, - on_detach = function(...) - ---@diagnostic disable-next-line:redundant-parameter - self:on_detach(...) + on_detach = function() + self:on_detach() end, }) @@ -147,7 +145,7 @@ function TSHighlighter:destroy() end end ----@private +---@package ---@param tstree TSTree ---@return TSHighlightState function TSHighlighter:get_highlight_state(tstree) @@ -166,19 +164,19 @@ function TSHighlighter:reset_highlight_state() self._highlight_states = {} end ----@private +---@package ---@param start_row integer ---@param new_end integer function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end) a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1) end ----@private +---@package function TSHighlighter:on_detach() self:destroy() end ----@private +---@package ---@param changes integer[][]? function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes or {}) do @@ -188,7 +186,7 @@ end --- Gets the query used for @param lang -- ----@private +---@package ---@param lang string Language used by the highlighter. ---@return TSHighlighterQuery function TSHighlighter:get_query(lang) @@ -205,7 +203,6 @@ end ---@param line integer ---@param is_spell_nav boolean local function on_line_impl(self, buf, line, is_spell_nav) - ---@diagnostic disable:invisible self.tree:for_each_tree(function(tstree, tree) if not tstree then return @@ -268,7 +265,7 @@ local function on_line_impl(self, buf, line, is_spell_nav) state.next_row = start_row end end - end, true) + end) end ---@private -- cgit From cbbf8bd666c8419fdab80a0887948c8a36279c19 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Fri, 24 Mar 2023 14:43:14 +0000 Subject: feat(treesitter)!: deprecate top level indexes to modules (#22761) The following top level Treesitter functions have been moved: - vim.treesitter.inspect_language() -> vim.treesitter.language.inspect() - vim.treesitter.get_query_files() -> vim.treesitter.query.get_files() - vim.treesitter.set_query() -> vim.treesitter.query.set() - vim.treesitter.query.set_query() -> vim.treesitter.query.set() - vim.treesitter.get_query() -> vim.treesitter.query.get() - vim.treesitter.query.get_query() -> vim.treesitter.query.get() - vim.treesitter.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.query.parse_query() -> vim.treesitter.query.parse() - vim.treesitter.add_predicate() -> vim.treesitter.query.add_predicate() - vim.treesitter.add_directive() -> vim.treesitter.query.add_directive() - vim.treesitter.list_predicates() -> vim.treesitter.query.list_predicates() - vim.treesitter.list_directives() -> vim.treesitter.query.list_directives() - vim.treesitter.query.get_range() -> vim.treesitter.get_range() - vim.treesitter.query.get_node_text() -> vim.treesitter.get_node_text() --- runtime/lua/vim/treesitter/highlighter.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index e24b3ba5df..729cd34090 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,5 +1,5 @@ local a = vim.api -local query = require('vim.treesitter.query') +local query = vim.treesitter.query ---@alias TSHlIter fun(): integer, TSNode, TSMetadata @@ -45,9 +45,9 @@ function TSHighlighterQuery.new(lang, query_string) }) if query_string then - self._query = query.parse_query(lang, query_string) + self._query = query.parse(lang, query_string) else - self._query = query.get_query(lang, 'highlights') + self._query = query.get(lang, 'highlights') end return self -- cgit From 469e6bfc56aa18350bfab13bef8a51b02a5b3c65 Mon Sep 17 00:00:00 2001 From: danilax999 <75566563+danilax999@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:26:21 +0300 Subject: fix(treesitter): use capture metadata range if exists use `treesitter.get_range` instead of inline expression --- runtime/lua/vim/treesitter/highlighter.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 729cd34090..d3cc1b698c 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -236,7 +236,8 @@ local function on_line_impl(self, buf, line, is_spell_nav) break end - local start_row, start_col, end_row, end_col = node:range() + local range = vim.treesitter.get_range(node, buf, metadata[capture]) + local start_row, start_col, _, end_row, end_col, _ = unpack(range) local hl = highlighter_query.hl_cache[capture] local capture_name = highlighter_query:query().captures[capture] -- cgit From 34ac75b32927328a0c691c5bda987c0fdb5ce9eb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 5 Apr 2023 17:19:53 +0100 Subject: refactor: rename local API alias from a to api Problem: Codebase inconsistently binds vim.api onto a or api. Solution: Use api everywhere. a as an identifier is too short to have at the module level. --- runtime/lua/vim/treesitter/highlighter.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d3cc1b698c..ac2a929487 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,4 +1,4 @@ -local a = vim.api +local api = vim.api local query = vim.treesitter.query ---@alias TSHlIter fun(): integer, TSNode, TSMetadata @@ -25,7 +25,7 @@ TSHighlighter.active = TSHighlighter.active or {} local TSHighlighterQuery = {} TSHighlighterQuery.__index = TSHighlighterQuery -local ns = a.nvim_create_namespace('treesitter/highlighter') +local ns = api.nvim_create_namespace('treesitter/highlighter') ---@private function TSHighlighterQuery.new(lang, query_string) @@ -36,7 +36,7 @@ function TSHighlighterQuery.new(lang, query_string) local name = self._query.captures[capture] local id = 0 if not vim.startswith(name, '_') then - id = a.nvim_get_hl_id_by_name('@' .. name .. '.' .. lang) + id = api.nvim_get_hl_id_by_name('@' .. name .. '.' .. lang) end rawset(table, capture, id) @@ -121,7 +121,7 @@ function TSHighlighter.new(tree, opts) vim.cmd.runtime({ 'syntax/synload.vim', bang = true }) end - a.nvim_buf_call(self.bufnr, function() + api.nvim_buf_call(self.bufnr, function() vim.opt_local.spelloptions:append('noplainbuffer') end) @@ -140,7 +140,7 @@ function TSHighlighter:destroy() vim.bo[self.bufnr].spelloptions = self.orig_spelloptions vim.b[self.bufnr].ts_highlight = nil if vim.g.syntax_on == 1 then - a.nvim_exec_autocmds('FileType', { group = 'syntaxset', buffer = self.bufnr }) + api.nvim_exec_autocmds('FileType', { group = 'syntaxset', buffer = self.bufnr }) end end end @@ -168,7 +168,7 @@ end ---@param start_row integer ---@param new_end integer function TSHighlighter:on_bytes(_, _, start_row, _, _, _, _, _, new_end) - a.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1) + api.nvim__buf_redraw_range(self.bufnr, start_row, start_row + new_end + 1) end ---@package @@ -180,7 +180,7 @@ end ---@param changes integer[][]? function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes or {}) do - a.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) + api.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) end end @@ -252,7 +252,7 @@ local function on_line_impl(self, buf, line, is_spell_nav) local spell_pri_offset = capture_name == 'nospell' and 1 or 0 if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then - a.nvim_buf_set_extmark(buf, ns, start_row, start_col, { + api.nvim_buf_set_extmark(buf, ns, start_row, start_col, { end_line = end_row, end_col = end_col, hl_group = hl, @@ -323,7 +323,7 @@ function TSHighlighter._on_win(_, _win, buf, _topline) return true end -a.nvim_set_decoration_provider(ns, { +api.nvim_set_decoration_provider(ns, { on_buf = TSHighlighter._on_buf, on_win = TSHighlighter._on_win, on_line = TSHighlighter._on_line, -- cgit From 19a793545f15bb7e0bac2fc8f705c600e8f9c9bb Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Sun, 30 Apr 2023 16:11:38 +0100 Subject: fix(treesitter): redraw added/removed injections properly (#23287) When injections are added or removed make sure to: - invoke 'changedtree' callbacks for when new trees are added. - invoke 'changedtree' callbacks for when trees are invalidated - redraw regions when languagetree children are removed --- runtime/lua/vim/treesitter/highlighter.lua | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index ac2a929487..4bb764c5c6 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -76,9 +76,6 @@ function TSHighlighter.new(tree, opts) opts = opts or {} ---@type { queries: table } self.tree = tree tree:register_cbs({ - on_changedtree = function(...) - self:on_changedtree(...) - end, on_bytes = function(...) self:on_bytes(...) end, @@ -87,6 +84,17 @@ function TSHighlighter.new(tree, opts) end, }) + tree:register_cbs({ + on_changedtree = function(...) + self:on_changedtree(...) + end, + on_child_removed = function(child) + child:for_each_tree(function(t) + self:on_changedtree(t:included_ranges(true)) + end) + end, + }, true) + self.bufnr = tree:source() --[[@as integer]] self.edit_count = 0 self.redraw_count = 0 @@ -177,10 +185,10 @@ function TSHighlighter:on_detach() end ---@package ----@param changes integer[][]? +---@param changes Range6[][] function TSHighlighter:on_changedtree(changes) - for _, ch in ipairs(changes or {}) do - api.nvim__buf_redraw_range(self.bufnr, ch[1], ch[3] + 1) + for _, ch in ipairs(changes) do + api.nvim__buf_redraw_range(self.bufnr, ch[1], ch[4] + 1) end end -- cgit From 8c9dab3e0d788d44c8a2fee83a6193f5955c814e Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Sun, 18 Jun 2023 09:42:17 -0500 Subject: fix(treesitter): use vim.highlight.priorities instead of hardcoded 100 (#24052) Problem: Treesitter highlighting base priority cannot be customized. Solution: Use `vim.highlight.priorities.treesitter` instead of hard-coded value. --- runtime/lua/vim/treesitter/highlighter.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 4bb764c5c6..d4db6bc404 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -260,12 +260,14 @@ local function on_line_impl(self, buf, line, is_spell_nav) local spell_pri_offset = capture_name == 'nospell' and 1 or 0 if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then + local priority = (tonumber(metadata.priority) or vim.highlight.priorities.treesitter) + + spell_pri_offset api.nvim_buf_set_extmark(buf, ns, start_row, start_col, { end_line = end_row, end_col = end_col, hl_group = hl, ephemeral = true, - priority = (tonumber(metadata.priority) or 100) + spell_pri_offset, -- Low but leaves room below + priority = priority, conceal = metadata.conceal, spell = spell, }) -- cgit From be74807eef13ff8c90d55cf8b22b01d6d33b1641 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 18 Jul 2023 15:42:30 +0100 Subject: docs(lua): more improvements (#24387) * 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 --------- Co-authored-by: Justin M. Keyes --- runtime/lua/vim/treesitter/highlighter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index d4db6bc404..f8ec5b175d 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -17,6 +17,7 @@ local query = vim.treesitter.query local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {} TSHighlighter.__index = TSHighlighter +--- @nodoc TSHighlighter.active = TSHighlighter.active or {} ---@class TSHighlighterQuery @@ -205,7 +206,6 @@ function TSHighlighter:get_query(lang) return self._queries[lang] end ----@private ---@param self TSHighlighter ---@param buf integer ---@param line integer -- cgit From 2ca076e45fb3f1c08f6a1a374834df0701b8d778 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 10 Aug 2023 14:21:56 +0100 Subject: feat(treesitter)!: incremental injection parsing Problem: Treesitter highlighting is slow for large files with lots of injections. Solution: Only parse injections we are going to render during a redraw cycle. --- - `LanguageTree:parse()` will no longer parse injections by default and now requires an explicit range argument to be passed. - `TSHighlighter` now parses injections incrementally during on_win callbacks for the line range being rendered. - Plugins which require certain injections to be parsed must run `parser:parse({ start_row, end_row })` before using the tree. --- runtime/lua/vim/treesitter/highlighter.lua | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index f8ec5b175d..56b075b723 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -1,5 +1,6 @@ local api = vim.api local query = vim.treesitter.query +local Range = require('vim.treesitter._range') ---@alias TSHlIter fun(): integer, TSNode, TSMetadata @@ -14,6 +15,7 @@ local query = vim.treesitter.query ---@field _highlight_states table ---@field _queries table ---@field tree LanguageTree +---@field redraw_count integer local TSHighlighter = rawget(vim.treesitter, 'TSHighlighter') or {} TSHighlighter.__index = TSHighlighter @@ -139,6 +141,7 @@ function TSHighlighter.new(tree, opts) return self end +--- @nodoc --- Removes all internal references to the highlighter function TSHighlighter:destroy() if TSHighlighter.active[self.bufnr] then @@ -186,7 +189,7 @@ function TSHighlighter:on_detach() end ---@package ----@param changes Range6[][] +---@param changes Range6[] function TSHighlighter:on_changedtree(changes) for _, ch in ipairs(changes) do api.nvim__buf_redraw_range(self.bufnr, ch[1], ch[4] + 1) @@ -245,7 +248,7 @@ local function on_line_impl(self, buf, line, is_spell_nav) end local range = vim.treesitter.get_range(node, buf, metadata[capture]) - local start_row, start_col, _, end_row, end_col, _ = unpack(range) + local start_row, start_col, end_row, end_col = Range.unpack4(range) local hl = highlighter_query.hl_cache[capture] local capture_name = highlighter_query:query().captures[capture] @@ -309,32 +312,23 @@ function TSHighlighter._on_spell_nav(_, _, buf, srow, _, erow, _) end end ----@private ----@param buf integer -function TSHighlighter._on_buf(_, buf) - local self = TSHighlighter.active[buf] - if self then - self.tree:parse() - end -end - ---@private ---@param _win integer ---@param buf integer ----@param _topline integer -function TSHighlighter._on_win(_, _win, buf, _topline) +---@param topline integer +---@param botline integer +function TSHighlighter._on_win(_, _win, buf, topline, botline) local self = TSHighlighter.active[buf] if not self then return false end - + self.tree:parse({ topline, botline }) self:reset_highlight_state() self.redraw_count = self.redraw_count + 1 return true end api.nvim_set_decoration_provider(ns, { - on_buf = TSHighlighter._on_buf, on_win = TSHighlighter._on_win, on_line = TSHighlighter._on_line, _on_spell_nav = TSHighlighter._on_spell_nav, -- cgit From 65738202f8be3ca63b75197d48f2c7a9324c035b Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Tue, 12 Sep 2023 04:29:39 +0900 Subject: fix(decorations): better approximation of botline #24794 Problem: * The guessed botline might be smaller than the actual botline e.g. when there are folds and the user is typing in insert mode. This may result in incorrect treesitter highlights for injections. * botline can be larger than the last line number of the buffer, which results in errors when placing extmarks. Solution: * Take a more conservative approximation. I am not sure if it is sufficient to guarantee correctness, but it seems to be good enough for the case mentioned above. * Clamp it to the last line number. Co-authored-by: Lewis Russell --- runtime/lua/vim/treesitter/highlighter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 56b075b723..8d4d6a9337 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -322,7 +322,7 @@ function TSHighlighter._on_win(_, _win, buf, topline, botline) if not self then return false end - self.tree:parse({ topline, botline }) + self.tree:parse({ topline, botline + 1 }) self:reset_highlight_state() self.redraw_count = self.redraw_count + 1 return true -- cgit From 07080f67fe7e526576d5d50777fb122a99b3e183 Mon Sep 17 00:00:00 2001 From: L Lllvvuu Date: Sat, 16 Sep 2023 02:48:49 -0700 Subject: perf(treesitter): do not scan past given line for predicate match Problem --- If a highlighter query returns a significant number of predicate non-matches, the highlighter will scan well past the end of the window. Solution --- In the iterator returned from `iter_captures`, accept an optional parameter `end_line`. If no parameter provided, the behavior is unchanged, hence this is a non-invasive tweak. Fixes: #25113 nvim-treesitter/nvim-treesitter#5057 --- runtime/lua/vim/treesitter/highlighter.lua | 63 ++++++++++++++++-------------- 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'runtime/lua/vim/treesitter/highlighter.lua') diff --git a/runtime/lua/vim/treesitter/highlighter.lua b/runtime/lua/vim/treesitter/highlighter.lua index 8d4d6a9337..496193c6ed 100644 --- a/runtime/lua/vim/treesitter/highlighter.lua +++ b/runtime/lua/vim/treesitter/highlighter.lua @@ -2,7 +2,7 @@ local api = vim.api local query = vim.treesitter.query local Range = require('vim.treesitter._range') ----@alias TSHlIter fun(): integer, TSNode, TSMetadata +---@alias TSHlIter fun(end_line: integer|nil): integer, TSNode, TSMetadata ---@class TSHighlightState ---@field next_row integer @@ -241,40 +241,43 @@ local function on_line_impl(self, buf, line, is_spell_nav) end while line >= state.next_row do - local capture, node, metadata = state.iter() + local capture, node, metadata = state.iter(line) - if capture == nil then - break + local range = { root_end_row + 1, 0, root_end_row + 1, 0 } + if node then + range = vim.treesitter.get_range(node, buf, metadata and metadata[capture]) end - - local range = vim.treesitter.get_range(node, buf, metadata[capture]) local start_row, start_col, end_row, end_col = Range.unpack4(range) - local hl = highlighter_query.hl_cache[capture] - - local capture_name = highlighter_query:query().captures[capture] - local spell = nil ---@type boolean? - if capture_name == 'spell' then - spell = true - elseif capture_name == 'nospell' then - spell = false - end - -- Give nospell a higher priority so it always overrides spell captures. - local spell_pri_offset = capture_name == 'nospell' and 1 or 0 - - if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then - local priority = (tonumber(metadata.priority) or vim.highlight.priorities.treesitter) - + spell_pri_offset - api.nvim_buf_set_extmark(buf, ns, start_row, start_col, { - end_line = end_row, - end_col = end_col, - hl_group = hl, - ephemeral = true, - priority = priority, - conceal = metadata.conceal, - spell = spell, - }) + if capture then + local hl = highlighter_query.hl_cache[capture] + + local capture_name = highlighter_query:query().captures[capture] + local spell = nil ---@type boolean? + if capture_name == 'spell' then + spell = true + elseif capture_name == 'nospell' then + spell = false + end + + -- Give nospell a higher priority so it always overrides spell captures. + local spell_pri_offset = capture_name == 'nospell' and 1 or 0 + + if hl and end_row >= line and (not is_spell_nav or spell ~= nil) then + local priority = (tonumber(metadata.priority) or vim.highlight.priorities.treesitter) + + spell_pri_offset + api.nvim_buf_set_extmark(buf, ns, start_row, start_col, { + end_line = end_row, + end_col = end_col, + hl_group = hl, + ephemeral = true, + priority = priority, + conceal = metadata.conceal, + spell = spell, + }) + end end + if start_row > line then state.next_row = start_row end -- cgit