Skip to content

Commit 91d3cd7

Browse files
committed
Add ability to move panes
1 parent 087b410 commit 91d3cd7

File tree

1 file changed

+105
-1
lines changed

1 file changed

+105
-1
lines changed

src/lua/tiling.lua

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,98 @@ local function move_focus(direction)
11741174
end
11751175
end
11761176

1177+
---Swap the focused pane with a sibling pane in the given direction
1178+
---@param direction "left"|"right"|"up"|"down"
1179+
local function swap_pane(direction)
1180+
local root = get_active_root()
1181+
if not state.focused_id or not root then
1182+
return
1183+
end
1184+
1185+
local path = find_node_path(root, state.focused_id)
1186+
if not path then
1187+
return
1188+
end
1189+
1190+
-- "left"/"right" implies moving along "row"
1191+
-- "up"/"down" implies moving along "col"
1192+
local target_split_type = (direction == "left" or direction == "right") and "row" or "col"
1193+
local forward = (direction == "right" or direction == "down")
1194+
1195+
local sibling_node = nil
1196+
1197+
-- Traverse up the path to find a split of the correct type where we can swap
1198+
for i = #path - 1, 1, -1 do
1199+
local node = path[i]
1200+
local child = path[i + 1]
1201+
1202+
if node.type == "split" and node.direction == target_split_type then
1203+
-- Find index of child
1204+
local idx = 0
1205+
for k, c in ipairs(node.children) do
1206+
if c == child then
1207+
idx = k
1208+
break
1209+
end
1210+
end
1211+
1212+
if forward then
1213+
if idx < #node.children then
1214+
sibling_node = node.children[idx + 1]
1215+
break
1216+
end
1217+
else
1218+
if idx > 1 then
1219+
sibling_node = node.children[idx - 1]
1220+
break
1221+
end
1222+
end
1223+
end
1224+
end
1225+
1226+
if sibling_node then
1227+
-- Found a sibling tree/pane. Find the closest leaf.
1228+
local target_leaf
1229+
if forward then
1230+
target_leaf = get_first_leaf(sibling_node)
1231+
else
1232+
target_leaf = get_last_leaf(sibling_node)
1233+
end
1234+
1235+
if target_leaf and target_leaf.id ~= state.focused_id then
1236+
-- Find both panes
1237+
local focused_path = find_node_path(root, state.focused_id)
1238+
local target_path = find_node_path(root, target_leaf.id)
1239+
1240+
if focused_path and target_path then
1241+
local focused_pane = focused_path[#focused_path]
1242+
local target_pane = target_path[#target_path]
1243+
1244+
-- Unfocus the currently focused pane before swapping
1245+
if state.app_focused then
1246+
focused_pane.pty:set_focus(false)
1247+
end
1248+
1249+
-- Swap both the PTY references and the IDs so everything stays consistent
1250+
focused_pane.pty, target_pane.pty = target_pane.pty, focused_pane.pty
1251+
focused_pane.id, target_pane.id = target_pane.id, focused_pane.id
1252+
1253+
-- Focus stays on the same ID (which now moved to the target position)
1254+
-- state.focused_id doesn't need to change since we swapped the IDs
1255+
1256+
-- Focus the pane that now has our original ID (at target position)
1257+
if state.app_focused then
1258+
target_pane.pty:set_focus(true)
1259+
end
1260+
1261+
update_cached_git_branch()
1262+
prise.request_frame()
1263+
prise.save()
1264+
end
1265+
end
1266+
end
1267+
end
1268+
11771269
local function open_rename_tab()
11781270
if not state.rename_tab.input then
11791271
state.rename_tab.input = prise.create_text_input()
@@ -1733,7 +1825,19 @@ function M.update(event)
17331825
return
17341826
end
17351827

1736-
if k == "h" then
1828+
if event.data.ctrl and k == "h" then
1829+
swap_pane("left")
1830+
handled = true
1831+
elseif event.data.ctrl and k == "l" then
1832+
swap_pane("right")
1833+
handled = true
1834+
elseif event.data.ctrl and k == "j" then
1835+
swap_pane("down")
1836+
handled = true
1837+
elseif event.data.ctrl and k == "k" then
1838+
swap_pane("up")
1839+
handled = true
1840+
elseif k == "h" then
17371841
move_focus("left")
17381842
handled = true
17391843
elseif k == "l" then

0 commit comments

Comments
 (0)