commit 15d57ab0ba5e0031072cfa41fd83817a9ac60483
parent 029b7a149fa77cefe45e8df5524ef41ed4ee78eb
Author: glepnir <glephunter@gmail.com>
Date: Tue, 29 Jul 2025 21:24:44 +0800
fix(api): single-line visual block insert triggers extra on_lines #35098
Problem: Visual block insert on a single line incorrectly triggers two
on_lines callbacks - one for the correct line (0-indexed) and another
for a non-existent additional line.
Solution: Only call changed_lines() in block_insert() when additional
lines beyond the first were actually modified (start.lnum < end.lnum).
Diffstat:
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
@@ -710,7 +710,11 @@ static void block_insert(oparg_T *oap, const char *s, size_t slen, bool b_insert
State = oldstate;
- changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true);
+ // Only call changed_lines if we actually modified additional lines beyond the first
+ // This matches the condition for the for loop above: start + 1 <= end
+ if (oap->start.lnum < oap->end.lnum) {
+ changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true);
+ }
}
// Keep the last expression line here, for repeating.
diff --git a/test/functional/lua/buffer_updates_spec.lua b/test/functional/lua/buffer_updates_spec.lua
@@ -449,6 +449,19 @@ describe('lua buffer event callbacks: on_lines', function()
eq({ 'bytes', 2, 5, 0, 0, 0, 4, 0, 40, 0, 10, 10 }, api.nvim_get_var('qf_on_bytes'))
eq({ 'lines', 2, 6, 0, 5, 1, 42 }, api.nvim_get_var('qf_on_lines'))
end)
+
+ it('single-line visual block insert should not trigger extra on_lines #22009', function()
+ exec_lua(function()
+ _G.res = {}
+ vim.api.nvim_buf_attach(0, false, {
+ on_lines = function(_, bufnr, _, first, last, last_updated, _, _, _)
+ _G.res = { bufnr, first, last, last_updated }
+ end,
+ })
+ end)
+ feed('<C-v>I <ESC>')
+ eq({ api.nvim_get_current_buf(), 0, 1, 1 }, exec_lua('return _G.res'))
+ end)
end)
describe('lua: nvim_buf_attach on_bytes', function()