diff --git a/src/web/public/terminal-ui.js b/src/web/public/terminal-ui.js index 4dfa7364..17b934cc 100644 --- a/src/web/public/terminal-ui.js +++ b/src/web/public/terminal-ui.js @@ -1428,8 +1428,11 @@ Object.assign(CodemanApp.prototype, { // frame — this observer only ever measured Pane A's container, so // without this call Pane B never learned about a window resize, an // Alt+B sidebar toggle, or a tab-rail drag, and its PTY silently - // stayed at whatever size it was last dragged to. - this._forEachTile?.((tile) => tile.fit()); + // stayed at whatever size it was last dragged to. Grid tiles are left + // out: the grid's own observer (tile-grid.js _scheduleTileGridRefit) + // refits every one of them on the same resize, and a second fit here + // only re-measured six panes to send nothing. + this._forEachTile?.((tile) => tile.fit(), { grid: false }); }, 300); // Trailing-edge: only fire after 300ms of no resize events }; diff --git a/test/tile-grid-park-guards.test.ts b/test/tile-grid-park-guards.test.ts index b995ce60..d7a21b65 100644 --- a/test/tile-grid-park-guards.test.ts +++ b/test/tile-grid-park-guards.test.ts @@ -29,6 +29,8 @@ * tile-grid.js in one `vm` context, with the shared fake DOM and fake * TerminalTile (test/mocks/tile-grid-vm.ts). Port: N/A. */ +import { readFileSync } from 'node:fs'; +import { resolve } from 'node:path'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FakeTile, @@ -357,6 +359,22 @@ describe('panes and fonts while the grid is open', () => { expect(pane.sessionId).toBe('s-a'); }); + it("the main terminal's window-resize timer leaves grid tiles to the grid's own observer", () => { + // A window resize fires both: the grid's ResizeObserver refits every tile + // (tile-grid.js _scheduleTileGridRefit) and the main terminal's trailing + // timer used to refit them again, twelve fit() calls for six tiles and + // nothing more sent (measured). The timer lives inside initTerminal(), so + // this reads its source; the split's Pane B is still refitted there. + const src = readFileSync(resolve(import.meta.dirname, '../src/web/public/terminal-ui.js'), 'utf8'); + const start = src.indexOf('const throttledResize = () => {'); + const end = src.indexOf("window.addEventListener('resize', throttledResize)", start); + expect(start).toBeGreaterThan(-1); + expect(end).toBeGreaterThan(start); + const calls = src.slice(start, end).match(/this\._forEachTile\?\.\([^;]*;/g) ?? []; + expect(calls).toHaveLength(1); + expect(calls[0]).toContain('{ grid: false }'); + }); + it('_forEachTile reaches every grid tile; { grid: false } skips them', () => { const app = appWithGrid(true); const seen: string[] = [];