mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 00:03:46 +00:00
fix(terminal): gate metric writes on the pixel box, not the fit floor
canApplyPaneMetricOptions reused canMeasurePaneForFit, whose >=8 cols / >=4 rows floor exists to stop a fit pinning the PTY to a sliver. But the divider clamp is 50px, which clears the 48px pixel floor and proposes ~5 cols — so a pane dragged to the clamp deferred every font change and never flushed: it never hides, and its box never changes, so no reveal and no ResizeObserver entry ever arrives. It rendered a stale font until widened, where pre-PR the write was unconditional. Gate metric writes on display plus the pixel box only. Hidden panes and the transient worktree-switch overlay are near-zero, so they still defer — the deferral's purpose is unchanged. The cols/rows floor stays on the fit, including the post-flush re-check in performSafeFit. Apply and flush share the same predicate, so no "applies but never flushes" state can open up.
This commit is contained in:
@@ -20,13 +20,18 @@ export function getProposedPaneDimensions(
|
||||
}
|
||||
}
|
||||
|
||||
export function canMeasurePaneForFit(pane: ManagedPane): boolean {
|
||||
function hasPaneFitPixelBox(pane: ManagedPane): boolean {
|
||||
const measure = pane.container?.getBoundingClientRect
|
||||
if (typeof measure === 'function') {
|
||||
const rect = measure.call(pane.container)
|
||||
if (rect.width < MIN_PANE_FIT_WIDTH_PX || rect.height < MIN_PANE_FIT_HEIGHT_PX) {
|
||||
return false
|
||||
}
|
||||
if (typeof measure !== 'function') {
|
||||
return true
|
||||
}
|
||||
const rect = measure.call(pane.container)
|
||||
return rect.width >= MIN_PANE_FIT_WIDTH_PX && rect.height >= MIN_PANE_FIT_HEIGHT_PX
|
||||
}
|
||||
|
||||
export function canMeasurePaneForFit(pane: ManagedPane): boolean {
|
||||
if (!hasPaneFitPixelBox(pane)) {
|
||||
return false
|
||||
}
|
||||
const dims = getProposedPaneDimensions(pane)
|
||||
if (!dims) {
|
||||
@@ -37,8 +42,14 @@ export function canMeasurePaneForFit(pane: ManagedPane): boolean {
|
||||
return dims.cols >= MIN_PANE_FIT_COLS && dims.rows >= MIN_PANE_FIT_ROWS
|
||||
}
|
||||
|
||||
/** Why only the pixel box, not the fit floor: a pane held at the 50px divider
|
||||
* clamp proposes ~5 cols, so the fit floor would reject it forever — it never
|
||||
* hides and its box never changes, so nothing would flush and it would render
|
||||
* a stale font until widened. A hidden pane or the transient worktree-switch
|
||||
* overlay is near-zero, so the pixel floor still defers those. The cols/rows
|
||||
* floor stays where it belongs: on the fit. */
|
||||
export function canApplyPaneMetricOptions(pane: ManagedPane): boolean {
|
||||
return !isManagedPaneDisplayNone(pane) && canMeasurePaneForFit(pane)
|
||||
return !isManagedPaneDisplayNone(pane) && hasPaneFitPixelBox(pane)
|
||||
}
|
||||
|
||||
/** Why the pending check comes first: it is an O(1) WeakMap lookup, while the
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { ManagedPane, ManagedPaneInternal } from './pane-manager-types'
|
||||
import { toPublicPane } from './pane-public-view'
|
||||
import { canApplyPaneMetricOptions, canMeasurePaneForFit } from './pane-fit-measurability'
|
||||
import {
|
||||
applyOrDeferPaneMetricOptions,
|
||||
flushDeferredPaneMetricOptions,
|
||||
@@ -138,3 +139,29 @@ describe('pane-metric-options-deferral', () => {
|
||||
expect(pane.terminal.options.fontSize).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('canApplyPaneMetricOptions gating', () => {
|
||||
function makeSizedPane(rect: { width: number; height: number }, cols: number): ManagedPane {
|
||||
return {
|
||||
id: 2,
|
||||
terminal: { options: {} },
|
||||
container: { getBoundingClientRect: () => rect },
|
||||
fitAddon: { proposeDimensions: () => ({ cols, rows: 20 }) }
|
||||
} as unknown as ManagedPane
|
||||
}
|
||||
|
||||
it('applies to a pane clamped narrow by a divider drag', () => {
|
||||
// 50px is the divider clamp: over the pixel floor but ~5 cols, under the
|
||||
// fit floor. Gating on the fit floor would strand it on a stale font,
|
||||
// because it never hides and its box never changes.
|
||||
expect(canApplyPaneMetricOptions(makeSizedPane({ width: 50, height: 600 }, 5))).toBe(true)
|
||||
})
|
||||
|
||||
it('still defers on a near-zero box (hidden pane / worktree-switch overlay)', () => {
|
||||
expect(canApplyPaneMetricOptions(makeSizedPane({ width: 0, height: 0 }, 0))).toBe(false)
|
||||
})
|
||||
|
||||
it('leaves the cols/rows floor on the fit itself', () => {
|
||||
expect(canMeasurePaneForFit(makeSizedPane({ width: 50, height: 600 }, 5))).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user