summaryrefslogtreecommitdiffstats
path: root/sphinx/ext/autosectionlabel.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/ext/autosectionlabel.py')
-rw-r--r--sphinx/ext/autosectionlabel.py69
1 files changed, 69 insertions, 0 deletions
diff --git a/sphinx/ext/autosectionlabel.py b/sphinx/ext/autosectionlabel.py
new file mode 100644
index 0000000..d423fcc
--- /dev/null
+++ b/sphinx/ext/autosectionlabel.py
@@ -0,0 +1,69 @@
+"""Allow reference sections by :ref: role using its title."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, cast
+
+from docutils import nodes
+
+import sphinx
+from sphinx.domains.std import StandardDomain
+from sphinx.locale import __
+from sphinx.util import logging
+from sphinx.util.nodes import clean_astext
+
+if TYPE_CHECKING:
+ from docutils.nodes import Node
+
+ from sphinx.application import Sphinx
+
+logger = logging.getLogger(__name__)
+
+
+def get_node_depth(node: Node) -> int:
+ i = 0
+ cur_node = node
+ while cur_node.parent != node.document:
+ cur_node = cur_node.parent
+ i += 1
+ return i
+
+
+def register_sections_as_label(app: Sphinx, document: Node) -> None:
+ domain = cast(StandardDomain, app.env.get_domain('std'))
+ for node in document.findall(nodes.section):
+ if (app.config.autosectionlabel_maxdepth and
+ get_node_depth(node) >= app.config.autosectionlabel_maxdepth):
+ continue
+ labelid = node['ids'][0]
+ docname = app.env.docname
+ title = cast(nodes.title, node[0])
+ ref_name = getattr(title, 'rawsource', title.astext())
+ if app.config.autosectionlabel_prefix_document:
+ name = nodes.fully_normalize_name(docname + ':' + ref_name)
+ else:
+ name = nodes.fully_normalize_name(ref_name)
+ sectname = clean_astext(title)
+
+ logger.debug(__('section "%s" gets labeled as "%s"'),
+ ref_name, name,
+ location=node, type='autosectionlabel', subtype=docname)
+ if name in domain.labels:
+ logger.warning(__('duplicate label %s, other instance in %s'),
+ name, app.env.doc2path(domain.labels[name][0]),
+ location=node, type='autosectionlabel', subtype=docname)
+
+ domain.anonlabels[name] = docname, labelid
+ domain.labels[name] = docname, labelid, sectname
+
+
+def setup(app: Sphinx) -> dict[str, Any]:
+ app.add_config_value('autosectionlabel_prefix_document', False, 'env')
+ app.add_config_value('autosectionlabel_maxdepth', None, 'env')
+ app.connect('doctree-read', register_sections_as_label)
+
+ return {
+ 'version': sphinx.__display_version__,
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }