Skip to content

Commit a4218e3

Browse files
abeldekatechasnovski
authored andcommitted
fix(jump): consumes a char on dot-repeat when target not in text
Resolve #2290
1 parent 0098de9 commit a4218e3

2 files changed

Lines changed: 39 additions & 22 deletions

File tree

lua/mini/jump.lua

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ MiniJump.state = {
181181
MiniJump.jump = function(target, backward, till, n_times)
182182
if H.is_disabled() then return end
183183

184+
-- Ensure to undo "consuming a character" effect if there is no target found
185+
-- Do it here to act on dot-repeat
186+
local has_changed_cursor = false
187+
local undo_no_move = function()
188+
if not has_changed_cursor then vim.cmd('undo!') end
189+
end
190+
if MiniJump._is_expr then vim.schedule(undo_no_move) end
191+
184192
-- Dot-repeat should not change the state, so save it to later restore
185193
local is_dot_repeat = MiniJump._is_expr and not MiniJump._is_expr_init
186194
MiniJump._is_expr, MiniJump._is_expr_init = nil, nil
@@ -234,7 +242,7 @@ MiniJump.jump = function(target, backward, till, n_times)
234242

235243
-- Track cursor position to account for movement not caught by `CursorMoved`
236244
H.cache.latest_cursor = H.get_cursor_data()
237-
H.cache.has_changed_cursor = not vim.deep_equal(H.cache.latest_cursor, init_cursor_data)
245+
has_changed_cursor = not vim.deep_equal(H.cache.latest_cursor, init_cursor_data)
238246

239247
-- Restore the state if needed
240248
if is_dot_repeat then
@@ -404,11 +412,6 @@ H.make_expr_jump = function(backward, till)
404412
if isnt_repeat_jump and target == nil then return '<Esc>' end
405413
H.update_state(target)
406414

407-
vim.schedule(function()
408-
if H.cache.has_changed_cursor then return end
409-
vim.cmd('undo!')
410-
end)
411-
412415
-- Set a flag to distinguish first call from dot-repeat
413416
MiniJump._is_expr_init = true
414417

tests/test_jump.lua

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -531,36 +531,49 @@ end
531531

532532
T['Jumping with f/t/F/T']['does nothing if there is no place to jump'] = function()
533533
-- Normal mode
534-
local validate_normal = function(keys, start_col, ref_mode)
535-
set_lines({ 'abcdefg' })
534+
local validate_normal = function(keys, start_col, ref_mode, line)
535+
set_lines({ line })
536536
set_cursor(1, start_col)
537537

538538
type_keys(keys, 'd')
539539

540540
-- It shouldn't move anywhere and should not modify text
541541
eq(get_cursor(), { 1, start_col })
542-
eq(get_lines(), { 'abcdefg' })
542+
eq(get_lines(), { line })
543+
eq(child.fn.mode(), ref_mode)
544+
545+
-- The above applies to subsequent dot-repeats as well
546+
type_keys('.')
547+
eq(get_cursor(), { 1, start_col })
548+
eq(get_lines(), { line })
543549
eq(child.fn.mode(), ref_mode)
544550

545551
-- Ensure there is no jumping
546552
child.lua('MiniJump.stop_jumping()')
547553
child.ensure_normal_mode()
548554
end
549555

550-
validate_normal('f', 4, 'n')
551-
validate_normal('t', 4, 'n')
552-
validate_normal('F', 2, 'n')
553-
validate_normal('T', 2, 'n')
554-
555-
validate_normal('vf', 4, 'v')
556-
validate_normal('vt', 4, 'v')
557-
validate_normal('vF', 2, 'v')
558-
validate_normal('vT', 2, 'v')
556+
local validate_by_line = function(line)
557+
validate_normal('f', 4, 'n', line)
558+
validate_normal('t', 4, 'n', line)
559+
validate_normal('F', 2, 'n', line)
560+
validate_normal('T', 2, 'n', line)
561+
562+
validate_normal('vf', 4, 'v', line)
563+
validate_normal('vt', 4, 'v', line)
564+
validate_normal('vF', 2, 'v', line)
565+
validate_normal('vT', 2, 'v', line)
566+
567+
validate_normal('df', 4, 'n', line)
568+
validate_normal('dt', 4, 'n', line)
569+
validate_normal('dF', 2, 'n', line)
570+
validate_normal('dT', 2, 'n', line)
571+
end
559572

560-
validate_normal('df', 4, 'n')
561-
validate_normal('dt', 4, 'n')
562-
validate_normal('dF', 2, 'n')
563-
validate_normal('dT', 2, 'n')
573+
-- Target d is present but not reachable
574+
validate_by_line('abcdefg')
575+
-- Target d is not present
576+
validate_by_line('abcxefg')
564577
end
565578

566579
T['Jumping with f/t/F/T']['can be dot-repeated if did not jump at first'] = function()
@@ -720,6 +733,7 @@ T['Jumping with f/t/F/T']['stops jumping if no target is found'] = function()
720733
-- General idea: there was a bug which didn't reset jumping state if target
721734
-- was not found by `vim.fn.search()`. In that case, next typing of jumping
722735
-- key wouldn't make effect, but it should.
736+
-- Related test case: 'Enters jumping mode even if first jump is impossible'
723737
for _, key in ipairs({ 'f', 't', 'F', 'T' }) do
724738
local start_col = key == key:lower() and 0 or 3
725739
set_cursor(1, start_col)

0 commit comments

Comments
 (0)