Syntax highlighting¶
This page explains how the theme handles code-block syntax highlighting in light and dark modes, and how downstream projects can override the palettes.
How it works¶
Syntax highlighting colors are generated by
Pygments at build time. Because the theme’s
light/dark toggle is class-based (body.is-light / body.is-dark +
localStorage), the palettes cannot rely on Sphinx’s built-in
pygments_dark_style (which uses a prefers-color-scheme media query that
follows the browser setting instead of the toggle).
Instead, the theme ships two static stylesheets, both scoped to the toggle classes:
File |
Pygments style |
Scoped to |
|---|---|---|
|
|
|
|
|
|
Both are registered in theme.toml and generated by a single script:
python3 ulwazi/theme/ulwazi/static/css/generate_pygments_css.py
The generated files are committed to the repository; re-run the script only when changing a style or the token set.
The code-block background is not part of the palettes. It is owned by the
Vanilla token --vf-color-background-code (see _ulwazi.scss), so the
highlighting colors composite correctly over the themed surface in both
modes.
Overriding the palettes¶
Downstream projects can replace or tweak the palettes in two ways.
Full replacement (file shadowing)¶
Sphinx copies files from html_static_path into the output after theme
files, so a file with the same relative path replaces the theme’s version
entirely:
docs/
└── _static/
└── css/
├── pygments-light.css # replaces the theme's light palette
└── pygments-dark.css # replaces the theme's dark palette
To generate a custom palette, reuse the theme’s script pattern:
from pygments.formatters.html import HtmlFormatter
css = HtmlFormatter(style="monokai").get_style_defs(".highlight")
# Scope each rule under body.is-dark (or body.is-light) and strip the
# background rules -- see generate_pygments_css.py for details.
Note that a shadowed file is owned by the downstream project from then on: the theme’s updates to that palette will no longer propagate.
Partial tweaks (cascade override)¶
For adjusting individual token colors, add a custom stylesheet that loads after the theme’s:
# conf.py
html_css_files = ["custom-pygments.css"]
/* docs/_static/custom-pygments.css */
body.is-dark .highlight .k { color: #ff7b72; } /* keywords */
body.is-dark .highlight .s { color: #a5d6ff; } /* strings */
Selectors must match the theme’s specificity (body.is-dark .highlight .k);
a bare .highlight .k rule would lose the cascade.