Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ $ uv add gp-sphinx --prerelease allow

<!-- To maintainers and contributors: Please add notes for the forthcoming version below -->

### What's new

#### `sphinx-gp-theme`: Light-mode code blocks now render with a light palette

Light mode previously fell back to monokai-on-light because both
Furo Pygments slots defaulted to monokai. The theme now ships
`gp-sphinx-light` (a CodeMirror-derived light palette) and pairs it
with monokai under `body[data-theme="dark"]`, so both modes pick up
appropriate code-block colors out of the box. (#24)

### Bug fixes

#### `sphinx-gp-theme`: argparse directives now follow the active theme

`.. argparse::` blocks hardcoded a One Dark palette and rendered
dark-on-light in light mode. Token colors now flow through
`--gp-sphinx-argparse-*` custom properties with light defaults and
dark overrides scoped to `body[data-theme="dark"]`. (#24)

## gp-sphinx 0.0.1a12 (2026-04-27)

### Bug fixes
Expand Down
17 changes: 14 additions & 3 deletions packages/gp-sphinx/src/gp_sphinx/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,22 @@ class FontConfig(_FontConfigRequired, total=False):
['_templates']
"""

DEFAULT_PYGMENTS_STYLE: str = "monokai"
"""Default Pygments syntax highlighting style."""
DEFAULT_PYGMENTS_STYLE: str = "gp-sphinx-light"
"""Default Pygments style applied in Furo's light mode.

Resolves to :class:`sphinx_gp_theme.pygments_styles.GpSphinxLightStyle`
via the ``pygments.styles`` entry point shipped by ``sphinx-gp-theme``.
The palette mirrors the Microviz CodeMirror light theme.
"""

DEFAULT_PYGMENTS_DARK_STYLE: str = "monokai"
"""Default Pygments syntax highlighting style for dark mode."""
"""Default Pygments style applied in Furo's dark mode.

Furo combines :data:`DEFAULT_PYGMENTS_STYLE` and this value into a single
``pygments.css`` whose dark rules are scoped under
``body[data-theme="dark"] .highlight``. ``monokai`` is kept here because it
is the long-standing dark-mode appearance for git-pull project docs.
"""

DEFAULT_SPHINX_FONTS: list[FontConfig] = [
{
Expand Down
3 changes: 3 additions & 0 deletions packages/sphinx-gp-theme/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ dependencies = [
[project.entry-points."sphinx.html_themes"]
"sphinx-gp-theme" = "sphinx_gp_theme"

[project.entry-points."pygments.styles"]
"gp-sphinx-light" = "sphinx_gp_theme.pygments_styles:GpSphinxLightStyle"

[project.urls]
Repository = "https://github.com/git-pull/gp-sphinx"

Expand Down
141 changes: 141 additions & 0 deletions packages/sphinx-gp-theme/src/sphinx_gp_theme/pygments_styles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""Pygments styles bundled with sphinx-gp-theme.

Defines :class:`GpSphinxLightStyle`, a light syntax-highlighting style derived
from the CodeMirror light palette used by the Microviz design system. The
style is registered through the ``pygments.styles`` entry point declared in
``pyproject.toml``, which makes it discoverable as ``"gp-sphinx-light"`` via
:func:`pygments.styles.get_style_by_name`.

Furo emits a single combined ``pygments.css`` whose unscoped rules apply in
light mode and whose ``body[data-theme="dark"]``-scoped rules apply in dark
mode, so pairing this light style with a dark Pygments style (e.g. ``monokai``)
is enough to render distinct light- and dark-mode code blocks.

Examples
--------
>>> from pygments.styles import get_style_by_name
>>> style = get_style_by_name("gp-sphinx-light")
>>> style.background_color
'#f8fafc'
>>> style.__name__
'GpSphinxLightStyle'
"""

from __future__ import annotations

import typing as t

from pygments import style, token

__all__ = ["GpSphinxLightStyle"]


class GpSphinxLightStyle(style.Style):
"""Light Pygments style mirroring the Microviz CodeMirror light palette.

The token-to-color mapping follows the OKLCH-derived palette used by the
CodeMirror editor in ``social-embed`` and ``microviz``: slate-900 text on
a slate-50 background, with purple keywords, yellow strings, blue numbers,
orange built-ins, red HTML tags, and slate-500 italic comments.

Examples
--------
>>> GpSphinxLightStyle.name
'gp-sphinx-light'
>>> GpSphinxLightStyle.background_color
'#f8fafc'
>>> GpSphinxLightStyle.styles[token.Keyword]
'bold #7c3aed'
>>> GpSphinxLightStyle.styles[token.String]
'#ca8a04'
>>> GpSphinxLightStyle.styles[token.Comment]
'italic #64748b'
"""

name = "gp-sphinx-light"

background_color = "#f8fafc"
highlight_color = "#dbeafe"
line_number_color = "#64748b"
line_number_background_color = "#f1f5f9"
line_number_special_color = "#0f172a"
line_number_special_background_color = "#dbeafe"

styles: t.ClassVar[dict[token._TokenType, str]] = {
token.Whitespace: "#cbd5e1",
token.Text: "#0f172a",
token.Error: "border:#dc2626 #dc2626",
token.Other: "#0f172a",
token.Comment: "italic #64748b",
token.Comment.Hashbang: "italic #64748b",
token.Comment.Multiline: "italic #64748b",
token.Comment.Preproc: "noitalic #7c3aed",
token.Comment.PreprocFile: "noitalic #ca8a04",
token.Comment.Single: "italic #64748b",
token.Comment.Special: "italic bold #64748b",
token.Keyword: "bold #7c3aed",
token.Keyword.Constant: "bold #ea580c",
token.Keyword.Declaration: "bold #7c3aed",
token.Keyword.Namespace: "bold #7c3aed",
token.Keyword.Pseudo: "nobold #7c3aed",
token.Keyword.Reserved: "bold #7c3aed",
token.Keyword.Type: "nobold #a855f7",
token.Operator: "#0f172a",
token.Operator.Word: "bold #7c3aed",
token.Punctuation: "#0f172a",
token.Name: "#0f172a",
token.Name.Attribute: "#a855f7",
token.Name.Builtin: "#ea580c",
token.Name.Builtin.Pseudo: "#ea580c",
token.Name.Class: "bold #0f172a",
token.Name.Constant: "#ea580c",
token.Name.Decorator: "#a855f7",
token.Name.Entity: "bold #dc2626",
token.Name.Exception: "bold #dc2626",
token.Name.Function: "#0f172a",
token.Name.Function.Magic: "#a855f7",
token.Name.Label: "#475569",
token.Name.Namespace: "bold #0f172a",
token.Name.Other: "#0f172a",
token.Name.Tag: "#dc2626",
token.Name.Variable: "#0f172a",
token.Name.Variable.Class: "#0f172a",
token.Name.Variable.Global: "#0f172a",
token.Name.Variable.Instance: "#0f172a",
token.Name.Variable.Magic: "#a855f7",
token.Number: "#3b82f6",
token.Number.Bin: "#3b82f6",
token.Number.Float: "#3b82f6",
token.Number.Hex: "#3b82f6",
token.Number.Integer: "#3b82f6",
token.Number.Integer.Long: "#3b82f6",
token.Number.Oct: "#3b82f6",
token.Literal: "#0f172a",
token.Literal.Date: "#ca8a04",
token.String: "#ca8a04",
token.String.Affix: "bold #ca8a04",
token.String.Backtick: "#ca8a04",
token.String.Char: "#ca8a04",
token.String.Delimiter: "#ca8a04",
token.String.Doc: "italic #64748b",
token.String.Double: "#ca8a04",
token.String.Escape: "bold #b45309",
token.String.Heredoc: "#ca8a04",
token.String.Interpol: "bold #b45309",
token.String.Other: "#ca8a04",
token.String.Regex: "#ea580c",
token.String.Single: "#ca8a04",
token.String.Symbol: "#ca8a04",
token.Generic: "#0f172a",
token.Generic.Deleted: "#dc2626",
token.Generic.Emph: "italic",
token.Generic.Error: "#dc2626",
token.Generic.Heading: "bold #0f172a",
token.Generic.Inserted: "#16a34a",
token.Generic.Output: "#475569",
token.Generic.Prompt: "bold #475569",
token.Generic.Strong: "bold",
token.Generic.EmphStrong: "bold italic",
token.Generic.Subheading: "bold #475569",
token.Generic.Traceback: "#dc2626",
}
Loading