fix(lsp): malformed edit if apply_text_edits() is called twice (#39347)

Problem:
Use vim.lsp.util.apply_text_edits to re-apply the same textedit causes
an incorrect edit, because apply_text_edits silently modifies the
parameter.

Solution:
- Avoid changing `text_edit._index`.
- Document this fun feature.

Helped-by: Riley Bruins <ribru17@hotmail.com>
Helped-by: Yi Ming <ofseed@foxmail.com>

(cherry picked from commit 790a8be5f3)

Co-authored-by: geril07 <62308020+geril07@users.noreply.github.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
This commit is contained in:
neovim-backports[bot]
2026-04-23 19:24:04 -04:00
committed by GitHub
parent c4d3a3d363
commit 0bd6e62509
2 changed files with 9 additions and 3 deletions

View File

@@ -2870,7 +2870,8 @@ apply_text_document_edit({text_document_edit}, {index}, {position_encoding},
*vim.lsp.util.apply_text_edits()*
apply_text_edits({text_edits}, {bufnr}, {position_encoding},
{change_annotations})
Applies a list of text edits to a buffer.
Applies a list of text edits to a buffer. Note: this mutates `text_edits`
(sorts in-place and adds `_index` fields).
Parameters: ~
• {text_edits} (`(lsp.TextEdit|lsp.AnnotatedTextEdit)[]`)

View File

@@ -291,7 +291,9 @@ local function get_line_byte_from_position(bufnr, position, position_encoding)
return col
end
--- Applies a list of text edits to a buffer.
--- Applies a list of text edits to a buffer. Note: this mutates `text_edits` (sorts in-place and
--- adds `_index` fields).
---
---@param text_edits (lsp.TextEdit|lsp.AnnotatedTextEdit)[]
---@param bufnr integer Buffer id
---@param position_encoding 'utf-8'|'utf-16'|'utf-32'
@@ -320,7 +322,10 @@ function M.apply_text_edits(text_edits, bufnr, position_encoding, change_annotat
-- Fix reversed range and indexing each text_edits
for index, text_edit in ipairs(text_edits) do
--- @cast text_edit lsp.TextEdit|{_index: integer}
text_edit._index = index
-- XXX: Preserve existing _index to avoid surprises if the same edit is reapplied. #39344
if text_edit._index == nil then
text_edit._index = index
end
if
text_edit.range.start.line > text_edit.range['end'].line