diff --git a/lua/nvim-paredit/api/dragging.lua b/lua/nvim-paredit/api/dragging.lua index ed0dac2..789480d 100644 --- a/lua/nvim-paredit/api/dragging.lua +++ b/lua/nvim-paredit/api/dragging.lua @@ -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") @@ -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) diff --git a/lua/nvim-paredit/api/text.lua b/lua/nvim-paredit/api/text.lua new file mode 100644 index 0000000..4f1c0ea --- /dev/null +++ b/lua/nvim-paredit/api/text.lua @@ -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 diff --git a/lua/nvim-paredit/treesitter/pairs.lua b/lua/nvim-paredit/treesitter/pairs.lua index 443d89f..a01e255 100644 --- a/lua/nvim-paredit/treesitter/pairs.lua +++ b/lua/nvim-paredit/treesitter/pairs.lua @@ -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 diff --git a/tests/nvim-paredit/motion_spec.lua b/tests/nvim-paredit/motion_spec.lua index 663efaa..c2a2760 100644 --- a/tests/nvim-paredit/motion_spec.lua +++ b/tests/nvim-paredit/motion_spec.lua @@ -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) diff --git a/tests/nvim-paredit/pair_drag_spec.lua b/tests/nvim-paredit/pair_drag_spec.lua index 7a904a1..aea161b 100644 --- a/tests/nvim-paredit/pair_drag_spec.lua +++ b/tests/nvim-paredit/pair_drag_spec.lua @@ -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}",