fix(app): terminal tab close
This commit is contained in:
@@ -18,7 +18,7 @@ const DEFAULT_TOGGLE_TERMINAL_KEYBIND = "ctrl+`"
|
|||||||
export interface TerminalProps extends ComponentProps<"div"> {
|
export interface TerminalProps extends ComponentProps<"div"> {
|
||||||
pty: LocalPTY
|
pty: LocalPTY
|
||||||
onSubmit?: () => void
|
onSubmit?: () => void
|
||||||
onCleanup?: (pty: LocalPTY) => void
|
onCleanup?: (pty: Partial<LocalPTY> & { id: string }) => void
|
||||||
onConnect?: () => void
|
onConnect?: () => void
|
||||||
onConnectError?: (error: unknown) => void
|
onConnectError?: (error: unknown) => void
|
||||||
}
|
}
|
||||||
@@ -126,8 +126,8 @@ const persistTerminal = (input: {
|
|||||||
term: Term | undefined
|
term: Term | undefined
|
||||||
addon: SerializeAddon | undefined
|
addon: SerializeAddon | undefined
|
||||||
cursor: number
|
cursor: number
|
||||||
pty: LocalPTY
|
id: string
|
||||||
onCleanup?: (pty: LocalPTY) => void
|
onCleanup?: (pty: Partial<LocalPTY> & { id: string }) => void
|
||||||
}) => {
|
}) => {
|
||||||
if (!input.addon || !input.onCleanup || !input.term) return
|
if (!input.addon || !input.onCleanup || !input.term) return
|
||||||
const buffer = (() => {
|
const buffer = (() => {
|
||||||
@@ -140,7 +140,7 @@ const persistTerminal = (input: {
|
|||||||
})()
|
})()
|
||||||
|
|
||||||
input.onCleanup({
|
input.onCleanup({
|
||||||
...input.pty,
|
id: input.id,
|
||||||
buffer,
|
buffer,
|
||||||
cursor: input.cursor,
|
cursor: input.cursor,
|
||||||
rows: input.term.rows,
|
rows: input.term.rows,
|
||||||
@@ -158,6 +158,19 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
const server = useServer()
|
const server = useServer()
|
||||||
let container!: HTMLDivElement
|
let container!: HTMLDivElement
|
||||||
const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnect", "onConnectError"])
|
const [local, others] = splitProps(props, ["pty", "class", "classList", "onConnect", "onConnectError"])
|
||||||
|
const id = local.pty.id
|
||||||
|
const restore = typeof local.pty.buffer === "string" ? local.pty.buffer : ""
|
||||||
|
const restoreSize =
|
||||||
|
restore &&
|
||||||
|
typeof local.pty.cols === "number" &&
|
||||||
|
Number.isSafeInteger(local.pty.cols) &&
|
||||||
|
local.pty.cols > 0 &&
|
||||||
|
typeof local.pty.rows === "number" &&
|
||||||
|
Number.isSafeInteger(local.pty.rows) &&
|
||||||
|
local.pty.rows > 0
|
||||||
|
? { cols: local.pty.cols, rows: local.pty.rows }
|
||||||
|
: undefined
|
||||||
|
const scrollY = typeof local.pty.scrollY === "number" ? local.pty.scrollY : undefined
|
||||||
let ws: WebSocket | undefined
|
let ws: WebSocket | undefined
|
||||||
let term: Term | undefined
|
let term: Term | undefined
|
||||||
let ghostty: Ghostty
|
let ghostty: Ghostty
|
||||||
@@ -190,7 +203,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
const pushSize = (cols: number, rows: number) => {
|
const pushSize = (cols: number, rows: number) => {
|
||||||
return sdk.client.pty
|
return sdk.client.pty
|
||||||
.update({
|
.update({
|
||||||
ptyID: local.pty.id,
|
ptyID: id,
|
||||||
size: { cols, rows },
|
size: { cols, rows },
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@@ -319,18 +332,6 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
const mod = loaded.mod
|
const mod = loaded.mod
|
||||||
const g = loaded.ghostty
|
const g = loaded.ghostty
|
||||||
|
|
||||||
const restore = typeof local.pty.buffer === "string" ? local.pty.buffer : ""
|
|
||||||
const restoreSize =
|
|
||||||
restore &&
|
|
||||||
typeof local.pty.cols === "number" &&
|
|
||||||
Number.isSafeInteger(local.pty.cols) &&
|
|
||||||
local.pty.cols > 0 &&
|
|
||||||
typeof local.pty.rows === "number" &&
|
|
||||||
Number.isSafeInteger(local.pty.rows) &&
|
|
||||||
local.pty.rows > 0
|
|
||||||
? { cols: local.pty.cols, rows: local.pty.rows }
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const t = new mod.Terminal({
|
const t = new mod.Terminal({
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
cursorStyle: "bar",
|
cursorStyle: "bar",
|
||||||
@@ -427,14 +428,14 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
await write(restore)
|
await write(restore)
|
||||||
fit.fit()
|
fit.fit()
|
||||||
scheduleSize(t.cols, t.rows)
|
scheduleSize(t.cols, t.rows)
|
||||||
if (typeof local.pty.scrollY === "number") t.scrollToLine(local.pty.scrollY)
|
if (scrollY !== undefined) t.scrollToLine(scrollY)
|
||||||
startResize()
|
startResize()
|
||||||
} else {
|
} else {
|
||||||
fit.fit()
|
fit.fit()
|
||||||
scheduleSize(t.cols, t.rows)
|
scheduleSize(t.cols, t.rows)
|
||||||
if (restore) {
|
if (restore) {
|
||||||
await write(restore)
|
await write(restore)
|
||||||
if (typeof local.pty.scrollY === "number") t.scrollToLine(local.pty.scrollY)
|
if (scrollY !== undefined) t.scrollToLine(scrollY)
|
||||||
}
|
}
|
||||||
startResize()
|
startResize()
|
||||||
}
|
}
|
||||||
@@ -446,9 +447,9 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
const once = { value: false }
|
const once = { value: false }
|
||||||
let closing = false
|
let closing = false
|
||||||
|
|
||||||
const url = new URL(sdk.url + `/pty/${local.pty.id}/connect`)
|
const url = new URL(sdk.url + `/pty/${id}/connect`)
|
||||||
url.searchParams.set("directory", sdk.directory)
|
url.searchParams.set("directory", sdk.directory)
|
||||||
url.searchParams.set("cursor", String(start !== undefined ? start : local.pty.buffer ? -1 : 0))
|
url.searchParams.set("cursor", String(start !== undefined ? start : restore ? -1 : 0))
|
||||||
url.protocol = url.protocol === "https:" ? "wss:" : "ws:"
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:"
|
||||||
url.username = server.current?.http.username ?? ""
|
url.username = server.current?.http.username ?? ""
|
||||||
url.password = server.current?.http.password ?? ""
|
url.password = server.current?.http.password ?? ""
|
||||||
@@ -542,7 +543,7 @@ export const Terminal = (props: TerminalProps) => {
|
|||||||
if (ws && ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) ws.close(1000)
|
if (ws && ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) ws.close(1000)
|
||||||
|
|
||||||
const finalize = () => {
|
const finalize = () => {
|
||||||
persistTerminal({ term, addon: serializeAddon, cursor, pty: local.pty, onCleanup: props.onCleanup })
|
persistTerminal({ term, addon: serializeAddon, cursor, id, onCleanup: props.onCleanup })
|
||||||
cleanup()
|
cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export function TerminalPanel() {
|
|||||||
|
|
||||||
const all = createMemo(() => terminal.all())
|
const all = createMemo(() => terminal.all())
|
||||||
const ids = createMemo(() => all().map((pty) => pty.id))
|
const ids = createMemo(() => all().map((pty) => pty.id))
|
||||||
const byId = createMemo(() => new Map(all().map((pty) => [pty.id, pty])))
|
const byId = createMemo(() => new Map(all().map((pty) => [pty.id, { ...pty }])))
|
||||||
|
|
||||||
const handleTerminalDragStart = (event: unknown) => {
|
const handleTerminalDragStart = (event: unknown) => {
|
||||||
const id = getDraggableId(event)
|
const id = getDraggableId(event)
|
||||||
@@ -189,7 +189,13 @@ export function TerminalPanel() {
|
|||||||
>
|
>
|
||||||
<Tabs.List class="h-10">
|
<Tabs.List class="h-10">
|
||||||
<SortableProvider ids={ids()}>
|
<SortableProvider ids={ids()}>
|
||||||
<For each={all()}>{(pty) => <SortableTerminalTab terminal={pty} onClose={close} />}</For>
|
<For each={ids()}>
|
||||||
|
{(id) => (
|
||||||
|
<Show when={byId().get(id)}>
|
||||||
|
{(pty) => <SortableTerminalTab terminal={pty()} onClose={close} />}
|
||||||
|
</Show>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
</SortableProvider>
|
</SortableProvider>
|
||||||
<div class="h-full flex items-center justify-center">
|
<div class="h-full flex items-center justify-center">
|
||||||
<TooltipKeybind
|
<TooltipKeybind
|
||||||
|
|||||||
Reference in New Issue
Block a user