summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-02-06 09:54:38 -0600
committerAdam <[email protected]>2026-02-06 12:10:05 -0600
commit6324d1c351618c5f7146a3d31d6b4f78b16f256c (patch)
tree48f67db288866cae4b0e2dad1d98ea529760ef53
parent95ad6758af9049dd031a04c5af5bfbb7ed231884 (diff)
downloadopencode-6324d1c351618c5f7146a3d31d6b4f78b16f256c.tar.gz
opencode-6324d1c351618c5f7146a3d31d6b4f78b16f256c.zip
fix(app): more terminal replay issues
-rw-r--r--packages/app/src/components/terminal.tsx45
1 files changed, 30 insertions, 15 deletions
diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx
index 2ee2e074e..64adc797c 100644
--- a/packages/app/src/components/terminal.tsx
+++ b/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
})()