fix(treesitter): enforce lowercase language names (#28546)

* fix(treesitter): enforce lowercase language names

Problem: On case-insensitive file systems (e.g., macOS), `has_parser`
will return `true` for uppercase aliases, which will then try to inject
the uppercase language unsuccessfully.

Solution: Enforce and assume parser names to be lowercase when
resolving language names.
This commit is contained in:
Christian Clason 2024-04-28 16:27:47 +02:00 committed by GitHub
parent 4625394a76
commit 26b5405d18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 8 additions and 12 deletions

View File

@ -30,6 +30,9 @@ A parser can also be loaded manually using a full path: >lua
vim.treesitter.language.add('python', { path = "/path/to/python.so" }) vim.treesitter.language.add('python', { path = "/path/to/python.so" })
< <
Parser names are assumed to be lower case if the file system is
case-sensitive.
To associate certain |filetypes| with a treesitter language (name of parser), To associate certain |filetypes| with a treesitter language (name of parser),
use |vim.treesitter.language.register()|. For example, to use the `xml` use |vim.treesitter.language.register()|. For example, to use the `xml`
treesitter parser for buffers with filetype `svg` or `xslt`, use: >lua treesitter parser for buffers with filetype `svg` or `xslt`, use: >lua

View File

@ -88,6 +88,9 @@ function M.add(lang, opts)
filetype = { filetype, { 'string', 'table' }, true }, filetype = { filetype, { 'string', 'table' }, true },
}) })
-- parser names are assumed to be lowercase (consistent behavior on case-insensitive file systems)
lang = lang:lower()
if vim._ts_has_language(lang) then if vim._ts_has_language(lang) then
M.register(lang, filetype) M.register(lang, filetype)
return return

View File

@ -758,7 +758,6 @@ local has_parser = vim.func._memoize(1, function(lang)
end) end)
--- Return parser name for language (if exists) or filetype (if registered and exists). --- Return parser name for language (if exists) or filetype (if registered and exists).
--- Also attempts with the input lower-cased.
--- ---
---@param alias string language or filetype name ---@param alias string language or filetype name
---@return string? # resolved parser name ---@return string? # resolved parser name
@ -772,19 +771,10 @@ local function resolve_lang(alias)
return alias return alias
end end
if has_parser(alias:lower()) then
return alias:lower()
end
local lang = vim.treesitter.language.get_lang(alias) local lang = vim.treesitter.language.get_lang(alias)
if lang and has_parser(lang) then if lang and has_parser(lang) then
return lang return lang
end end
lang = vim.treesitter.language.get_lang(alias:lower())
if lang and has_parser(lang) then
return lang
end
end end
---@private ---@private
@ -808,7 +798,7 @@ function LanguageTree:_get_injection(match, metadata)
-- Lang should override any other language tag -- Lang should override any other language tag
if name == 'injection.language' then if name == 'injection.language' then
local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] }) local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] })
lang = resolve_lang(text) lang = resolve_lang(text:lower()) -- language names are always lower case
elseif name == 'injection.filename' then elseif name == 'injection.filename' then
local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] }) local text = vim.treesitter.get_node_text(node, self._source, { metadata = metadata[id] })
local ft = vim.filetype.match({ filename = text }) local ft = vim.filetype.match({ filename = text })

View File

@ -484,7 +484,7 @@ describe('treesitter highlighting (C)', function()
exec_lua [[ exec_lua [[
vim.treesitter.language.register("c", "foo") vim.treesitter.language.register("c", "foo")
local parser = vim.treesitter.get_parser(0, "c", { local parser = vim.treesitter.get_parser(0, "c", {
injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "fOO")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "fOO"))'} injections = {c = '(preproc_def (preproc_arg) @injection.content (#set! injection.language "foo")) (preproc_function_def value: (preproc_arg) @injection.content (#set! injection.language "foo"))'}
}) })
local highlighter = vim.treesitter.highlighter local highlighter = vim.treesitter.highlighter
test_hl = highlighter.new(parser, {queries = {c = hl_query}}) test_hl = highlighter.new(parser, {queries = {c = hl_query}})