feat(treesitter): add 'injection.self' and 'injection.parent'

Co-authored-by: ObserverOfTime <chronobserver@disroot.org>
This commit is contained in:
Amaan Qureshi 2023-08-22 00:51:38 -04:00 committed by Christian Clason
parent 466c18b818
commit c6ec7fa8d7
4 changed files with 47 additions and 3 deletions

View File

@ -131,6 +131,8 @@ The following new APIs and features were added.
• `@injection.language` now has smarter resolution and will now fallback to language aliases and/or attempt lower case variants of the text. • `@injection.language` now has smarter resolution and will now fallback to language aliases and/or attempt lower case variants of the text.
language via aliases (e.g., filetype) registered via language via aliases (e.g., filetype) registered via
`vim.treesitter.language.register`. `vim.treesitter.language.register`.
• The `#set!` directive now supports `injection.self` and `injection.parent` for injecting either the current node's language
or the parent LanguageTree's language, respectively.
• |vim.ui.open()| opens URIs using the system default handler (macOS `open`, • |vim.ui.open()| opens URIs using the system default handler (macOS `open`,
Windows `explorer`, Linux `xdg-open`, etc.) Windows `explorer`, Linux `xdg-open`, etc.)

View File

@ -523,6 +523,10 @@ associated with patterns:
node's entire text should be re-parsed, including the text of its child node's entire text should be re-parsed, including the text of its child
nodes. By default, child nodes' text will be excluded from the injected nodes. By default, child nodes' text will be excluded from the injected
document. document.
• `injection.self` - indicates that the node's text should be parsed with
the same language as the node's LanguageTree.
• `injection.parent` - indicates that the captured nodes text should
be parsed with the same language as the node's parent LanguageTree.
============================================================================== ==============================================================================
VIM.TREESITTER *lua-treesitter* VIM.TREESITTER *lua-treesitter*

View File

@ -82,6 +82,7 @@ local TSCallbackNames = {
---List of regions this tree should manage and parse. If nil then regions are ---List of regions this tree should manage and parse. If nil then regions are
---taken from _trees. This is mostly a short-lived cache for included_regions() ---taken from _trees. This is mostly a short-lived cache for included_regions()
---@field private _lang string Language name ---@field private _lang string Language name
---@field private _parent_lang? string Parent language name
---@field private _source (integer|string) Buffer or string to parse ---@field private _source (integer|string) Buffer or string to parse
---@field private _trees TSTree[] Reference to parsed tree (one for each language) ---@field private _trees TSTree[] Reference to parsed tree (one for each language)
---@field private _valid boolean|table<integer,boolean> If the parsed tree is valid ---@field private _valid boolean|table<integer,boolean> If the parsed tree is valid
@ -105,8 +106,9 @@ LanguageTree.__index = LanguageTree
---@param opts (table|nil) Optional arguments: ---@param opts (table|nil) Optional arguments:
--- - injections table Map of language to injection query strings. Overrides the --- - injections table Map of language to injection query strings. Overrides the
--- built-in runtime file searching for language injections. --- built-in runtime file searching for language injections.
---@param parent_lang? string Parent language name of this tree
---@return LanguageTree parser object ---@return LanguageTree parser object
function LanguageTree.new(source, lang, opts) function LanguageTree.new(source, lang, opts, parent_lang)
language.add(lang) language.add(lang)
---@type LanguageTreeOpts ---@type LanguageTreeOpts
opts = opts or {} opts = opts or {}
@ -121,6 +123,7 @@ function LanguageTree.new(source, lang, opts)
local self = { local self = {
_source = source, _source = source,
_lang = lang, _lang = lang,
_parent_lang = parent_lang,
_children = {}, _children = {},
_trees = {}, _trees = {},
_opts = opts, _opts = opts,
@ -489,7 +492,7 @@ function LanguageTree:add_child(lang)
self:remove_child(lang) self:remove_child(lang)
end end
local child = LanguageTree.new(self._source, lang, self._opts) local child = LanguageTree.new(self._source, lang, self._opts, self:lang())
-- Inherit recursive callbacks -- Inherit recursive callbacks
for nm, cb in pairs(self._callbacks_rec) do for nm, cb in pairs(self._callbacks_rec) do
@ -752,7 +755,9 @@ end
function LanguageTree:_get_injection(match, metadata) function LanguageTree:_get_injection(match, metadata)
local ranges = {} ---@type Range6[] local ranges = {} ---@type Range6[]
local combined = metadata['injection.combined'] ~= nil local combined = metadata['injection.combined'] ~= nil
local lang = metadata['injection.language'] --[[@as string?]] local lang = metadata['injection.self'] ~= nil and self:lang()
or metadata['injection.parent'] ~= nil and self._parent_lang
or metadata['injection.language'] --[[@as string?]]
local include_children = metadata['injection.include-children'] ~= nil local include_children = metadata['injection.include-children'] ~= nil
for id, node in pairs(match) do for id, node in pairs(match) do

View File

@ -696,6 +696,39 @@ int x = INT_MAX;
end) end)
end) end)
describe("when using injection.self", function()
it("should inject the source language", function()
exec_lua([[
parser = vim.treesitter.get_parser(0, "c", {
injections = {
c = '(preproc_def (preproc_arg) @injection.content (#set! injection.self)) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.self))'}})
parser:parse(true)
]])
eq("table", exec_lua("return type(parser:children().c)"))
eq(5, exec_lua("return #parser:children().c:trees()"))
eq({
{0, 0, 7, 0}, -- root tree
{3, 14, 3, 17}, -- VALUE 123
{4, 15, 4, 18}, -- VALUE1 123
{5, 15, 5, 18}, -- VALUE2 123
{1, 26, 1, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
{2, 29, 2, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
helpers.feed('ggo<esc>')
eq(5, exec_lua("return #parser:children().c:trees()"))
eq({
{0, 0, 8, 0}, -- root tree
{4, 14, 4, 17}, -- VALUE 123
{5, 15, 5, 18}, -- VALUE1 123
{6, 15, 6, 18}, -- VALUE2 123
{2, 26, 2, 63}, -- READ_STRING(x, y) (char *)read_string((x), (size_t)(y))
{3, 29, 3, 66} -- READ_STRING_OK(x, y) (char *)read_string((x), (size_t)(y))
}, get_ranges())
end)
end)
describe("when using the offset directive", function() describe("when using the offset directive", function()
it("should shift the range by the directive amount", function() it("should shift the range by the directive amount", function()
exec_lua([[ exec_lua([[