From dc6a9170eb10032439200d1585ac8daa77d161f6 Mon Sep 17 00:00:00 2001 From: "neovim-backports[bot]" <175700243+neovim-backports[bot]@users.noreply.github.com> Date: Sun, 14 Jun 2026 11:25:18 -0400 Subject: [PATCH] backport: fix(lsp): trailing blank line when edit inserts past end of buffer (#40176) Problem: A text edit positioned entirely past the last buffer line, with newText ending in a newline, leaves a stray blank line: the past-the-end path appends the trailing empty fragment produced by vim.split() and does not set has_eol_text_edit, so the end-of-buffer cleanup is skipped. Formatting servers emit such edits whenever formatting moves text to the end of a document. Regression from ec94014cd1 (#20137), which split the past-the-end fast path off the clamp path that sets the flag. Solution: Set has_eol_text_edit in the past-the-end path, like the adjacent path that clamps end_row. (cherry picked from commit d42f7ee9dcbbece1c65d901fb9825fbe97eeedce) Co-authored-by: Aaron Tinio --- runtime/lua/vim/lsp/util.lua | 1 + test/functional/plugin/lsp_spec.lua | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 3677a414cf..cc9e4e3690 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -378,6 +378,7 @@ function M.apply_text_edits(text_edits, bufnr, position_encoding, change_annotat -- of the buffer. if max <= start_row then api.nvim_buf_set_lines(bufnr, max, max, false, text) + has_eol_text_edit = true else local last_line_len = #(get_line(bufnr, math.min(end_row, max - 1)) or '') -- Some LSP servers may return +1 range of the buffer content but nvim_buf_set_text can't diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua index 2e68f2cbfe..93ecc71b04 100644 --- a/test/functional/plugin/lsp_spec.lua +++ b/test/functional/plugin/lsp_spec.lua @@ -2248,6 +2248,20 @@ describe('LSP', function() }, buf_lines(1)) end) + it('applies newline-terminated text edits at the end of the document', function() + apply_text_edits({ + { 5, 0, 5, 0, 'foobar\n' }, + }) + eq({ + 'First line of text', + 'Second line of text', + 'Third line of text', + 'Fourth line of text', + 'å å ɧ 汉语 ↥ 🤦 🦄', + 'foobar', + }, buf_lines(1)) + end) + it('it restores marks', function() eq(true, api.nvim_buf_set_mark(1, 'a', 2, 1, {})) apply_text_edits({