import type { Theme } from "@earendil-works/pi-coding-agent"; import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui"; import type { PolishedTuiConfig } from "../../app/config/shell.ts"; import { safeThemeFg } from "../../shared/style.ts"; import { renderUserMessageStyle } from "../context/message/user-message-styles.ts"; import { sanitizeEditorMetadataText } from "../editor/editor-metadata-format.ts"; import { renderMinimalistFrame } from "../editor/minimalist-editor.ts"; export const SETTINGS_PREVIEW_MAX_WIDTH = 72; export const SETTINGS_PREVIEW_MAX_ROWS = 10; export const EDITOR_PREVIEW_INPUT = "Explain this change safely."; export const USER_MESSAGE_PREVIEW_MARKDOWN = "Please review **this change** safely."; function boundedRows(rows: string[], width: number): string[] { const safeWidth = Math.max(0, Math.min(SETTINGS_PREVIEW_MAX_WIDTH, width)); if (safeWidth <= 0) return []; const bounded = rows .slice(0, SETTINGS_PREVIEW_MAX_ROWS) .map((line) => truncateToWidth(line, safeWidth, "")); while (bounded.length > 0 && visibleWidth(bounded.at(-1) ?? "") === 0) bounded.pop(); return bounded; } function previewConfig(config: PolishedTuiConfig): PolishedTuiConfig { const derived = structuredClone(config); derived.icons = Object.fromEntries( Object.entries(derived.icons).map(([key, value]) => [ key, typeof value === "string" ? sanitizeEditorMetadataText(value) : value, ]), ) as typeof derived.icons; return derived; } function adaptiveBorder(theme: Theme): (text: string) => string { return (text) => safeThemeFg(theme, "thinkingHigh", text); } export function renderEditorSettingsPreview( config: PolishedTuiConfig, theme: Theme, width: number, ): string[] { const previewWidth = Math.max(0, Math.min(SETTINGS_PREVIEW_MAX_WIDTH, width)); if (previewWidth <= 0) return []; const safeConfig = previewConfig(config); const editor = safeConfig.components.editor; const borderColor = adaptiveBorder(theme); const modelLabel = editor.modelLabel === "name" ? "Sonnet 4" : "sonnet-4"; const editorLines = [EDITOR_PREVIEW_INPUT]; const autocompleteLines = [ safeThemeFg(theme, "accent", "→ settings Open settings"), " files Search files", safeThemeFg(theme, "muted", " (1/47)"), ]; const viewport = editor.viewportIndicators ? { above: "2", below: "3" } : undefined; const frame = renderMinimalistFrame({ width: previewWidth, editorLines, autocompleteLines, viewport, inputText: EDITOR_PREVIEW_INPUT, metadata: { cwd: "/workspace/zentui/src", projectRoot: "/workspace/zentui", branch: "feat/settings-previews", dirty: true, ahead: 2, behind: 1, costLabel: "$.12", modelLabel, thinkingLevel: "high", sessionName: "Preview", agentDurationMs: 12_000, agentActive: true, }, uiTheme: theme, config: safeConfig, borderColor, }); return boundedRows(frame, previewWidth); } export function renderUserMessageSettingsPreview( config: PolishedTuiConfig, theme: Theme, width: number, text = USER_MESSAGE_PREVIEW_MARKDOWN, ): string[] { const previewWidth = Math.max(0, Math.min(SETTINGS_PREVIEW_MAX_WIDTH, width)); if (previewWidth <= 0) return []; const safeConfig = previewConfig(config); const frame = renderUserMessageStyle({ text, width: previewWidth, theme, config: safeConfig, }); return boundedRows(frame, previewWidth); }