Просмотр исходного кода

fix(app): more terminal stability fixes

Adam 1 неделя назад
Родитель
Сommit
2875405514

+ 2 - 5
bun.lock

@@ -44,7 +44,7 @@
         "@thisbeyond/solid-dnd": "0.7.5",
         "diff": "catalog:",
         "fuzzysort": "catalog:",
-        "ghostty-web": "0.3.0",
+        "ghostty-web": "0.4.0",
         "luxon": "catalog:",
         "marked": "catalog:",
         "marked-shiki": "catalog:",
@@ -496,9 +496,6 @@
     "web-tree-sitter",
     "tree-sitter-bash",
   ],
-  "patchedDependencies": {
-    "[email protected]": "patches/[email protected]",
-  },
   "overrides": {
     "@types/bun": "catalog:",
     "@types/node": "catalog:",
@@ -2605,7 +2602,7 @@
 
     "get-tsconfig": ["[email protected]", "", { "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": ["[email protected]", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="],
 

+ 1 - 3
package.json

@@ -100,7 +100,5 @@
     "@types/bun": "catalog:",
     "@types/node": "catalog:"
   },
-  "patchedDependencies": {
-    "[email protected]": "patches/[email protected]"
-  }
+  "patchedDependencies": {}
 }

+ 1 - 1
packages/app/package.json

@@ -54,7 +54,7 @@
     "@thisbeyond/solid-dnd": "0.7.5",
     "diff": "catalog:",
     "fuzzysort": "catalog:",
-    "ghostty-web": "0.3.0",
+    "ghostty-web": "0.4.0",
     "luxon": "catalog:",
     "marked": "catalog:",
     "marked-shiki": "catalog:",

+ 38 - 8
packages/app/src/components/terminal.tsx

@@ -70,6 +70,7 @@ export const Terminal = (props: TerminalProps) => {
   let handleTextareaBlur: () => void
   let disposed = false
   const cleanups: VoidFunction[] = []
+  let tail = local.pty.tail ?? ""
 
   const cleanup = () => {
     if (!cleanups.length) return
@@ -256,6 +257,7 @@ export const Terminal = (props: TerminalProps) => {
       serializeAddon = serializer
 
       t.open(container)
+
       container.addEventListener("pointerdown", handlePointerDown)
       cleanups.push(() => container.removeEventListener("pointerdown", handlePointerDown))
 
@@ -276,15 +278,11 @@ export const Terminal = (props: TerminalProps) => {
 
       focusTerminal()
 
+      fit.fit()
+
       if (local.pty.buffer) {
-        if (local.pty.rows && local.pty.cols) {
-          t.resize(local.pty.cols, local.pty.rows)
-        }
         t.write(local.pty.buffer, () => {
-          if (local.pty.scrollY) {
-            t.scrollToLine(local.pty.scrollY)
-          }
-          fitAddon.fit()
+          if (local.pty.scrollY) t.scrollToLine(local.pty.scrollY)
         })
       }
 
@@ -322,6 +320,19 @@ export const Terminal = (props: TerminalProps) => {
       // 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 = () => {
         local.onConnect?.()
         sdk.client.pty
@@ -338,7 +349,25 @@ export const Terminal = (props: TerminalProps) => {
       cleanups.push(() => socket.removeEventListener("open", handleOpen))
 
       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)
       cleanups.push(() => socket.removeEventListener("message", handleMessage))
@@ -392,6 +421,7 @@ export const Terminal = (props: TerminalProps) => {
       props.onCleanup({
         ...local.pty,
         buffer,
+        tail,
         rows: t.rows,
         cols: t.cols,
         scrollY: t.getViewportY(),

+ 1 - 0
packages/app/src/context/terminal.tsx

@@ -13,6 +13,7 @@ export type LocalPTY = {
   cols?: number
   buffer?: string
   scrollY?: number
+  tail?: string
 }
 
 const WORKSPACE_KEY = "__workspace__"