[clang-tools-extra] [llvm] [clang-tools-extra][docs] Use Furo theme to match clang (PR #222196)

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 8 16:53:00 PDT 2026


https://github.com/rnk updated https://github.com/llvm/llvm-project/pull/222196

>From a5d612bce7c59340c3e76632f8b4b88a1fcb4ca9 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <rkleckner at nvidia.com>
Date: Tue, 11 Aug 2026 23:45:02 +0000
Subject: [PATCH] [clang-tools-extra][docs] Use Furo theme

Adopt the shared Furo configuration for the clang-tools-extra documentation. Remove page-local TOCs mechanically with the included `utils/docs/remove_page_tocs.py` helper.

Clang Furo PR: https://github.com/llvm/llvm-project/pull/214869
RFC: https://discourse.llvm.org/t/rfc-use-furo-theme-for-clang-docs/91505/7
Preview: https://clangdocs.staging.reidkleckner.dev/after/clang-tools-extra/docs/
---
 clang-tools-extra/Maintainers.md              |  3 -
 clang-tools-extra/docs/ReleaseNotes.md        |  4 --
 .../docs/_static/clang-tools-extra-styles.css | 21 ++++++
 .../docs/clang-change-namespace.md            |  2 -
 clang-tools-extra/docs/clang-doc.md           |  2 -
 clang-tools-extra/docs/clang-include-fixer.md |  2 -
 .../docs/clang-reorder-fields.md              |  2 -
 clang-tools-extra/docs/clang-tidy/index.rst   |  2 -
 clang-tools-extra/docs/conf.py                | 20 ++----
 utils/docs/remove_page_tocs.py                | 72 +++++++++++++++++++
 10 files changed, 100 insertions(+), 30 deletions(-)
 create mode 100644 utils/docs/remove_page_tocs.py

diff --git a/clang-tools-extra/Maintainers.md b/clang-tools-extra/Maintainers.md
index 57f7d96213d75..8830b86e09d7d 100644
--- a/clang-tools-extra/Maintainers.md
+++ b/clang-tools-extra/Maintainers.md
@@ -4,9 +4,6 @@ This file is a list of the
 [maintainers](https://llvm.org/docs/DeveloperPolicy.html#maintainers)
 for the [Extra Clang Tools](https://clang.llvm.org/extra/index.html) project.
 
-```{contents} Table of Contents
-:depth: 2
-```
 
 # Active Maintainers
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 93fbe57a58321..c8030b55376f3 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -12,10 +12,6 @@ myst:
 {#extra-clang-tools-release-releasenotestitle}
 # Extra Clang Tools {{env.config.release}} {{ (('(In-Progress) ' if env.app.tags.has('PreRelease') else '') ~ 'Release Notes') }}
 
-```{contents}
-:depth: 3
-:local: true
-```
 
 Written by the [LLVM Team](https://llvm.org/)
 
diff --git a/clang-tools-extra/docs/_static/clang-tools-extra-styles.css b/clang-tools-extra/docs/_static/clang-tools-extra-styles.css
index 1a6cd710e483a..7fe4207cf680e 100644
--- a/clang-tools-extra/docs/_static/clang-tools-extra-styles.css
+++ b/clang-tools-extra/docs/_static/clang-tools-extra-styles.css
@@ -21,3 +21,24 @@ details summary:hover {
   background-color: rgba(50, 150, 220, 0.2);
   cursor: pointer;
 }
+
+/* Use the full viewport on ordinary desktop displays, where Furo's fixed
+   content width leaves little room after both sidebars. Once the content area
+   reaches 90em (84em plus padding), grow symmetric outer margins instead. */
+ at media (min-width: 67em) {
+  .page .sidebar-drawer {
+    width: max(15em, calc(50% - 45em));
+  }
+
+  .main > .content {
+    width: min(84em, calc(100vw - 36em));
+  }
+}
+
+/* Furo moves the page-local TOC into a drawer below 82em, freeing its 15em
+   column for the main content. */
+ at media (min-width: 67em) and (max-width: 82em) {
+  .main > .content {
+    width: calc(100vw - 21em);
+  }
+}
diff --git a/clang-tools-extra/docs/clang-change-namespace.md b/clang-tools-extra/docs/clang-change-namespace.md
index b44c1a359f8ac..7e5eb3fb11268 100644
--- a/clang-tools-extra/docs/clang-change-namespace.md
+++ b/clang-tools-extra/docs/clang-change-namespace.md
@@ -1,7 +1,5 @@
 # Clang-Change-Namespace
 
-```{contents}
-```
 
 ```{toctree}
 :maxdepth: 1
diff --git a/clang-tools-extra/docs/clang-doc.md b/clang-tools-extra/docs/clang-doc.md
index 11aa4ddaf943d..f24a4697a4991 100644
--- a/clang-tools-extra/docs/clang-doc.md
+++ b/clang-tools-extra/docs/clang-doc.md
@@ -1,7 +1,5 @@
 # Clang-Doc
 
-```{contents}
-```
 
 ```{toctree}
 :maxdepth: 1
diff --git a/clang-tools-extra/docs/clang-include-fixer.md b/clang-tools-extra/docs/clang-include-fixer.md
index 6be1251457310..b16c46f4553b0 100644
--- a/clang-tools-extra/docs/clang-include-fixer.md
+++ b/clang-tools-extra/docs/clang-include-fixer.md
@@ -1,7 +1,5 @@
 # Clang-Include-Fixer
 
-```{contents}
-```
 
 One of the major nuisances of C++ compared to other languages is the manual
 management of `#include` directives in any file.
diff --git a/clang-tools-extra/docs/clang-reorder-fields.md b/clang-tools-extra/docs/clang-reorder-fields.md
index 632583e90feaa..b2114d5df7203 100644
--- a/clang-tools-extra/docs/clang-reorder-fields.md
+++ b/clang-tools-extra/docs/clang-reorder-fields.md
@@ -1,7 +1,5 @@
 # Clang-Reorder-Fields
 
-```{contents}
-```
 
 ```{toctree}
 :maxdepth: 1
diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst
index cfa77eb670ecf..9325307b6c9e4 100644
--- a/clang-tools-extra/docs/clang-tidy/index.rst
+++ b/clang-tools-extra/docs/clang-tidy/index.rst
@@ -2,8 +2,6 @@
 Clang-Tidy
 ==========
 
-.. contents::
-
 See also:
 
 .. toctree::
diff --git a/clang-tools-extra/docs/conf.py b/clang-tools-extra/docs/conf.py
index a80bbcf8638b5..d0ca4e9902dc3 100644
--- a/clang-tools-extra/docs/conf.py
+++ b/clang-tools-extra/docs/conf.py
@@ -70,14 +70,13 @@
 
 # -- Options for HTML output ---------------------------------------------------
 
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-html_theme = "haiku"
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
+configure_furo(
+    globals(),
+    source_directory="clang-tools-extra/docs/",
+    html_title="Extra Clang Tools",
+    local_static_path=["_static"],
+    extra_css_files=["clang-tools-extra-styles.css"],
+)
 
 # Add any paths that contain custom themes here, relative to this directory.
 # html_theme_path = []
@@ -98,11 +97,6 @@
 # pixels large.
 # html_favicon = None
 
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
-
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
 # html_last_updated_fmt = '%b %d, %Y'
diff --git a/utils/docs/remove_page_tocs.py b/utils/docs/remove_page_tocs.py
new file mode 100644
index 0000000000000..148dd300d73b3
--- /dev/null
+++ b/utils/docs/remove_page_tocs.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""Remove page-local contents directives from Sphinx documentation."""
+
+from __future__ import annotations
+
+import argparse
+import re
+from pathlib import Path
+
+CONTENTS = re.compile(
+    r"(?m)^```\{contents\}[^\n]*\n(?:.*\n)*?^```\n?|"
+    r"\n*^\.\. contents::[^\n]*(?:\n(?:[ \t].*|[ \t]*))*\n*"
+)
+SUFFIXES = (".rst", ".md", ".td")
+
+
+def iter_sources(root: Path):
+    if root.is_file():
+        if root.suffix in SUFFIXES:
+            yield root
+        return
+
+    for suffix in SUFFIXES:
+        yield from root.rglob(f"*{suffix}")
+
+
+def rewrite(path: Path) -> int:
+    text = path.read_text(encoding="utf-8")
+
+    def replacement(match: re.Match[str]) -> str:
+        if match.group(0).lstrip("\n").startswith("```") or not match.start():
+            return ""
+        return "\n\n" if match.end() < len(text) else "\n"
+
+    new_text, removed = CONTENTS.subn(replacement, text)
+    if new_text != text:
+        path.write_text(new_text, encoding="utf-8")
+    return removed
+
+
+def main() -> int:
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+        "roots",
+        nargs="*",
+        type=Path,
+        default=[
+            Path("clang/docs"),
+            Path("clang/Maintainers.md"),
+            Path("clang/include/clang/Basic"),
+            Path("clang/include/clang/Options"),
+        ],
+        help="Documentation roots to scan, defaults to Clang docs and generated-doc inputs.",
+    )
+    args = parser.parse_args()
+
+    removals = [
+        (path, rewrite(path))
+        for root in args.roots
+        for path in sorted(iter_sources(root))
+    ]
+    changed = [(path, count) for path, count in removals if count]
+    for path, count in changed:
+        print(f"{path}: removed {count} contents directive(s)")
+    print(
+        f"removed {sum(count for _, count in changed)} contents directive(s) from {len(changed)} file(s)"
+    )
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())



More information about the cfe-commits mailing list