From f2a5c90cbc2a06d5a1f18b82a1971db1061f6c90 Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sat, 18 Apr 2026 12:53:00 +0200 Subject: [PATCH] fix(marks): adjust marks when unloading "nofile" buffer #39118 Problem: Marks are not adjusted unloading a buffer that doesn't exist on disk. E.g. extmarks are still valid (and will be beyond the end of the buffer if the buffer is reloaded), even though the text is lost. Solution: Adjust marks for a cleared buffer when unloading a buffer that doesn't exist on disk. (cherry picked from commit 68f7acaaae662b7511cc71a20901066174e03538) --- src/nvim/buffer.c | 8 ++++++++ test/functional/api/extmark_spec.lua | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 02f93bc64a..fc969d0978 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -909,8 +909,16 @@ void buf_freeall(buf_T *buf, int flags) unblock_autocmds(); } + linenr_T count = buf->b_ml.ml_line_count; ml_close(buf, true); // close and delete the memline/memfile buf->b_ml.ml_line_count = 0; // no lines in buffer + + // Ensure marks are adjusted for cleared buffer in case buffer not on disk: + // if it is reloaded the buffer will be empty. + if (bt_nofilename(buf) && !exiting) { + mark_adjust_buf(buf, 1, count, MAXLNUM, -count, false, kMarkAdjustNormal, kExtmarkNoUndo); + } + if ((flags & BFA_KEEP_UNDO) == 0) { // free the memory allocated for undo // and reset all undo information diff --git a/test/functional/api/extmark_spec.lua b/test/functional/api/extmark_spec.lua index 3245eba80c..911d9fb0bf 100644 --- a/test/functional/api/extmark_spec.lua +++ b/test/functional/api/extmark_spec.lua @@ -1959,6 +1959,16 @@ describe('API/extmarks', function() }, } end) + + it('are invalidated when "nofile" buffer is unloaded', function() + local buf = api.nvim_create_buf(false, true) + api.nvim_buf_set_name(buf, 'foo') + api.nvim_buf_set_lines(buf, 0, 0, false, { 'foo', 'bar' }) + local id = api.nvim_buf_set_extmark(buf, ns, 1, 0, { invalidate = true }) + api.nvim_buf_delete(buf, { unload = true }) + local mark = { 0, 0, { invalid = true, invalidate = true, ns_id = 3, right_gravity = true } } + eq(mark, api.nvim_buf_get_extmark_by_id(buf, ns, id, { details = true })) + end) end) describe('Extmarks buffer api with many marks', function()