diff options
| author | Adam <[email protected]> | 2026-01-21 13:23:45 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-21 13:23:50 -0600 |
| commit | 3ba1111ed047ca4cc42bc964ae23c32959c0e8fd (patch) | |
| tree | 552c5bdfa4a83f667b8bc80a8ccec7e5f9cb2476 /packages | |
| parent | 6f7a1c69a517b6f46e7b7c18b69fc38fa7aaa10f (diff) | |
| download | opencode-3ba1111ed047ca4cc42bc964ae23c32959c0e8fd.tar.gz opencode-3ba1111ed047ca4cc42bc964ae23c32959c0e8fd.zip | |
fix(app): terminal issues/regression
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/app/src/components/session/session-sortable-terminal-tab.tsx | 29 | ||||
| -rw-r--r-- | packages/app/src/components/terminal.tsx | 7 | ||||
| -rw-r--r-- | packages/app/src/pages/session.tsx | 29 |
3 files changed, 52 insertions, 13 deletions
diff --git a/packages/app/src/components/session/session-sortable-terminal-tab.tsx b/packages/app/src/components/session/session-sortable-terminal-tab.tsx index 539195553..2c661edf8 100644 --- a/packages/app/src/components/session/session-sortable-terminal-tab.tsx +++ b/packages/app/src/components/session/session-sortable-terminal-tab.tsx @@ -18,12 +18,22 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => const [menuPosition, setMenuPosition] = createSignal({ x: 0, y: 0 }) const [blurEnabled, setBlurEnabled] = createSignal(false) + const isDefaultTitle = () => { + const number = props.terminal.titleNumber + if (!Number.isFinite(number) || number <= 0) return false + const match = props.terminal.title.match(/^Terminal (\d+)$/) + if (!match) return false + const parsed = Number(match[1]) + if (!Number.isFinite(parsed) || parsed <= 0) return false + return parsed === number + } + const label = () => { language.locale() + if (props.terminal.title && !isDefaultTitle()) return props.terminal.title + const number = props.terminal.titleNumber - if (Number.isFinite(number) && number > 0) { - return language.t("terminal.title.numbered", { number }) - } + if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number }) if (props.terminal.title) return props.terminal.title return language.t("terminal.title") } @@ -102,8 +112,15 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => } return ( - // @ts-ignore - <div use:sortable classList={{ "h-full": true, "opacity-0": sortable.isActiveDraggable }}> + <div + // @ts-ignore + use:sortable + class="outline-none focus:outline-none focus-visible:outline-none" + classList={{ + "h-full": true, + "opacity-0": sortable.isActiveDraggable, + }} + > <div class="relative h-full"> <Tabs.Trigger classes={{ button: "border-0" }} @@ -111,6 +128,8 @@ export function SortableTerminalTab(props: { terminal: LocalPTY; onClose?: () => onClick={focus} onMouseDown={(e) => e.preventDefault()} onContextMenu={menu} + class="!shadow-none" + classes={{ button: "outline-none focus:outline-none focus-visible:outline-none !shadow-none !ring-0" }} closeButton={ <IconButton icon="close" diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index 1ab171898..6bedcfae2 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -10,6 +10,7 @@ export interface TerminalProps extends ComponentProps<"div"> { pty: LocalPTY onSubmit?: () => void onCleanup?: (pty: LocalPTY) => void + onConnect?: () => void onConnectError?: (error: unknown) => void } @@ -40,7 +41,7 @@ export const Terminal = (props: TerminalProps) => { const settings = useSettings() const theme = useTheme() let container!: HTMLDivElement - const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnectError"]) + const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnect", "onConnectError"]) let ws: WebSocket | undefined let term: Term | undefined let ghostty: Ghostty @@ -241,6 +242,7 @@ export const Terminal = (props: TerminalProps) => { // console.log("Scroll position:", ydisp) // }) socket.addEventListener("open", () => { + local.onConnect?.() sdk.client.pty .update({ ptyID: local.pty.id, @@ -255,10 +257,12 @@ export const Terminal = (props: TerminalProps) => { t.write(event.data) }) socket.addEventListener("error", (error) => { + if (disposed) return console.error("WebSocket error:", error) local.onConnectError?.(error) }) socket.addEventListener("close", (event) => { + if (disposed) return // Normal closure (code 1000) means PTY process exited - server event handles cleanup // For other codes (network issues, server restart), trigger error handler if (event.code !== 1000) { @@ -268,6 +272,7 @@ export const Terminal = (props: TerminalProps) => { }) onCleanup(() => { + disposed = true if (handleResize) { window.removeEventListener("resize", handleResize) } diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 7dcf60b72..560c13330 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -1231,11 +1231,15 @@ export default function Page() { language.locale() const label = (pty: LocalPTY) => { + const title = pty.title const number = pty.titleNumber - if (Number.isFinite(number) && number > 0) { - return language.t("terminal.title.numbered", { number }) - } - if (pty.title) return pty.title + const match = title.match(/^Terminal (\d+)$/) + const parsed = match ? Number(match[1]) : undefined + const isDefaultTitle = Number.isFinite(number) && number > 0 && Number.isFinite(parsed) && parsed === number + + if (title && !isDefaultTitle) return title + if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number }) + if (title) return title return language.t("terminal.title") } @@ -2002,7 +2006,12 @@ export default function Page() { <Terminal pty={pty} onCleanup={(data) => terminal.update({ ...data, id: pty.id })} + onConnect={() => { + terminal.update({ id: pty.id, error: false }) + setDismissed(false) + }} onConnectError={() => { + setDismissed(false) terminal.update({ id: pty.id, error: true }) }} /> @@ -2056,11 +2065,17 @@ export default function Page() { {(t) => ( <div class="relative p-1 h-10 flex items-center bg-background-stronger text-14-regular"> {(() => { + const title = t().title const number = t().titleNumber - if (Number.isFinite(number) && number > 0) { + const match = title.match(/^Terminal (\d+)$/) + const parsed = match ? Number(match[1]) : undefined + const isDefaultTitle = + Number.isFinite(number) && number > 0 && Number.isFinite(parsed) && parsed === number + + if (title && !isDefaultTitle) return title + if (Number.isFinite(number) && number > 0) return language.t("terminal.title.numbered", { number }) - } - if (t().title) return t().title + if (title) return title return language.t("terminal.title") })()} </div> |
