Skip to content

Commit e2cd9f9

Browse files
committed
added swaparound feature
1 parent 86ae3cf commit e2cd9f9

File tree

7 files changed

+101
-55
lines changed

7 files changed

+101
-55
lines changed

lua/treewalker/init.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Treewalker.opts = {
1111
highlight_duration = 250,
1212
highlight_group = "CursorLine",
1313
jumplist = true,
14+
swaparound = true
1415
}
1516

1617
-- This does not need to be called for Treewalker to work. The defaults are preinitialized and aim to be sane.

lua/treewalker/nodes.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,22 @@ function M.next_sib(node)
176176
return node:next_named_sibling()
177177
end
178178

179+
---@param node TSNode
180+
---@param fn function
181+
---@return TSNode | nil
182+
function M.farthest_sibling(node, fn)
183+
if not node then return nil end
184+
185+
---@type TSNode | nil
186+
local iter = fn(node)
187+
188+
while iter do
189+
node = iter
190+
iter = fn(iter)
191+
end
192+
return node
193+
end
194+
179195
-- Convenience for give me back prev sibling of a potentially nil node
180196
---@param node TSNode | nil
181197
function M.prev_sib(node)

lua/treewalker/swap.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function M.swap_right()
121121
current = strategies.get_highest_string_node(current) or current
122122
current = nodes.get_highest_coincident(current)
123123

124-
local target = nodes.next_sib(current)
124+
local target = nodes.next_sib(current) or nodes.farthest_sibling(current, nodes.prev_sib)
125125

126126
if not current or not target then return end
127127

@@ -158,7 +158,7 @@ function M.swap_left()
158158
current = strategies.get_highest_string_node(current) or current
159159
current = nodes.get_highest_coincident(current)
160160

161-
local target = nodes.prev_sib(current)
161+
local target = nodes.prev_sib(current) or nodes.farthest_sibling(current, nodes.next_sib)
162162

163163
if not current or not target then return end
164164

tests/treewalker/c_sharp_spec.lua

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,12 @@ describe("In a C Sharp file", function()
4141
assert.same(first_block, lines.get_lines(30, 48))
4242
h.assert_cursor_at(7, 5)
4343
end)
44+
45+
it("swaparound behavior works", function()
46+
vim.fn.cursor(52, 31) -- (|node1, node2)
47+
tw.swap_left()
48+
assert.same(" public static int Add(int b, int a) => a + b;", lines.get_line(52))
49+
tw.swap_right()
50+
assert.same(" public static int Add(int a, int b) => a + b;", lines.get_line(52))
51+
end)
4452
end)

tests/treewalker/c_spec.lua

Lines changed: 55 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,51 +5,59 @@ local h = require 'tests.treewalker.helpers'
55
local lines = require 'treewalker.lines'
66

77
describe("In a c file:", function()
8-
before_each(function()
9-
load_fixture("/c.c")
10-
end)
11-
12-
h.ensure_has_parser("c")
13-
14-
it("Moves around", function()
15-
vim.fn.cursor(46, 1)
16-
tw.move_down()
17-
h.assert_cursor_at(50, 1, "int main")
18-
tw.move_down()
19-
h.assert_cursor_at(64, 1)
20-
tw.move_down()
21-
h.assert_cursor_at(69, 1)
22-
end)
23-
24-
it("swaps right, when cursor is inside a string, the whole string", function()
25-
vim.fn.cursor(14, 17) -- the o in one
26-
assert.same(' printf("one\\n", "two\\n");', lines.get_line(14))
27-
tw.swap_right()
28-
assert.same(' printf("two\\n", "one\\n");', lines.get_line(14))
29-
end)
30-
31-
it("swaps left, when cursor is inside a string, the whole string", function()
32-
vim.fn.cursor(17, 28) -- the t in two
33-
assert.same(' printf("one\\n", "\\ntwo\\n");', lines.get_line(17))
34-
tw.swap_left()
35-
assert.same(' printf("\\ntwo\\n", "one\\n");', lines.get_line(17))
36-
end)
37-
38-
it("swaps down on next line bracket structured functions", function()
39-
local first_block = lines.get_lines(63, 67)
40-
local second_block = lines.get_lines(69, 72)
41-
vim.fn.cursor(64, 1)
42-
tw.swap_down()
43-
assert.same(first_block, lines.get_lines(68, 72))
44-
assert.same(second_block, lines.get_lines(63, 66))
45-
end)
46-
47-
it("swaps up on next line bracket structured functions", function()
48-
local first_block = lines.get_lines(63, 67)
49-
local second_block = lines.get_lines(69, 72)
50-
vim.fn.cursor(69, 1)
51-
tw.swap_up()
52-
assert.same(first_block, lines.get_lines(68, 72))
53-
assert.same(second_block, lines.get_lines(63, 66))
54-
end)
8+
before_each(function()
9+
load_fixture("/c.c")
10+
end)
11+
12+
h.ensure_has_parser("c")
13+
14+
it("Moves around", function()
15+
vim.fn.cursor(46, 1)
16+
tw.move_down()
17+
h.assert_cursor_at(50, 1, "int main")
18+
tw.move_down()
19+
h.assert_cursor_at(64, 1)
20+
tw.move_down()
21+
h.assert_cursor_at(69, 1)
22+
end)
23+
24+
it("swaps right, when cursor is inside a string, the whole string", function()
25+
vim.fn.cursor(14, 17) -- the o in one
26+
assert.same(' printf("one\\n", "two\\n");', lines.get_line(14))
27+
tw.swap_right()
28+
assert.same(' printf("two\\n", "one\\n");', lines.get_line(14))
29+
end)
30+
31+
it("swaps left, when cursor is inside a string, the whole string", function()
32+
vim.fn.cursor(17, 28) -- the t in two
33+
assert.same(' printf("one\\n", "\\ntwo\\n");', lines.get_line(17))
34+
tw.swap_left()
35+
assert.same(' printf("\\ntwo\\n", "one\\n");', lines.get_line(17))
36+
end)
37+
38+
it("swaps down on next line bracket structured functions", function()
39+
local first_block = lines.get_lines(63, 67)
40+
local second_block = lines.get_lines(69, 72)
41+
vim.fn.cursor(64, 1)
42+
tw.swap_down()
43+
assert.same(first_block, lines.get_lines(68, 72))
44+
assert.same(second_block, lines.get_lines(63, 66))
45+
end)
46+
47+
it("swaps up on next line bracket structured functions", function()
48+
local first_block = lines.get_lines(63, 67)
49+
local second_block = lines.get_lines(69, 72)
50+
vim.fn.cursor(69, 1)
51+
tw.swap_up()
52+
assert.same(first_block, lines.get_lines(68, 72))
53+
assert.same(second_block, lines.get_lines(63, 66))
54+
end)
55+
56+
it("swaparound behavior works", function()
57+
vim.fn.cursor(11, 24) -- (|node1, node2)
58+
tw.swap_left()
59+
assert.same("Account* createAccount(float initialBalance, int accountNumber) {", lines.get_line(11))
60+
tw.swap_right()
61+
assert.same("Account* createAccount(int accountNumber, float initialBalance) {", lines.get_line(11))
62+
end)
5563
end)

tests/treewalker/haskell_spec.lua

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ describe("In a haskell file: ", function()
77
load_fixture("/haskell.hs")
88
end)
99

10-
h.ensure_has_parser("haskell")
11-
12-
-- Oh dang when did this break?
13-
pending("moves around in a haskell file", function ()
10+
h.ensure_has_parser("haskell") -- Oh dang when did this break?
11+
pending("moves around in a haskell file", function()
1412
vim.fn.cursor(1, 1)
1513
tw.move_down()
1614
h.assert_cursor_at(2, 1)
@@ -27,6 +25,12 @@ describe("In a haskell file: ", function()
2725
tw.move_out()
2826
h.assert_cursor_at(19, 1)
2927
end)
30-
end)
31-
3228

29+
it("swaparound behavior works", function()
30+
vim.fn.cursor(40, 15) -- (|node1, node2)
31+
tw.swap_left()
32+
assert.same(" printEvens [9, 3, 5, 7, 1]\", lines.get_line(40)")
33+
tw.swap_right()
34+
assert.same(" printEvens [1, 3, 5, 7, 9]\", lines.get_line(40)")
35+
end)
36+
end)

tests/treewalker/lua_spec.lua

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,15 @@ describe("Swapping in a regular lua file:", function()
321321
apply_text_edits_stub:revert()
322322
end)
323323

324+
it("swaparound behavior works", function()
325+
vim.fn.cursor(38, 32) -- (|node1, node2)
326+
tw.swap_left()
327+
assert.same("local function have_same_range(node2, node1)", lines.get_line(38))
328+
tw.swap_right()
329+
assert.same("local function have_same_range(node1, node2)", lines.get_line(38))
330+
end)
331+
332+
324333
-- Actually I don't think this is supposed to work. It's ambiguous what
325334
-- node we're on. We'd need to do the lowest coincident that is the highest string
326335
-- or something.

0 commit comments

Comments
 (0)