From d4b06b29fa45e5fc5d14fff3381a103ccd98d5af Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 11 Aug 2026 23:38:05 -0400 Subject: [PATCH] fix(tui): refine error detail hints --- .../src/component/dialog-error-details.tsx | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/tui/src/component/dialog-error-details.tsx b/packages/tui/src/component/dialog-error-details.tsx index 0dde159474..45531767d1 100644 --- a/packages/tui/src/component/dialog-error-details.tsx +++ b/packages/tui/src/component/dialog-error-details.tsx @@ -1,6 +1,6 @@ -import { TextAttributes, type ScrollBoxRenderable } from "@opentui/core" -import { useKeyboard, useTerminalDimensions } from "@opentui/solid" -import { createMemo, createSignal, onMount } from "solid-js" +import { CliRenderEvents, TextAttributes, type ScrollBoxRenderable } from "@opentui/core" +import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/solid" +import { createEffect, createMemo, createSignal, onCleanup, onMount } from "solid-js" import { useConfig } from "../config" import { useClipboard } from "../context/clipboard" import { Keymap } from "../context/keymap" @@ -15,14 +15,33 @@ export function DialogErrorDetails(props: { title: string; error: string; onBack const toast = useToast() const theme = useTheme("elevated") const overlayTheme = useTheme("overlay") + const renderer = useRenderer() const dimensions = useTerminalDimensions() const config = useConfig().data const [copied, setCopied] = createSignal(false) + const [scrollable, setScrollable] = createSignal(false) const height = createMemo(() => Math.max(3, Math.floor(dimensions().height / 2) - 5)) let scroll: ScrollBoxRenderable | undefined + let measure: (() => void) | undefined onMount(() => dialog.setSize("large")) + createEffect(() => { + dimensions() + props.error + if (measure) renderer.off(CliRenderEvents.FRAME, measure) + measure = () => { + measure = undefined + setScrollable(Boolean(scroll && scroll.scrollHeight > scroll.viewport.height)) + } + renderer.once(CliRenderEvents.FRAME, measure) + renderer.requestRender() + }) + + onCleanup(() => { + if (measure) renderer.off(CliRenderEvents.FRAME, measure) + }) + const copy = () => { void clipboard .write(props.error) @@ -37,6 +56,7 @@ export function DialogErrorDetails(props: { title: string; error: string; onBack useKeyboard((event) => { if (event.name === "c") return copy() + if (!scrollable()) return if (event.name === "up") return scroll?.scrollBy(-1) if (event.name === "down") return scroll?.scrollBy(1) if (event.name === "pageup") return scroll?.scrollBy(-height()) @@ -75,9 +95,12 @@ export function DialogErrorDetails(props: { title: string; error: string; onBack - ↑↓ scroll - - {copied() ? "✓ copied" : "c copy details"} + {scrollable() ? "↑↓ scroll" : ""} + + + {copied() ? "✓ copied" : "copy details"} + + {copied() ? "" : " c"}