diff --git a/packages/tui/src/component/prompt/index.tsx b/packages/tui/src/component/prompt/index.tsx
index 44bc0764384..2115fa1b00c 100644
--- a/packages/tui/src/component/prompt/index.tsx
+++ b/packages/tui/src/component/prompt/index.tsx
@@ -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 (
+
+ esc{" "}
+
+ {props.armed ? "again to interrupt" : "interrupt"}
+
+
+ )
+}
+
function hasEditorRangeSelection(selection: EditorSelection["ranges"][number]) {
return (
selection.selection.start.line !== selection.selection.end.line ||
@@ -1804,21 +1821,12 @@ export function Prompt(props: PromptProps) {
- 0 ? theme.background.action.primary.default : theme.text.default}
- wrapMode="none"
- truncate
- flexShrink={1}
- >
- esc{" "}
- 0 ? theme.background.action.primary.default : theme.text.subdued,
- }}
- >
- {store.interrupt > 0 ? "again to interrupt" : "interrupt"}
-
-
+ 0}
+ text={theme.text.default}
+ subdued={theme.text.subdued}
+ warning={theme.text.feedback.warning.default}
+ />
diff --git a/packages/tui/test/cli/tui/prompt-interrupt-status.test.tsx b/packages/tui/test/cli/tui/prompt-interrupt-status.test.tsx
new file mode 100644
index 00000000000..ebb9269c80f
--- /dev/null
+++ b/packages/tui/test/cli/tui/prompt-interrupt-status.test.tsx
@@ -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(
+ () => ,
+ { 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()
+ }
+})