diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 2db77606c0..92d761c072 100644 --- 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 index 1d568e7d05..836166be05 100644 --- 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('I ') + eq({ api.nvim_get_current_buf(), 0, 1, 1 }, exec_lua('return _G.res')) + end) end) describe('lua: nvim_buf_attach on_bytes', function()