From a16704893900e50d57f43fb4e6a1f4d062a14585 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Thu, 17 Sep 2026 10:17:34 -0400 Subject: [PATCH] Restore the contrasting version in the docs title Themes reuse html_title for the tag, which is why the styled version span was dropped in 2d69e4a: the markup showed up escaped in browser tabs. Add HtmlTitle, a str whose __html__ returns the tag-stripped text. Sphinx renders docstitle raw in the theme header but pipes it through |e or |striptags|e for <title>, and both filters go via __html__, so one value gives markup in the header and plain text in the tab. html_title itself stays a plain str, since check_confval_types compares type(value) exactly and rejects str subclasses, and a class defined in the generated conf.py cannot be pickled with the build environment. The styled form is injected as context["docstitle"] instead, skipping the search page, which is the one template that interpolates docstitle unfiltered. --- yardang/conf.py.j2 | 12 ++++++++++-- yardang/utils.py | 14 +++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/yardang/conf.py.j2 b/yardang/conf.py.j2 index c1815074..fac57902 100644 --- a/yardang/conf.py.j2 +++ b/yardang/conf.py.j2 @@ -21,6 +21,7 @@ from pathlib import Path from packaging.version import Version from yardang.markdown import copy_relative_html_assets, rebase_relative_references +from yardang.utils import HtmlTitle ######################## # COMMON CONFIGURATION # @@ -34,9 +35,12 @@ copyright = """{{copyright}}""" title = """{{title}}""" version = "{{version}}" release = "{{version}}" -# Sphinx reuses this as the <title> tag, so it has to stay plain text; markup -# here shows up escaped in browser tabs and search results. +# Sphinx type-checks this as a plain str, so the styled form goes into the page +# context instead (see run_title_fallback). html_title = """{{title}} v{{version}}""" +styled_html_title = HtmlTitle( + """{{title}} <code style='font-size: var(--font-size--small--4);color: var(--sd-color-primary);'>v{{version}}</code>""" +) docs_host_root = "{{docs_root}}" root = "{{root}}" cname = "{{ cname or '' }}" @@ -425,6 +429,10 @@ def run_title_fallback(app, pagename, templatename, context, doctree): # root page reading "<no title>". if context.get("title") in (None, "", "<no title>", "<no title>"): context["title"] = title + # furo's search page is the one template that drops docstitle into <title> + # unfiltered, so it keeps the plain form. + if pagename != "search": + context["docstitle"] = styled_html_title def setup(app): diff --git a/yardang/utils.py b/yardang/utils.py index e6dd8d36..990b750f 100644 --- a/yardang/utils.py +++ b/yardang/utils.py @@ -1,9 +1,21 @@ import os +import re from pathlib import Path import toml -__all__ = ("get_config", "get_config_flex") +__all__ = ("HtmlTitle", "get_config", "get_config_flex") + + +class HtmlTitle(str): + """A title carrying markup that degrades to plain text for the ``<title>`` tag. + + Themes render ``docstitle`` into the header verbatim but escape it for the + browser tab; ``__html__`` is what the ``|e`` and ``|striptags`` filters pick up. + """ + + def __html__(self): + return re.sub(r"<[^>]+>", "", self) def get_pyproject_toml():