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 , 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 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}} v{{version}}"""
+)
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 "".
if context.get("title") in (None, "", "<no title>", ""):
context["title"] = title
+ # furo's search page is the one template that drops docstitle into
+ # 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 ```` 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():