aboutsummaryrefslogtreecommitdiff
path: root/test/functional/editor/cmdatom_spec.lua
diff options
context:
space:
mode:
authorQiming zhao <chemzqm@gmail.com>2026-09-30 22:16:27 +0800
committerGitHub <noreply@github.com>2026-09-30 10:16:27 -0400
commitcc4e0c8d60ede60d2a48efe322a9bd1f71198b8a (patch)
tree764e653f90e52726c1cf149d3d69fc1bb6ec4865 /test/functional/editor/cmdatom_spec.lua
parenta8062120ad8c144d5da853a611dc9d51708f2d83 (diff)
downloadrneovim-cc4e0c8d60ede60d2a48efe322a9bd1f71198b8a.tar.gz
rneovim-cc4e0c8d60ede60d2a48efe322a9bd1f71198b8a.tar.bz2
rneovim-cc4e0c8d60ede60d2a48efe322a9bd1f71198b8a.zip
fix(input): end Visual mode when aborting redo #42151
Problem: Skipping buffer flushing in Visual mode breaks map-error and leaves failed redo motions that raise errors stuck in Visual mode. Solution: Keep flushing on errors and exit Visual mode when pending redo is discarded. Cover failed motions, unset marks, macros, and mappings. AI-assisted
Diffstat (limited to 'test/functional/editor/cmdatom_spec.lua')
-rw-r--r--test/functional/editor/cmdatom_spec.lua48
1 files changed, 48 insertions, 0 deletions
diff --git a/test/functional/editor/cmdatom_spec.lua b/test/functional/editor/cmdatom_spec.lua
index 4d805a794e..7c70a2d07b 100644
--- a/test/functional/editor/cmdatom_spec.lua
+++ b/test/functional/editor/cmdatom_spec.lua
@@ -54,6 +54,54 @@ describe('dot-repeat', function()
eq({ 'acbzacbonexy', 'czacbtwo' }, get_lines())
end)
+ it('ends Visual mode when a replayed motion fails #41896', function()
+ fn.setline(1, { '1', '2', '3' })
+ feed('<C-V>jI1<Esc>')
+ eq({ '11', '12', '3' }, get_lines())
+ feed('j.')
+ eq({ '11', '112', '13' }, get_lines())
+ feed('j.')
+ eq({ '11', '112', '13' }, get_lines())
+ eq('n', fn.mode(1))
+ -- A failed repeat does not replace the last change.
+ feed('k0.')
+ eq({ '11', '1112', '113' }, get_lines())
+ eq('n', fn.mode(1))
+ end)
+
+ for _, errorbells in ipairs({ 'noerrorbells', 'errorbells' }) do
+ it('ends Visual mode when a replayed motion raises an error with ' .. errorbells, function()
+ command('set ' .. errorbells)
+ fn.setline(1, { 'one', 'two' })
+ feed('majV`a~')
+ eq({ 'ONE', 'TWO' }, get_lines())
+ command('delmarks a')
+ feed('.')
+ eq('E20: Mark not set', api.nvim_get_vvar('errmsg'))
+ eq({ 'ONE', 'TWO' }, get_lines())
+ eq('n', fn.mode(1))
+ end)
+ end
+
+ it('still stops macros and mappings on failed Visual motions', function()
+ fn.setline(1, { 'one', 'two', 'three' })
+ fn.setreg('q', 'Vjd')
+ feed('2@q')
+ eq({ 'three' }, get_lines())
+ eq('V', fn.mode(1))
+ feed('<Esc>')
+ command('nnoremap Q Vjd')
+ feed('Q')
+ eq({ 'three' }, get_lines())
+ eq('V', fn.mode(1))
+ feed('<Esc>')
+ -- An ordinary failed motion still leaves the selection active.
+ feed('vj')
+ eq('v', fn.mode(1))
+ feed('d')
+ eq({ 'hree' }, get_lines())
+ end)
+
it('of a visual op does not churn showcmd', function()
local screen = Screen.new(40, 8, { ext_messages = true })
command('set showcmd')