Skip to content

Commit

Permalink
Merge pull request #46 from julienvincent/exclusive_motion_support
Browse files Browse the repository at this point in the history
fixes #42: Exclusive motion support
  • Loading branch information
julienvincent committed Oct 26, 2023
2 parents ac9d19e + 14caa5b commit 5818754
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 12 deletions.
39 changes: 32 additions & 7 deletions lua/nvim-paredit/api/motions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ local function get_next_node_from_cursor(lang, reversed)
end
end

function M._move_to_element(count, reversed, is_head)
function M._move_to_element(count, reversed, is_head, is_exclusive)
is_exclusive = is_exclusive or false
is_head = is_head or false
local lang = langs.get_language_api()

Expand Down Expand Up @@ -97,39 +98,61 @@ function M._move_to_element(count, reversed, is_head)
if is_in_middle then
count = count - 1
end
local sibling = traversal_fn(current_node, {
local sibling, count_left = traversal_fn(current_node, {
lang = lang,
count = count,
})

if sibling then
if is_head then
if is_head and count_left > 1 and not reversed then
is_head = false
is_exclusive = false
next_pos = { sibling:end_() }
elseif is_head then
next_pos = { sibling:start() }
else
next_pos = { sibling:end_() }
end
elseif is_head and not reversed then
-- convert head to tail motion
is_head = false
is_exclusive = false
next_pos = { current_node:end_() }
end
end

if not next_pos then
return
end

local offset = 0
if is_exclusive then
if reversed then
offset = 1
else
offset = -1
end
end

if is_head then
cursor_pos = { next_pos[1] + 1, next_pos[2] }
cursor_pos = { next_pos[1] + 1, next_pos[2] + offset }
else
cursor_pos = { next_pos[1] + 1, next_pos[2] - 1 }
cursor_pos = { next_pos[1] + 1, next_pos[2] - 1 + offset }
end

vim.api.nvim_win_set_cursor(0, cursor_pos)
end

-- When in operator-pending mode (`o` or `no`) then we need to switch to
-- visual mode in order for the operator to apply over a range of text.
-- returns true if operator mode is on, false otherwise
local function ensure_visual_if_operator_pending()
local mode = vim.api.nvim_get_mode().mode
if mode == "o" or mode == "no" then
common.ensure_visual_mode()
return true
end
return false
end

local function move_to_form_edge(form_node, direction, lang)
Expand Down Expand Up @@ -196,10 +219,12 @@ function M.move_to_next_element_tail()
M._move_to_element(count, false, false)
end

-- also jumps to current element tail if there is no
-- next element
function M.move_to_next_element_head()
local count = vim.v.count1
ensure_visual_if_operator_pending()
M._move_to_element(count, false, true)
local is_operator = ensure_visual_if_operator_pending()
M._move_to_element(count, false, true, is_operator)
end

function M.move_to_parent_form_start()
Expand Down
4 changes: 2 additions & 2 deletions lua/nvim-paredit/utils/traversal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ end
local function get_sibling_ignoring_comments(node, opts)
local sibling = opts.sibling_fn(node)
if not sibling then
return opts.sibling or nil
return opts.sibling or nil, opts.count + 1
end

if sibling:extra() or opts.lang.node_is_comment(sibling) then
Expand All @@ -94,7 +94,7 @@ local function get_sibling_ignoring_comments(node, opts)
return get_sibling_ignoring_comments(sibling, new_opts)
end

return sibling
return sibling, opts.count
end

function M.get_next_sibling_ignoring_comments(node, opts)
Expand Down
9 changes: 8 additions & 1 deletion tests/nvim-paredit/motion_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@ describe("motions", function()
expect({
cursor = { 1, 15 },
})
end)

it("should jump to current element's tail if there is no next element", function()
prepare_buffer({
content = "(aa (bb) @(cc) #{1})",
cursor = { 1, 15 },
})

paredit.move_to_next_element_head()
expect({
cursor = { 1, 15 },
cursor = { 1, 18 },
})
end)

Expand Down
40 changes: 38 additions & 2 deletions tests/nvim-paredit/operator_motion_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ local defaults = require("nvim-paredit.defaults")
describe("motions with operator pending", function()
before_each(function()
keybindings.setup_keybindings({
keys = defaults.default_keys
keys = defaults.default_keys,
})
end)

Expand All @@ -29,6 +29,42 @@ describe("motions with operator pending", function()
})
end)

it("should delete til next", function()
prepare_buffer({
content = "(a a) (b b)",
cursor = { 1, 0 },
})
feedkeys("d<S-w>")
expect({
content = "(b b)",
cursor = { 1, 0 },
})
end)

it("should delete form if there is no next", function()
prepare_buffer({
content = "(b b)",
cursor = { 1, 0 },
})
feedkeys("d<S-w>")
expect({
content = "",
cursor = { 1, 0 },
})
end)

it("should delete 2 forms within parent form and join up", function()
prepare_buffer({
content = {"[(a a) (b b) (c c)]"},
cursor = { 1, 1 },
})
feedkeys("2d<S-w>")
expect({
content = "[(c c)]",
cursor = { 1, 1 },
})
end)

it("should delete next form (multiline)", function()
prepare_buffer({
content = { "(a a)", ";; comment", "(b b)" },
Expand Down Expand Up @@ -91,7 +127,7 @@ end)
describe("motions with operator pending and v:count", function()
before_each(function()
keybindings.setup_keybindings({
keys = defaults.default_keys
keys = defaults.default_keys,
})
end)

Expand Down

0 comments on commit 5818754

Please sign in to comment.