fix(panel): draw a terminal in its web font only once the font has loaded

Merged
DA
5d ago
+122-2

This came out of the 390px phone check for the Terminal tab on the web (#4357, #4360). It is independent of both.

The bug

  • A page fetches a web font only once something draws in it, and xterm measures its cells as it opens.
  • The web profile's monospace face is the JetBrains Mono web font (--luke-font-mono in @luke/ui's profiles.css). A terminal opened before that font landed measured its cells in the stand-in face, and fit its columns to them.
  • The next resize measured the cells again in the face that had landed, but kept the columns. On a phone, the next resize is the keyboard coming up.
  • So the screen drew about 17% past its box, and every long line was cut off at the right edge. At 390px it was 62 columns of 7 px in a 371 px screen; with the fix it is 53.
  • The desktop never hits this: its monospace faces are the system's, loaded already.

The fix

terminal-surface.ts:

  • Face still loading (document.fonts.check false): the terminal opens in the system's monospace and switches to its own face once document.fonts.load lands. The switch is a change of xterm's font option, so xterm measures the cells again, and the screen is fitted to them.
  • Face already loaded: drawn in at once, and nothing is fetched.
  • Face that fails to load: the terminal keeps the stand-in.

Tests

terminal/index.test.ts, through the bundle's own door (terminal.mount), reads the face the DOM renderer's rules draw the rows in:

  • A face still loading is stood in for by monospace, and the full stack is drawn in once the load lands.
  • A face already loaded is drawn in at once, and nothing is fetched.

Checked by hand

I drew the real Terminal tab full screen at 390×844 (3× scale, DOM renderer), typed ls, and shrank the stage to 390×508 for the keyboard:

  • Before: .xterm-screen was 434 px wide in a 390 px tab, and lines were cut off at the right edge.
  • After: 371 px, lines wrap inside the screen, and the prompt stays above the keyboard.

Made with Luke


Devin Review