diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 14512cf61fb..e5b1f4804c2 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1328,6 +1328,24 @@ REGEN_TEXI = \
)
noinst_TEXINFOS = doc/bfdint.texi
+
+# The HTML manual is built with the navigation sidebar shared from
+# texinfo/toc-sidebar: toc-sidebar.init drives texi2any and writes the
+# contents tree (toc-sidebar-data.js) into the output directory; copy
+# the static assets in alongside it. On a texi2any too old for the
+# sidebar the init file disables itself and the plain manual is built.
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+
+# ROCm branding.
+MANUAL_CSS = $(srcdir)/../rocm-theme.css
all: $(BUILT_SOURCES) config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -2531,9 +2549,12 @@ doc/bfdver.texi: $(srcdir)/Makefile.in
fi
html-local: doc/bfd/index.html
-doc/bfd/index.html: doc/bfd.texi $(bfd_TEXINFOS) doc/$(am__dirstamp)
+doc/bfd/index.html: doc/bfd.texi $(bfd_TEXINFOS) doc/$(am__dirstamp) $(MANUAL_CSS)
$(AM_V_at)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -o doc/bfd $(srcdir)/doc/bfd.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) doc/bfd
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/bfd/doc/local.mk b/bfd/doc/local.mk
index bae2bd50ae3..97dcd28fd13 100644
--- a/bfd/doc/local.mk
+++ b/bfd/doc/local.mk
@@ -142,9 +142,30 @@ DISTCLEANFILES += %D%/bfd.?? %D%/bfd.??? texput.log
MAINTAINERCLEANFILES += $(DOCFILES)
+# The HTML manual is built with the navigation sidebar shared from
+# texinfo/toc-sidebar: toc-sidebar.init drives texi2any and writes the
+# contents tree (toc-sidebar-data.js) into the output directory; copy
+# the static assets in alongside it. On a texi2any too old for the
+# sidebar the init file disables itself and the plain manual is built.
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+MANUAL_CSS =
+
+# ROCm branding.
+MANUAL_CSS += $(srcdir)/../rocm-theme.css
+
html-local: %D%/bfd/index.html
-%D%/bfd/index.html: %D%/bfd.texi $(bfd_TEXINFOS) %D%/$(am__dirstamp)
+%D%/bfd/index.html: %D%/bfd.texi $(bfd_TEXINFOS) %D%/$(am__dirstamp) $(MANUAL_CSS)
$(AM_V_at)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -o %D%/bfd $(srcdir)/%D%/bfd.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) %D%/bfd
MAINTAINERCLEANFILES += %D%/bfd.info
diff --git a/binutils/Makefile.in b/binutils/Makefile.in
index 7f3ca38a9d7..cfd1ac14536 100644
--- a/binutils/Makefile.in
+++ b/binutils/Makefile.in
@@ -893,6 +893,21 @@ AM_MAKEINFOFLAGS = -I "$(srcdir)/doc" -I "$(top_srcdir)/../libiberty" \
TEXI2DVI = texi2dvi -I "$(srcdir)/doc" -I "$(top_srcdir)/../libiberty" \
-I "$(top_srcdir)/../bfd/doc" -I ../bfd/doc
+
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+
+# ROCm branding.
+MANUAL_CSS = $(srcdir)/../rocm-theme.css
all: $(BUILT_SOURCES) config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -2171,10 +2186,17 @@ doc/$(DEMANGLER_NAME).1: doc/cxxfilt.man Makefile doc/$(am__dirstamp)
sed -e 's/cxxfilt/$(DEMANGLER_NAME)/' < $$man \
> doc/$(DEMANGLER_NAME).1
+# Unlike the ld and gas manuals, this rule passes no -o, so texi2any
+# derives the split output directory from binutils.texi's @setfilename
+# (binutils.info) and writes the manual to binutils_html; the copied
+# assets must land in that same directory.
html-local: doc/binutils/index.html
-doc/binutils/index.html: doc/binutils.texi $(binutils_TEXINFOS)
+doc/binutils/index.html: doc/binutils.texi $(binutils_TEXINFOS) $(MANUAL_CSS)
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir) $(srcdir)/doc/binutils.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) binutils_html
# Maintenance
diff --git a/binutils/doc/local.mk b/binutils/doc/local.mk
index 63124abc3bb..7146387dced 100644
--- a/binutils/doc/local.mk
+++ b/binutils/doc/local.mk
@@ -180,10 +180,32 @@ MAINTAINERCLEANFILES += $(man_MANS) %D%/binutils.info %D%/cxxfilt.man
sed -e 's/cxxfilt/$(DEMANGLER_NAME)/' < $$man \
> %D%/$(DEMANGLER_NAME).1
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+MANUAL_CSS =
+
+# ROCm branding.
+MANUAL_CSS += $(srcdir)/../rocm-theme.css
+
+# Unlike the ld and gas manuals, this rule passes no -o, so texi2any
+# derives the split output directory from binutils.texi's @setfilename
+# (binutils.info) and writes the manual to binutils_html; the copied
+# assets must land in that same directory.
html-local: %D%/binutils/index.html
-%D%/binutils/index.html: %D%/binutils.texi $(binutils_TEXINFOS)
+%D%/binutils/index.html: %D%/binutils.texi $(binutils_TEXINFOS) $(MANUAL_CSS)
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir) $(srcdir)/%D%/binutils.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) binutils_html
# Maintenance
diff --git a/gas/Makefile.in b/gas/Makefile.in
index b2bb505cc69..fc8156e4ab6 100644
--- a/gas/Makefile.in
+++ b/gas/Makefile.in
@@ -1026,6 +1026,21 @@ CPU_DOCS = \
# This one isn't ready for prime time yet. Not even a little bit.
noinst_TEXINFOS = doc/internals.texi
+
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+
+# ROCm branding.
+MANUAL_CSS = $(srcdir)/../rocm-theme.css
all: config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -2272,9 +2287,12 @@ doc/as.1: $(srcdir)/doc/as.texi doc/asconfig.texi $(CPU_DOCS) doc/$(am__dirstamp
$(AM_V_at)rm -f doc/as.pod
html-local: doc/as/index.html
-doc/as/index.html: doc/as.texi $(doc_as_TEXINFOS) doc/$(am__dirstamp)
+doc/as/index.html: doc/as.texi $(doc_as_TEXINFOS) doc/$(am__dirstamp) $(MANUAL_CSS)
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir)/doc -o doc/as $(srcdir)/doc/as.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) doc/as
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/gas/doc/local.mk b/gas/doc/local.mk
index 4185cfe9a3c..c16182a07ce 100644
--- a/gas/doc/local.mk
+++ b/gas/doc/local.mk
@@ -124,9 +124,27 @@ info-local: $(MANS)
(rm -f $@.T$$$$ && exit 1)
$(AM_V_at)rm -f %D%/as.pod
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+MANUAL_CSS =
+
+# ROCm branding.
+MANUAL_CSS += $(srcdir)/../rocm-theme.css
+
html-local: %D%/as/index.html
-%D%/as/index.html: %D%/as.texi $(%C%_as_TEXINFOS) %D%/$(am__dirstamp)
+%D%/as/index.html: %D%/as.texi $(%C%_as_TEXINFOS) %D%/$(am__dirstamp) $(MANUAL_CSS)
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir)/%D% -o %D%/as $(srcdir)/%D%/as.texi
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) %D%/as
MAINTAINERCLEANFILES += %D%/as.info
diff --git a/gdb/doc/Makefile.in b/gdb/doc/Makefile.in
index 73d439fac01..ec4153b9d1d 100644
--- a/gdb/doc/Makefile.in
+++ b/gdb/doc/Makefile.in
@@ -85,6 +85,12 @@ PACKAGE = @PACKAGE@
PKGVERSION = @PKGVERSION@
BUGURL_TEXI = @REPORT_BUGS_TEXI@
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+MANUAL_CSS =
+
# Where is the source dir for the READLINE library doc?
# Traditionally readline is in .. or .
READLINE_DIR = ${gdbdir}/../readline/readline/doc
@@ -542,11 +548,24 @@ gdb.mm: $(GDB_DOC_FILES) links2roff
# GDB MANUAL: HTML file
-gdb/index.html: ${GDB_DOC_FILES}
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+TOC_SIDEBAR_INIT = $(TOC_SIDEBAR_DIR)/toc-sidebar.init
+
+# ROCm branding.
+MANUAL_CSS += $(srcdir)/../../rocm-theme.css
+
+gdb/index.html: ${GDB_DOC_FILES} $(TOC_SIDEBAR_INIT) $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS)
$(ECHO_GEN) $(MAKEHTML) $(MAKEHTMLFLAGS) \
+ --init-file=$(TOC_SIDEBAR_INIT) \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
-o gdb \
$(READLINE_TEXI_INCFLAG) -I ${GDBMI_DIR} -I $(srcdir) \
$(srcdir)/gdb.texinfo
+ $(SILENCE) cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) gdb/
# ANNOTATE DOCUMENTATION: TeX dvi file
annotate.dvi : $(ANNOTATE_DOC_FILES)
diff --git a/ld/Makefile.am b/ld/Makefile.am
index 3ae3d7f14f6..15b04891870 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -816,11 +816,29 @@ diststuff: info $(EXTRA_DIST)
# ld.1 to support parallel build.
info-recursive: ld.1
+# Wire in the TOC navigation sidebar with the HTML manual.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+MANUAL_CSS =
+
+# ROCm branding.
+MANUAL_CSS += $(srcdir)/../rocm-theme.css
+
html-local: doc/ld/index.html
-doc/ld/index.html: ld.texi $(ld_TEXINFOS)
+doc/ld/index.html: ld.texi $(ld_TEXINFOS) $(MANUAL_CSS)
$(AM_V_at)$(MKDIR_P) doc
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir) $(srcdir)/ld.texi -o doc/ld
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) doc/ld
DISTCLEANFILES = site.exp development.exp enablings.exp site.bak
distclean-local:
diff --git a/ld/Makefile.in b/ld/Makefile.in
index d879f04a17c..5b30105a6ca 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -1084,6 +1084,21 @@ CLEANFILES = dep.sed DEP DEPA DEP1 DEP2 spu_ovl.s spu_ovl.@OBJEXT@ spu_icache.s
EXTRA_DIST = ldgram.c ldgram.h ldlex.c emultempl/spu_ovl.@OBJEXT@_c \
emultempl/spu_icache.@OBJEXT@_c deffilep.c deffilep.h $(man_MANS)
+
+# Hook in the TOC navigation sidebar.
+#
+TOC_SIDEBAR_DIR = $(srcdir)/../texinfo/toc-sidebar
+TOC_SIDEBAR_ASSETS = $(TOC_SIDEBAR_DIR)/toc-sidebar.css \
+ $(TOC_SIDEBAR_DIR)/toc-sidebar.js
+
+
+# List of extra stylesheets to brand the HTML manual. Each stylesheet
+# is referenced with --css-ref and copied into the output directory.
+# It is empty by default and can be set on the make command line, so a
+# build can theme the manual without editing the sources.
+
+# ROCm branding.
+MANUAL_CSS = $(srcdir)/../rocm-theme.css
DISTCLEANFILES = site.exp development.exp enablings.exp site.bak
all: $(BUILT_SOURCES) config.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
@@ -2475,10 +2490,13 @@ diststuff: info $(EXTRA_DIST)
info-recursive: ld.1
html-local: doc/ld/index.html
-doc/ld/index.html: ld.texi $(ld_TEXINFOS)
+doc/ld/index.html: ld.texi $(ld_TEXINFOS) $(MANUAL_CSS)
$(AM_V_at)$(MKDIR_P) doc
$(AM_V_GEN)$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) \
+ --init-file=$(TOC_SIDEBAR_DIR)/toc-sidebar.init \
+ $(foreach css,$(MANUAL_CSS),--css-ref=$(notdir $(css))) \
--split=node -I$(srcdir) $(srcdir)/ld.texi -o doc/ld
+ $(AM_V_at)cp $(TOC_SIDEBAR_ASSETS) $(MANUAL_CSS) doc/ld
distclean-local:
rm -rf ldscripts
diff --git a/rocm-theme-sync.py b/rocm-theme-sync.py
new file mode 100755
index 00000000000..4a9b809db9d
--- /dev/null
+++ b/rocm-theme-sync.py
@@ -0,0 +1,252 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
+
+# This file is part of GDB.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Refresh rocm-theme.css's generated token block from the live ROCm docs.
+
+The ROCm theme stylesheet (rocm-theme.css) defines a block of
+--toc-sidebar-* custom properties so that the manual matches the ROCm
+documentation site. Those values are the light-mode design tokens of
+the pydata-sphinx-theme the ROCm site is built with -- the color
+palette, the heading font-size ramp and weight, and the base and
+monospace font stacks. ROCm leaves the pydata defaults in place
+except for a couple of overrides shipped in rocm_custom.css.
+
+This script fetches the live site's CSS, reads those source variables,
+and rewrites the generated :root block of the sibling stylesheet in
+place. The file is only touched when a value actually changed, to
+avoid bumping the css's modification time unnecessarily.
+
+Only the tokens pydata exposes as --pst-* custom properties are
+synced. The rest of the theme's metrics (the body and heading
+line-heights, the heading margins, the pre and inline-code box) live
+in pydata's rule bodies rather than in custom properties, i.e., they
+are maintained by hand in the stylesheet, which is why they are not
+touched here.
+
+Needs network access to https://rocm.docs.amd.com.
+
+"""
+
+import argparse
+import os
+import re
+import sys
+import urllib.request
+
+BASE = "https://rocm.docs.amd.com/en/latest/_static"
+
+# The pydata theme stylesheet (which carries the --pst-* defaults) and
+# the ROCm custom stylesheet (carries the site's own overrides).
+PYDATA_CSS = f"{BASE}/styles/pydata-sphinx-theme.css"
+ROCM_CSS = f"{BASE}/rocm_custom.css"
+
+# The committed theme file, a sibling of this script.
+THEME_CSS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "rocm-theme.css")
+
+# The first line inside the generated :root block. It both labels the
+# block as machine-generated and is the anchor that update_css() keys
+# on to find the block to replace. Emitter and matcher share this one
+# constant.
+MARKER = "/* generated by rocm-theme-sync.py */"
+
+# Each mapping row is a tuple of:
+#
+# - our property (--toc-sidebar-* or --rocm-*)
+# - the pydata/ROCm source variable whose light-mode value we copy
+#
+# pydata has no variable literally named for links: the site paints
+# links with --pst-color-primary and link-hover with
+# --pst-color-secondary, which is why those feed our two accents (and
+# why the hover accent comes out purple). Every value is a stock
+# pydata light-mode default except the row-hover background, which
+# ROCm overrides in rocm_custom.css.
+#
+# The --toc-sidebar-* properties come first: those are the contract
+# that toc-sidebar.css reads. The --rocm-* properties follow; they are
+# used only within rocm-theme.css. Some of both groups happen to share
+# a source token (e.g. --toc-sidebar-bg and --rocm-code-bg are both
+# --pst-color-surface), which the trailing source comments record.
+PALETTE = [
+ # contract: read by toc-sidebar.css
+ ("--toc-sidebar-accent", "--pst-color-primary"), # site link color
+ ("--toc-sidebar-text", "--pst-color-text-base"),
+ ("--toc-sidebar-muted", "--pst-color-text-muted"),
+ ("--toc-sidebar-border", "--pst-color-border"),
+ ("--toc-sidebar-bg", "--pst-color-surface"),
+ ("--toc-sidebar-hover-bg", "--pst-color-table-row-hover-bg"), # rocm override
+ ("--toc-sidebar-search-bg", "--pst-color-background"),
+ ("--toc-sidebar-on-accent", "--pst-color-primary-text"),
+ # internal: used only within rocm-theme.css
+ ("--rocm-accent-dark", "--pst-color-secondary"), # site link-hover color
+ ("--rocm-code-bg", "--pst-color-surface"),
+ ("--rocm-inline-code", "--pst-color-inline-code"),
+]
+
+# The heading font-size ramp and the heading weight. pydata's
+# headings are set in the site's light weight, not bold.
+TYPE_SCALE = [
+ ("--rocm-font-size-h1", "--pst-font-size-h1"),
+ ("--rocm-font-size-h2", "--pst-font-size-h2"),
+ ("--rocm-font-size-h3", "--pst-font-size-h3"),
+ ("--rocm-font-size-h4", "--pst-font-size-h4"),
+ ("--rocm-font-size-h5", "--pst-font-size-h5"),
+ ("--rocm-font-size-h6", "--pst-font-size-h6"),
+ ("--rocm-heading-weight", "--pst-font-weight-heading"),
+]
+
+# The UI and monospace font stacks. We copy the *-system variables,
+# which hold the literal stacks; the plain --pst-font-family-* names
+# are just var() aliases of these.
+FONT_STACKS = [
+ ("--rocm-font-base", "--pst-font-family-base-system"),
+ ("--rocm-font-mono", "--pst-font-family-monospace-system"),
+]
+
+# The groups emitted into the block, in order. The third element says
+# whether to pad the rows so the trailing /* source */ comments line
+# up. The font stacks are long enough that aligning their comments
+# would push them far off to the right, so that group is left
+# unaligned.
+GROUPS = [
+ ("palette", PALETTE, True),
+ ("type scale", TYPE_SCALE, True),
+ ("font stacks", FONT_STACKS, False),
+]
+
+
+def fetch(url):
+ """Return the text of URL, decoded as UTF-8."""
+ with urllib.request.urlopen(url, timeout=30) as r:
+ return r.read().decode("utf-8", "replace")
+
+
+def light_values(css):
+ """Map every --pst-* name to its light-mode value.
+
+ pydata defines the light palette under the html:not([data-theme])
+ rule and the dark palette under html[data-theme=dark]. ROCm's
+ overrides sit under html[data-theme='light']. We want the
+ light-mode value, so we skip any definition that falls inside a
+ dark-theme block and keep the rest; a later light definition (an
+ override) wins over an earlier default, which is the cascade order
+ on the page too.
+ """
+ values = {}
+ # Walk the stylesheet in source order, tracking nothing more than
+ # whether the current selector is a dark-theme block.
+ for sel, body in re.findall(r"([^{}]*)\{([^{}]*)\}", css):
+ flat = sel.replace(" ", "").replace('"', "").replace("'", "")
+ if "data-theme=dark" in flat:
+ continue
+ for name, val in re.findall(r"(--pst-[a-z0-9-]+)\s*:\s*([^;]+)", body):
+ values[name] = val.strip()
+ return values
+
+
+def format_value(val, *, is_font_stack):
+ """Normalize a source value for emission into the stylesheet."""
+ # Lowercase hex colors; the source mixes cases and the committed
+ # file keeps them lowercase.
+ val = re.sub(r"#[0-9a-fA-F]+", lambda m: m.group().lower(), val)
+ # The site ships the font stacks comma-packed. Space them out so
+ # that the committed value reads like regular CSS.
+ if is_font_stack:
+ val = re.sub(r",\s*", ", ", val)
+ return val
+
+
+def build_root():
+ """Return the full generated :root block as a string of CSS.
+
+ Fetch the live stylesheets, look up each mapped source variable's
+ light-mode value, and lay the --toc-sidebar-* properties out group
+ by group, each group introduced by a comment and (when aligned)
+ padded so its trailing /* source */ comments line up. Exit if a
+ mapped source variable is missing, which means the upstream theme
+ changed too much to handle here.
+ """
+ pyd = light_values(fetch(PYDATA_CSS))
+ rocm = light_values(fetch(ROCM_CSS))
+ # ROCm overrides take precedence over the pydata defaults.
+ src = {**pyd, **rocm}
+
+ wanted = [theirs for _, group, _ in GROUPS for _, theirs in group]
+ missing = [v for v in wanted if v not in src]
+ if missing:
+ sys.exit(
+ f"source variables not found (theme changed?): "
+ f"{', '.join(sorted(set(missing)))}"
+ )
+
+ lines = [f" {MARKER}"]
+ for label, group, align in GROUPS:
+ # Build each " --toc-sidebar-x: value;" prefix, then (for aligned
+ # groups) pad them to a common width so the trailing comments
+ # line up.
+ rows = []
+ for ours, theirs in group:
+ val = format_value(src[theirs], is_font_stack=(label == "font stacks"))
+ rows.append((f" {ours}: {val};", theirs.replace("--", "")))
+ width = max(len(prefix) for prefix, _ in rows) if align else 0
+ lines.append("")
+ lines.append(f" /* {label} */")
+ for prefix, comment in rows:
+ lines.append(f"{prefix.ljust(width)} /* {comment} */")
+ return ":root {\n" + "\n".join(lines) + "\n}"
+
+
+def update_css(root):
+ """Replace the generated :root block of the theme file with ROOT.
+
+ Rewrite the file only when the block changes, so that an unchanged
+ refresh leaves the mtime untouched. Return True if it was
+ rewritten.
+ """
+ with open(THEME_CSS) as f:
+ old = f.read()
+ # Anchor on a column-0 ":root {" whose first inner line is MARKER,
+ # then run to the next line that is just "}".
+ pattern = r"^:root \{\n " + re.escape(MARKER) + r"\n.*?\n\}"
+ new, n = re.subn(
+ pattern, lambda m: root, old, count=1, flags=re.DOTALL | re.MULTILINE
+ )
+ if n == 0:
+ sys.exit(f"no generated :root block found in {THEME_CSS}")
+ if new == old:
+ return False
+ with open(THEME_CSS, "w") as f:
+ f.write(new)
+ return True
+
+
+def main():
+ """Rewrite the generated block in place and report what happened."""
+ argparse.ArgumentParser(
+ description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
+ ).parse_args()
+
+ name = os.path.basename(THEME_CSS)
+ if update_css(build_root()):
+ print(f"updated {name}; review the change with git diff")
+ else:
+ print(f"{name} already matches the live ROCm docs site")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/rocm-theme.css b/rocm-theme.css
new file mode 100644
index 00000000000..74063fbd465
--- /dev/null
+++ b/rocm-theme.css
@@ -0,0 +1,144 @@
+/* Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+/* ROCm theme for the HTML manual, styled after the AMD ROCm
+ documentation site. This sets the palette (the --toc-sidebar-*
+ custom properties the feature reads) and the manual's general look,
+ the body type and content typography.
+
+ The font stacks are copied from the ROCm documentation site so the
+ manual matches the surrounding pages.
+
+ The block below is generated from the live ROCm documentation site,
+ which is built with pydata-sphinx-theme; these are that theme's
+ light-mode design tokens (ROCm overrides only the row-hover
+ background). The palette, the heading size ramp and weight, and
+ the font stacks are all sourced this way, with the source variable
+ named in each comment. Do not edit the block by hand, as
+ rocm-theme-sync.py rewrites it in place from the live site. */
+:root {
+ /* generated by rocm-theme-sync.py */
+
+ /* palette */
+ --toc-sidebar-accent: #0a7d91; /* pst-color-primary */
+ --toc-sidebar-text: #222832; /* pst-color-text-base */
+ --toc-sidebar-muted: #48566b; /* pst-color-text-muted */
+ --toc-sidebar-border: #d1d5da; /* pst-color-border */
+ --toc-sidebar-bg: #f3f4f5; /* pst-color-surface */
+ --toc-sidebar-hover-bg: #e2e8f0; /* pst-color-table-row-hover-bg */
+ --toc-sidebar-search-bg: #fff; /* pst-color-background */
+ --toc-sidebar-on-accent: #fff; /* pst-color-primary-text */
+ --rocm-accent-dark: #8045e5; /* pst-color-secondary */
+ --rocm-code-bg: #f3f4f5; /* pst-color-surface */
+ --rocm-inline-code: #912583; /* pst-color-inline-code */
+
+ /* type scale */
+ --rocm-font-size-h1: 2.5rem; /* pst-font-size-h1 */
+ --rocm-font-size-h2: 2rem; /* pst-font-size-h2 */
+ --rocm-font-size-h3: 1.75rem; /* pst-font-size-h3 */
+ --rocm-font-size-h4: 1.5rem; /* pst-font-size-h4 */
+ --rocm-font-size-h5: 1.25rem; /* pst-font-size-h5 */
+ --rocm-font-size-h6: 1.1rem; /* pst-font-size-h6 */
+ --rocm-heading-weight: 400; /* pst-font-weight-heading */
+
+ /* font stacks */
+ --rocm-font-base: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Helvetica Neue", "Arial", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; /* pst-font-family-base-system */
+ --rocm-font-mono: "SFMono-Regular", "Menlo", "Consolas", "Monaco", "Liberation Mono", "Lucida Console", monospace; /* pst-font-family-monospace-system */
+}
+
+html { scroll-behavior: smooth; }
+
+body {
+ color: var(--toc-sidebar-text);
+ font-family: var(--rocm-font-base);
+ font-size: 16px; /* pydata light-mode value, hand-transcribed */
+ line-height: 1.65; /* pydata light-mode value, hand-transcribed */
+}
+
+/* Heading line-height and margins are pydata-sphinx-theme's
+ light-mode values, transcribed by hand. Unlike the size ramp and
+ weight above, pydata keeps these in its heading rule body rather
+ than in custom properties, so rocm-theme-sync.py cannot pull
+ them. */
+h1, h2, h3, h4, h5, h6 {
+ line-height: 1.15;
+ margin: 2.75rem 0 1.05rem;
+ font-weight: var(--rocm-heading-weight);
+}
+h1 { font-size: var(--rocm-font-size-h1); }
+h2 { font-size: var(--rocm-font-size-h2); }
+h3 { font-size: var(--rocm-font-size-h3); }
+h4 { font-size: var(--rocm-font-size-h4); }
+h5 { font-size: var(--rocm-font-size-h5); }
+h6 { font-size: var(--rocm-font-size-h6); }
+
+/* The ROCm site underlines links rather than relying on color alone;
+ the hover color comes from the palette. */
+a { color: var(--toc-sidebar-accent); text-decoration: underline; }
+a:hover { color: var(--rocm-accent-dark); }
+
+pre, code, samp, kbd {
+ font-family: var(--rocm-font-mono);
+}
+
+/* The code box's border-radius and padding (here and on the inline
+ code/samp rule below) are pydata-sphinx-theme's light-mode values,
+ transcribed by hand: like the heading metrics above, pydata keeps
+ them in its rule bodies rather than in custom properties, so
+ rocm-theme-sync.py cannot pull them. */
+pre {
+ background: var(--rocm-code-bg);
+ border: 1px solid var(--toc-sidebar-border);
+ border-radius: 0.25rem;
+ padding: 1rem;
+ line-height: 1.2; /* tighter than body text; code reads better dense */
+ margin: 1.5em 0; /* gap above and below, off the surrounding text */
+ overflow-x: auto;
+}
+
+code, samp {
+ color: var(--rocm-inline-code);
+ background: var(--rocm-code-bg);
+ border: 1px solid var(--toc-sidebar-border);
+ /* See note in the pre rule above. */
+ border-radius: 0.25rem;
+ padding: 0.1rem 0.25rem;
+}
+pre code, pre samp {
+ color: inherit; background: none; border: none; padding: 0;
+}
+
+/* The texinfo per-node prev/next/up panel, toned down with a smaller
+ type. nav-panel is a class texinfo emits in its own HTML output,
+ and texinfo does not promise it as a stable name. If a texinfo
+ version ever renames it, this rule stops matching and the panel
+ falls back to the browser's default styling. */
+.nav-panel {
+ font-size: 0.85rem;
+ color: var(--toc-sidebar-muted);
+ background: var(--toc-sidebar-bg);
+ border: 1px solid var(--toc-sidebar-border);
+ border-radius: 6px;
+ padding: 0.4rem 0.75rem;
+ margin-bottom: 1.5rem;
+}
+
+table { border-collapse: collapse; }
+table td, table th {
+ border: 1px solid var(--toc-sidebar-border);
+ padding: 0.4rem 0.6rem;
+}
diff --git a/texinfo/toc-sidebar/README b/texinfo/toc-sidebar/README
new file mode 100644
index 00000000000..efc19c274aa
--- /dev/null
+++ b/texinfo/toc-sidebar/README
@@ -0,0 +1,96 @@
+toc-sidebar: a navigation sidebar for texinfo HTML manuals
+==========================================================
+
+These files add a persistent navigation sidebar -- a table-of-contents
+pane on the left of every page -- to the HTML build of a texinfo
+manual.
+
+texinfo has no built-in support for a sidebar, but it can be driven
+through a texi2any init file, which is enough to build a sidebar
+ourselves. The init file uses a texi2any init API introduced in
+version 7.0 and guards on it, falling back to the default
+contents-only manual on older texi2any.
+
+The files here are manual-agnostic. Each manual's HTML build rule
+wires the files here in (see that manual's Makefile). This directory
+is just the shared implementation.
+
+The files
+---------
+
+toc-sidebar.init
+ A texi2any init file, loaded with --init-file. On every page it
+ injects an empty sidebar. Once, at the end of the manual
+ generation, it writes the manual's whole table of contents and its
+ title to toc-sidebar-data.js in the output directory.
+
+toc-sidebar.js
+ Loaded on every page. Fills in the sidebar shell from the
+ contents tree of toc-sidebar-data.js, and handles all the sidebar
+ logic.
+
+toc-sidebar.css
+ The sidebar's layout and default theme.
+
+toc-sidebar-data.js
+ Not in this directory: generated into the output directory at build
+ time by toc-sidebar.init. Holds the shared contents tree and title
+ that every page's toc-sidebar.js reads.
+
+
+How it fits together
+--------------------
+
+The contents tree exists only in index.html. Rather than inline it
+into all the pages (about 90 MB across a manual the size of gdb's) or
+fetch it at runtime (blocked under file://), toc-sidebar.init writes
+it once to the shared toc-sidebar-data.js. Every page loads that one
+file with a plain
+
+
\n");
+
+# Pull in the sidebar's own stylesheet here rather than with
+# texi2any's --css-ref. The sidebar exists only when this init file
+# runs, i.e. on texi2any 7.0+, and referencing toc-sidebar.css from
+# here ties it to that, so a build that falls back to the plain manual
+# never points at a stylesheet for a sidebar it did not emit.
+#
+# Mark the page as script-enabled. This inline script has no "defer",
+# so the parser runs it immediately, here in the head before the body
+# is laid out.
+#
+# Add the "js" class to , which the stylesheet keys the sidebar
+# layout off. Setting the class before the first paint means the page
+# is drawn the right way the first time: with the sidebar when
+# JavaScript is on, and as a single column when it is off. If class
+# were set later instead, the page would first be drawn as a single
+# column and then re-laid out once the sidebar appeared. The contents
+# data (toc-sidebar-data.js) and the sidebar script (toc-sidebar.js)
+# load from the body, next to the sidebar shell; see the comment on
+# $sidebar above for why they go there and not here.
+texinfo_set_from_init_file('EXTRA_HEAD',
+ ''
+ . '');
+
+1;
diff --git a/texinfo/toc-sidebar/toc-sidebar.js b/texinfo/toc-sidebar/toc-sidebar.js
new file mode 100644
index 00000000000..a64fcb4ae1e
--- /dev/null
+++ b/texinfo/toc-sidebar/toc-sidebar.js
@@ -0,0 +1,589 @@
+/* Copyright (C) 2026 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see . */
+
+/* Build the left navigation sidebar of the HTML manual.
+
+ Each page ships with an empty sidebar shell (put there by
+ toc-sidebar.init) and pulls in toc-sidebar-data.js, which sets
+ window.TOC_SIDEBAR_CONTENTS to the manual's whole table of contents
+ as a string of HTML. This script turns that string into the
+ sidebar tree, marks the current entry for the current page, and
+ makes interior nodes collapsible. The sections the user expands
+ stay open when moving from one page to the next.
+
+ With JavaScript off, this script never runs -- the stylesheet hides
+ the sidebar and the page shows a single content column.
+*/
+
+(function ()
+{
+ "use strict";
+
+ /* Remember which sections the user has expanded. Each page is a
+ separate file load that rebuilds the tree from scratch, so
+ without this, a manual expansion would be lost on when navigating
+ between pages.
+
+ The set is a map from a node's href to true, kept in
+ sessionStorage as JSON. This relies on the hrefs being the same
+ on every page, which is true because every page builds its tree
+ from the the same shared toc-sidebar-data.js. That is what makes
+ a set saved on one page apply to the next. Storage is not always
+ available (private browsing, or some browsers under file://), so
+ every access is guarded and falls back to an empty set. */
+ var STORAGE_KEY = "toc-sidebar-open";
+
+ /* The set of open sections, or an empty set when none are stored
+ yet or storage is unavailable. */
+ function loadOpenSet ()
+ {
+ try
+ {
+ var raw = window.sessionStorage.getItem (STORAGE_KEY);
+ return raw ? JSON.parse (raw) : {};
+ }
+ catch (e)
+ {
+ return {};
+ }
+ }
+
+ /* Remember the set of open sections. */
+ function saveOpenSet (open)
+ {
+ try
+ {
+ window.sessionStorage.setItem (STORAGE_KEY, JSON.stringify (open));
+ }
+ catch (e)
+ {
+ /* Persistence is a nice-to-have, so a failure here is
+ fine. */
+ }
+ }
+
+ /* How far down the sidebar is scrolled is remembered the same way
+ as the open set. Each page is a separate file whose sidebar
+ starts scrolled to the top, so without this the scroll position
+ lost on every navigation. The value is the sidebar's scrollTop
+ in pixels, as a string, in sessionStorage. */
+ var SCROLL_KEY = "toc-sidebar-scroll";
+
+ /* The stored sidebar scroll offset in pixels, or null when there is
+ none yet or storage is unavailable. */
+ function loadScroll ()
+ {
+ try
+ {
+ var raw = window.sessionStorage.getItem (SCROLL_KEY);
+ return raw === null ? null : parseFloat (raw);
+ }
+ catch (e)
+ {
+ return null;
+ }
+ }
+
+ /* Remember the sidebar scroll offset, given in pixels. */
+ function saveScroll (px)
+ {
+ try
+ {
+ window.sessionStorage.setItem (SCROLL_KEY, px);
+ }
+ catch (e)
+ {
+ /* Persistence is a nice-to-have, so a failure here is
+ fine. */
+ }
+ }
+
+ /* Return whether LINK's box lies entirely within SIDEBAR's visible
+ area, so the user can already see it without the sidebar
+ moving. */
+ function entryVisible (sidebar, link)
+ {
+ var sr = sidebar.getBoundingClientRect ();
+ var lr = link.getBoundingClientRect ();
+ return lr.top >= sr.top && lr.bottom <= sr.bottom;
+ }
+
+ /* Save the SIDEBAR's scroll offset whenever the user scrolls it, so
+ that the next page opens at the same place. */
+ function rememberScroll (sidebar)
+ {
+ /* Defer the write to the next animation frame so a burst of
+ scroll events collapses into one write rather than hitting
+ storage on every pixel. */
+ var pending = false;
+ sidebar.addEventListener ("scroll", function ()
+ {
+ if (pending)
+ return;
+ pending = true;
+ window.requestAnimationFrame (function ()
+ {
+ pending = false;
+ saveScroll (sidebar.scrollTop);
+ });
+ });
+ }
+
+ /* Basename of the current document. For a directory URL, returns
+ index.html. */
+ function currentFile ()
+ {
+ var path = window.location.pathname;
+ var base = path.substring (path.lastIndexOf ("/") + 1);
+ return base === "" ? "index.html" : base;
+ }
+
+ /* Basename of a link target, with any #anchor dropped. */
+ function linkFile (href)
+ {
+ var hash = href.indexOf ("#");
+ if (hash >= 0)
+ href = href.substring (0, hash);
+ return href.substring (href.lastIndexOf ("/") + 1);
+ }
+
+ /* The "#anchor" part of a link target, or empty string when there
+ is none. */
+ function linkAnchor (href)
+ {
+ var hash = href.indexOf ("#");
+ return hash >= 0 ? href.substring (hash) : "";
+ }
+
+ /* Pick the contents entry for the current page. Several entries can
+ point into the same page when a page holds sections that have no
+ node of their own, which texinfo emits as anchors within the one
+ file. Among the entries for this page, prefer the one whose anchor
+ matches the address bar. With no anchor there, that is the entry
+ for the top of the page itself. */
+ function pickCurrent (candidates)
+ {
+ var hash = window.location.hash;
+ var i;
+ for (i = 0; i < candidates.length; i++)
+ if (linkAnchor (candidates[i].getAttribute ("href")) === hash)
+ return candidates[i];
+ for (i = 0; i < candidates.length; i++)
+ if (linkAnchor (candidates[i].getAttribute ("href")) === "")
+ return candidates[i];
+ return candidates.length ? candidates[0] : null;
+ }
+
+ /* Highlight the entry for the current page and anchor, and open the
+ path of sections down to it. CANDIDATES are the entries that
+ point at the current page; which one is current depends on the
+ address-bar anchor, so this clears any previous highlight first
+ and reruns on every anchor change, not only on load -- see the
+ listener in decorate. Returns the highlighted entry, or null
+ when none matches. */
+ function markCurrent (container, candidates, open)
+ {
+ var previous = container.querySelector (".toc-sidebar-current");
+ if (previous)
+ previous.classList.remove ("toc-sidebar-current");
+
+ var current = pickCurrent (candidates);
+ if (!current)
+ return null;
+
+ current.classList.add ("toc-sidebar-current");
+
+ /* Open the path down to the current entry, and remember it the
+ same way a manual expansion is remembered. Otherwise a section
+ opened only because the user walked into it would collapse
+ again the moment they moved to another part of the manual. */
+ var node = current.closest ("li");
+ while (node)
+ {
+ node.classList.add ("toc-sidebar-open");
+ var nodeLink = node.querySelector (":scope > a");
+ if (nodeLink)
+ open[nodeLink.getAttribute ("href")] = true;
+ node = node.parentElement ? node.parentElement.closest ("li") : null;
+ }
+ saveOpenSet (open);
+
+ return current;
+ }
+
+ /* Bring CURRENT on screen, but only when it is not already visible.
+ When the user moves between two nearby entries, the sidebar stays
+ put. Only a jump to a far-off part of the TOC scrolls. */
+ function revealCurrent (sidebar, current)
+ {
+ if (sidebar && current && !entryVisible (sidebar, current))
+ current.scrollIntoView ({ block: "center" });
+ }
+
+ /* Make the plain TOC tree interactive. Flag every node that has
+ children (toc-sidebar-has-children) and give it a [+]/[-] toggle.
+ Then, find the entry for the current page, highlight it, and open
+ the path down to it. */
+ function decorate (container)
+ {
+ var here = currentFile ();
+ var open = loadOpenSet ();
+ var candidates = [];
+ var sidebar = document.getElementById ("toc-sidebar");
+
+ var items = container.querySelectorAll ("li");
+ items.forEach (function (li)
+ {
+ var sublist = li.querySelector (":scope > ul");
+ var link = li.querySelector (":scope > a");
+ var key = link ? link.getAttribute ("href") : null;
+
+ if (sublist)
+ {
+ li.classList.add ("toc-sidebar-has-children");
+ if (key && open[key])
+ li.classList.add ("toc-sidebar-open");
+ var toggle = document.createElement ("span");
+ toggle.className = "toc-sidebar-toggle";
+ toggle.setAttribute ("role", "button");
+ toggle.setAttribute ("aria-label", "Toggle section");
+ toggle.addEventListener ("click", function (event)
+ {
+ event.preventDefault ();
+ var nowOpen = li.classList.toggle ("toc-sidebar-open");
+ if (key)
+ {
+ if (nowOpen)
+ open[key] = true;
+ else
+ delete open[key];
+ saveOpenSet (open);
+ }
+ });
+ li.insertBefore (toggle, li.firstChild);
+ }
+
+ if (link && linkFile (link.getAttribute ("href")) === here)
+ candidates.push (link);
+ });
+
+ var current = markCurrent (container, candidates, open);
+ if (current)
+ {
+ /* Put the sidebar back where the user had it on the previous
+ page, now that the path down to the current entry is open
+ and the tree has its final height. Then center the current
+ entry only if that restored position does not already show
+ it. Centering updates scrollTop, so the explicit save
+ below records the centered position for the next page.
+ Restoring it there then leaves the entry on screen, so the
+ next page does not scroll either. */
+ if (sidebar)
+ {
+ var saved = loadScroll ();
+ if (saved !== null)
+ sidebar.scrollTop = saved;
+ revealCurrent (sidebar, current);
+ }
+ }
+ else if (sidebar)
+ {
+ /* Nothing matched: we're in the contents page itself, whose
+ Top node has no entry in its own table of contents, or some
+ auxiliary page. Leave the tree collapsed -- the top-level
+ entries are always shown, and any sections the user
+ expanded elsewhere are open through the saved set -- and
+ just restore the saved scroll position. */
+ var savedTop = loadScroll ();
+ if (savedTop !== null)
+ sidebar.scrollTop = savedTop;
+ }
+
+ if (sidebar)
+ {
+ saveScroll (sidebar.scrollTop);
+ rememberScroll (sidebar);
+ }
+
+ /* Several subsections can share one page, emitted as anchors
+ within the one file. Following such a link from elsewhere on
+ that same page is an in-document jump -- the browser moves to
+ the anchor without reloading. In that case this script does
+ not run again and the highlight would otherwise stay on the
+ entry the user came from. Handle every hash change so the
+ sidebar follows the user into these intra-page sections. */
+ window.addEventListener ("hashchange", function ()
+ {
+ revealCurrent (sidebar, markCurrent (container, candidates, open));
+ });
+ }
+
+ /* Replace the placeholder in the shell with the decorated tree. */
+ function inject (ul)
+ {
+ var toc = document.getElementById ("toc-sidebar-tree");
+ if (!toc)
+ return;
+ toc.innerHTML = "";
+ toc.appendChild (ul);
+ decorate (toc);
+ }
+
+ /* Parse window.TOC_SIDEBAR_CONTENTS and return its top-level
,
+ or null.
+
+ This is where the script meets texinfo's generated HTML. The
+ contents tree comes from texinfo's format_contents and is a plain
+ nested list:
+
+