mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-20 17:23:26 +00:00
fix(tui): keep interrupt confirmation visible (#42096)
This commit is contained in:
parent
c80472b6d5
commit
f713d39c61
2 changed files with 48 additions and 15 deletions
|
|
@ -5,6 +5,7 @@ import {
|
|||
MouseEvent,
|
||||
PasteEvent,
|
||||
decodePasteBytes,
|
||||
type ColorInput,
|
||||
type KeyEvent,
|
||||
} from "@opentui/core"
|
||||
import { createEffect, createMemo, onMount, createSignal, onCleanup, on, Show, Switch, Match, For } from "solid-js"
|
||||
|
|
@ -107,6 +108,22 @@ function fadeColor(color: RGBA, alpha: number) {
|
|||
return RGBA.fromValues(color.r, color.g, color.b, color.a * alpha)
|
||||
}
|
||||
|
||||
export function PromptInterruptStatus(props: {
|
||||
armed: boolean
|
||||
text: ColorInput
|
||||
subdued: ColorInput
|
||||
warning: ColorInput
|
||||
}) {
|
||||
return (
|
||||
<text fg={props.armed ? props.warning : props.text} wrapMode="none" truncate flexShrink={1}>
|
||||
esc{" "}
|
||||
<span style={{ fg: props.armed ? props.warning : props.subdued }}>
|
||||
{props.armed ? "again to interrupt" : "interrupt"}
|
||||
</span>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
|
||||
function hasEditorRangeSelection(selection: EditorSelection["ranges"][number]) {
|
||||
return (
|
||||
selection.selection.start.line !== selection.selection.end.line ||
|
||||
|
|
@ -1804,21 +1821,12 @@ export function Prompt(props: PromptProps) {
|
|||
<spinner color={spinnerDef().color} frames={spinnerDef().frames} interval={40} />
|
||||
</Show>
|
||||
</box>
|
||||
<text
|
||||
fg={store.interrupt > 0 ? theme.background.action.primary.default : theme.text.default}
|
||||
wrapMode="none"
|
||||
truncate
|
||||
flexShrink={1}
|
||||
>
|
||||
esc{" "}
|
||||
<span
|
||||
style={{
|
||||
fg: store.interrupt > 0 ? theme.background.action.primary.default : theme.text.subdued,
|
||||
}}
|
||||
>
|
||||
{store.interrupt > 0 ? "again to interrupt" : "interrupt"}
|
||||
</span>
|
||||
</text>
|
||||
<PromptInterruptStatus
|
||||
armed={store.interrupt > 0}
|
||||
text={theme.text.default}
|
||||
subdued={theme.text.subdued}
|
||||
warning={theme.text.feedback.warning.default}
|
||||
/>
|
||||
</box>
|
||||
</Match>
|
||||
<Match when={move.progress()}>
|
||||
|
|
|
|||
25
packages/tui/test/cli/tui/prompt-interrupt-status.test.tsx
Normal file
25
packages/tui/test/cli/tui/prompt-interrupt-status.test.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/** @jsxImportSource @opentui/solid */
|
||||
import { RGBA } from "@opentui/core"
|
||||
import { testRender } from "@opentui/solid"
|
||||
import { expect, test } from "bun:test"
|
||||
import { PromptInterruptStatus } from "../../../src/component/prompt"
|
||||
|
||||
test("armed interrupt status renders visible warning text", async () => {
|
||||
const text = RGBA.fromHex("#ffffff")
|
||||
const subdued = RGBA.fromHex("#808080")
|
||||
const warning = RGBA.fromHex("#fbbf24")
|
||||
const app = await testRender(
|
||||
() => <PromptInterruptStatus armed text={text} subdued={subdued} warning={warning} />,
|
||||
{ width: 30, height: 1 },
|
||||
)
|
||||
|
||||
try {
|
||||
await app.renderOnce()
|
||||
const line = app.renderer.currentRenderBuffer.getSpanLines()[0]!
|
||||
|
||||
expect(line.spans.map((span) => span.text).join("")).toContain("esc again to interrupt")
|
||||
expect(line.spans.filter((span) => span.text.trim()).every((span) => span.fg.equals(warning))).toBeTrue()
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue