fix(tmux): prefer split-or-defer with FIFO deferred attach
This commit is contained in:
@@ -2,14 +2,52 @@ import { spawn } from "bun"
|
||||
import type { TmuxLayout } from "../../../config/schema"
|
||||
import { getTmuxPath } from "../../../tools/interactive-bash/tmux-path-resolver"
|
||||
|
||||
type TmuxSpawnCommand = (
|
||||
args: string[],
|
||||
options: { stdout: "ignore"; stderr: "ignore" },
|
||||
) => { exited: Promise<number> }
|
||||
|
||||
interface LayoutDeps {
|
||||
spawnCommand?: TmuxSpawnCommand
|
||||
}
|
||||
|
||||
interface MainPaneWidthOptions {
|
||||
mainPaneSize?: number
|
||||
mainPaneMinWidth?: number
|
||||
agentPaneMinWidth?: number
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
return Math.max(min, Math.min(max, value))
|
||||
}
|
||||
|
||||
function calculateMainPaneWidth(
|
||||
windowWidth: number,
|
||||
options?: MainPaneWidthOptions,
|
||||
): number {
|
||||
const dividerWidth = 1
|
||||
const sizePercent = clamp(options?.mainPaneSize ?? 50, 20, 80)
|
||||
const minMainPaneWidth = options?.mainPaneMinWidth ?? 0
|
||||
const minAgentPaneWidth = options?.agentPaneMinWidth ?? 0
|
||||
const desiredMainPaneWidth = Math.floor(
|
||||
(windowWidth - dividerWidth) * (sizePercent / 100),
|
||||
)
|
||||
const maxMainPaneWidth = Math.max(
|
||||
0,
|
||||
windowWidth - dividerWidth - minAgentPaneWidth,
|
||||
)
|
||||
|
||||
return clamp(Math.max(desiredMainPaneWidth, minMainPaneWidth), 0, maxMainPaneWidth)
|
||||
}
|
||||
|
||||
export async function applyLayout(
|
||||
tmux: string,
|
||||
layout: TmuxLayout,
|
||||
mainPaneSize: number,
|
||||
deps?: LayoutDeps,
|
||||
): Promise<void> {
|
||||
const tmux = await getTmuxPath()
|
||||
if (!tmux) return
|
||||
|
||||
const layoutProc = spawn([tmux, "select-layout", layout], {
|
||||
const spawnCommand: TmuxSpawnCommand = deps?.spawnCommand ?? spawn
|
||||
const layoutProc = spawnCommand([tmux, "select-layout", layout], {
|
||||
stdout: "ignore",
|
||||
stderr: "ignore",
|
||||
})
|
||||
@@ -18,7 +56,7 @@ export async function applyLayout(
|
||||
if (layout.startsWith("main-")) {
|
||||
const dimension =
|
||||
layout === "main-horizontal" ? "main-pane-height" : "main-pane-width"
|
||||
const sizeProc = spawn(
|
||||
const sizeProc = spawnCommand(
|
||||
[tmux, "set-window-option", dimension, `${mainPaneSize}%`],
|
||||
{ stdout: "ignore", stderr: "ignore" },
|
||||
)
|
||||
@@ -29,15 +67,17 @@ export async function applyLayout(
|
||||
export async function enforceMainPaneWidth(
|
||||
mainPaneId: string,
|
||||
windowWidth: number,
|
||||
mainPaneSize: number,
|
||||
mainPaneSizeOrOptions?: number | MainPaneWidthOptions,
|
||||
): Promise<void> {
|
||||
const { log } = await import("../../logger")
|
||||
const tmux = await getTmuxPath()
|
||||
if (!tmux) return
|
||||
|
||||
const dividerWidth = 1
|
||||
const boundedMainPaneSize = Math.max(20, Math.min(80, mainPaneSize))
|
||||
const mainWidth = Math.floor(((windowWidth - dividerWidth) * boundedMainPaneSize) / 100)
|
||||
const options: MainPaneWidthOptions =
|
||||
typeof mainPaneSizeOrOptions === "number"
|
||||
? { mainPaneSize: mainPaneSizeOrOptions }
|
||||
: mainPaneSizeOrOptions ?? {}
|
||||
const mainWidth = calculateMainPaneWidth(windowWidth, options)
|
||||
|
||||
const proc = spawn([tmux, "resize-pane", "-t", mainPaneId, "-x", String(mainWidth)], {
|
||||
stdout: "ignore",
|
||||
@@ -49,6 +89,8 @@ export async function enforceMainPaneWidth(
|
||||
mainPaneId,
|
||||
mainWidth,
|
||||
windowWidth,
|
||||
mainPaneSize: boundedMainPaneSize,
|
||||
mainPaneSize: options?.mainPaneSize,
|
||||
mainPaneMinWidth: options?.mainPaneMinWidth,
|
||||
agentPaneMinWidth: options?.agentPaneMinWidth,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user