Skip to content

Commit

Permalink
Swap both elements of a pair together
Browse files Browse the repository at this point in the history
Currently when performing a swap, each element in a pair is swapped with
it's corresponding paired element.

This works for simple cases but breaks when the number of lines are
different between the two pairs as the ranges the nodes represent have
now changed from previous edits.

This fixes the issue by finding the full range represented by both
elements in a pair and swapping this entire range in one go.
  • Loading branch information
julienvincent committed Oct 24, 2024
1 parent f842d84 commit 885657d
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 23 deletions.
44 changes: 39 additions & 5 deletions lua/nvim-paredit/api/dragging.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local ts_forms = require("nvim-paredit.treesitter.forms")
local ts_pairs = require("nvim-paredit.treesitter.pairs")
local traversal = require("nvim-paredit.utils.traversal")
local common = require("nvim-paredit.utils.common")
local text_api = require("nvim-paredit.api.text")
local ts = require("nvim-treesitter.ts_utils")
local config = require("nvim-paredit.config")

Expand Down Expand Up @@ -76,13 +77,46 @@ local function drag_node_in_pair(current_node, nodes, opts)
return
end

local buf = vim.api.nvim_get_current_buf()
if pair[2] and corresponding_pair[2] then
ts.swap_nodes(pair[2], corresponding_pair[2], buf, true)
local left_pair, right_pair
if direction == 1 then
left_pair = pair
right_pair = corresponding_pair
else
left_pair = corresponding_pair
right_pair = pair
end

if not left_pair[1] or not left_pair[2] then
return
end

if not right_pair[1] or not right_pair[2] then
return
end
if pair[1] and corresponding_pair[1] then
ts.swap_nodes(pair[1], corresponding_pair[1], buf, true)

local left_range_1 = { left_pair[1]:range() }
local left_range_2 = { left_pair[2]:range() }
-- stylua: ignore
local left_range = {
left_range_1[1], left_range_1[2],
left_range_2[3], left_range_2[4]
}

local right_range_1 = { right_pair[1]:range() }
local right_range_2 = { right_pair[2]:range() }
-- stylua: ignore
local right_range = {
right_range_1[1], right_range_1[2],
right_range_2[3], right_range_2[4]
}

local buf = vim.api.nvim_get_current_buf()
local cursor_pos = 1
if opts.reversed then
cursor_pos = 0
end

text_api.swap_ranges(buf, left_range, right_range, cursor_pos)
end

local function drag_pair(opts)
Expand Down
40 changes: 40 additions & 0 deletions lua/nvim-paredit/api/text.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
local M = {}

-- Swap the text in the given buffer represented by left_range and right_range
function M.swap_ranges(buf, left_range, right_range, cursor_pos)
-- stylua: ignore
local left_text = vim.api.nvim_buf_get_text(
buf,
left_range[1], left_range[2],
left_range[3], left_range[4],
{}
)
-- stylua: ignore
local right_text = vim.api.nvim_buf_get_text(buf,
right_range[1], right_range[2],
right_range[3], right_range[4],
{}
)

-- stylua: ignore
vim.api.nvim_buf_set_text(buf,
right_range[1], right_range[2],
right_range[3], right_range[4],
left_text
)
if cursor_pos == 1 then
vim.api.nvim_win_set_cursor(0, { right_range[1] + 1, right_range[2] })
end

-- stylua: ignore
vim.api.nvim_buf_set_text(buf,
left_range[1], left_range[2],
left_range[3], left_range[4],
right_text
)
if cursor_pos == 0 then
vim.api.nvim_win_set_cursor(0, { left_range[1] + 1, left_range[2] })
end
end

return M
2 changes: 1 addition & 1 deletion lua/nvim-paredit/treesitter/pairs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ local M = {}
-- matched nodes.
function M.find_pairwise_nodes(target_node, opts)
local root_node = ts_utils.find_local_root(target_node)
local enclosing_form = ts_forms.find_nearest_form(target_node, opts)
local enclosing_form = ts_forms.get_node_root(target_node, opts):parent()
if not enclosing_form then
return
end
Expand Down
25 changes: 8 additions & 17 deletions tests/nvim-paredit/motion_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -268,52 +268,43 @@ describe("motions :: ", function()
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})"
})

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

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

-- |(aa (bb) @(cc) #{1})
internal_api.move_to_parent_form_start()
expect({
cursor = { 1, 0 },
"|(aa (bb) @(cc) #{1})"
})
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})",
})

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

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

-- (aa (bb) @(cc) #{1}|)
internal_api.move_to_parent_form_end()
expect({
cursor = { 1, 19 },
"(aa (bb) @(cc) #{1}|)",
})
end)
end)
38 changes: 38 additions & 0 deletions tests/nvim-paredit/pair_drag_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,44 @@ describe("pair dragging ::", function()
})
end)

it("should drag multiline pairs", function()
prepare_buffer({
"{:a |{:a1 1",
" :a2 2}",
" :b {:b1 1",
" :b2 2}}",
})
paredit.drag_element_forwards({
dragging = {
auto_drag_pairs = true,
},
})
expect({
"{:b {:b1 1",
" :b2 2}",
" |:a {:a1 1",
" :a2 2}}",
})
end)

it("should drag pairs with differing line counts", function()
prepare_buffer({
"{:a |{:a1 1",
" :a2 2}",
" :b {:b1 1 :b2 2}}",
})
paredit.drag_element_forwards({
dragging = {
auto_drag_pairs = true,
},
})
expect({
"{:b {:b1 1 :b2 2}",
" |:a {:a1 1",
" :a2 2}}",
})
end)

it("should drag map pairs backwards", function()
prepare_buffer({
content = "{:a 1 :b 2}",
Expand Down

0 comments on commit 885657d

Please sign in to comment.