#! /usr/bin/env node const { execSync } = require('child_process'), // limitation: can't act on hy3 nodes (and is generally unaware of them) // TODO add floating window resize // helpers hcd = args => { console.log(`hyprctl dispatch -- ${args}`) console.log(execSync(`hyprctl dispatch -- ${args}`).toString()) }, hcj = args => JSON.parse(execSync(`hyprctl -j ${args}`).toString()), leftOf = w => w.at[0], rightOf = w => w.at[0] + w.size[0], topOf = w => w.at[1], bottomOf = w => w.at[1] + w.size[1], maxBy = f => as => as.reduce((a, b) => f(a) > f(b) && a || b), minBy = f => as => as.reduce((a, b) => f(a) < f(b) && a || b), resizeX = Δ => ({ address }) => () => hcd(`resizewindowpixel ${Δ} 0,address:${address}`), resizeY = Δ => ({ address }) => () => hcd(`resizewindowpixel 0 ${Δ},address:${address}`), // args direction = process.argv[2], Δ = process.argv[3], // main workspaceId = hcj("activeworkspace").id, ws = hcj("clients").filter(w => w.workspace.id == workspaceId), target = ws.find(w => w.focusHistoryID == 0), targetLeft = leftOf(target), targetRight = rightOf(target), targetTop = topOf(target), targetBottom = bottomOf(target), halfΔ = Math.floor(Δ / 2), isLeftmost = ws.every(w => leftOf(w) >= targetLeft), isRightmost = ws.every(w => rightOf(w) <= targetRight), windowsLeft = ws.filter(w => leftOf(w) < targetLeft), isUpmost = ws.every(w => topOf(w) >= targetTop), isDownmost = ws.every(w => bottomOf(w) <= targetBottom), windowsUp = ws.filter(w => topOf(w) < targetTop), // HACK a limitation is that shrinking left doesn't mean only the window to the right will fill the empty space ― it will be distributed evenly // so we also expand the target window by half the distance. ditto for shrinking up resizeLeft = isLeftmost && resizeX(-Δ)(target) || isRightmost && resizeX(Δ)(target) || (() => { resizeX(-Δ)(maxBy(leftOf)(windowsLeft))(); resizeX(halfΔ)(target)() }), resizeRight = isRightmost && resizeX(-Δ)(target) || resizeX(Δ)(target), resizeUp = isUpmost && resizeY(-Δ)(target) || isDownmost && resizeY(Δ)(target) || (() => { resizeY(-Δ)(minBy(bottomOf)(windowsUp))(); resizeY(halfΔ)(target)() }), resizeDown = isDownmost && resizeY(-Δ)(target) || resizeY(Δ)(target), matchDirection = { '←': resizeLeft, '→': resizeRight, '↑': resizeUp, '↓': resizeDown } matchDirection[direction]()