diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index 0d4a1a54dd..4b2628609a 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -110,6 +110,10 @@ function LanguageTree.new(source, lang, opts) ---@type LanguageTreeOpts opts = opts or {} + if source == 0 then + source = vim.api.nvim_get_current_buf() + end + local injections = opts.injections or {} local self = setmetatable({ _source = source, @@ -561,11 +565,13 @@ end ---@param node TSNode ---@param source string|integer ---@param metadata TSMetadata +---@param include_children boolean ---@return Range6[] local function get_node_ranges(node, source, metadata, include_children) local range = vim.treesitter.get_range(node, source, metadata) + local child_count = node:named_child_count() - if include_children then + if include_children or child_count == 0 then return { range } end @@ -573,7 +579,8 @@ local function get_node_ranges(node, source, metadata, include_children) local srow, scol, sbyte, erow, ecol, ebyte = Range.unpack6(range) - for i = 0, node:named_child_count() - 1 do + -- We are excluding children so we need to mask out their ranges + for i = 0, child_count - 1 do local child = node:named_child(i) local c_srow, c_scol, c_sbyte, c_erow, c_ecol, c_ebyte = child:range(true) if c_srow > srow or c_scol > scol then @@ -604,7 +611,10 @@ end ---@param combined boolean ---@param ranges Range6[] local function add_injection(t, tree_index, pattern, lang, combined, ranges) - assert(type(lang) == 'string') + if #ranges == 0 then + -- Make sure not to add an empty range set as this is interpreted to mean the whole buffer. + return + end -- Each tree index should be isolated from the other nodes. if not t[tree_index] then diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index f0144e6f6d..da84f435c9 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -982,4 +982,38 @@ int x = INT_MAX; eq(rb, r) end) + + it("does not produce empty injection ranges (#23409)", function() + insert [[ + Examples: >lua + local a = {} +< + ]] + + -- This is not a valid injection since (code) has children and include-children is not set + exec_lua [[ + parser1 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + injections = { + vimdoc = "((codeblock (language) @injection.language (code) @injection.content))" + } + }) + parser1:parse() + ]] + + eq(0, exec_lua("return #vim.tbl_keys(parser1:children())")) + + exec_lua [[ + parser2 = require('vim.treesitter.languagetree').new(0, "vimdoc", { + injections = { + vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))" + } + }) + parser2:parse() + ]] + + eq(1, exec_lua("return #vim.tbl_keys(parser2:children())")) + eq( { { { 1, 0, 21, 2, 0, 42 } } }, exec_lua("return parser2:children().lua:included_regions()")) + + end) + end)