From fed49dba6d55a325b5d55e738f9d5632929242e8 Mon Sep 17 00:00:00 2001 From: Fusion Date: Sun, 24 May 2026 15:30:34 +0200 Subject: [PATCH] debug: add logging and simplify fit logic - Simplified fit logic: just fit after open, after fonts load, and on resize - Added console logging to debug what FitAddon calculates - Single fitTerminal() function used everywhere - Removed complex retry logic that wasn't working --- apps/web/src/components/terminal.tsx | 103 ++++++++------------------- 1 file changed, 30 insertions(+), 73 deletions(-) diff --git a/apps/web/src/components/terminal.tsx b/apps/web/src/components/terminal.tsx index 93745f0..fc64b1e 100644 --- a/apps/web/src/components/terminal.tsx +++ b/apps/web/src/components/terminal.tsx @@ -201,74 +201,35 @@ export const TerminalComponent: React.FC = ({ term.loadAddon(fitAddon); term.loadAddon(new WebLinksAddon()); - // Wait for container to have non-zero dimensions before opening xterm - // xterm docs: "parent must be visible (have dimensions) when open is called" const container = terminalRef.current; let ws: WebSocket; - const initTerminal = () => { - term.open(container); + // Open xterm immediately + term.open(container); + ws = connectWebSocket(); - // Connect WebSocket - ws = connectWebSocket(); - - // Robust fitting: wait for fonts and stable dimensions - const performFit = () => { - fitAddon.fit(); - const { cols, rows } = term; - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - type: "resize", - cols, - rows, - }) - ); - } - return { cols, rows }; - }; - - const ensureProperFit = (attempt = 0) => { - const { cols, rows } = performFit(); - // If dimensions are unreasonably small, retry (layout still settling) - if ((rows <= 1 || cols <= 10) && attempt < 30) { - setTimeout(() => ensureProperFit(attempt + 1), 100); - } - }; - - // Wait for fonts to load, then fit with retry logic - document.fonts.ready.then(() => { - requestAnimationFrame(() => { - requestAnimationFrame(() => { - ensureProperFit(); - }); - }); - }); - - // Fit after mobile header auto-hides (3s delay + 0.3s transition) - setTimeout(() => { - performFit(); - }, 4000); + // Fit terminal and notify backend + const fitTerminal = () => { + if (!fitAddonRef.current || !termRef.current) return; + fitAddonRef.current.fit(); + const { cols, rows } = termRef.current; + console.log(`[Terminal] Fitted: ${cols}x${rows}, container: ${container.clientWidth}x${container.clientHeight}`); + if (ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ type: "resize", cols, rows })); + } }; - // Check if container already has dimensions - const rect = container.getBoundingClientRect(); - if (rect.width > 0 && rect.height > 0) { - initTerminal(); - } else { - // Wait for container to be laid out - const resizeObserver = new ResizeObserver((entries) => { - for (const entry of entries) { - const { width, height } = entry.contentRect; - if (width > 0 && height > 0) { - resizeObserver.disconnect(); - initTerminal(); - break; - } - } + // Initial fit after layout settles + requestAnimationFrame(() => { + requestAnimationFrame(() => { + fitTerminal(); }); - resizeObserver.observe(container); - } + }); + + // Refit after font load (metrics may change) + document.fonts.ready.then(() => { + requestAnimationFrame(() => fitTerminal()); + }); // Handle terminal input term.onData((data) => { @@ -288,27 +249,22 @@ export const TerminalComponent: React.FC = ({ ws.send(data); }); - // Handle resize with debounce + // Handle window resize with debounce let resizeTimeout: ReturnType; const handleResize = () => { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { - fitAddon.fit(); - const { cols, rows } = term; - if (ws.readyState === WebSocket.OPEN) { - ws.send( - JSON.stringify({ - type: "resize", - cols, - rows, - }) - ); - } + fitTerminal(); }, 250); }; window.addEventListener("resize", handleResize); + // Refit after mobile header auto-hides (3s delay + 0.3s transition) + const headerHideTimeout = setTimeout(() => { + fitTerminal(); + }, 4000); + // Notify parent about terminal readiness if (onTerminalReadyRef.current) { const sendData = (data: string) => { @@ -336,6 +292,7 @@ export const TerminalComponent: React.FC = ({ return () => { clearTimeout(resizeTimeout); + clearTimeout(headerHideTimeout); window.removeEventListener("resize", handleResize); document.removeEventListener("visibilitychange", handleVisibilityChange); if (ws) {