From 6519a947feb7265fcbcd082a1626cea1c10fd685 Mon Sep 17 00:00:00 2001 From: Jon Ayers Date: Tue, 25 Nov 2025 15:05:56 +0000 Subject: [PATCH] fix(demo): improve terminal resizing to fit container - Add overflow: hidden and position: relative to #terminal container so the container constrains the canvas size rather than expanding to fit it - Call fitAddon.observeResize() for automatic resize on container changes - Use term.onResize event to notify PTY of dimension changes (works with both observeResize and manual fit calls) - Keep window resize handler for browsers that don't trigger ResizeObserver on window resize This ensures the terminal properly sizes itself to fill the container on initial load and responds to container/window size changes. fix: expose renderer publicly for FitAddon to access FitAddon.proposeDimensions() was returning undefined because it couldn't access the terminal's renderer to get font metrics. The renderer was private, so FitAddon couldn't calculate the correct terminal dimensions. Changes: - Make Terminal.renderer public so FitAddon can access getMetrics() - Add observeResize() call to demo/index.html - Make initTerminal async and await term.open() in demo/index.html - Update demo/bin/demo.js CSS to use absolute positioning for #terminal The root cause was that FitAddon needs renderer.getMetrics() to calculate how many cols/rows fit in the container, but the renderer field was private. --- demo/bin/demo.js | 22 ++++++++++++++++------ demo/bun.lock | 2 +- demo/index.html | 7 ++++--- lib/terminal.ts | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/demo/bin/demo.js b/demo/bin/demo.js index 94f11a75..69c754ee 100644 --- a/demo/bin/demo.js +++ b/demo/bin/demo.js @@ -160,11 +160,16 @@ const HTML_TEMPLATE = ` padding: 0; min-height: 400px; height: 60vh; + position: relative; } #terminal { - width: 100%; - height: 100%; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: hidden; } @@ -203,6 +208,7 @@ const HTML_TEMPLATE = ` const container = document.getElementById('terminal'); await term.open(container); fitAddon.fit(); + fitAddon.observeResize(); // Auto-fit when container resizes // Status elements const statusDot = document.getElementById('status-dot'); @@ -249,13 +255,17 @@ const HTML_TEMPLATE = ` } }); - // Handle resize - window.addEventListener('resize', () => { - fitAddon.fit(); + // Handle resize - notify PTY when terminal dimensions change + term.onResize(({ cols, rows }) => { if (ws && ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ type: 'resize', cols: term.cols, rows: term.rows })); + ws.send(JSON.stringify({ type: 'resize', cols, rows })); } }); + + // Also handle window resize (for browsers that don't trigger ResizeObserver on window resize) + window.addEventListener('resize', () => { + fitAddon.fit(); + }); `; diff --git a/demo/bun.lock b/demo/bun.lock index 6503f070..09b1d17b 100644 --- a/demo/bun.lock +++ b/demo/bun.lock @@ -6,7 +6,7 @@ "name": "@ghostty-web/demo", "dependencies": { "@lydell/node-pty": "^1.0.1", - "ghostty-web": "^0.2.1", + "ghostty-web": "latest", }, }, }, diff --git a/demo/index.html b/demo/index.html index 53394a5a..8c709ae6 100644 --- a/demo/index.html +++ b/demo/index.html @@ -138,7 +138,7 @@ let ws; let fitAddon; - function initTerminal() { + async function initTerminal() { term = new Terminal({ cursorBlink: true, fontSize: 14, @@ -153,10 +153,11 @@ fitAddon = new FitAddon(); term.loadAddon(fitAddon); - term.open(document.getElementById('terminal-container')); + await term.open(document.getElementById('terminal-container')); fitAddon.fit(); + fitAddon.observeResize(); // Auto-fit when container resizes - // Handle window resize + // Handle window resize (for browsers that don't trigger ResizeObserver on window resize) window.addEventListener('resize', () => { fitAddon.fit(); }); diff --git a/lib/terminal.ts b/lib/terminal.ts index cb6cbfc5..82cd0c1c 100644 --- a/lib/terminal.ts +++ b/lib/terminal.ts @@ -67,7 +67,7 @@ export class Terminal implements ITerminalCore { // Components (created on open()) private ghostty?: Ghostty; public wasmTerm?: GhosttyTerminal; // Made public for link providers - private renderer?: CanvasRenderer; + public renderer?: CanvasRenderer; // Made public for FitAddon private inputHandler?: InputHandler; private selectionManager?: SelectionManager; private canvas?: HTMLCanvasElement;