Skip to content

Expose Shiki's bundled themes (and custom theme files) via a top-level syntax_theme #415

@eduwass

Description

@eduwass

Hi @benvinegar !

Wanted to share this idea to see what you think — structured as What / Why / How below.

What do you want to change?

A single new top-level config key, syntax_theme, that points Hunk's syntax highlighting at any Shiki theme — either one of the 65 themes Shiki already bundles (by name), or a Shiki theme file you bring yourself.

theme = "graphite"        # your UI theme — untouched
syntax_theme = "dracula"  # the one new line: any bundled Shiki theme, by name

# syntax_theme = "my-theme.json"   # … or a Shiki theme file you bring
  • A single new key, top-level and orthogonal. It's deliberately a sibling of theme, not nested under [custom_theme], so it composes with any base theme — built-in or custom — and you never have to opt into the custom-theme system to use it.
  • A bare name resolves to one of Shiki's 65 bundled themes — nothing to download or register.
  • A path / .json loads a custom Shiki theme from disk (via registerCustomTheme), resolved next to the config file.
  • Purely additive. theme, [custom_theme], and [custom_theme.syntax] all stay exactly as they are — nothing is deprecated, nothing changes for existing configs.

Same diff, one config line each

Identical diff and UI palette — only syntax_theme changes:

Hunk today — no syntax_theme; only pierre-dark / pierre-light are reachable

Image

syntax_theme = "dracula" — a bundled Shiki theme, by name (zero setup)

Image

syntax_theme = "nord" — another bundled theme, one line

Image

syntax_theme = "tokyo-night" — any of Shiki's 65 bundled themes

Image

Why?

Hunk already bundles Shiki as its highlighter — and with it, Shiki's full set of 65 bundled themes. For syntax highlighting, though, only pierre-dark / pierre-light are ever reachable; the other 63 ship in the binary but can't be selected.

Today there are two syntax levers, and both are good at what they do: pick a base theme, then use [custom_theme.syntax] to override individual token categories (keyword, string, comment, …). That's exactly the right tool for "graphite, but with purpler strings" — a few deltas on top of a base. This proposal doesn't touch it.

What there's no path for is adopting a whole syntax theme — either one of the 65 Shiki already bundles, or a Shiki theme file you bring yourself. That's a different shape of input: not a handful of overrides on a base, but a complete set of 140+ token-color rules across ~260 scopes, including language-specific ones (JSON keys, JSX, CSS, Markdown) that a few generic categories can't name. [custom_theme.syntax] was never meant to carry that, and shouldn't have to.

And the custom-file path unlocks a whole ecosystem. Shiki reads TextMate-grammar themes — the same tokenColors format the VS Code theme ecosystem is built on — so it isn't limited to bundled or hand-written themes. Users can tap into the hundreds of community themes you can browse at galleries like vscodethemes.com, and you don't maintain a single extra theme to make any of it work.

How? (optional)

The highlighter you already ship accepts these themes by name:

// @pierre/diffs
type DiffsThemeNames = BundledTheme | 'pierre-dark' | 'pierre-light' | (string & {});

… and exposes registerCustomTheme(name, loader) for files on disk. So this isn't a new theming engine — it's wiring one config string to an API the bundled highlighter already exposes. The capability is already in the binary; this just makes it reachable.

  • The config resolves a bundled name straight through to the highlighter; a custom file is loaded from disk and registered.
  • The resolved theme name rides on the existing app theme through the highlight path, keyed into the highlight cache so theme switches re-highlight.

How it relates to the existing theme system:

  • UI chrome is never touched. theme and the [custom_theme] colours (panels, borders, accents, diff backgrounds) keep full control of the interface. syntax_theme only swaps the code-highlighting palette.
  • Works with any theme value. Built-in (graphite, midnight, …) or theme = "custom"syntax_theme applies on top either way, because it's resolved independently of the theme machinery.
  • vs. [custom_theme.syntax]: two answers to different needs; they don't stack. [custom_theme.syntax] nudges a handful of token categories on a built-in base. syntax_theme hands the whole highlighting job to a complete theme — which defines every scope, so when it's set there's nothing left for the per-token overrides to do, and the full theme wins. Existing configs that only use [custom_theme.syntax] behave exactly as before.

I have a working implementation behind this, tests / typecheck / lint green — and the four screenshots above are real captures from that build.

Would you be open to checking a PR for this? Just wanted to share the design first.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions