import type { Theme } from "@earendil-works/pi-coding-agent"; import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui"; export function clamp(value: number, min: number, max: number): number { return Math.min(max, Math.max(min, value)); } export function truncateDisplayText(text: string, width: number): string { if (width <= 0) return ""; return truncateToWidth(text, width, "…", true); } export function joinPartsToWidth(parts: string[], width: number): string { let line = ""; for (const part of parts) { if (!part) continue; const next = line + part; if (visibleWidth(next) <= width) { line = next; continue; } return truncateToWidth(line || part, width, "…", true); } return truncateToWidth(line, width, "…", true); } export function appendRightAlignedAdaptiveHint( left: string, width: number, theme: Theme, candidates: string[], ): string { if (width <= 0) return ""; const leftWidth = visibleWidth(left); for (const candidate of candidates) { const hint = theme.fg("dim", ` ${candidate}`); const hintWidth = visibleWidth(hint); if (hintWidth > width) continue; if (leftWidth + hintWidth <= width) { return left + " ".repeat(Math.max(0, width - leftWidth - hintWidth)) + hint; } const availableLeftWidth = Math.max(0, width - hintWidth); const truncatedLeft = truncateToWidth(left, availableLeftWidth, "…", true); const truncatedLeftWidth = visibleWidth(truncatedLeft); return truncatedLeft + " ".repeat(Math.max(0, width - truncatedLeftWidth - hintWidth)) + hint; } return truncateToWidth(left, width, "…", true); } export function getTuiSize(tui: { terminal?: { columns?: number; rows?: number } }): { width: number; height: number } { return { width: tui.terminal?.columns ?? process.stdout.columns ?? 120, height: tui.terminal?.rows ?? process.stdout.rows ?? 40, }; }