Skip to content

An imported theme colours the preview, not only the editor - #736

Merged
PathGao merged 1 commit into
masterfrom
feat/preview-theme-colours
Sep 1, 2026
Merged

An imported theme colours the preview, not only the editor#736
PathGao merged 1 commit into
masterfrom
feat/preview-theme-colours

Conversation

@PathGao

@PathGao PathGao commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

What this is

An imported VS Code theme now colours the preview's headings, bold, italic,
inline code, links, strikethrough and blockquotes, the way it already coloured
them in the editor.

Fallgrim, who reported #676, tested 2.7.6 and said in
#682 (comment) that the
editor colouring arrived but "nothing has changed for the preview mode", and
that preview is where it matters more for them because they open existing files
there. This does not close #682 — that issue asks for arbitrary custom CSS,
which is a different and much larger question.

Mechanism

A VS Code theme file has two halves and only one of them reached the preview.

theme.colorseditor.background, editor.foreground, textLink.foreground,
terminal.ansi* — is turned into --color-* and --hljs-* in
parseAndApplyVscodeTheme, so the preview's background, body text, links and
fenced-code highlighting have always followed an imported theme.

theme.tokenColors — which is where markup.bold, markup.heading,
markup.inline.raw and the rest live — went to monacoTokenRules and
defineTheme and nowhere else. #678, #684, #686 and #689 all worked on that
path. So an imported theme arrived on the editor and stopped at the splitter,
and every construct the reporter came for kept --color-fg-default in the
preview.

The preview renders the same constructs the editor tokenizes, but as HTML with
the markup gone: **bold** is a <strong>, ## is an <h2>. So the colours
reach it as CSS variables rather than as token rules, and they land on the
construct's text, which is all that is left of it. importedThemeRules already
built a kind-to-colour map to rewrite its base rules; that map is now a named
function the importer also reads, and seven of its kinds are written into the
same :root[data-theme="vscode"] block the rest of the variables go into.

Scope

Every rule keeps the value it already had as its var() fallback, so a theme
naming none of these kinds, and a built-in theme with no tokenColors at all,
render the preview exactly as before. No setting: importing a theme is the
opt-in, the same way #684 gave the built-in themes their editor colours without
one.

Deliberately left alone:

  • The built-in light and dark themes. Colouring the preview by default is a
    different decision — VS Code's own markdown preview colours none of this, and
    Obsidian ships --h1-color, --bold-color and --italic-color defaulting to
    the body colour for the user to fill in. If it is ever wanted, the variables
    are now there and it is a value per theme block.
  • mark and ins. ==highlight== and ++insert++ have no markup.* scope,
    so there is nothing in a theme file to read for them.
  • Fenced code, which stays with the --hljs-* rules. --md-code is scoped to
    :not(pre) > code so a code block is not repainted with the inline-code
    colour.
  • Fonts. markup.* settings carry fontStyle, not a family, and font-src is
    'self'.

Tests

Three in scripts/markdownTokenColours.test.ts, beside the #676 ones:

  • markdownKindColors returns a colour per construct, and drops a non-Markdown
    scope and a rule with only a fontStyle.
  • A theme with no tokenColorsundefined, null, [], a non-array —
    yields an empty map, which is what leaves the built-in themes alone.
  • Every variable the importer writes is read by styles.css with a fallback.
    The two halves are joined by a variable name and nothing else: no type or
    import holds --md-strong in theme.ts to --md-strong in the stylesheet,
    and renaming one silently drops the colour. The anchor is the variable name
    and the comma after it, both of which are the contract rather than today's
    spelling of a call site. Dropping either half of the change turns it red.

Verification

npm audit        found 0 vulnerabilities
npm run check    822 files, 0 errors, 0 warnings
npm test         1003 pass, 0 fail
cargo test       164 pass, 0 fail

The colours themselves were read out of a browser rather than reasoned about:
a page built from src/styles.css with the :root[data-theme="vscode"] block
the importer would write, then getComputedStyle().color for each construct
with and without the attribute. Without it every element keeps today's value
(#1f2328 body, #656d76 for h6 and blockquote, #0969da links); with it
each takes its own colour and the fenced block stays on the body colour.

Not verified: a real import in the running app on Windows or Linux, and the
--md-* block travelling into an exported HTML file. The export copies the
generated <style> tag with the rest of the stylesheet, so it should follow,
but I reasoned about that rather than exporting a document and opening it.

…itor (#682)

A VS Code theme file has two halves. `colors` painted the whole app,
preview included; `tokenColors` — which is where `markup.bold`,
`markup.heading` and the rest live — only ever reached Monaco. So an
imported theme arrived on the editor and stopped at the splitter, and the
reporter of #676 saw the colours they came for on one half of the window.

The preview renders the same constructs the editor tokenizes, but as HTML
with the markup gone: `**bold**` is a `<strong>`, `##` is an `<h2>`. So
the colours reach it through CSS variables rather than through a token
rule, and land on the construct's text, which is all that is left of it.

Seven constructs, each with the value its rule already had as the
fallback: a theme that names none of them, or a built-in theme with no
`tokenColors` at all, renders the preview exactly as before.

Verified: the suite, plus computed colours read out of a page built from
`styles.css` — every construct takes the theme's colour under
`data-theme="vscode"`, keeps its old one without it, and a fenced block
stays with the `--hljs-*` rules rather than taking the inline-code colour.
@PathGao
PathGao merged commit 04d0791 into master Sep 1, 2026
4 checks passed
@PathGao
PathGao deleted the feat/preview-theme-colours branch September 1, 2026 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom CSS

1 participant