diff options
-rw-r--r-- | runtime/doc/treesitter.txt | 62 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/languagetree.lua | 21 | ||||
-rw-r--r-- | runtime/lua/vim/treesitter/query.lua | 27 |
3 files changed, 70 insertions, 40 deletions
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 339ae0c2ed..52b415bbd1 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -261,36 +261,37 @@ for a node or match and perform side effects. For example, the |set!| predicate sets metadata on the match or node : > ((identifier) @foo (#set! "type" "parameter")) -Here is a list of built-in directives: +Built-in directives: - `set!` *ts-directive-set!* - Sets key/value metadata for a specific node or match : > - ((identifier) @foo (#set! @foo "kind" "parameter")) - ((node1) @left (node2) @right (#set! "type" "pair")) + `set!` *ts-directive-set!* + Sets key/value metadata for a specific match or capture. + Value is accessible as either `metadata[key]` (match + specific) or `metadata[capture_id][key]` (capture specific). + + Parameters: ~ + {capture_id} (optional) + {key} + {value} + + Examples: > + ((identifier) @foo (#set! @foo "kind" "parameter")) + ((node1) @left (node2) @right (#set! "type" "pair")) < - `offset!` *ts-directive-offset!* - Takes the range of the captured node and applies the offsets - to it's range : > - ((identifier) @constant (#offset! @constant 0 1 0 -1)) -< This will generate a range object for the captured node with - the offsets applied. The arguments are - `({capture_id}, {start_row}, {start_col}, {end_row}, {end_col}, {key?})` - The default key is "offset". - - *vim.treesitter.query.add_directive()* -vim.treesitter.query.add_directive({name}, {handler}) - -This adds a directive with the name {name} to be used in queries. -{handler} should be a function whose signature will be : > - handler(match, pattern, bufnr, predicate, metadata) -Handlers can set match level data by setting directly on the metadata object -`metadata.key = value` Handlers can set node level data by using the capture -id on the metadata table `metadata[capture_id].key = value` + `offset!` *ts-directive-offset!* + Takes the range of the captured node and applies an offset. + This will generate a new range object for the captured node + as `metadata[capture_id].range`. - *vim.treesitter.query.list_directives()* -vim.treesitter.query.list_directives() + Parameters: ~ + {capture_id} + {start_row} + {start_col} + {end_row} + {end_col} -This lists the currently available directives to use in queries. + Example: > + ((identifier) @constant (#offset! @constant 0 1 0 -1)) +< Treesitter syntax highlighting (WIP) *lua-treesitter-highlight* @@ -409,10 +410,15 @@ Lua module: vim.treesitter.query *treesitter-query* add_directive({name}, {handler}, {force}) *add_directive()* Adds a new directive to be used in queries + Handlers can set match level data by setting directly on the + metadata object `metadata.key = value`, additionally, handlers + can set node level data by using the capture id on the + metadata table `metadata[capture_id].key = value` + Parameters: ~ {name} the name of the directive, without leading # {handler} the handler function to be used signature will - be (match, pattern, bufnr, predicate) + be (match, pattern, bufnr, predicate, metadata) add_predicate({name}, {handler}, {force}) *add_predicate()* Adds a new predicate to be used in queries @@ -451,6 +457,8 @@ get_query_files({lang}, {query_name}, {is_included}) as `nil` list_directives() *list_directives()* + Lists the currently available directives to use in queries. + Return: ~ The list of supported directives. diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 57d8c5fd21..5a05a29da8 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -295,6 +295,14 @@ function LanguageTree:included_regions() return self._regions end +---@private +local function get_node_range(node, id, metadata) + if metadata[id] and metadata[id].range then + return metadata[id].range + end + return { node:range() } +end + --- Gets language injection points by language. --- --- This is where most of the injection processing occurs. @@ -327,10 +335,10 @@ function LanguageTree:_get_injections() -- Allow for captured nodes to be used if type(content) == 'number' then - content = { match[content] } + content = { match[content]:range() } end - if content then + if type(content) == 'table' and #content >= 4 then vim.list_extend(ranges, content) end end @@ -351,7 +359,7 @@ function LanguageTree:_get_injections() elseif name == 'combined' then combined = true elseif name == 'content' and #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) -- Ignore any tags that start with "_" -- Allows for other tags to be used in matches elseif string.sub(name, 1, 1) ~= '_' then @@ -360,7 +368,7 @@ function LanguageTree:_get_injections() end if #ranges == 0 then - table.insert(ranges, node) + table.insert(ranges, get_node_range(node, id, metadata)) end end end @@ -397,7 +405,10 @@ function LanguageTree:_get_injections() for _, entry in pairs(patterns) do if entry.combined then - table.insert(result[lang], vim.tbl_flatten(entry.regions)) + local regions = vim.tbl_map(function(e) + return vim.tbl_flatten(e) + end, entry.regions) + table.insert(result[lang], regions) else for _, ranges in ipairs(entry.regions) do table.insert(result[lang], ranges) diff --git a/runtime/lua/vim/treesitter/query.lua b/runtime/lua/vim/treesitter/query.lua index 3c4c8fdb96..0cc2b6d2a4 100644 --- a/runtime/lua/vim/treesitter/query.lua +++ b/runtime/lua/vim/treesitter/query.lua @@ -313,20 +313,22 @@ local directive_handlers = { ['set!'] = function(_, _, _, pred, metadata) if #pred == 4 then -- (#set! @capture "key" "value") - local capture = pred[2] - if not metadata[capture] then - metadata[capture] = {} + local _, capture_id, key, value = unpack(pred) + if not metadata[capture_id] then + metadata[capture_id] = {} end - metadata[capture][pred[3]] = pred[4] + metadata[capture_id][key] = value else + local _, key, value = unpack(pred) -- (#set! "key" "value") - metadata[pred[2]] = pred[3] + metadata[key] = value end end, -- Shifts the range of a node. -- Example: (#offset! @_node 0 1 0 -1) ['offset!'] = function(match, _, _, pred, metadata) - local offset_node = match[pred[2]] + local capture_id = pred[2] + local offset_node = match[capture_id] local range = { offset_node:range() } local start_row_offset = pred[3] or 0 local start_col_offset = pred[4] or 0 @@ -340,7 +342,10 @@ local directive_handlers = { -- If this produces an invalid range, we just skip it. if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then - metadata.content = { range } + if not metadata[capture_id] then + metadata[capture_id] = {} + end + metadata[capture_id].range = range end end, } @@ -360,9 +365,14 @@ end --- Adds a new directive to be used in queries --- +--- Handlers can set match level data by setting directly on the +--- metadata object `metadata.key = value`, additionally, handlers +--- can set node level data by using the capture id on the +--- metadata table `metadata[capture_id].key = value` +--- ---@param name the name of the directive, without leading # ---@param handler the handler function to be used ---- signature will be (match, pattern, bufnr, predicate) +--- signature will be (match, pattern, bufnr, predicate, metadata) function M.add_directive(name, handler, force) if directive_handlers[name] and not force then error(string.format('Overriding %s', name)) @@ -371,6 +381,7 @@ function M.add_directive(name, handler, force) directive_handlers[name] = handler end +--- Lists the currently available directives to use in queries. ---@return The list of supported directives. function M.list_directives() return vim.tbl_keys(directive_handlers) |