From 6cfca21bac6bb39b50cba1c23ffb2b69e2d94df8 Mon Sep 17 00:00:00 2001 From: Christian Clason Date: Tue, 2 Apr 2024 10:54:40 +0200 Subject: [PATCH] feat(treesitter): add `@injection.filename` Problem: Injecting languages for file redirects (e.g., in bash) is not possible. Solution: Add `@injection.filename` capture that is piped through `vim.filetype.match({ filename = node_text })`; the resulting filetype (if not `nil`) is then resolved as a language (either directly or through the list maintained via `vim.treesitter.language.register()`). Note: `@injection.filename` is a non-standard capture introduced by Helix; having two editors implement it makes it likely to be upstreamed. --- runtime/doc/news.txt | 3 +++ runtime/doc/treesitter.txt | 4 ++++ runtime/lua/vim/treesitter/languagetree.lua | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index e39cf95da9..5aa274637b 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -240,6 +240,9 @@ The following new APIs and features were added. language aliases (e.g., filetype or custom shorthands) registered via |vim.treesitter.language.register()| and/or attempt lower case variants of the text. + • `@injection.filename` will try to match the node text via + |vim.filetype.match()| and treat the result as a language name in the same + way as `@injection.language`. • 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. diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 0d5511ac40..2356a0c235 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -654,6 +654,10 @@ parent tree. The language injection query allows you to specify these • `@injection.language` - indicates that the captured node’s text may contain the name of a language that should be used to re-parse the `@injection.content`. + • `@injection.filename` - indicates that the captured node’s text may + contain a filename; the corresponding filetype is then looked-up up via + |vim.filetype.match()| and treated as the name of a language that should + be used to re-parse the `@injection.content`. The language injection behavior can also be configured by some properties associated with patterns: diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 3b5d8953c9..8f65cb57c3 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -809,6 +809,10 @@ function LanguageTree:_get_injection(match, metadata) if name == 'injection.language' then local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] }) lang = resolve_lang(text) + elseif name == 'injection.filename' then + local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] }) + local ft = vim.filetype.match({ filename = text }) + lang = ft and resolve_lang(ft) elseif name == 'injection.content' then ranges = get_node_ranges(node, self._source, metadata[id], include_children) end