Skip to content

Commit

Permalink
Support multiple targets on one section
Browse files Browse the repository at this point in the history
Apply transform before PropagateTargets to special-case the first target and
prioritize its ID and name

Changelog: add::
  • Loading branch information
GeeTransit committed Mar 4, 2024
1 parent a198c5d commit 6638490
Showing 1 changed file with 47 additions and 7 deletions.
54 changes: 47 additions & 7 deletions sphinx_better_subsection.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ class PreferSectionTarget(Transform):
Nested subsections are also checked.
"""
# Post processing priority from
# https://www.sphinx-doc.org/en/master/extdev/appapi.html?highlight=transform#sphinx.application.Sphinx.add_transform
default_priority = 700
# Run before `docutils.transforms.references.PropagateTransform` which has
# priority 260.
default_priority = 255

def apply(self):
"""Docutils transform entry point"""
Expand All @@ -79,14 +79,54 @@ def apply(self):
# Filter away nodes that aren't targets
if not isinstance(last, nodes.target):
continue
# Internal hyperlink targets have refid (external ones have refuri)
if "refid" not in last:
# Filter away targets with content
if (
isinstance(last.parent, nodes.TextElement)
or last.hasattr("refid")
or last.hasattr("refuri")
or last.hasattr("refname")
):
continue
refid = last["refid"]
assert refid in node["ids"]

# Store ID and name
refname = last["names"][0]
refid = last["ids"][0]

# Propagate the previous target
# Source from `PropagateTargets.apply`
node["ids"].extend(last["ids"])
node["names"].extend(last["names"])
# Set defaults for node.expect_referenced_by_name/id.
if not hasattr(node, "expect_referenced_by_name"):
node.expect_referenced_by_name = {}
if not hasattr(node, "expect_referenced_by_id"):
node.expect_referenced_by_id = {}
for id_ in last["ids"]:
node.expect_referenced_by_id[id_] = last
# Update IDs to node mapping.
self.document.ids[id_] = node
last["ids"] = []
for name in last["names"]:
node.expect_referenced_by_name[name] = last
last["names"] = []
# If there are any expect_referenced_by_name/id attributes in
# target set, copy them to node.
node.expect_referenced_by_name.update(
getattr(last, "expect_referenced_by_name", {}))
node.expect_referenced_by_id.update(
getattr(last, "expect_referenced_by_id", {}))
# Set refid to point to the first former ID of target which is now
# an ID of next_node.
last["refid"] = refid
self.document.note_refid(last)
# End source

# Prefer the target's ID
node["ids"].remove(refid)
node["ids"].insert(0, refid)
# Also prefer the target's name
node["names"].remove(refname)
node["names"].insert(0, refname)

def setup(app):
"""Sphinx extension entry point"""
Expand Down

0 comments on commit 6638490

Please sign in to comment.