diff --git a/src/features/terminal/terminal.test.ts b/src/features/terminal/terminal.test.ts index f6b1a7dfc..e649fdc42 100644 --- a/src/features/terminal/terminal.test.ts +++ b/src/features/terminal/terminal.test.ts @@ -285,7 +285,7 @@ describe("split layout", () => { }); describe("terminalFont", () => { - const BASE = '"JetBrains Mono Variable", "JetBrains Mono", ui-monospace, Menlo, monospace'; + const BASE = '"JetBrains Mono", "JetBrains Mono Variable", ui-monospace, Menlo, monospace'; const t = { useEditorFont: true, fontFamily: "JetBrains Mono", @@ -303,13 +303,13 @@ describe("terminalFont", () => { "editor font, default family", t, editor, - `"JetBrains Mono Variable", "JetBrains Mono", ${BASE.replace(", monospace", "")}, `, + `"JetBrains Mono", "JetBrains Mono Variable", ${BASE.replace(", monospace", "")}, `, ], [ "editor font, no editor settings", t, undefined, - `"JetBrains Mono Variable", "JetBrains Mono", ${BASE.replace(", monospace", "")}, `, + `"JetBrains Mono", "JetBrains Mono Variable", ${BASE.replace(", monospace", "")}, `, ], [ "editor font, custom family", @@ -321,13 +321,13 @@ describe("terminalFont", () => { "editor font, editor fallback", t, { ...editor, fallbackFont: "PingFang SC" }, - `"JetBrains Mono Variable", "JetBrains Mono", "PingFang SC", ${BASE.replace(", monospace", "")}, `, + `"JetBrains Mono", "JetBrains Mono Variable", "PingFang SC", ${BASE.replace(", monospace", "")}, `, ], [ "own font, default family", { ...t, useEditorFont: false }, editor, - `"JetBrains Mono Variable", "JetBrains Mono", ${BASE.replace(", monospace", "")}, `, + `"JetBrains Mono", "JetBrains Mono Variable", ${BASE.replace(", monospace", "")}, `, ], [ "own font, custom + fallback", @@ -343,14 +343,14 @@ describe("terminalFont", () => { }); it("resolves bundled Inter in inherited, independent and fallback selections", () => { - expect(terminalFont(t, { ...editor, fontFamily: "Inter" }, BASE).family).toMatch(/^"Inter Variable", "Inter",/); + expect(terminalFont(t, { ...editor, fontFamily: "Inter" }, BASE).family).toMatch(/^"Inter", "Inter Variable",/); expect(terminalFont({ ...t, useEditorFont: false, fontFamily: "Inter" }, editor, BASE).family).toMatch( - /^"Inter Variable", "Inter",/, + /^"Inter", "Inter Variable",/, ); expect(terminalFont({ ...t, fallbackFontFamily: "Inter" }, editor, BASE).family).toContain( - '"Inter Variable", "Inter"', + '"Inter", "Inter Variable"', ); - expect(terminalFont(t, { ...editor, fallbackFont: "Inter" }, BASE).family).toContain('"Inter Variable", "Inter"'); + expect(terminalFont(t, { ...editor, fallbackFont: "Inter" }, BASE).family).toContain('"Inter", "Inter Variable"'); }); it("prefers the terminal's fallback over the editor's", () => { diff --git a/src/platform/fonts.test.ts b/src/platform/fonts.test.ts index 65cf7520f..b8dca68b6 100644 --- a/src/platform/fonts.test.ts +++ b/src/platform/fonts.test.ts @@ -6,14 +6,15 @@ const BASE = "var(--font-mono)"; describe("monoFontFamily", () => { it.each([ // #26: the default family names the bundled face, so it renders without a system install. - ["JetBrains Mono", "", `"JetBrains Mono Variable", "JetBrains Mono", ${BASE}`], - ["", "", `"JetBrains Mono Variable", "JetBrains Mono", ${BASE}`], - [undefined, "", `"JetBrains Mono Variable", "JetBrains Mono", ${BASE}`], - ["JetBrains Mono", "PingFang SC", `"JetBrains Mono Variable", "JetBrains Mono", "PingFang SC", ${BASE}`], - ["Inter", "", `"Inter Variable", "Inter", ${BASE}`], - ["Fira Code", "Inter", `"Fira Code", "Inter Variable", "Inter", ${BASE}`], - ["Inter", "JetBrains Mono", `"Inter Variable", "Inter", "JetBrains Mono Variable", "JetBrains Mono", ${BASE}`], - ["inter", "jetbrains mono", `"Inter Variable", "Inter", "JetBrains Mono Variable", "JetBrains Mono", ${BASE}`], + // #2305: the installed family comes first, so its hinted outlines render like IDEA's. + ["JetBrains Mono", "", `"JetBrains Mono", "JetBrains Mono Variable", ${BASE}`], + ["", "", `"JetBrains Mono", "JetBrains Mono Variable", ${BASE}`], + [undefined, "", `"JetBrains Mono", "JetBrains Mono Variable", ${BASE}`], + ["JetBrains Mono", "PingFang SC", `"JetBrains Mono", "JetBrains Mono Variable", "PingFang SC", ${BASE}`], + ["Inter", "", `"Inter", "Inter Variable", ${BASE}`], + ["Fira Code", "Inter", `"Fira Code", "Inter", "Inter Variable", ${BASE}`], + ["Inter", "JetBrains Mono", `"Inter", "Inter Variable", "JetBrains Mono", "JetBrains Mono Variable", ${BASE}`], + ["inter", "jetbrains mono", `"Inter", "Inter Variable", "JetBrains Mono", "JetBrains Mono Variable", ${BASE}`], ["Fira Code", "", `"Fira Code", ${BASE}`], ['"Cascadia Code"', " Microsoft YaHei ", `"Cascadia Code", "Microsoft YaHei", ${BASE}`], ])("%j + fallback %j", (family, fallback, expected) => { @@ -36,11 +37,11 @@ it("escapes CSS special characters without turning a family into a list", () => describe("uiFontFamily", () => { it.each([ - ["Inter", "", '"Inter Variable", "Inter", system-ui, sans-serif'], - ["JetBrains Mono", "", '"JetBrains Mono Variable", "JetBrains Mono", system-ui, sans-serif'], + ["Inter", "", '"Inter", "Inter Variable", system-ui, sans-serif'], + ["JetBrains Mono", "", '"JetBrains Mono", "JetBrains Mono Variable", system-ui, sans-serif'], [' "PingFang SC" ', "", '"PingFang SC", system-ui, sans-serif'], - ["Inter", "思源黑体", '"Inter Variable", "Inter", "思源黑体", system-ui, sans-serif'], - ["Inter", " ", '"Inter Variable", "Inter", system-ui, sans-serif'], + ["Inter", "思源黑体", '"Inter", "Inter Variable", "思源黑体", system-ui, sans-serif'], + ["Inter", " ", '"Inter", "Inter Variable", system-ui, sans-serif'], ])("%j + %j", (family, fallback, expected) => { expect(uiFontFamily(family, fallback)).toBe(expected); }); @@ -131,7 +132,7 @@ describe("macOS user font resolver", () => { it("loads a UI fallback through the shared macOS user font resolver", async () => { const { fonts, invoke, registered } = await resolver(false); const family = fonts.uiFontFamily("Inter", "Maple Mono NF CN"); - expect(family).toBe('"Inter Variable", "Inter", "OpenIDEA User Font 0", "Maple Mono NF CN", system-ui, sans-serif'); + expect(family).toBe('"Inter", "Inter Variable", "OpenIDEA User Font 0", "Maple Mono NF CN", system-ui, sans-serif'); expect(fonts.monoFontFamily("Inter", "Maple Mono NF CN")).toContain('"OpenIDEA User Font 0"'); await fonts.fontsLoaded(family, 13); expect(invoke).toHaveBeenCalledExactlyOnceWith("user_font_data", { family: "Maple Mono NF CN" }); diff --git a/src/platform/fonts.ts b/src/platform/fonts.ts index 9acf9eb31..110d3f75e 100644 --- a/src/platform/fonts.ts +++ b/src/platform/fonts.ts @@ -4,20 +4,22 @@ import { guessOs } from "./platformInfo"; /** * Monospace font-family lists shared by every consumer of the editor / terminal * font. "JetBrains Mono" is the bundled default, but the bundle registers it as - * "JetBrains Mono Variable" (`@fontsource-variable/jetbrains-mono`); a list that - * only names "JetBrains Mono" falls through to the system's generic monospace - * wherever the font isn't installed (SimSun on Chinese Windows). + * "JetBrains Mono Variable" (`@fontsource-variable/jetbrains-mono`); the bundled + * variable face stays in the list so the family renders without a system install + * (SimSun on Chinese Windows otherwise, #26), but the installed family comes + * first: its hinted static outlines render like IntelliJ IDEA's, while the + * unhinted variable webfont looks blurred next to them at editor sizes (#2305). */ export const BUNDLED_MONO_FAMILY = "JetBrains Mono"; export const BUNDLED_UI_FAMILY = "Inter"; const BUNDLED_FACES: ReadonlyMap = new Map([ - [BUNDLED_MONO_FAMILY.toLowerCase(), ['"JetBrains Mono Variable"', '"JetBrains Mono"']], + [BUNDLED_MONO_FAMILY.toLowerCase(), ['"JetBrains Mono"', '"JetBrains Mono Variable"']], ["jetbrains mono variable", ['"JetBrains Mono Variable"']], ["inter variable", ['"Inter Variable"']], - [BUNDLED_UI_FAMILY.toLowerCase(), ['"Inter Variable"', '"Inter"']], + [BUNDLED_UI_FAMILY.toLowerCase(), ['"Inter"', '"Inter Variable"']], ]); -const MONO_STACK_FALLBACK = '"JetBrains Mono Variable", "JetBrains Mono", ui-monospace, Menlo, monospace'; +const MONO_STACK_FALLBACK = '"JetBrains Mono", "JetBrains Mono Variable", ui-monospace, Menlo, monospace'; /** Quote one CSS family safely (including quotes, backslashes and control characters). */ export const quoteFontFamily = (family: string) => diff --git a/src/styles/tokens.css b/src/styles/tokens.css index ea589dd4c..54e5fb63d 100644 --- a/src/styles/tokens.css +++ b/src/styles/tokens.css @@ -240,7 +240,7 @@ html { --font-ui: "Inter Variable", Inter, system-ui, -apple-system, sans-serif; /* Shortcut glyphs (⌘⇧⌥⌃↵) render best in the system UI font, as in macOS menus. */ --font-keys: -apple-system, BlinkMacSystemFont, "Segoe UI Symbol", system-ui, sans-serif; - --font-mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, Menlo, monospace; + --font-mono: "JetBrains Mono", "JetBrains Mono Variable", ui-monospace, Menlo, monospace; --fs-ui: 13px; --fs-small: 12px; --fs-tiny: 11px;