aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2022-05-28 18:22:18 +0100
committerGitHub <noreply@github.com>2022-05-28 19:22:18 +0200
commiteab4d03a3264b2afaf803ed839fa25bc4e7acedd (patch)
treec7ffb19ab84792f2562273df931e759dc0e2209a
parent081eb72a80afd83398465382171765bdeaf6dba5 (diff)
downloadrneovim-eab4d03a3264b2afaf803ed839fa25bc4e7acedd.tar.gz
rneovim-eab4d03a3264b2afaf803ed839fa25bc4e7acedd.tar.bz2
rneovim-eab4d03a3264b2afaf803ed839fa25bc4e7acedd.zip
fix(treesitter): offset directive associates range with capture (#18276)
Previously the `offset!` directive populated the metadata in such a way that the new range could be attributed to a specific capture. #14046 made it so the directive simply stored just the new range in the metadata and information about what capture the range is based from is lost. This change reverts that whilst also correcting the docs.
-rw-r--r--runtime/doc/treesitter.txt62
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua21
-rw-r--r--runtime/lua/vim/treesitter/query.lua27
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)