mirror of
https://github.com/neovim/neovim.git
synced 2026-06-16 00:31:16 +00:00
fix(treesitter): get_node_text() inconsistent trailing newline #39409
Problem:
`get_node_text()` returned inconsistent results between buffer and
string sources when a node's range ends at `end_col == 0` (i.e. the node
ends with a newline). The buffer path dropped the trailing newline; the
string path included it correctly.
Solution:
Append `'\n'` in `buf_range_get_text()` when `end_col == 0` and
`start_row ~= end_row`. The `start_row ~= end_row` guard excludes
zero-width nodes at column 0, which should return `""`.
Remove the workaround in the `#trim!` directive that manually
compensated for the missing newline.
Strip whitespace in `resolve_lang()` so injection language nodes ending
at `end_col == 0` (e.g. `">lua\n"`) still resolve correctly.
(cherry picked from commit 7ed5609439)
This commit is contained in:
committed by
github-actions[bot]
parent
44baa8d94b
commit
4f22640b86
@@ -201,6 +201,8 @@ end
|
||||
---@returns string
|
||||
local function buf_range_get_text(buf, range)
|
||||
local start_row, start_col, end_row, end_col = M._range.unpack4(range)
|
||||
local append_newline = end_col == 0 and start_row ~= end_row
|
||||
|
||||
if end_col == 0 then
|
||||
if start_row == end_row then
|
||||
start_col = -1
|
||||
@@ -209,7 +211,12 @@ local function buf_range_get_text(buf, range)
|
||||
end_col = -1
|
||||
end_row = end_row - 1
|
||||
end
|
||||
|
||||
local lines = api.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {})
|
||||
if append_newline then
|
||||
table.insert(lines, '')
|
||||
end
|
||||
|
||||
return table.concat(lines, '\n')
|
||||
end
|
||||
|
||||
|
||||
@@ -1023,7 +1023,9 @@ end)
|
||||
---@return string? # resolved parser name
|
||||
local function resolve_lang(alias)
|
||||
-- normalize: treesitter language names are always lower case and use underscores
|
||||
alias = alias and alias:lower():gsub('%-', '_')
|
||||
-- Language name (from `get_text_node`) may end with "\n".
|
||||
alias = alias and alias:gsub('%s+', ''):lower():gsub('%-', '_')
|
||||
|
||||
-- validate that `alias` is a legal language
|
||||
if not (alias and alias:match('[%w_]+') == alias) then
|
||||
return
|
||||
|
||||
@@ -706,10 +706,6 @@ local directive_handlers = {
|
||||
local start_row, start_col, end_row, end_col = node:range()
|
||||
|
||||
local node_text = vim.split(vim.treesitter.get_node_text(node, bufnr), '\n')
|
||||
if end_col == 0 then
|
||||
-- get_node_text() will ignore the last line if the node ends at column 0
|
||||
node_text[#node_text + 1] = ''
|
||||
end
|
||||
|
||||
local end_idx = #node_text
|
||||
local start_idx = 1
|
||||
|
||||
@@ -227,6 +227,32 @@ describe('treesitter node API', function()
|
||||
eq({ 0, 0, 2, 3 }, lua_eval('range'))
|
||||
end)
|
||||
|
||||
it(
|
||||
'get_node_text() includes trailing newline for buffer source when node end_col == 0',
|
||||
function()
|
||||
insert('local x = 1')
|
||||
|
||||
exec_lua(function()
|
||||
_G.node = vim.treesitter.get_parser(0, 'lua'):parse()[1]:root()
|
||||
end)
|
||||
|
||||
eq('local x = 1\n', lua_eval('vim.treesitter.get_node_text(_G.node, 0)'))
|
||||
end
|
||||
)
|
||||
|
||||
it(
|
||||
'get_node_text() includes trailing newline for string source when node end_col == 0',
|
||||
function()
|
||||
exec_lua(function()
|
||||
local source = 'local x = 1\n'
|
||||
_G.source = source
|
||||
_G.node = vim.treesitter.get_string_parser(source, 'lua'):parse()[1]:root()
|
||||
end)
|
||||
|
||||
eq('local x = 1\n', lua_eval('vim.treesitter.get_node_text(_G.node, _G.source)'))
|
||||
end
|
||||
)
|
||||
|
||||
it('tree:root() is idempotent', function()
|
||||
insert([[
|
||||
function x()
|
||||
|
||||
@@ -441,7 +441,7 @@ describe('treesitter parser API', function()
|
||||
local tree = parser:parse()[1]
|
||||
return vim.treesitter.get_node_text(tree:root(), 0)
|
||||
end)
|
||||
eq(t.dedent(test_text), res)
|
||||
eq(t.dedent(test_text) .. '\n', res)
|
||||
|
||||
local res2 = exec_lua(function()
|
||||
local parser = vim.treesitter.get_parser(0, 'c')
|
||||
|
||||
Reference in New Issue
Block a user