Przeglądaj źródła

fix(app): more terminal replay issues

Adam 2 miesięcy temu
rodzic
commit
6324d1c351
1 zmienionych plików z 30 dodań i 15 usunięć
  1. 30 15
      packages/app/src/components/terminal.tsx

+ 30 - 15
packages/app/src/components/terminal.tsx

@@ -287,6 +287,27 @@ export const Terminal = (props: TerminalProps) => {
       handleResize = () => fit.fit()
       window.addEventListener("resize", handleResize)
       cleanups.push(() => window.removeEventListener("resize", handleResize))
+      const limit = 16_384
+      const min = 32
+      const windowMs = 750
+      const seed = tail.length > limit ? tail.slice(-limit) : tail
+      let sync = seed.length >= min
+      let syncUntil = 0
+      const stopSync = () => {
+        sync = false
+        syncUntil = 0
+      }
+
+      const overlap = (data: string) => {
+        if (!seed) return 0
+        const max = Math.min(seed.length, data.length)
+        if (max < min) return 0
+        for (let i = max; i >= min; i--) {
+          if (seed.slice(-i) === data.slice(0, i)) return i
+        }
+        return 0
+      }
+
       const onResize = t.onResize(async (size) => {
         if (socket.readyState === WebSocket.OPEN) {
           await sdk.client.pty
@@ -302,6 +323,7 @@ export const Terminal = (props: TerminalProps) => {
       })
       cleanups.push(() => disposeIfDisposable(onResize))
       const onData = t.onData((data) => {
+        if (data) stopSync()
         if (socket.readyState === WebSocket.OPEN) {
           socket.send(data)
         }
@@ -317,21 +339,9 @@ 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?.()
+        if (sync) syncUntil = Date.now() + windowMs
         sdk.client.pty
           .update({
             ptyID: local.pty.id,
@@ -346,18 +356,23 @@ export const Terminal = (props: TerminalProps) => {
       cleanups.push(() => socket.removeEventListener("open", handleOpen))
 
       const handleMessage = (event: MessageEvent) => {
+        if (disposed) return
         const data = typeof event.data === "string" ? event.data : ""
         if (!data) return
 
         const next = (() => {
           if (!sync) return data
+          if (syncUntil && Date.now() > syncUntil) {
+            stopSync()
+            return data
+          }
           const n = overlap(data)
           if (!n) {
-            sync = false
+            stopSync()
             return data
           }
           const trimmed = data.slice(n)
-          if (trimmed) sync = false
+          if (trimmed) stopSync()
           return trimmed
         })()