Skip to content

Commit

Permalink
Merge pull request #38 from Samy-33/master
Browse files Browse the repository at this point in the history
feat(motion): allows movement to parent form's edges using `(, )`
  • Loading branch information
julienvincent committed Oct 2, 2023
2 parents 0e7db6a + eb9556d commit 2f117b3
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ paredit.setup({
mode = { "n", "x", "o", "v" },
},

["("] = {
paredit.api.move_to_parent_form_start,
"Jump to parent form's head",
repeatable = false,
mode = { "n", "x", "v" },
},
[")"] = {
paredit.api.move_to_parent_form_end,
"Jump to parent form's tail",
repeatable = false,
mode = { "n", "x", "v" },
},

-- These are text object selection keybindings which can used with standard `d, y, c`, `v`
["af"] = {
paredit.api.select_around_form,
Expand Down
3 changes: 3 additions & 0 deletions lua/nvim-paredit/api/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ local M = {
move_to_prev_element_head = motions.move_to_prev_element_head,
move_to_prev_element_tail = motions.move_to_prev_element_tail,

move_to_parent_form_start = motions.move_to_parent_form_start,
move_to_parent_form_end = motions.move_to_parent_form_end,

select_around_form = selections.select_around_form,
select_in_form = selections.select_in_form,
select_around_top_level_form = selections.select_around_top_level_form,
Expand Down
56 changes: 56 additions & 0 deletions lua/nvim-paredit/api/motions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ local common = require("nvim-paredit.utils.common")
local ts = require("nvim-treesitter.ts_utils")
local langs = require("nvim-paredit.lang")

local MOTION_DIRECTIONS = { LEFT = "left", RIGHT = "right" }

local M = {}

-- When the cursor is placed on whitespace within a form then the node returned by
Expand Down Expand Up @@ -130,6 +132,52 @@ local function ensure_visual_if_operator_pending()
end
end

local function move_to_form_edge(form_node, direction, lang)
if not form_node then
return
end

local form_edges = lang.get_form_edges(form_node)
local final_cursor_pos = {
form_edges[direction].range[1] + 1,
form_edges[direction].range[2]
}

vim.api.nvim_win_set_cursor(0, final_cursor_pos)
end

local function is_cursor_at_form_edge(form_node, direction, cur_cursor_pos, lang)
local form_edges = lang.get_form_edges(form_node)
local edge_cursor_pos = {
form_edges[direction].range[1] + 1,
form_edges[direction].range[2]
}

return common.compare_positions(edge_cursor_pos, cur_cursor_pos) == 0
end

local function move_to_parent_form_edge(direction)
local lang = langs.get_language_api()
local cur_node = ts.get_node_at_cursor()

local nearest_form_node = traversal.find_nearest_form(cur_node, { lang = lang })
if not nearest_form_node or nearest_form_node:type() == "source" then
return
end

local cur_cursor_pos = vim.api.nvim_win_get_cursor(0)
local form_node_to_move_to = nearest_form_node
while is_cursor_at_form_edge(form_node_to_move_to, direction, cur_cursor_pos, lang)
do
form_node_to_move_to = lang.get_node_root(form_node_to_move_to):parent()
if not form_node_to_move_to or form_node_to_move_to:type() == "source" then
return
end
end

move_to_form_edge(form_node_to_move_to, direction, lang)
end

function M.move_to_prev_element_head()
local count = vim.v.count1
ensure_visual_if_operator_pending()
Expand All @@ -154,4 +202,12 @@ function M.move_to_next_element_head()
M._move_to_element(count, false, true)
end

function M.move_to_parent_form_start()
move_to_parent_form_edge(MOTION_DIRECTIONS.LEFT)
end

function M.move_to_parent_form_end()
move_to_parent_form_edge(MOTION_DIRECTIONS.RIGHT)
end

return M
19 changes: 19 additions & 0 deletions lua/nvim-paredit/defaults.lua
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ M.default_keys = {
repeatable = false,
mode = { "n", "x", "o", "v" },
},

["B"] = {
api.move_to_prev_element_head,
"Previous element head",
Expand All @@ -43,24 +44,41 @@ M.default_keys = {
mode = { "n", "x", "o", "v" },
},

["("] = {
api.move_to_parent_form_start,
"Parent form's head",
repeatable = false,
mode = { "n", "x", "v" },
},

[")"] = {
api.move_to_parent_form_end,
"Parent form's tail",
repeatable = false,
mode = { "n", "x", "v" },
},

["af"] = {
api.select_around_form,
"Around form",
repeatable = false,
mode = { "o", "v" },
},

["if"] = {
api.select_in_form,
"In form",
repeatable = false,
mode = { "o", "v" },
},

["aF"] = {
api.select_around_top_level_form,
"Around top level form",
repeatable = false,
mode = { "o", "v" },
},

["iF"] = {
api.select_in_top_level_form,
"In top level form",
Expand All @@ -74,6 +92,7 @@ M.default_keys = {
repeatable = false,
mode = { "o", "v" },
},

["ie"] = {
api.select_element,
"Element",
Expand Down
53 changes: 53 additions & 0 deletions tests/nvim-paredit/motion_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,57 @@ describe("motions", function()
cursor = { 1, 4 },
})
end)

it("should move to parent form start", function()
-- (aa (bb) @(|cc) #{1})
prepare_buffer({
content = "(aa (bb) @(cc) #{1})",
cursor = { 1, 11 },
})

-- (aa (bb) @|(cc) #{1})
internal_api.move_to_parent_form_start()
expect({
cursor = { 1, 10 },
})

-- |(aa (bb) @(cc) #{1})
internal_api.move_to_parent_form_start()
expect({
cursor = { 1, 0 },
})

-- |(aa (bb) @(cc) #{1})
internal_api.move_to_parent_form_start()
expect({
cursor = { 1, 0 },
})
end)


it("should move to parent form end", function()
-- (aa (bb) |@(cc) #{1})
prepare_buffer({
content = "(aa (bb) @(cc) #{1})",
cursor = { 1, 9 },
})

-- (aa (bb) @(cc|) #{1})
internal_api.move_to_parent_form_end()
expect({
cursor = { 1, 13 },
})

-- (aa (bb) @(cc) #{1}|)
internal_api.move_to_parent_form_end()
expect({
cursor = { 1, 19 },
})

-- (aa (bb) @(cc) #{1}|)
internal_api.move_to_parent_form_end()
expect({
cursor = { 1, 19 },
})
end)
end)

0 comments on commit 2f117b3

Please sign in to comment.