Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions apps/web/src/terminal/ghostty/surface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
terminalLinkAtPositionWithRange,
terminalContentOriginY,
terminalFontFamily,
fittedTerminalFontSize,
terminalFontSize,
terminalWheelArrowData,
terminalWheelDeltaRows,
Expand Down Expand Up @@ -343,24 +342,6 @@ describe("terminal font resolution", () => {
expect(terminalFontFamily(" , ")).toBe(DEFAULT_TERMINAL_FONT_FAMILY);
});

it("slides the rendered size down until a full-width grid fits the canvas", () => {
// SF Mono-like advance: 0.6em per cell.
const cellWidthAt = (size: number) => size * 0.6;
// A wide drawer keeps the preference untouched.
expect(fittedTerminalFontSize(cellWidthAt, 20, 1140)).toBe(20);
// A split pane at the same preference shrinks until 80 columns fit.
const fitted = fittedTerminalFontSize(cellWidthAt, 20, 570);
expect(fitted).toBeLessThan(20);
expect(Math.floor((570 - 8) / cellWidthAt(fitted))).toBeGreaterThanOrEqual(80);
// A tiny pane stops at the legibility floor instead of vanishing.
expect(fittedTerminalFontSize(cellWidthAt, 20, 220)).toBe(8);
// A preference below the floor is honored as-is.
expect(fittedTerminalFontSize(cellWidthAt, 6, 220)).toBe(6);
// Unmeasured layouts leave the preference alone.
expect(fittedTerminalFontSize(cellWidthAt, 14, 0)).toBe(14);
expect(fittedTerminalFontSize(() => 0, 14, 600)).toBe(14);
});

it("clamps requested font sizes to the supported range", () => {
expect(terminalFontSize()).toBe(DEFAULT_TERMINAL_FONT_SIZE);
expect(terminalFontSize(Number.NaN)).toBe(DEFAULT_TERMINAL_FONT_SIZE);
Expand Down
55 changes: 0 additions & 55 deletions apps/web/src/terminal/ghostty/surface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,42 +129,6 @@ export async function loadTerminalFontFamily(
return (environment?.resolve ?? terminalFontFamily)(family);
}

/**
* Grids narrower than a classic 80-column terminal wrap command output hard,
* so the rendered font size follows the canvas width: the preference is the
* ceiling, and the size slides down (to a legibility floor) until a full-width
* grid fits. A widening pane slides it back up toward the preference.
*/
const MIN_TERMINAL_FIT_COLUMNS = 80;
const MIN_TERMINAL_FIT_FONT_SIZE = 8;

export function fittedTerminalFontSize(
cellWidthAt: (size: number) => number,
requested: number,
mountWidth: number,
): number {
const available = mountWidth - CONTENT_PADDING * 2;
if (available <= 0) return requested;
const floor = Math.min(requested, MIN_TERMINAL_FIT_FONT_SIZE);
const fits = (cellWidth: number) =>
cellWidth > 0 && Math.floor(available / cellWidth) >= MIN_TERMINAL_FIT_COLUMNS;
let cellWidth = cellWidthAt(requested);
if (cellWidth <= 0 || fits(cellWidth)) return requested;
// The advance scales linearly with size for monospace faces: jump close to
// the fitting size, then settle the remaining rounding one step at a time.
const targetCellWidth = available / MIN_TERMINAL_FIT_COLUMNS;
let size = Math.max(
floor,
Math.min(requested, Math.floor((requested * targetCellWidth) / cellWidth)),
);
while (size > floor) {
cellWidth = cellWidthAt(size);
if (cellWidth <= 0 || fits(cellWidth)) break;
size -= 1;
}
return size;
}

export function terminalFontSize(size?: number): number {
if (size === undefined || !Number.isFinite(size)) return DEFAULT_TERMINAL_FONT_SIZE;
return Math.max(MIN_TERMINAL_FONT_SIZE, Math.min(MAX_TERMINAL_FONT_SIZE, Math.round(size)));
Expand Down Expand Up @@ -519,7 +483,6 @@ export class GhosttyTerminalSurface {
private fontFamily: string;
private requestedFontFamily: string | undefined;
private fontSize: number;
private requestedFontSize: number;
private fontEpoch = 0;
private pendingFontEpoch: number | null = null;
private readonly resizeObserver: ResizeObserver;
Expand Down Expand Up @@ -601,7 +564,6 @@ export class GhosttyTerminalSurface {
this.fontFamily = fontFamily;
this.requestedFontFamily = options.font?.family;
this.fontSize = terminalFontSize(options.font?.size);
this.requestedFontSize = this.fontSize;
this.resizeObserver = new ResizeObserver(() => this.fit());
this.installEvents();
this.watchDevicePixelRatio();
Expand Down Expand Up @@ -719,7 +681,6 @@ export class GhosttyTerminalSurface {
this.pendingFontEpoch = null;
this.fontFamily = fontFamily;
this.requestedFontFamily = font.family;
this.requestedFontSize = fontSize;
this.fontSize = fontSize;
this.applyFontMetrics();
}
Expand Down Expand Up @@ -775,22 +736,6 @@ export class GhosttyTerminalSurface {
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
if (width <= 0 || height <= 0) return false;
const fitted = fittedTerminalFontSize(
(size) => measureGhosttyCell(this.context, size, this.fontFamily).width,
this.requestedFontSize,
width,
);
if (fitted !== this.fontSize) {
this.fontSize = fitted;
this.metrics = measureGhosttyCell(this.context, this.fontSize, this.fontFamily);
// The grid-change branch below resizes the core, but only when the
// column count moved; the cell geometry always did, so sync it here.
this.core.resize(this.cols, this.rows, this.metrics.width, this.metrics.height);
this.inputLeft = -1;
this.inputTop = -1;
this.forceFullRender = true;
this.scrollbarDirty = true;
}
const ratio = window.devicePixelRatio || 1;
const pixelWidth = Math.max(1, Math.round(width * ratio));
const pixelHeight = Math.max(1, Math.round(height * ratio));
Expand Down
Loading