fix(app): more terminal stability fixes
parent
8c0300c021
commit
2875405514
7
bun.lock
7
bun.lock
|
|
@ -44,7 +44,7 @@
|
||||||
"@thisbeyond/solid-dnd": "0.7.5",
|
"@thisbeyond/solid-dnd": "0.7.5",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"ghostty-web": "0.3.0",
|
"ghostty-web": "0.4.0",
|
||||||
"luxon": "catalog:",
|
"luxon": "catalog:",
|
||||||
"marked": "catalog:",
|
"marked": "catalog:",
|
||||||
"marked-shiki": "catalog:",
|
"marked-shiki": "catalog:",
|
||||||
|
|
@ -496,9 +496,6 @@
|
||||||
"web-tree-sitter",
|
"web-tree-sitter",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
],
|
],
|
||||||
"patchedDependencies": {
|
|
||||||
"ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch",
|
|
||||||
},
|
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
|
|
@ -2605,7 +2602,7 @@
|
||||||
|
|
||||||
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
|
"get-tsconfig": ["get-tsconfig@4.13.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ=="],
|
||||||
|
|
||||||
"ghostty-web": ["ghostty-web@0.3.0", "", {}, "sha512-SAdSHWYF20GMZUB0n8kh1N6Z4ljMnuUqT8iTB2n5FAPswEV10MejEpLlhW/769GL5+BQa1NYwEg9y/XCckV5+A=="],
|
"ghostty-web": ["ghostty-web@0.4.0", "", {}, "sha512-0puDBik2qapbD/QQBW9o5ZHfXnZBqZWx/ctBiVtKZ6ZLds4NYb+wZuw1cRLXZk9zYovIQ908z3rvFhexAvc5Hg=="],
|
||||||
|
|
||||||
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
"gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,5 @@
|
||||||
"@types/bun": "catalog:",
|
"@types/bun": "catalog:",
|
||||||
"@types/node": "catalog:"
|
"@types/node": "catalog:"
|
||||||
},
|
},
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {}
|
||||||
"ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
"@thisbeyond/solid-dnd": "0.7.5",
|
"@thisbeyond/solid-dnd": "0.7.5",
|
||||||
"diff": "catalog:",
|
"diff": "catalog:",
|
||||||
"fuzzysort": "catalog:",
|
"fuzzysort": "catalog:",
|
||||||
"ghostty-web": "0.3.0",
|
"ghostty-web": "0.4.0",
|
||||||
"luxon": "catalog:",
|
"luxon": "catalog:",
|
||||||
"marked": "catalog:",
|
"marked": "catalog:",
|
||||||
"marked-shiki": "catalog:",
|
"marked-shiki": "catalog:",
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
let handleTextareaBlur: () => void
|
let handleTextareaBlur: () => void
|
||||||
let disposed = false
|
let disposed = false
|
||||||
const cleanups: VoidFunction[] = []
|
const cleanups: VoidFunction[] = []
|
||||||
|
let tail = local.pty.tail ?? ""
|
||||||
|
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
if (!cleanups.length) return
|
if (!cleanups.length) return
|
||||||
|
|
@ -256,6 +257,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
serializeAddon = serializer
|
serializeAddon = serializer
|
||||||
|
|
||||||
t.open(container)
|
t.open(container)
|
||||||
|
|
||||||
container.addEventListener("pointerdown", handlePointerDown)
|
container.addEventListener("pointerdown", handlePointerDown)
|
||||||
cleanups.push(() => container.removeEventListener("pointerdown", handlePointerDown))
|
cleanups.push(() => container.removeEventListener("pointerdown", handlePointerDown))
|
||||||
|
|
||||||
|
|
@ -276,15 +278,11 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
|
|
||||||
focusTerminal()
|
focusTerminal()
|
||||||
|
|
||||||
|
fit.fit()
|
||||||
|
|
||||||
if (local.pty.buffer) {
|
if (local.pty.buffer) {
|
||||||
if (local.pty.rows && local.pty.cols) {
|
|
||||||
t.resize(local.pty.cols, local.pty.rows)
|
|
||||||
}
|
|
||||||
t.write(local.pty.buffer, () => {
|
t.write(local.pty.buffer, () => {
|
||||||
if (local.pty.scrollY) {
|
if (local.pty.scrollY) t.scrollToLine(local.pty.scrollY)
|
||||||
t.scrollToLine(local.pty.scrollY)
|
|
||||||
}
|
|
||||||
fitAddon.fit()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,6 +320,19 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
// console.log("Scroll position:", ydisp)
|
// console.log("Scroll position:", ydisp)
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
const limit = 16_384
|
||||||
|
const seed = tail
|
||||||
|
let sync = !!seed
|
||||||
|
|
||||||
|
const overlap = (data: string) => {
|
||||||
|
if (!seed) return 0
|
||||||
|
const max = Math.min(seed.length, data.length)
|
||||||
|
for (let i = max; i > 0; i--) {
|
||||||
|
if (seed.slice(-i) === data.slice(0, i)) return i
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
local.onConnect?.()
|
local.onConnect?.()
|
||||||
sdk.client.pty
|
sdk.client.pty
|
||||||
|
|
@ -338,7 +349,25 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
cleanups.push(() => socket.removeEventListener("open", handleOpen))
|
cleanups.push(() => socket.removeEventListener("open", handleOpen))
|
||||||
|
|
||||||
const handleMessage = (event: MessageEvent) => {
|
const handleMessage = (event: MessageEvent) => {
|
||||||
t.write(event.data)
|
const data = typeof event.data === "string" ? event.data : ""
|
||||||
|
if (!data) return
|
||||||
|
|
||||||
|
const next = (() => {
|
||||||
|
if (!sync) return data
|
||||||
|
const n = overlap(data)
|
||||||
|
if (!n) {
|
||||||
|
sync = false
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
const trimmed = data.slice(n)
|
||||||
|
if (trimmed) sync = false
|
||||||
|
return trimmed
|
||||||
|
})()
|
||||||
|
|
||||||
|
if (!next) return
|
||||||
|
|
||||||
|
t.write(next)
|
||||||
|
tail = next.length >= limit ? next.slice(-limit) : (tail + next).slice(-limit)
|
||||||
}
|
}
|
||||||
socket.addEventListener("message", handleMessage)
|
socket.addEventListener("message", handleMessage)
|
||||||
cleanups.push(() => socket.removeEventListener("message", handleMessage))
|
cleanups.push(() => socket.removeEventListener("message", handleMessage))
|
||||||
|
|
@ -392,6 +421,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||||
props.onCleanup({
|
props.onCleanup({
|
||||||
...local.pty,
|
...local.pty,
|
||||||
buffer,
|
buffer,
|
||||||
|
tail,
|
||||||
rows: t.rows,
|
rows: t.rows,
|
||||||
cols: t.cols,
|
cols: t.cols,
|
||||||
scrollY: t.getViewportY(),
|
scrollY: t.getViewportY(),
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ export type LocalPTY = {
|
||||||
cols?: number
|
cols?: number
|
||||||
buffer?: string
|
buffer?: string
|
||||||
scrollY?: number
|
scrollY?: number
|
||||||
|
tail?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const WORKSPACE_KEY = "__workspace__"
|
const WORKSPACE_KEY = "__workspace__"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue