| ... | ... | @@ -129,42 +129,6 @@ export async function loadTerminalFontFamily( |
| 129 | 129 | return (environment?.resolve ?? terminalFontFamily)(family); |
| 130 | 130 | } |
| 131 | 131 | |
| 132 | | /** |
| 133 | | * Grids narrower than a classic 80-column terminal wrap command output hard, |
| 134 | | * so the rendered font size follows the canvas width: the preference is the |
| 135 | | * ceiling, and the size slides down (to a legibility floor) until a full-width |
| 136 | | * grid fits. A widening pane slides it back up toward the preference. |
| 137 | | */ |
| 138 | | const MIN_TERMINAL_FIT_COLUMNS = 80; |
| 139 | | const MIN_TERMINAL_FIT_FONT_SIZE = 8; |
| 140 | | |
| 141 | | export function fittedTerminalFontSize( |
| 142 | | cellWidthAt: (size: number) => number, |
| 143 | | requested: number, |
| 144 | | mountWidth: number, |
| 145 | | ): number { |
| 146 | | const available = mountWidth - CONTENT_PADDING * 2; |
| 147 | | if (available <= 0) return requested; |
| 148 | | const floor = Math.min(requested, MIN_TERMINAL_FIT_FONT_SIZE); |
| 149 | | const fits = (cellWidth: number) => |
| 150 | | cellWidth > 0 && Math.floor(available / cellWidth) >= MIN_TERMINAL_FIT_COLUMNS; |
| 151 | | let cellWidth = cellWidthAt(requested); |
| 152 | | if (cellWidth <= 0 || fits(cellWidth)) return requested; |
| 153 | | // The advance scales linearly with size for monospace faces: jump close to |
| 154 | | // the fitting size, then settle the remaining rounding one step at a time. |
| 155 | | const targetCellWidth = available / MIN_TERMINAL_FIT_COLUMNS; |
| 156 | | let size = Math.max( |
| 157 | | floor, |
| 158 | | Math.min(requested, Math.floor((requested * targetCellWidth) / cellWidth)), |
| 159 | | ); |
| 160 | | while (size > floor) { |
| 161 | | cellWidth = cellWidthAt(size); |
| 162 | | if (cellWidth <= 0 || fits(cellWidth)) break; |
| 163 | | size -= 1; |
| 164 | | } |
| 165 | | return size; |
| 166 | | } |
| 167 | | |
| 168 | 132 | export function terminalFontSize(size?: number): number { |
| 169 | 133 | if (size === undefined || !Number.isFinite(size)) return DEFAULT_TERMINAL_FONT_SIZE; |
| 170 | 134 | return Math.max(MIN_TERMINAL_FONT_SIZE, Math.min(MAX_TERMINAL_FONT_SIZE, Math.round(size))); |
| ... | ... | @@ -519,7 +483,6 @@ export class GhosttyTerminalSurface { |
| 519 | 483 | private fontFamily: string; |
| 520 | 484 | private requestedFontFamily: string | undefined; |
| 521 | 485 | private fontSize: number; |
| 522 | | private requestedFontSize: number; |
| 523 | 486 | private fontEpoch = 0; |
| 524 | 487 | private pendingFontEpoch: number | null = null; |
| 525 | 488 | private readonly resizeObserver: ResizeObserver; |
| ... | ... | @@ -601,7 +564,6 @@ export class GhosttyTerminalSurface { |
| 601 | 564 | this.fontFamily = fontFamily; |
| 602 | 565 | this.requestedFontFamily = options.font?.family; |
| 603 | 566 | this.fontSize = terminalFontSize(options.font?.size); |
| 604 | | this.requestedFontSize = this.fontSize; |
| 605 | 567 | this.resizeObserver = new ResizeObserver(() => this.fit()); |
| 606 | 568 | this.installEvents(); |
| 607 | 569 | this.watchDevicePixelRatio(); |
| ... | ... | @@ -719,7 +681,6 @@ export class GhosttyTerminalSurface { |
| 719 | 681 | this.pendingFontEpoch = null; |
| 720 | 682 | this.fontFamily = fontFamily; |
| 721 | 683 | this.requestedFontFamily = font.family; |
| 722 | | this.requestedFontSize = fontSize; |
| 723 | 684 | this.fontSize = fontSize; |
| 724 | 685 | this.applyFontMetrics(); |
| 725 | 686 | } |
| ... | ... | @@ -775,22 +736,6 @@ export class GhosttyTerminalSurface { |
| 775 | 736 | const width = this.mount.clientWidth; |
| 776 | 737 | const height = this.mount.clientHeight; |
| 777 | 738 | if (width <= 0 || height <= 0) return false; |
| 778 | | const fitted = fittedTerminalFontSize( |
| 779 | | (size) => measureGhosttyCell(this.context, size, this.fontFamily).width, |
| 780 | | this.requestedFontSize, |
| 781 | | width, |
| 782 | | ); |
| 783 | | if (fitted !== this.fontSize) { |
| 784 | | this.fontSize = fitted; |
| 785 | | this.metrics = measureGhosttyCell(this.context, this.fontSize, this.fontFamily); |
| 786 | | // The grid-change branch below resizes the core, but only when the |
| 787 | | // column count moved; the cell geometry always did, so sync it here. |
| 788 | | this.core.resize(this.cols, this.rows, this.metrics.width, this.metrics.height); |
| 789 | | this.inputLeft = -1; |
| 790 | | this.inputTop = -1; |
| 791 | | this.forceFullRender = true; |
| 792 | | this.scrollbarDirty = true; |
| 793 | | } |
| 794 | 739 | const ratio = window.devicePixelRatio || 1; |
| 795 | 740 | const pixelWidth = Math.max(1, Math.round(width * ratio)); |
| 796 | 741 | const pixelHeight = Math.max(1, Math.round(height * ratio)); |