feat(treesitter)!: apply offset! directive to all captures #34383

This commit changes the `offset!` directive so that instead of setting a
`metadata.range` value for the entire pattern, it will set a
`metadata.offset` value. This offset will be applied to the range only
in `vim.treesitter.get_range()`, rather than at directive application
time. This allows the offset to be applied to any and all nodes captured
by the given pattern, and removes the requirement that `#offset!` be
applied to only a single node.

The downside of this change is that plugins which read from
`metadata.range` may be thrown off course, but such plugins should
prefer `vim.treesitter.get_range()` when retrieving ranges anyway.

Note that `#trim!` still sets `metadata.range`, and
`vim.treesitter.get_range()` still reads from `metadata.range`, if it
exists.
This commit is contained in:
Riley Bruins
2025-06-13 06:42:10 -07:00
committed by GitHub
parent 9ec6c19c67
commit 1d5b3b5b4c
6 changed files with 87 additions and 27 deletions

View File

@@ -165,6 +165,31 @@ function M.get_node_range(node_or_range)
end
end
---@param node TSNode
---@param source integer|string Buffer or string from which the {node} is extracted
---@param offset Range4
---@return Range6
local function apply_range_offset(node, source, offset)
---@diagnostic disable-next-line: missing-fields LuaLS varargs bug
local range = { node:range() } ---@type Range4
local start_row_offset = offset[1]
local start_col_offset = offset[2]
local end_row_offset = offset[3]
local end_col_offset = offset[4]
range[1] = range[1] + start_row_offset
range[2] = range[2] + start_col_offset
range[3] = range[3] + end_row_offset
range[4] = range[4] + end_col_offset
if range[1] < range[3] or (range[1] == range[3] and range[2] <= range[4]) then
return M._range.add_bytes(source, range)
end
-- If this produces an invalid range, we just skip it.
return { node:range(true) }
end
---Get the range of a |TSNode|. Can also supply {source} and {metadata}
---to get the range with directives applied.
---@param node TSNode
@@ -172,9 +197,12 @@ end
---@param metadata vim.treesitter.query.TSMetadata|nil
---@return Range6
function M.get_range(node, source, metadata)
if metadata and metadata.range then
assert(source)
return M._range.add_bytes(source, metadata.range)
if metadata then
if metadata.range then
return M._range.add_bytes(assert(source), metadata.range)
elseif metadata.offset then
return apply_range_offset(node, assert(source), metadata.offset)
end
end
return { node:range(true) }
end