Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions lua/mini/jump.lua
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ MiniJump.jump = function(target, backward, till, n_times)
H.timers.idle_stop:stop()
H.timers.idle_stop:start(config.delay.idle_stop, 0, vim.schedule_wrap(function() MiniJump.stop_jumping() end))

-- Force charwise-visual in Operator-pending expression mapping
if is_expr then vim.cmd('normal! v') end

-- Make jump(s)
H.cache.n_cursor_moved = 0
local was_jumping = MiniJump.state.jumping
Expand All @@ -224,15 +227,16 @@ 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()

-- Restore the state if needed. It should a jumping state if there was jump
-- Restore the state if needed. The jumping state is applied if there was jump
-- or if it is possible to jump in other direction (i.e. target is present).
MiniJump.state = is_dot_repeat and state_snapshot or MiniJump.state
local search_pattern = '\\V' .. vim.fn.escape(MiniJump.state.target, '\\')
MiniJump.state.jumping = has_jumped or vim.fn.search(search_pattern, 'wn') ~= 0

-- Ensure to undo "consume a character" effect in Operator-pending expression
-- mapping if there is no target found. Do it here to also act on dot-repeat.
if is_expr and not has_jumped then vim.schedule(function() vim.cmd('undo!') end) end
-- If target not found in Operator-pending expression mapping, charwise-visual
-- is reverted, preventing a character from being consumed.
-- Do it here to also act on dot-repeat.
if is_expr and not has_jumped then vim.cmd('normal! v') end
end

--- Make smart jump
Expand Down Expand Up @@ -404,7 +408,7 @@ H.make_expr_jump = function(backward, till)
-- for `repeat_jump` case to have it using latest jumping state during
-- dot-repeat also (as does `nvim --clean`).
local args = string.format('%s,%s,%s,%s', vim.inspect(target), backward, till, count)
return 'v<Cmd>lua MiniJump._is_expr=true; MiniJump.jump(' .. args .. ')<CR>'
return '<Cmd>lua MiniJump._is_expr=true; MiniJump.jump(' .. args .. ')<CR>'
end
end

Expand Down
60 changes: 33 additions & 27 deletions tests/test_jump.lua
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ T['state']['updates `mode`'] = function()
child.ensure_normal_mode()

type_keys('d', 't', 'e')
eq(get_state().mode, 'nov')
eq(get_state().mode, 'no')

-- Ensure dot-repeat does not update mode after the jump
type_keys('V', 't', 'e')
Expand Down Expand Up @@ -558,50 +558,56 @@ T['Jumping with f/t/F/T']['enters jumping mode even if first jump is impossible'
end

T['Jumping with f/t/F/T']['does nothing if there is no place to jump'] = function()
local validate_single = function(keys, start_line, start_col, ref_mode)
set_lines({ start_line })
set_cursor(1, start_col)
local validate_single = function(keys, lines, start_line, start_col, ref_mode)
set_lines(lines)
set_cursor(start_line, start_col)

type_keys(keys, 'd')

-- It shouldn't move anywhere and should not modify text
eq(get_cursor(), { 1, start_col })
eq(get_lines(), { start_line })
eq(get_cursor(), { start_line, start_col })
eq(get_lines(), lines)
eq(child.fn.mode(), ref_mode)

-- The above applies to subsequent dot-repeats as well
type_keys('.')
eq(get_cursor(), { 1, start_col })
eq(get_lines(), { start_line })
eq(get_cursor(), { start_line, start_col })
eq(get_lines(), lines)
eq(child.fn.mode(), ref_mode)

-- Ensure there is no jumping
child.lua('MiniJump.stop_jumping()')
child.ensure_normal_mode()
end

local validate = function(line)
validate_single('f', line, 4, 'n')
validate_single('t', line, 4, 'n')
validate_single('F', line, 2, 'n')
validate_single('T', line, 2, 'n')

validate_single('vf', line, 4, 'v')
validate_single('vt', line, 4, 'v')
validate_single('vF', line, 2, 'v')
validate_single('vT', line, 2, 'v')

validate_single('df', line, 4, 'n')
validate_single('dt', line, 4, 'n')
validate_single('dF', line, 2, 'n')
validate_single('dT', line, 2, 'n')
local validate = function(lines, start_line)
start_line = start_line == nil and 1 or start_line

local start_col = start_line > 1 and 0 or 4
validate_single('f', lines, start_line, start_col, 'n')
validate_single('t', lines, start_line, start_col, 'n')
validate_single('vf', lines, start_line, start_col, 'v')
validate_single('vt', lines, start_line, start_col, 'v')
validate_single('df', lines, start_line, start_col, 'n')
validate_single('dt', lines, start_line, start_col, 'n')

start_col = start_line > 1 and 0 or 2
validate_single('F', lines, start_line, start_col, 'n')
validate_single('T', lines, start_line, start_col, 'n')
validate_single('vF', lines, start_line, start_col, 'v')
validate_single('vT', lines, start_line, start_col, 'v')
validate_single('dF', lines, start_line, start_col, 'n')
validate_single('dT', lines, start_line, start_col, 'n')
end

-- Target is present but not reachable
validate('abcdefg')
validate({ 'abcdefg' })

-- Target is not present
validate('abcxefg')
validate({ 'abcxefg' })

-- Target is not present and cursor is on empty line
validate({ 'abcxefg', '' }, 2)
end

T['Jumping with f/t/F/T']['can be dot-repeated if did not jump at first'] = function()
Expand Down Expand Up @@ -1322,7 +1328,7 @@ T['Events']['work in Visual and Operator-pending modes'] = function()
validate_log_and_clean({ { event = 'MiniJumpGetTarget', state = state } })

type_keys('e')
state.mode = mode == 'v' and 'v' or 'nov'
state.mode = mode == 'v' and 'v' or 'no'
state.jumping, state.target = true, 'e'
validate_log_and_clean({
{ event = 'MiniJumpStart', state = state },
Expand Down Expand Up @@ -1425,7 +1431,7 @@ T['Events']['work with dot-repeat'] = function()
child.lua('_G.log = {}')

type_keys('.')
local state = { mode = 'nov', jumping = true, target = 'e', backward = false, till = false, n_times = 1 }
local state = { mode = 'no', jumping = true, target = 'e', backward = false, till = false, n_times = 1 }
validate_log_and_clean({
{ event = 'MiniJumpStart', state = state },
{ event = 'MiniJumpJump', state = state },
Expand Down
Loading