fix(vcs): follow the editor font settings in diff and merge viewers (#253)

The VCS viewers (diff, merge, local history) hard-coded the default mono
font, size and line height, so Settings > Editor > Font had no effect on
them. Read the editor font variables like the main editor does, and apply
fontExtension next to the caret, kept in step with the settings.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jaw
2026-10-29 19:43:40 +08:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 74b2d5f5d7
commit a20207110e
2 changed files with 67 additions and 8 deletions
@@ -0,0 +1,36 @@
import { afterEach, describe, expect, it } from "vitest";
import { EditorState } from "@codemirror/state";
import { EditorView } from "@codemirror/view";
import { useProject } from "@/platform/project";
import type { Settings } from "@/platform/ipc";
import { viewerBase } from "../cm";
const previous = useProject.getState().settings;
const views: EditorView[] = [];
afterEach(() => {
views.splice(0).forEach((v) => v.destroy());
useProject.setState({ settings: previous });
});
const setEditor = (editor: object) => useProject.setState({ settings: { editor } as unknown as Settings });
describe("viewer font", () => {
it("follows the editor's font settings, also when they change", () => {
setEditor({ fontFamily: "Fira Code", fontSize: 16, lineHeight: 22 });
const view = new EditorView({
state: EditorState.create({ doc: "a", extensions: viewerBase({ readOnly: true }) }),
});
views.push(view);
const style = () => view.dom.style;
expect(style().getPropertyValue("--openidea-editor-font")).toContain("Fira Code");
expect(style().getPropertyValue("--openidea-editor-font-size")).toBe("16px");
expect(style().getPropertyValue("--openidea-editor-line-height")).toBe("22px");
expect(view.dom.classList.contains("cm-openidea-ligatures")).toBe(false);
setEditor({ fontSize: 11, ligatures: true });
expect(style().getPropertyValue("--openidea-editor-font")).toBe("");
expect(style().getPropertyValue("--openidea-editor-font-size")).toBe("11px");
expect(view.dom.classList.contains("cm-openidea-ligatures")).toBe(true);
});
});
+31 -8
View File
@@ -8,6 +8,7 @@ import {
EditorState,
RangeSet,
RangeSetBuilder,
StateEffect,
StateField,
type Extension,
type Line,
@@ -30,6 +31,7 @@ import { search, searchKeymap } from "@codemirror/search";
import { tags as t } from "@lezer/highlight";
import { findExtension } from "@/editor/core/cm/find";
import { caretExtension } from "@/editor/core/cm/prefs";
import { fontExtension } from "@/editor/core/cm/setup";
import { caretStyles, findLocals, findStyles } from "@/editor/core/cm/theme";
import { editorPrefs } from "@/platform/editorSettings";
import { useProject } from "@/platform/project";
@@ -145,10 +147,16 @@ export const viewerTheme = EditorView.theme(
height: "100%",
backgroundColor: "var(--bg-app)",
color: "var(--fg)",
fontSize: "var(--fs-code)",
fontSize: "var(--openidea-editor-font-size, var(--fs-code))",
...findLocals,
},
".cm-scroller": { fontFamily: "var(--font-mono)", fontWeight: "var(--fw-code, 400)", lineHeight: "var(--lh-code)" },
".cm-scroller": {
fontFamily: "var(--openidea-editor-font, var(--font-mono))",
fontWeight: "var(--fw-code, 400)",
lineHeight: "var(--openidea-editor-line-height, var(--lh-code))",
fontVariantLigatures: "none",
},
"&.cm-openidea-ligatures .cm-scroller": { fontVariantLigatures: "normal" },
".cm-content": { caretColor: "var(--caret, var(--fg-strong))", WebkitUserSelect: "text", userSelect: "text" },
...caretStyles,
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, ::selection": {
@@ -231,18 +239,33 @@ export const viewerTheme = EditorView.theme(
);
const caretSlot = new Compartment();
const fontSlot = new Compartment();
/** The editor's caret (Settings › Editor › General › Appearance), kept in step with the settings. */
function viewerCaret(): Extension {
const editorSettings = () => useProject.getState().settings?.editor;
/**
* The editor's caret (Settings › Editor › General › Appearance) and font
* (Settings › Editor › Font), kept in step with the settings.
*/
function viewerEditorLook(): Extension {
return [
caretSlot.of(caretExtension(editorPrefs())),
fontSlot.of(fontExtension(editorSettings())),
ViewPlugin.define((view) => {
let appearance = editorPrefs().appearance;
let editor = editorSettings();
const unsubscribe = useProject.subscribe(() => {
const effects: StateEffect<unknown>[] = [];
const next = editorPrefs();
if (JSON.stringify(next.appearance) === JSON.stringify(appearance)) return;
appearance = next.appearance;
view.dispatch({ effects: caretSlot.reconfigure(caretExtension(next)) });
if (JSON.stringify(next.appearance) !== JSON.stringify(appearance)) {
appearance = next.appearance;
effects.push(caretSlot.reconfigure(caretExtension(next)));
}
if (editorSettings() !== editor) {
editor = editorSettings();
effects.push(fontSlot.reconfigure(fontExtension(editor)));
}
if (effects.length) view.dispatch({ effects });
});
return { destroy: unsubscribe };
}),
@@ -256,7 +279,7 @@ function viewerCaret(): Extension {
export function viewerBase(opts: { readOnly: boolean; lineNumbers?: boolean; findBar?: boolean }): Extension[] {
return [
opts.lineNumbers === false ? [] : lineNumbers(),
viewerCaret(),
viewerEditorLook(),
highlightActiveLine(),
opts.findBar
? [findExtension(), keymap.of(defaultKeymap)]