doc: generate separate commands/topics/extension pages
This change modifies gendoc.py and Makefile so that individual pages for
commands, help topics, and extensions can be generated. A new index page is
also generated with links to all these pages. This makes it easier to look up
and search the help text of a given command or topic, instead of having to
deal with the giant hg.1 "all-in-one" page.
Since the list of individual pages varies based on the source code, we generate
a dynamic Makefile that contains this list of files as individual targets.
This gives us fine-grained control over output files. However, it greatly
increases the time spent generating all help pages. It's recommended to run
make with -j to make use of multi-core archs.
Individual man pages are produced in doc/man, and HTML ones are in doc/html
--- a/.hgignore Mon Oct 09 22:11:21 2023 -0700
+++ b/.hgignore Mon Oct 09 22:14:24 2023 -0700
@@ -40,10 +40,17 @@
dist
packages
doc/common.txt
+doc/commandlist.txt
+doc/extensionlist.txt
+doc/topiclist.txt
+doc/*.mk
doc/*.[0-9]
doc/*.[0-9].txt
doc/*.[0-9].gendoc.txt
doc/*.[0-9].{x,ht}ml
+doc/build
+doc/html
+doc/man
MANIFEST
MANIFEST.in
patches
--- a/doc/Makefile Mon Oct 09 22:11:21 2023 -0700
+++ b/doc/Makefile Mon Oct 09 22:14:24 2023 -0700
@@ -3,6 +3,7 @@
HTML=$(SOURCES:%.txt=%.html)
GENDOC=gendoc.py ../mercurial/commands.py ../mercurial/help.py \
../mercurial/helptext/*.txt ../hgext/*.py ../hgext/*/__init__.py
+RUNRST=runrst
PREFIX=/usr/local
MANDIR=$(PREFIX)/share/man
INSTALL=install -m 644
@@ -14,10 +15,150 @@
else
PYTHON?=python3
endif
+
RSTARGS=
+GENDOCARGS=
+GENDOCCMD=$(PYTHON) gendoc.py $(GENDOCARGS)
+
+# Output directories for individual help pages.
+MANOUT=man
+HTMLOUT=html
+BUILDDIR=build
export HGENCODING=UTF-8
+.PHONY: all man html install clean knownrefs
+
+# Generate a list of hg commands and extensions.
+commandlist.txt: $(GENDOC)
+ ${GENDOCCMD} commandlist > $@.tmp
+ mv $@.tmp $@
+
+topiclist.txt: $(GENDOC)
+ ${GENDOCCMD} topiclist > $@.tmp
+ mv $@.tmp $@
+
+extensionlist.txt: $(GENDOC)
+ ${GENDOCCMD} extensionlist > $@.tmp
+ mv $@.tmp $@
+
+# Build target for running runrst more easily by hand
+knownrefs: commandlist.txt topiclist.txt extensionlist.txt
+
+BUILDFILES=commandlist.txt topiclist.txt extensionlist.txt
+
+# We want to generate a sub-Makefile that can build the RST/man/html doc for
+# each hg command. Here are templates that we'll use to generate this
+# sub-Makefile.
+HGCMDTPL=templates/cmdheader.txt
+TOPICTPL=templates/topicheader.txt
+EXTTPL=templates/extheader.txt
+
+define RuleAllCommandsTemplate
+HG_COMMANDS=$(1)
+all-commands: $$(HG_COMMANDS:%=$$(BUILDDIR)/hg-%.gendoc.txt)
+endef
+
+define RuleAllTopicsTemplate
+HG_TOPICS=$(1)
+all-topics: $$(HG_TOPICS:%=$$(BUILDDIR)/%.gendoc.txt)
+endef
+
+define RuleAllExtensionsTemplate
+HG_EXTENSIONS=$(1)
+all-extensions: $$(HG_EXTENSIONS:%=$$(BUILDDIR)/%.gendoc.txt)
+endef
+
+define RuleCommandTemplate
+$$(BUILDDIR)/hg-$C.gendoc.txt: $$(GENDOC) $$(HGCMDTPL)
+ mkdir -p $$(@D)
+ $${GENDOCCMD} cmd-$C > $$@.tmp
+ mv $$@.tmp $$@
+endef
+
+define RuleTopicTemplate
+$$(BUILDDIR)/topic-$T.gendoc.txt: $$(GENDOC) $$(TOPICTPL)
+ mkdir -p $$(@D)
+ $${GENDOCCMD} topic-$T > $$@.tmp
+ mv $$@.tmp $$@
+endef
+
+define RuleExtensionTemplate
+$$(BUILDDIR)/ext-$E.gendoc.txt: $$(GENDOC) $$(EXTTPL)
+ mkdir -p $$(@D)
+ $${GENDOCCMD} ext-$E > $$@.tmp
+ mv $$@.tmp $$@
+endef
+
+# Actually generate the sub-Makefile.
+# The $file function is only supported by GNU Make 4 and above.
+CommandsTopicsExtensions.mk: commandlist.txt topiclist.txt extensionlist.txt Makefile
+ifeq (4.0,$(firstword $(sort $(MAKE_VERSION) 4.0)))
+ $(file > $@.tmp,# Generated by Makefile)
+ $(file >> $@.tmp,$(call RuleAllCommandsTemplate,$(file < commandlist.txt)))
+ $(file >> $@.tmp,$(call RuleAllTopicsTemplate,$(file < topiclist.txt)))
+ $(file >> $@.tmp,$(call RuleAllExtensionsTemplate,$(file < extensionlist.txt)))
+ $(foreach C,$(file < commandlist.txt),$(file >> $@.tmp,$(RuleCommandTemplate)))
+ $(foreach T,$(file < topiclist.txt),$(file >> $@.tmp,$(RuleTopicTemplate)))
+ $(foreach E,$(file < extensionlist.txt),$(file >> $@.tmp,$(RuleExtensionTemplate)))
+ mv $@.tmp $@
+else
+ @echo "You are running make ${MAKE_VERSION} but you need make 4.0 or above"
+endif
+
+BUILDFILES+=CommandsTopicsExtensions.mk
+
+# Include the sub-Makefile that contains rules for generating each individual
+# command/help-topic/extension help page. This sub-Makefile is created by the
+# rule above (CommandsTopicsExtensions.mk) which in turn is created from the
+# plain-text lists of commands/help-topics/extensions.
+#
+# Any time the source code changes, these plain-text lists and this
+# sub-Makefile will get regenerated. Make will then restart itself to take
+# into account the rules inside the sub-Makefile.
+#
+# We want to avoid doing all this work for targets that we know don't need it
+# however. For example, running `make clean` would only generate these files
+# in order to delete them immediately. As a result, we don't include the
+# sub-Makefile (and therefore don't require generating it) if clean is one of
+# the targets. This might not do what we want when other targets are specified
+# but it's most likely what we want.
+ifeq (,$(filter clean,$(MAKECMDGOALS)))
+-include CommandsTopicsExtensions.mk
+endif
+
+# If the sub-Makefile is available, add all the hg commands, help-topics, and
+# extensions to the list of things to generate html and man pages for.
+#
+# Naming convention:
+# - commands: hg-foo (html and man)
+# - help topics: topic-foo (html), hgfoo (man)
+# - extensions: ext-foo (html), hgext-foo (man)
+#
+# Man pages for commands are in section 1 (user commands), topics and
+# extensions are in section 7 (miscellanea)
+#
+# NOTE: topics and extension are temporarily disabled for man pages because
+# they make docutils' RST converter crash.
+ifdef HG_COMMANDS
+HTML+=$(HG_COMMANDS:%=$(HTMLOUT)/hg-%.html)
+MAN+=$(HG_COMMANDS:%=$(MANOUT)/hg-%.1)
+endif
+
+ifdef HG_TOPICS
+HTML+=$(HG_TOPICS:%=$(HTMLOUT)/topic-%.html)
+#MAN+=$(HG_TOPICS:%=$(MANOUT)/hg%.7)
+endif
+
+ifdef HG_EXTENSIONS
+HTML+=$(HG_EXTENSIONS:%=$(HTMLOUT)/ext-%.html)
+#MAN+=$(HG_EXTENSIONS:%=$(MANOUT)/hgext-%.7)
+endif
+
+# Also add the HTML index page
+HTML+=$(HTMLOUT)/index.html
+
+
all: man html
man: $(MAN)
@@ -26,17 +167,45 @@
# This logic is duplicated in setup.py:hgbuilddoc()
common.txt $(SOURCES) $(SOURCES:%.txt=%.gendoc.txt): $(GENDOC)
- ${PYTHON} gendoc.py "$(basename $@)" > $@.tmp
+ ${GENDOCCMD} "$(basename $@)" > $@.tmp
mv $@.tmp $@
-%: %.txt %.gendoc.txt common.txt
+%: %.txt %.gendoc.txt common.txt $(RUNRST)
$(PYTHON) runrst hgmanpage $(RSTARGS) --halt warning \
--strip-elements-with-class htmlonly $*.txt $*
-%.html: %.txt %.gendoc.txt common.txt
+%.html: %.txt %.gendoc.txt common.txt $(RUNRST)
$(PYTHON) runrst html $(RSTARGS) --halt warning \
--link-stylesheet --stylesheet-path style.css $*.txt $*.html
+# Rules for index page and individual command/help-topic/extension pages
+# Because the naming isn't the same between html and man pages, we need to
+# break down man pages rules a bit more.
+$(BUILDDIR)/index.gendoc.txt: $(GENDOC)
+ mkdir -p $(@D)
+ ${GENDOCCMD} index > $@.tmp
+ mv $@.tmp $@
+
+$(MANOUT)/hg-%.1: $(BUILDDIR)/hg-%.gendoc.txt common.txt $(RUNRST)
+ mkdir -p $(@D)
+ $(PYTHON) runrst hgmanpage --hg-individual-pages $(RSTARGS) --halt warning \
+ --strip-elements-with-class htmlonly $(BUILDDIR)/hg-$*.gendoc.txt $@
+
+$(MANOUT)/hg%.7: $(BUILDDIR)/topic-%.gendoc.txt common.txt $(RUNRST)
+ mkdir -p $(@D)
+ $(PYTHON) runrst hgmanpage --hg-individual-pages $(RSTARGS) --halt warning \
+ --strip-elements-with-class htmlonly $(BUILDDIR)/topic-$*.gendoc.txt $@
+
+$(MANOUT)/hgext-%.7: $(BUILDDIR)/ext-%.gendoc.txt common.txt $(RUNRST)
+ mkdir -p $(@D)
+ $(PYTHON) runrst hgmanpage --hg-individual-pages $(RSTARGS) --halt warning \
+ --strip-elements-with-class htmlonly $(BUILDDIR)/ext-$*.gendoc.txt $@
+
+$(HTMLOUT)/%.html: $(BUILDDIR)/%.gendoc.txt common.txt $(RUNRST)
+ mkdir -p $(@D)
+ $(PYTHON) runrst html --hg-individual-pages $(RSTARGS) --halt warning \
+ --link-stylesheet --stylesheet-path style.css $(BUILDDIR)/$*.gendoc.txt $@
+
MANIFEST: man html
# tracked files are already in the main MANIFEST
$(RM) $@
@@ -51,5 +220,9 @@
$(INSTALL) $$i "$(DESTDIR)$(MANDIR)"/$$subdir ; \
done
+# The clean target explicitly doesn't bother with the sub-Makefile, so we don't
+# know anything about all the command/topic/extension targets and files.
+# $(HTML) only has the basic topics, so we need to delete $(HTMLOUT)/*.html and
+# other similar files "by hand" here.
clean:
- $(RM) $(MAN) $(HTML) common.txt $(SOURCES) $(SOURCES:%.txt=%.gendoc.txt) MANIFEST
+ $(RM) $(MAN) $(HTML) common.txt $(SOURCES) MANIFEST *.gendoc.txt $(BUILDFILES) $(BUILDDIR)/*.gendoc.* $(HTMLOUT)/*.html
--- a/doc/gendoc.py Mon Oct 09 22:11:21 2023 -0700
+++ b/doc/gendoc.py Mon Oct 09 22:14:24 2023 -0700
@@ -178,6 +178,202 @@
)
+def showcommandlist(ui, debugcmds=False):
+ """Render a plain text list of all command names
+
+ Args:
+ ui: the UI object to output to
+ debugcmds: whether to include debug commands
+ """
+ cmdnames = allcommandnames(table, debugcmds=debugcmds)
+ for mainname in cmdnames.keys():
+ # Make does not like semicolons in filenames (or what it
+ # considers as filenames). We use command names as targets so
+ # it applies here. For now let's skip commands with semicolons
+ # in them (at this time it only includes the `admin::verify`
+ # advanced command).
+ if b'::' in mainname:
+ continue
+ ui.write(mainname)
+ ui.write(b" ")
+
+
+def showtopiclist(ui):
+ """Render a plain text list of all help topic names
+
+ Args:
+ ui: the UI object to output to
+ """
+ for topic in helptable:
+ topicname = topic[0][0]
+ if help.filtertopic(ui, topicname):
+ continue
+ ui.write(topicname)
+ ui.write(b" ")
+
+
+def showextensionlist(ui):
+ """Render a plain text list of all extension names
+
+ Args:
+ ui: the UI object to output to
+ """
+ for extensionname in allextensionnames():
+ ui.write(extensionname)
+ ui.write(b" ")
+
+
+def showhelpindex(ui, debugcmds=False):
+ """Render restructured text for a complete mercurial help index
+
+ This index will show a list of commands, followed by a list of help topics,
+ and finally a list of extensions. These lists are split in categories and
+ ordered 'nicely' as defined by alphabetical and categeory order.
+
+ Each entry in this index is a reference to the specific help page of the
+ command, topic, or extension at hand.
+ """
+ ui.write(minirst.section(_(b"Mercurial Distributed SCM")))
+
+ missingdoc = _(b"(no help text available)")
+
+ cats, h, syns = help._getcategorizedhelpcmds(ui, table, None)
+ ui.write(minirst.subsection(_(b"Commands")))
+
+ for cat in help.CATEGORY_ORDER:
+ catfns = sorted(cats.get(cat, []))
+ if not catfns:
+ continue
+
+ catname = gettext(help.CATEGORY_NAMES[cat])
+ ui.write(minirst.subsubsection(catname))
+ for c in catfns:
+ url = b'hg-%s.html' % c
+ ui.write(b" :`%s <%s>`__: %s" % (c, url, h[c]))
+ syns[c].remove(c)
+ if syns[c]:
+ ui.write(_(b" (aliases: *%s*)") % (b', '.join(syns[c])))
+ ui.write(b"\n")
+ ui.write(b"\n\n")
+
+ ui.write(b"\n\n")
+
+ ui.write(minirst.subsection(_(b"Additional Help Topics")))
+ topiccats, topicsyns = help._getcategorizedhelptopics(ui, helptable)
+ for cat in help.TOPIC_CATEGORY_ORDER:
+ topics = topiccats.get(cat, [])
+ if not topics:
+ continue
+
+ catname = gettext(help.TOPIC_CATEGORY_NAMES[cat])
+ ui.write(minirst.subsubsection(catname))
+ for t, desc in topics:
+ url = b'topic-%s.html' % t
+ ui.write(b" :`%s <%s>`__: %s" % (t, url, desc))
+ topicsyns[t].remove(t)
+ if topicsyns[t]:
+ ui.write(_(b" (aliases: *%s*)") % (b', '.join(topicsyns[t])))
+ ui.write(b"\n")
+ ui.write(b"\n\n")
+
+ ui.write(b"\n\n")
+
+ # Add an alphabetical list of extensions, categorized by group.
+ sectionkeywords = [
+ (b"(ADVANCED)", _(b"(ADVANCED)")),
+ (b"(EXPERIMENTAL)", _(b"(EXPERIMENTAL)")),
+ (b"(DEPRECATED)", _(b"(DEPRECATED)")),
+ ]
+ extensionsections = [
+ (b"Extensions", []),
+ (b"Advanced Extensions", []),
+ (b"Experimental Extensions", []),
+ (b"Deprecated Extensions", []),
+ ]
+ for extensionname in allextensionnames():
+ mod = extensions.load(ui, extensionname, None)
+ shortdoc, longdoc = _splitdoc(mod)
+ for i, kwds in enumerate(sectionkeywords):
+ if any([kwd in shortdoc for kwd in kwds]):
+ extensionsections[i + 1][1].append(
+ (extensionname, mod, shortdoc)
+ )
+ break
+ else:
+ extensionsections[0][1].append((extensionname, mod, shortdoc))
+ for sectiontitle, extinfos in extensionsections:
+ ui.write(minirst.subsection(_(sectiontitle)))
+ for extinfo in sorted(extinfos, key=lambda ei: ei[0]):
+ extensionname, mod, shortdoc = extinfo
+ url = b'ext-%s.html' % extensionname
+ ui.write(
+ minirst.subsubsection(b'`%s <%s>`__' % (extensionname, url))
+ )
+ ui.write(shortdoc)
+ ui.write(b'\n\n')
+ cmdtable = getattr(mod, 'cmdtable', None)
+ if cmdtable:
+ cmdnames = allcommandnames(cmdtable, debugcmds=debugcmds)
+ for f in sorted(cmdnames.keys()):
+ d = get_cmd(cmdnames[f], cmdtable)
+ ui.write(b':%s: ' % d[b'cmd'])
+ ui.write(d[b'desc'][0] or (missingdoc + b"\n"))
+ ui.write(b'\n')
+ ui.write(b'\n')
+
+
+def showcommand(ui, mainname):
+ # Always pass debugcmds=True so that we find whatever command we are told
+ # to display.
+ cmdnames = allcommandnames(table, debugcmds=True)
+ allnames = cmdnames[mainname]
+ d = get_cmd(allnames, table)
+
+ header = _rendertpl(
+ 'cmdheader.txt',
+ {
+ 'cmdname': mainname,
+ 'cmdtitle': minirst.section(b'hg ' + mainname),
+ 'cmdshortdesc': minirst.subsection(d[b'desc'][0]),
+ 'cmdlongdesc': d[b'desc'][1],
+ 'cmdsynopsis': d[b'synopsis'],
+ },
+ )
+ ui.write(header.encode())
+
+ _optionsprinter(ui, d, minirst.subsubsection)
+ if d[b'aliases']:
+ ui.write(minirst.subsubsection(_(b"Aliases")))
+ ui.write(b"::\n\n ")
+ ui.write(b", ".join(d[b'aliases']))
+ ui.write(b"\n")
+
+
+def _splitdoc(obj):
+ objdoc = pycompat.getdoc(obj)
+ firstnl = objdoc.find(b'\n')
+ if firstnl > 0:
+ shortdoc = objdoc[:firstnl]
+ longdoc = objdoc[firstnl + 1 :]
+ else:
+ shortdoc = objdoc
+ longdoc = ''
+ return shortdoc.lstrip(), longdoc.lstrip()
+
+
+def _rendertpl(tplname, data):
+ tplpath = os.path.join(os.path.dirname(__file__), 'templates', tplname)
+ with open(tplpath, 'r') as f:
+ tpl = f.read()
+
+ if isinstance(tpl, bytes):
+ tpl = tpl.decode()
+ for k in data:
+ data[k] = data[k].decode()
+
+ return tpl % data
+
+
def gettopicstable():
extrahelptable = [
([b"common"], b'', loaddoc(b'common'), help.TOPIC_CATEGORY_MISC),
@@ -268,6 +464,41 @@
ui.write(b"\n")
+def showextension(ui, extensionname, debugcmds=False):
+ """Render the help text for an extension
+
+ Args:
+ ui: the UI object to output to
+ extensionname: the name of the extension to output
+ debugcmds: whether to include the extension's debug commands, if any
+ """
+ mod = extensions.load(ui, extensionname, None)
+
+ header = _rendertpl(
+ 'extheader.txt',
+ {'extname': extensionname, 'exttitle': minirst.section(extensionname)},
+ )
+ ui.write(header.encode())
+
+ shortdoc, longdoc = _splitdoc(mod)
+ if shortdoc:
+ ui.write(b"%s\n\n" % gettext(shortdoc))
+ if longdoc:
+ ui.write(minirst.subsection(_(b"Description")))
+ ui.write(b"%s\n\n" % gettext(longdoc))
+
+ cmdtable = getattr(mod, 'cmdtable', None)
+ if cmdtable:
+ ui.write(minirst.subsection(_(b'Commands')))
+ commandprinter(
+ ui,
+ cmdtable,
+ minirst.subsubsection,
+ minirst.subsubsubsection,
+ debugcmds=debugcmds,
+ )
+
+
def commandprinter(ui, cmdtable, sectionfunc, subsectionfunc, debugcmds=False):
"""Render restructuredtext describing a list of commands and their
documentations, grouped by command category.
@@ -427,7 +658,27 @@
# ui.debugflag determines if the help module returns debug commands to us.
ui.debugflag = debugcmds
+ # Render the 'all-in-one' giant documentation file
if doc == b'hg.1.gendoc':
showdoc(ui)
+ # Render a command/help-topic/extension name list (for internal use)
+ elif doc == b'commandlist':
+ showcommandlist(ui, debugcmds=debugcmds)
+ elif doc == b'topiclist':
+ showtopiclist(ui)
+ elif doc == b'extensionlist':
+ showextensionlist(ui)
+ # Render the help index/main page
+ elif doc == b'index':
+ showhelpindex(ui, debugcmds=debugcmds)
+ # Render an individual command/help-topic/extension page
+ elif doc.startswith(b'cmd-'):
+ showcommand(ui, doc[4:])
+ elif doc.startswith(b'topic-'):
+ showtopic(ui, doc[6:], wraptpl=True)
+ elif doc.startswith(b'ext-'):
+ showextension(ui, doc[4:], debugcmds=debugcmds)
+ # Render a help-topic page without any title/footer, for later inclusion
+ # into a hand-written help text file
else:
showtopic(ui, doc)
--- a/doc/runrst Mon Oct 09 22:11:21 2023 -0700
+++ b/doc/runrst Mon Oct 09 22:14:24 2023 -0700
@@ -13,6 +13,7 @@
"""
+import re
import sys
try:
@@ -31,13 +32,63 @@
)
sys.exit(-1)
+# Whether we are rendering a help page for a single topic.
+# If false, we are rendering a monolithic page with all topics together.
+is_individual_pages_mode = False
+
+
+def make_cmd_ref_uri(cmd):
+ if is_individual_pages_mode:
+ return "hg-%s.html" % cmd
+ else:
+ return "hg.1.html#%s" % cmd
+
+
+known_refs = None
+
+
+def load_known_refs(fname):
+ try:
+ with open(fname, 'r') as fp:
+ text = fp.read()
+ return re.split(r'[ \n]+', text)
+ except OSError:
+ sys.stderr.write(
+ "abort: couldn't find '%', please run documentation generation "
+ "through the Makefile, or run 'make knownrefs'\n"
+ )
+ sys.exit(-1)
+
+
+def find_known_ref(ref):
+ global known_refs
+ if known_refs is None:
+ cmds = load_known_refs('commandlist.txt')
+ topics = load_known_refs('topiclist.txt')
+ exts = load_known_refs('extensionlist.txt')
+ known_refs = {'hg': cmds, 'topic': topics, 'ext': exts}
+ for reftype, refnames in known_refs.items():
+ if ref in refnames:
+ return reftype
+ return None
+
+
+def make_any_ref_uri(ref):
+ if is_individual_pages_mode:
+ # Try to find if ref is a command, topic, or extension. If not,
+ # reference the anchor in the main hg.1 help page.
+ reftype = find_known_ref(ref)
+ if reftype:
+ return '%s-%s.html' % (reftype, ref)
+ return "hg.1.html#%s" % ref
+
def role_hg(name, rawtext, text, lineno, inliner, options=None, content=None):
text = "hg " + utils.unescape(text)
linktext = nodes.literal(rawtext, text)
parts = text.split()
cmd, args = parts[1], parts[2:]
- refuri = "hg.1.html#%s" % cmd
+ refuri = make_cmd_ref_uri(cmd)
if cmd == 'help' and args:
if args[0] == 'config':
# :hg:`help config`
@@ -48,9 +99,9 @@
elif len(args) >= 2 and args[0] == '-c':
# :hg:`help -c COMMAND ...` is equivalent to :hg:`COMMAND`
# (mainly for :hg:`help -c config`)
- refuri = "hg.1.html#%s" % args[1]
+ refuri = make_cmd_ref_uri(args[1])
else:
- refuri = "hg.1.html#%s" % args[0]
+ refuri = make_any_ref_uri(args[0])
node = nodes.reference(rawtext, '', linktext, refuri=refuri)
return [node], []
@@ -65,4 +116,8 @@
writer = sys.argv[1]
del sys.argv[1]
+ if sys.argv[1] == '--hg-individual-pages':
+ is_individual_pages_mode = True
+ del sys.argv[1]
+
core.publish_cmdline(writer_name=writer)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/templates/cmdheader.txt Mon Oct 09 22:14:24 2023 -0700
@@ -0,0 +1,22 @@
+.. _hg-%(cmdname)s.1:
+
+%(cmdtitle)s
+
+%(cmdshortdesc)s
+
+.. contents::
+ :backlinks: top
+ :class: htmlonly
+ :depth: 1
+
+Synopsis
+--------
+
+::
+
+ %(cmdsynopsis)s
+
+Description
+-----------
+%(cmdlongdesc)s
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/templates/extheader.txt Mon Oct 09 22:14:24 2023 -0700
@@ -0,0 +1,9 @@
+.. _ext-%(extname)s:
+
+%(exttitle)s
+
+.. contents::
+ :backlinks: top
+ :class: htmlonly
+ :depth: 2
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/templates/topicheader.txt Mon Oct 09 22:14:24 2023 -0700
@@ -0,0 +1,9 @@
+.. _topic-%(topicname)s:
+
+%(topictitle)s
+
+.. contents::
+ :backlinks: top
+ :class: htmlonly
+ :depth: 2
+