fix(run): pin the lane terminal font so Vietnamese glyphs never fall back

xterm left fontFamily unset, so it used the browser/OS default
(courier-new/monospace). That face is missing Vietnamese precomposed
diacritics on many systems, so the browser silently substitutes those
glyphs from another face with a different advance width — corrupting
the cell even under the canvas renderer, which only stops a glyph from
shoving its neighbours, not from overflowing its own cell. Pin the
terminal to the app's own bundled JetBrains Mono and import its
vietnamese subset (previously only latin was loaded).
This commit is contained in:
2026-08-28 13:18:12 +07:00
parent 52fbd852af
commit 5c297c6483
2 changed files with 21 additions and 1 deletions
+15 -1
View File
@@ -26,7 +26,21 @@ export function TerminalView({ runId, wsBaseUrl }: TerminalViewProps) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const term = new Terminal({ convertEol: true, fontSize: 13, cursorBlink: true });
// An explicit fontFamily pins every glyph to one bundled webfont. Left
// unset, xterm falls back to the browser/OS default (`courier-new`),
// which on Windows lacks Vietnamese precomposed diacritics — the OS then
// substitutes those specific glyphs from a different face with a
// mismatched advance width, corrupting the cell it's drawn into even
// under the canvas renderer (which only stops a glyph from shoving its
// *neighbours*, not from overflowing its own cell). JetBrains Mono is
// already bundled for the rest of the UI; main.tsx additionally imports
// its `vietnamese` subset so this covers the diacritics too.
const term = new Terminal({
convertEol: true,
fontSize: 13,
cursorBlink: true,
fontFamily: '"JetBrains Mono", monospace',
});
const fit = new FitAddon();
term.loadAddon(fit);
if (containerRef.current) term.open(containerRef.current);
+6
View File
@@ -57,6 +57,12 @@ import "@fontsource/inter/latin-600.css";
import "@fontsource/inter/latin-700.css";
import "@fontsource/jetbrains-mono/latin-400.css";
import "@fontsource/jetbrains-mono/latin-500.css";
// The lane terminal renders live Vietnamese output in this font (TerminalView),
// which the latin subset above doesn't cover — without it, missing glyphs fall
// back to another installed face with a different advance width and get
// visually mangled inside xterm's fixed-width cells.
import "@fontsource/jetbrains-mono/vietnamese-400.css";
import "@fontsource/jetbrains-mono/vietnamese-500.css";
import App from "./App";
import "./i18n";
import "./index.css";