revert: remove ResizeObserver and stty-on-every-resize to fix infinite loop
The ResizeObserver detected size changes caused by the stty command output appearing in the terminal, creating an infinite resize loop: 1. Resize detected -> fit() -> send resize to backend 2. Backend sends stty command through PTY 3. stty text appears in terminal output 4. ResizeObserver detects content height change 5. fit() calculates new rows -> send resize 6. Loop continues forever Reverted to: - Window resize event instead of ResizeObserver - stty command only sent once on first resize This means the container shell stays at the initial size and won't dynamically resize when the browser window changes, but prevents the infinite loop.
This commit is contained in:
@@ -142,11 +142,6 @@ class TerminalSession:
|
||||
if self._closed:
|
||||
logger.warning("Cannot resize: session is closed")
|
||||
return
|
||||
|
||||
# Only resize if dimensions actually changed
|
||||
if self._cols == cols and self._rows == rows:
|
||||
return
|
||||
|
||||
self._cols = cols
|
||||
self._rows = rows
|
||||
logger.info(f"resize() called for session {self.session_id}: {cols}x{rows}")
|
||||
@@ -154,9 +149,12 @@ class TerminalSession:
|
||||
|
||||
# Docker exec doesn't forward PTY resize to the container process,
|
||||
# so we need to explicitly set the size inside the container shell.
|
||||
stty_cmd = f"stty cols {cols} rows {rows}\n".encode()
|
||||
await self.write_input(stty_cmd)
|
||||
logger.info(f"Sent stty command to container for session {self.session_id}: {cols}x{rows}")
|
||||
# Only do this on the first resize to avoid interfering with user input.
|
||||
if not getattr(self, '_stty_sent', False):
|
||||
self._stty_sent = True
|
||||
stty_cmd = f"stty cols {cols} rows {rows}\n".encode()
|
||||
await self.write_input(stty_cmd)
|
||||
logger.info(f"Sent stty command to container for session {self.session_id}: {cols}x{rows}")
|
||||
|
||||
async def reset(self) -> None:
|
||||
"""Reset the session by killing the process and clearing state."""
|
||||
|
||||
@@ -254,15 +254,16 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
||||
ws.send(data);
|
||||
});
|
||||
|
||||
// Handle container resize with ResizeObserver (more reliable than window resize)
|
||||
// Handle window resize with debounce
|
||||
let resizeTimeout: ReturnType<typeof setTimeout>;
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
const handleResize = () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => {
|
||||
fitTerminal();
|
||||
}, 100);
|
||||
});
|
||||
resizeObserver.observe(container);
|
||||
}, 250);
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// Refit after mobile header auto-hides (3s delay + 0.3s transition)
|
||||
const headerHideTimeout = setTimeout(() => {
|
||||
@@ -297,7 +298,7 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
||||
return () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
clearTimeout(headerHideTimeout);
|
||||
resizeObserver.disconnect();
|
||||
window.removeEventListener("resize", handleResize);
|
||||
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
||||
if (ws) {
|
||||
ws.close();
|
||||
|
||||
Reference in New Issue
Block a user