Skip to content

Commit 114d884

Browse files
committed
fix(core): refresh dimensions after resize debounce
1 parent 4d82072 commit 114d884

3 files changed

Lines changed: 34 additions & 7 deletions

File tree

packages/core/src/renderer.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -893,9 +893,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
893893

894894
private _useConsole: boolean = true
895895
private sigwinchHandler: () => void = (() => {
896-
const width = this.stdout.columns || 80
897-
const height = this.stdout.rows || 24
898-
this.handleResize(width, height)
896+
this.handleResize()
899897
}).bind(this)
900898
private _capabilities: TerminalCapabilities | null = null
901899
private _latestPointer: { x: number; y: number } = { x: 0, y: 0 }
@@ -3814,10 +3812,16 @@ export class CliRenderer extends EventEmitter implements RenderContext {
38143812
}
38153813
}
38163814

3817-
private handleResize(width: number, height: number): void {
3815+
private handleResize(): void {
38183816
if (this._isDestroyed) return
3817+
const resize = () => {
3818+
const stdout = this.stdout as NodeJS.WriteStream & { _refreshSize?: () => void }
3819+
// PTY bridges can deliver SIGWINCH before the stream's cached dimensions reflect the new window size.
3820+
stdout._refreshSize?.()
3821+
this.processResize(stdout.columns || 80, stdout.rows || 24)
3822+
}
38193823
if (this._splitHeight > 0) {
3820-
this.processResize(width, height)
3824+
resize()
38213825
return
38223826
}
38233827

@@ -3828,7 +3832,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
38283832

38293833
this.resizeTimeoutId = this.clock.setTimeout(() => {
38303834
this.resizeTimeoutId = null
3831-
this.processResize(width, height)
3835+
resize()
38323836
}, this.resizeDebounceDelay)
38333837
}
38343838

packages/core/src/tests/renderer.clock.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { afterEach, beforeEach, expect, test } from "bun:test"
22
import { SystemClock } from "../lib/clock.js"
3+
import { CliRenderEvents } from "../renderer.js"
34
import { createTestRenderer, type TestRenderer } from "../testing/test-renderer.js"
45
import { ManualClock } from "../testing/manual-clock.js"
56

@@ -33,6 +34,25 @@ test("renderer init does not pre-schedule frames when size is unchanged", async
3334
expect(frameCalls).toBe(0)
3435
})
3536

37+
test("SIGWINCH refreshes terminal dimensions after the resize debounce", () => {
38+
const stdout = (renderer as unknown as { stdout: { columns: number; rows: number; _refreshSize?: () => void } })
39+
.stdout
40+
const dimensions: Array<[number, number]> = []
41+
renderer.on(CliRenderEvents.RESIZE, (width, height) => dimensions.push([width, height]))
42+
stdout._refreshSize = () => {
43+
stdout.columns = 60
44+
stdout.rows = 18
45+
}
46+
47+
// @ts-expect-error - invoke the private signal handler in a regression test
48+
renderer.sigwinchHandler()
49+
clock.advance(100)
50+
51+
expect(renderer.width).toBe(60)
52+
expect(renderer.height).toBe(18)
53+
expect(dimensions).toEqual([[60, 18]])
54+
})
55+
3656
test("requestRender() does not stall after a backward clock jump", async () => {
3757
clock.setTime(10_000)
3858
// @ts-expect-error - inspect private renderer timing state in regression test

packages/core/src/tests/renderer.console-startup.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,10 @@ test("CliRenderer uses its shared clock for debounced resize", async () => {
135135
})
136136

137137
renderer = result.renderer
138-
;(renderer as any).handleResize(70, 30)
138+
const stdout = (renderer as unknown as { stdout: { columns: number; rows: number } }).stdout
139+
stdout.columns = 70
140+
stdout.rows = 30
141+
;(renderer as unknown as { handleResize: () => void }).handleResize()
139142

140143
expect(renderer.width).toBe(40)
141144
expect(renderer.height).toBe(20)

0 commit comments

Comments
 (0)