mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-26 19:31:39 -04:00
fix(tui): use unicode ellipses in interface text (#45143)
This commit is contained in:
@@ -614,7 +614,7 @@ function App(props: { pair?: DialogPairCredentials }) {
|
||||
return
|
||||
}
|
||||
|
||||
renderer.setTerminalTitle(`OC | ${title.length > 40 ? title.slice(0, 37) + "..." : title}`)
|
||||
renderer.setTerminalTitle(`OC | ${title.length > 40 ? title.slice(0, 37) + "…" : title}`)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -971,7 +971,7 @@ function App(props: { pair?: DialogPairCredentials }) {
|
||||
const restart = client.restart
|
||||
if (!restart) return
|
||||
dialog.clear()
|
||||
toast.show({ variant: "info", message: "Restarting service...", duration: 30000 })
|
||||
toast.show({ variant: "info", message: "Restarting service…", duration: 30000 })
|
||||
// restart resolves once the replacement service is healthy; the
|
||||
// event stream reattaches through the reconnect loop.
|
||||
await restart()
|
||||
|
||||
@@ -360,7 +360,7 @@ export function DevToolsBar() {
|
||||
<PanelBox>
|
||||
<PanelTitle>Tools</PanelTitle>
|
||||
<Action onClick={() => void dump()} disabled={dumping()} hoverBackground>
|
||||
{dumping() ? "Writing debug snapshot..." : "Write debug snapshot"}
|
||||
{dumping() ? "Writing debug snapshot…" : "Write debug snapshot"}
|
||||
</Action>
|
||||
<Show when={dumpPath()}>
|
||||
{(file) => (
|
||||
|
||||
@@ -352,7 +352,7 @@ function CommandStarting(props: {
|
||||
if (!handedOff) closed = true
|
||||
})
|
||||
|
||||
return <CommandView title={props.method.label} output="" message="Starting command..." />
|
||||
return <CommandView title={props.method.label} output="" message="Starting command…" />
|
||||
}
|
||||
|
||||
function CommandPending(props: {
|
||||
@@ -412,7 +412,7 @@ function CommandPending(props: {
|
||||
})
|
||||
})
|
||||
|
||||
return <CommandView title={props.title} output={output()} message="Waiting for command to finish..." />
|
||||
return <CommandView title={props.title} output={output()} message="Waiting for command to finish…" />
|
||||
}
|
||||
|
||||
function CommandView(props: { title: string; output: string; message: string }) {
|
||||
@@ -541,7 +541,7 @@ function OAuthStarting(props: {
|
||||
})
|
||||
})
|
||||
|
||||
return <OAuthView title={props.method.label} message="Starting authorization..." />
|
||||
return <OAuthView title={props.method.label} message="Starting authorization…" />
|
||||
}
|
||||
|
||||
function OAuthAuto(props: {
|
||||
@@ -629,7 +629,7 @@ function OAuthAuto(props: {
|
||||
title={props.title}
|
||||
url={props.attempt.url}
|
||||
instructions={props.attempt.instructions}
|
||||
message="Waiting for authorization..."
|
||||
message="Waiting for authorization…"
|
||||
copy
|
||||
open
|
||||
/>
|
||||
@@ -953,7 +953,7 @@ async function externalAnswer(
|
||||
if (choice === true) return true
|
||||
const result = await new Promise<boolean | typeof CANCELLED>((resolve) => {
|
||||
dialog.replace(
|
||||
() => <OAuthView title={formLabel(field) || title} message="Opening link..." />,
|
||||
() => <OAuthView title={formLabel(field) || title} message="Opening link…" />,
|
||||
() => resolve(CANCELLED),
|
||||
)
|
||||
void open(field.url).then(
|
||||
|
||||
@@ -237,7 +237,7 @@ function buildIssueURL(message: string, stack: string, version: string) {
|
||||
// clipped trace is obvious. searchParams.set handles encoding without throwing,
|
||||
// so measuring url.toString() is both correct and safe on any input.
|
||||
const MAX_URL_LENGTH = 6000
|
||||
const marker = "\n... (truncated)"
|
||||
const marker = "\n… (truncated)"
|
||||
const head = `The OpenCode TUI crashed with an unexpected error.\n\n**Error:** ${message}\n\n**Stack trace:**\n`
|
||||
const setBody = (body: string) => url.searchParams.set("description", head + "```\n" + body + "\n```")
|
||||
|
||||
|
||||
@@ -1641,10 +1641,10 @@ export function Prompt(props: PromptProps) {
|
||||
const value = (() => {
|
||||
if (store.mode === "shell") {
|
||||
if (!shell().length) return undefined
|
||||
return `Run a command... "${shell()[store.placeholder % shell().length]}"`
|
||||
return `Run a command… "${shell()[store.placeholder % shell().length]}"`
|
||||
}
|
||||
if (!list().length) return undefined
|
||||
return `Ask anything... "${list()[store.placeholder % list().length]}"`
|
||||
return `Ask anything… "${list()[store.placeholder % list().length]}"`
|
||||
})()
|
||||
if (!value) return undefined
|
||||
const width = dimensions().width < 44 ? dimensions().width - 5 : Math.min(75, dimensions().width - 4) - 5
|
||||
|
||||
@@ -28,7 +28,7 @@ export function Reconnecting(props: { managed?: boolean }) {
|
||||
paddingRight={2}
|
||||
gap={1}
|
||||
>
|
||||
<Spinner color={theme.text.default}>{props.managed ? "Restarting service..." : "Connection lost..."}</Spinner>
|
||||
<Spinner color={theme.text.default}>{props.managed ? "Restarting service…" : "Connection lost…"}</Spinner>
|
||||
<text fg={theme.text.subdued}>
|
||||
{props.managed
|
||||
? "Your session will resume automatically."
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Spinner } from "./spinner"
|
||||
export function StartupLoading(props: { ready: () => boolean }) {
|
||||
const theme = useTheme("elevated")
|
||||
const [show, setShow] = createSignal(false)
|
||||
const text = createMemo(() => (props.ready() ? "Finishing startup..." : "Loading plugins..."))
|
||||
const text = createMemo(() => (props.ready() ? "Finishing startup…" : "Loading plugins…"))
|
||||
let wait: NodeJS.Timeout | undefined
|
||||
let hold: NodeJS.Timeout | undefined
|
||||
let stamp = 0
|
||||
|
||||
@@ -75,7 +75,7 @@ export function DialogFork(props: { sessionID: string; messageID?: string; onMov
|
||||
when={!pending()}
|
||||
fallback={
|
||||
<box paddingLeft={2} paddingRight={2} paddingBottom={1}>
|
||||
<Spinner>Forking session...</Spinner>
|
||||
<Spinner>Forking session…</Spinner>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
|
||||
@@ -3134,9 +3134,9 @@ function Shell(props: ToolProps) {
|
||||
when={command()}
|
||||
fallback={
|
||||
isRunning() || props.part.state.status === "streaming" ? (
|
||||
<Spinner color={color()}>Writing command...</Spinner>
|
||||
<Spinner color={color()}>Writing command…</Spinner>
|
||||
) : (
|
||||
<text fg={theme.text.subdued}>Writing command...</text>
|
||||
<text fg={theme.text.subdued}>Writing command…</text>
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -3183,7 +3183,7 @@ function Write(props: ToolProps) {
|
||||
</BlockTool>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<InlineTool icon="←" pending="Preparing write..." complete={stringValue(props.input.path)} part={props.part}>
|
||||
<InlineTool icon="←" pending="Preparing write…" complete={stringValue(props.input.path)} part={props.part}>
|
||||
Write {pathFormatter.format(stringValue(props.input.path))}
|
||||
</InlineTool>
|
||||
</Match>
|
||||
@@ -3194,7 +3194,7 @@ function Write(props: ToolProps) {
|
||||
function Glob(props: ToolProps) {
|
||||
const pathFormatter = usePathFormatter()
|
||||
return (
|
||||
<InlineTool icon="✱" pending="Finding files..." complete={stringValue(props.input.pattern)} part={props.part}>
|
||||
<InlineTool icon="✱" pending="Finding files…" complete={stringValue(props.input.pattern)} part={props.part}>
|
||||
Glob "{stringValue(props.input.pattern)}"{" "}
|
||||
<Show when={stringValue(props.input.path)}>in {pathFormatter.format(stringValue(props.input.path))} </Show>
|
||||
<Show when={finiteNumber(props.metadata.count)}>
|
||||
@@ -3218,7 +3218,7 @@ function Read(props: ToolProps) {
|
||||
<>
|
||||
<InlineTool
|
||||
icon="→"
|
||||
pending="Reading file..."
|
||||
pending="Reading file…"
|
||||
complete={stringValue(props.input.path)}
|
||||
spinner={isRunning()}
|
||||
part={props.part}
|
||||
@@ -3241,7 +3241,7 @@ function Read(props: ToolProps) {
|
||||
function Grep(props: ToolProps) {
|
||||
const pathFormatter = usePathFormatter()
|
||||
return (
|
||||
<InlineTool icon="✱" pending="Searching content..." complete={stringValue(props.input.pattern)} part={props.part}>
|
||||
<InlineTool icon="✱" pending="Searching content…" complete={stringValue(props.input.pattern)} part={props.part}>
|
||||
Grep "{stringValue(props.input.pattern)}"{" "}
|
||||
<Show when={stringValue(props.input.path)}>in {pathFormatter.format(stringValue(props.input.path))} </Show>
|
||||
<Show when={finiteNumber(props.metadata.matches)}>
|
||||
@@ -3253,7 +3253,7 @@ function Grep(props: ToolProps) {
|
||||
|
||||
function WebFetch(props: ToolProps) {
|
||||
return (
|
||||
<InlineTool icon="%" pending="Fetching from the web..." complete={stringValue(props.input.url)} part={props.part}>
|
||||
<InlineTool icon="%" pending="Fetching from the web…" complete={stringValue(props.input.url)} part={props.part}>
|
||||
WebFetch {stringValue(props.input.url)}
|
||||
</InlineTool>
|
||||
)
|
||||
@@ -3261,7 +3261,7 @@ function WebFetch(props: ToolProps) {
|
||||
|
||||
function WebSearch(props: ToolProps) {
|
||||
return (
|
||||
<InlineTool icon="◈" pending="Searching web..." complete={stringValue(props.input.query)} part={props.part}>
|
||||
<InlineTool icon="◈" pending="Searching web…" complete={stringValue(props.input.query)} part={props.part}>
|
||||
{webSearchProviderLabel(props.metadata.provider)} "{stringValue(props.input.query)}"
|
||||
</InlineTool>
|
||||
)
|
||||
@@ -3283,7 +3283,7 @@ function Subagent(props: ToolProps) {
|
||||
icon={continuation() ? "↳" : isRunning() ? "│" : props.part.state.status === "completed" ? "✓" : "│"}
|
||||
spinner={!continuation() && isRunning()}
|
||||
complete={description()}
|
||||
pending="Delegating..."
|
||||
pending="Delegating…"
|
||||
part={props.part}
|
||||
onClick={() => {
|
||||
const id = sessionID()
|
||||
@@ -3474,7 +3474,7 @@ function Edit(props: ToolProps) {
|
||||
? { label: "← Edit", value: pathFormatter.format(stringValue(props.input.path)) }
|
||||
: undefined
|
||||
}
|
||||
title={stringValue(props.input.path) ? undefined : "# Preparing edit..."}
|
||||
title={stringValue(props.input.path) ? undefined : "# Preparing edit…"}
|
||||
part={props.part}
|
||||
spinner={props.part.state.status === "streaming"}
|
||||
/>
|
||||
@@ -3629,7 +3629,7 @@ function Question(props: ToolProps) {
|
||||
</BlockTool>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<InlineTool icon="→" pending="Asking questions..." complete={count()} part={props.part}>
|
||||
<InlineTool icon="→" pending="Asking questions…" complete={count()} part={props.part}>
|
||||
Asked {count()} question{count() !== 1 ? "s" : ""}
|
||||
</InlineTool>
|
||||
</Match>
|
||||
@@ -3640,7 +3640,7 @@ function Question(props: ToolProps) {
|
||||
function Skill(props: ToolProps) {
|
||||
const name = createMemo(() => stringValue(props.metadata.name) ?? stringValue(props.input.id))
|
||||
return (
|
||||
<InlineTool icon="→" pending="Loading skill..." complete={name()} part={props.part}>
|
||||
<InlineTool icon="→" pending="Loading skill…" complete={name()} part={props.part}>
|
||||
Skill "{name()}"
|
||||
</InlineTool>
|
||||
)
|
||||
|
||||
@@ -100,11 +100,11 @@ export function DialogPrompt(props: DialogPromptProps) {
|
||||
cursorStyle={config.cursor}
|
||||
/>
|
||||
<Show when={props.busy}>
|
||||
<Spinner color={theme.text.subdued}>{props.busyText ?? "Working..."}</Spinner>
|
||||
<Spinner color={theme.text.subdued}>{props.busyText ?? "Working…"}</Spinner>
|
||||
</Show>
|
||||
</box>
|
||||
<box paddingBottom={1} gap={1} flexDirection="row">
|
||||
<Show when={!props.busy} fallback={<text fg={theme.text.subdued}>processing...</text>}>
|
||||
<Show when={!props.busy} fallback={<text fg={theme.text.subdued}>processing…</text>}>
|
||||
<Show when={shortcuts.get("dialog.prompt.submit")}>
|
||||
<text fg={theme.text.default}>
|
||||
{shortcuts.get("dialog.prompt.submit")} <span style={{ fg: theme.text.subdued }}>submit</span>
|
||||
|
||||
@@ -59,7 +59,7 @@ describe("DiffViewerFileTree", () => {
|
||||
<ThemedDiffViewerFileTree width={32} files={[]} loading={false} error={undefined} />
|
||||
))
|
||||
|
||||
expect(loading).not.toContain("Loading diff...")
|
||||
expect(loading).not.toContain("Loading diff…")
|
||||
expect(loading).not.toContain("No files")
|
||||
expect(failed).not.toContain("Failed to load diff")
|
||||
expect(failed).not.toContain("No files")
|
||||
|
||||
@@ -73,7 +73,7 @@ function Fixture(props: { errorExpanded?: boolean }) {
|
||||
|
||||
function FailedPendingToolFixture() {
|
||||
return (
|
||||
<InlineToolRow icon="%" complete={false} pending="Preparing patch..." failed={true} failure="Patch failed">
|
||||
<InlineToolRow icon="%" complete={false} pending="Preparing patch…" failed={true} failure="Patch failed">
|
||||
Patch
|
||||
</InlineToolRow>
|
||||
)
|
||||
@@ -81,7 +81,7 @@ function FailedPendingToolFixture() {
|
||||
|
||||
function FailedCompleteToolFixture() {
|
||||
return (
|
||||
<InlineToolRow icon="→" complete={true} pending="Reading file..." failed={true} failure="Read failed">
|
||||
<InlineToolRow icon="→" complete={true} pending="Reading file…" failed={true} failure="Read failed">
|
||||
Read src/index.ts
|
||||
</InlineToolRow>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user