hypr: migrate layout management to native Lua
Replace hypr-workspace-layout shell script with native Lua functions in keybinds.lua. Add custom Lua layouts (master-scroll variants, swap variants) to the SUPER+period cycle. Implement swap-on-focus via _G._hl_ws_layouts shared global so window.active handler can check per-workspace layout without IPC or hl.get_workspaces().
This commit is contained in:
@@ -86,7 +86,20 @@ hl.bind(mainMod .. " + SHIFT + O", hl.dsp.workspace.move({ monitor = "r" }))
|
||||
|
||||
-- ─── Workspace layout state ───────────────────────────────────────────────────
|
||||
local ws_layouts = {}
|
||||
local ws_cycle_order = { "dwindle", "master", "scrolling", "monocle" }
|
||||
_G._hl_ws_layouts = ws_layouts
|
||||
local ws_cycle_order = {
|
||||
"master",
|
||||
"lua:master-scroll",
|
||||
"lua:slave-master-scroll",
|
||||
"lua:center-master-scroll",
|
||||
"lua:top-master-scroll",
|
||||
"lua:center-master-scroll-v",
|
||||
"lua:master-swap",
|
||||
"lua:slave-master-swap",
|
||||
"lua:top-master-swap",
|
||||
"scrolling",
|
||||
"monocle",
|
||||
}
|
||||
|
||||
local function active_ws_id()
|
||||
local w = hl.get_active_window()
|
||||
@@ -107,7 +120,10 @@ local function set_ws_layout(layout)
|
||||
end
|
||||
|
||||
local function ws_toggle_ms()
|
||||
set_ws_layout(cur_ws_layout() == "master" and "scrolling" or "master")
|
||||
local cur = cur_ws_layout()
|
||||
-- Any master variant → scrolling; scrolling/monocle → master
|
||||
local next = (cur == "scrolling" or cur == "monocle") and "master" or "scrolling"
|
||||
set_ws_layout(next)
|
||||
end
|
||||
|
||||
local function ws_cycle()
|
||||
|
||||
@@ -401,41 +401,48 @@ hl.layout.register("center-master-scroll-v", {
|
||||
})
|
||||
|
||||
-- ─── Swap-on-focus layouts ────────────────────────────────────────────────────
|
||||
-- Focusing any window promotes it to master; old master drops to slave area.
|
||||
-- One address slot per layout; all updated on every focus event (only the
|
||||
-- active layout's recalculate runs, so cross-pollution is harmless).
|
||||
-- Focusing any window promotes it to master. recalculate reads the active
|
||||
-- window directly via hl.get_active_window() — no external address tracking.
|
||||
|
||||
local swap_master_addr = nil -- shared: only one swap layout active at a time
|
||||
|
||||
local function find_master_idx(targets, addr)
|
||||
if addr then
|
||||
local function swap_master_idx(targets)
|
||||
local aw = hl.get_active_window()
|
||||
if aw and aw.address then
|
||||
for i = 1, #targets do
|
||||
local w = targets[i].window
|
||||
if w and w.address == addr then return i end
|
||||
if w and w.address == aw.address then return i end
|
||||
end
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
-- ─── master-swap: master left, slaves right ───────────────────────────────────
|
||||
hl.layout.register("master-swap", {
|
||||
recalculate = function(ctx)
|
||||
local targets = ctx.targets
|
||||
local n = #targets
|
||||
if n == 0 then return end
|
||||
if n == 1 then targets[1]:place(ctx.area); return end
|
||||
|
||||
local midx = find_master_idx(targets, swap_master_addr)
|
||||
local slave_area = ctx:split(ctx.area, "right", 1.0 - mfact)
|
||||
local master_area = { x=ctx.area.x, y=ctx.area.y, w=slave_area.x-ctx.area.x, h=ctx.area.h }
|
||||
targets[midx]:place(master_area)
|
||||
|
||||
local sidx = {}
|
||||
for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end
|
||||
local function swap_place_slaves(targets, midx, slave_area, vertical)
|
||||
local sidx = {}
|
||||
for i = 1, #targets do if i ~= midx then sidx[#sidx+1] = i end end
|
||||
if #sidx == 0 then return end
|
||||
if vertical then
|
||||
local h = slave_area.h / #sidx
|
||||
for j, si in ipairs(sidx) do
|
||||
targets[si]:place({ x=slave_area.x, y=slave_area.y+(j-1)*h, w=slave_area.w, h=h })
|
||||
end
|
||||
else
|
||||
local w = slave_area.w / #sidx
|
||||
for j, si in ipairs(sidx) do
|
||||
targets[si]:place({ x=slave_area.x+(j-1)*w, y=slave_area.y, w=w, h=slave_area.h })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ─── master-swap: master left, slaves right ───────────────────────────────────
|
||||
hl.layout.register("master-swap", {
|
||||
recalculate = function(ctx)
|
||||
local targets, n = ctx.targets, #ctx.targets
|
||||
if n == 0 then return end
|
||||
if n == 1 then targets[1]:place(ctx.area); return end
|
||||
local midx = swap_master_idx(targets)
|
||||
local slave_area = ctx:split(ctx.area, "right", 1.0 - mfact)
|
||||
local master_area = { x=ctx.area.x, y=ctx.area.y, w=slave_area.x-ctx.area.x, h=ctx.area.h }
|
||||
targets[midx]:place(master_area)
|
||||
swap_place_slaves(targets, midx, slave_area, true)
|
||||
end,
|
||||
layout_msg = function(_, msg)
|
||||
if msg == "recalc" then return true end
|
||||
@@ -447,25 +454,14 @@ hl.layout.register("master-swap", {
|
||||
-- ─── slave-master-swap: slaves left, master right ─────────────────────────────
|
||||
hl.layout.register("slave-master-swap", {
|
||||
recalculate = function(ctx)
|
||||
local targets = ctx.targets
|
||||
local n = #targets
|
||||
local targets, n = ctx.targets, #ctx.targets
|
||||
if n == 0 then return end
|
||||
if n == 1 then targets[1]:place(ctx.area); return end
|
||||
|
||||
local midx = find_master_idx(targets, swap_master_addr)
|
||||
local slave_area = ctx:split(ctx.area, "left", 1.0 - mfact)
|
||||
local master_area = {
|
||||
x = slave_area.x + slave_area.w, y = ctx.area.y,
|
||||
w = ctx.area.w - slave_area.w, h = ctx.area.h,
|
||||
}
|
||||
local midx = swap_master_idx(targets)
|
||||
local slave_area = ctx:split(ctx.area, "left", 1.0 - mfact)
|
||||
local master_area = { x=slave_area.x+slave_area.w, y=ctx.area.y, w=ctx.area.w-slave_area.w, h=ctx.area.h }
|
||||
targets[midx]:place(master_area)
|
||||
|
||||
local sidx = {}
|
||||
for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end
|
||||
local h = slave_area.h / #sidx
|
||||
for j, si in ipairs(sidx) do
|
||||
targets[si]:place({ x=slave_area.x, y=slave_area.y+(j-1)*h, w=slave_area.w, h=h })
|
||||
end
|
||||
swap_place_slaves(targets, midx, slave_area, true)
|
||||
end,
|
||||
layout_msg = function(_, msg)
|
||||
if msg == "recalc" then return true end
|
||||
@@ -477,22 +473,14 @@ hl.layout.register("slave-master-swap", {
|
||||
-- ─── top-master-swap: master top, slaves bottom row ───────────────────────────
|
||||
hl.layout.register("top-master-swap", {
|
||||
recalculate = function(ctx)
|
||||
local targets = ctx.targets
|
||||
local n = #targets
|
||||
local targets, n = ctx.targets, #ctx.targets
|
||||
if n == 0 then return end
|
||||
if n == 1 then targets[1]:place(ctx.area); return end
|
||||
|
||||
local midx = find_master_idx(targets, swap_master_addr)
|
||||
local slave_area = ctx:split(ctx.area, "bottom", 1.0 - mfact_v)
|
||||
local midx = swap_master_idx(targets)
|
||||
local slave_area = ctx:split(ctx.area, "bottom", 1.0 - mfact_v)
|
||||
local master_area = { x=ctx.area.x, y=ctx.area.y, w=ctx.area.w, h=slave_area.y-ctx.area.y }
|
||||
targets[midx]:place(master_area)
|
||||
|
||||
local sidx = {}
|
||||
for i = 1, n do if i ~= midx then sidx[#sidx+1] = i end end
|
||||
local w = slave_area.w / #sidx
|
||||
for j, si in ipairs(sidx) do
|
||||
targets[si]:place({ x=slave_area.x+(j-1)*w, y=slave_area.y, w=w, h=slave_area.h })
|
||||
end
|
||||
swap_place_slaves(targets, midx, slave_area, false)
|
||||
end,
|
||||
layout_msg = function(_, msg)
|
||||
if msg == "recalc" then return true end
|
||||
@@ -507,9 +495,6 @@ local all_col_states = { ms, sm, cm_left, cm_right, tm, cm_vtop, cm_vbot }
|
||||
hl.on("window.active", function(w)
|
||||
if w == nil or w.address == nil then return end
|
||||
|
||||
-- Promote focused window to master in any active swap layout
|
||||
swap_master_addr = w.address
|
||||
|
||||
-- Auto-scroll: if the focused window is a peek slot, slide it into view
|
||||
for _, state in ipairs(all_col_states) do
|
||||
if w.address == state.peek_bottom_addr then
|
||||
@@ -519,9 +504,10 @@ hl.on("window.active", function(w)
|
||||
end
|
||||
end
|
||||
|
||||
-- For swap layouts (no scroll dispatched), trigger a recalculate.
|
||||
-- Guard by name so built-in layouts never receive an unknown message.
|
||||
local cur = hl.get_config("general.layout")
|
||||
-- Trigger recalc for swap layouts so the focused window becomes master.
|
||||
-- _G._hl_ws_layouts is set by keybinds.lua and tracks per-workspace layout.
|
||||
local ws_id = w.workspace and w.workspace.id
|
||||
local cur = ws_id and _G._hl_ws_layouts and _G._hl_ws_layouts[ws_id]
|
||||
if cur == "lua:master-swap" or cur == "lua:slave-master-swap" or cur == "lua:top-master-swap" then
|
||||
hl.dispatch(hl.dsp.layout("recalc"))
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user