diff --git a/lua/mini/jump.lua b/lua/mini/jump.lua index 7b16c98e..35eb759b 100644 --- a/lua/mini/jump.lua +++ b/lua/mini/jump.lua @@ -181,6 +181,11 @@ MiniJump.state = { MiniJump.jump = function(target, backward, till, n_times) if H.is_disabled() then return end + -- If dot-repeating the state needs to be restored after the jump + local needs_restore = MiniJump._is_expr and MiniJump.state.mode ~= 'no' + MiniJump._is_expr = nil + local state_snapshot = needs_restore and vim.deepcopy(MiniJump.state) or nil + -- Cache inputs for future use H.update_state(target, backward, till, n_times) @@ -230,6 +235,12 @@ MiniJump.jump = function(target, backward, till, n_times) -- Track cursor position to account for movement not caught by `CursorMoved` H.cache.latest_cursor = H.get_cursor_data() H.cache.has_changed_cursor = not vim.deep_equal(H.cache.latest_cursor, init_cursor_data) + + -- If dot-repeating restore the state to its value from before this jump + if needs_restore then + state_snapshot.jumping = true + MiniJump.state = state_snapshot + end end --- Make smart jump @@ -383,7 +394,8 @@ H.make_expr_jump = function(backward, till) return function() if H.is_disabled() then return '' end - H.update_state(nil, backward, till, vim.v.count1) + local count = vim.v.count1 + H.update_state(nil, backward, till, count) -- Ask for `target` for non-repeating jump as this will be used only in -- operator-pending mode. Dot-repeat is supported via expression-mapping. @@ -398,7 +410,10 @@ H.make_expr_jump = function(backward, till) if H.cache.has_changed_cursor then return end vim.cmd('undo!') end) - return 'vlua MiniJump.jump()' + + -- Encode state in expression for dot-repeat + local args = string.format('%s,%s,%s,%s', vim.inspect(target), backward, till, count) + return 'vlua MiniJump._is_expr=true; MiniJump.jump(' .. args .. ')' end end diff --git a/tests/test_jump.lua b/tests/test_jump.lua index bab12e30..f18a40e5 100644 --- a/tests/test_jump.lua +++ b/tests/test_jump.lua @@ -183,6 +183,12 @@ T['state']['updates `mode`'] = function() type_keys('d', 't', 'e') eq(get_state().mode, 'nov') + type_keys('V', 't', 'e') + eq(get_state().mode, 'V') + child.ensure_normal_mode() + -- Ensure dot-repeat does not update mode after the jump + type_keys('.') + eq(get_state().mode, 'V') child.lua('MiniJump.stop_jumping()') end @@ -402,7 +408,7 @@ T['Jumping with f/t/F/T']['works in Operator-pending mode'] = new_set({ type_keys('d', '2', key, 'e') eq(get_lines(), { line_seq[3] }) - -- Just typing `key` shouldn't repeat action + -- Just typing `key` shouldn't repeat motion local cur_pos = get_cursor() type_keys(key) eq(get_cursor(), cur_pos) @@ -582,6 +588,32 @@ T['Jumping with f/t/F/T']['can be dot-repeated if did not jump at first'] = func validate('dT', 1, 5, 'abcdg') end +T['Jumping with f/t/F/T']['inside dot-repeat is not affected by regular jumping'] = function() + -- Normal mode + local validate = function(keys, key_antagonist, result) + local line = '_xdxdx1x1xdxdx_' + local tests_forward = key_antagonist == string.upper(key_antagonist) + + set_lines({ line }) + set_cursor(1, tests_forward and 0 or (string.len(line) - 1)) + + type_keys(keys) + type_keys(tests_forward and '$' or '^') + type_keys(key_antagonist, '1') + type_keys('.') + eq(get_lines(), { result }) + + -- Ensure there is no jumping + child.lua('MiniJump.stop_jumping()') + child.ensure_normal_mode() + end + + validate('2dfd', 'T', 'x1x1x_') + validate('2dtd', 'F', 'dx1xdx_') + validate('2dFd', 't', '_x1x1x') + validate('2dTd', 'f', '_xdx1xd') +end + T['Jumping with f/t/F/T']['stops prompting for target if hit `` or ``'] = new_set({ parametrize = { { 'f', '' }, @@ -878,6 +910,26 @@ T['Repeat jump with ;']['works after jump in Operator-pending mode'] = function( type_keys('d', '2f', 'e', ';') eq(get_lines(), { '3e4e5e' }) eq(get_cursor(), { 1, 3 }) + + -- Like nvim --clean, it does not use the latest dot repeat + set_lines({ '1e2e3e3e4e5e6' }) + set_cursor(1, 0) + + type_keys('d', '2f', 'e') + eq(get_lines(), { '3e3e4e5e6' }) + eq(get_cursor(), { 1, 0 }) + + type_keys('$', 'T', '3') + eq(get_lines(), { '3e3e4e5e6' }) + eq(get_cursor(), { 1, 3 }) + + type_keys('.') + eq(get_lines(), { '3e36' }) + eq(get_cursor(), { 1, 3 }) + + type_keys(';') + eq(get_lines(), { '3e36' }) + eq(get_cursor(), { 1, 1 }) end T['Repeat jump with ;']['works in Operator-pending mode'] = function()