From d1a151f8bd80c7d0e9121b2bd09d21e4ab3bfc16 Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Sat, 4 Sep 2021 19:54:24 +0200 Subject: [PATCH] Fix anchor links --- jandd/sphinxext/ip.py | 64 +++++++++++++++++++++++++------------------ tests/test_ip.py | 6 ++-- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/jandd/sphinxext/ip.py b/jandd/sphinxext/ip.py index 03c7bf3..4e527b5 100644 --- a/jandd/sphinxext/ip.py +++ b/jandd/sphinxext/ip.py @@ -62,12 +62,13 @@ class IPV4RangeDirective(IPRangeDirective): title_prefix = _("IPv4 range") def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None: - signode["ids"].append("ip4_range" + "-" + sig) + anchor = "ip-ipv4range-{0}".format(sig) + signode["ids"].append(anchor) ips = self.env.get_domain("ip") ips.add_ip4_range(sig) idx_text = "{}; {}".format(self.title_prefix, name) self.indexnode["entries"] = [ - ("single", idx_text, name, "", None), + ("single", idx_text, anchor, "", None), ] @@ -75,12 +76,13 @@ class IPV6RangeDirective(IPRangeDirective): title_prefix = _("IPv6 range") def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None: - signode["ids"].append("ip6_range" + "-" + sig) + anchor = "ip-ipv6range-{0}".format(sig) + signode["ids"].append(anchor) ips = self.env.get_domain("ip") ips.add_ip6_range(sig) idx_text = "{}; {}".format(self.title_prefix, name) self.indexnode["entries"] = [ - ("single", idx_text, name, "", None), + ("single", idx_text, anchor, "", None), ] @@ -121,7 +123,7 @@ class IPXRefRole(XRefRole): node_list, message = super().result_nodes(document, env, node, is_ref) ip = env.get_domain("ip") - if self.reftype in ["v4", "v6"] and self.target not in ip.data["ips"]: + if self.reftype in ["v4", "v6"] and self.target not in ip.data["ip_dict"]: return node_list, message if ( self.reftype in ["v4range", "v6range"] @@ -130,7 +132,11 @@ class IPXRefRole(XRefRole): return node_list, message index_node = addnodes.index() - target_id = "index-{}".format(env.new_serialno("index")) + target_id = "ip-{}-{}".format(self.reftype, env.new_serialno("index")) + + if self.reftype in ["v4", "v6"]: + ip.add_ip_address_anchor(self.target, env.docname, target_id) + target_node = nodes.target("", "", ids=[target_id]) doc_title = next(d for d in document.traverse(nodes.title)).astext() @@ -175,10 +181,9 @@ class IPDomain(Domain): initial_data = { "range_nodes": [], - "ip_refs": [], + "ip_refs": defaultdict(list), "range_refs": [], "ranges": defaultdict(list), - "ips": defaultdict(list), "ip_dict": {}, } @@ -218,23 +223,15 @@ class IPDomain(Domain): self._add_ip_address_reference("v6", ip_address) def _add_ip_address_reference(self, family, sig): - name = "ip{}.{}".format(family, sig) - anchor = "ip-ip{}-{}".format(family, sig) + try: + self.data["ip_dict"][sig] = IP(sig) + except ValueError as e: + logger.error("invalid ip address '%s': %s", sig, e) + + def add_ip_address_anchor(self, sig, docname, anchor): try: ip = IP(sig) - self.data["ip_refs"].append( - ( - name, - sig, - "IP{}".format(family), - str(ip), - self.env.docname, - anchor, - 0, - ) - ) - self.data["ips"][sig].append((ip, self.env.docname, anchor)) - self.data["ip_dict"][sig] = ip + self.data["ip_refs"][sig].append((ip, docname, anchor)) except ValueError as e: logger.error("invalid ip address '%s': %s", sig, e) @@ -276,13 +273,25 @@ class IPDomain(Domain): contnode: nodes.Element, ) -> Optional[nodes.Element]: match = [] + + def address_tuple(docname, anchor, ip_range) -> Tuple[str, str, str]: + return ( + docname, + anchor, + _( + "IPv{0} range {1}".format( + ip_range.version(), ip_range.to_compressed() + ) + ), + ) + if typ in ("v4", "v6"): # reference to IP range if target not in self.data["ip_dict"]: # invalid ip address raise NoUri(target) match = [ - (docname, anchor) + address_tuple(docname, anchor, ip_range) for ip_range, docname, anchor in [ r for range_nodes in self.data["ranges"].values() @@ -293,7 +302,7 @@ class IPDomain(Domain): elif typ in ("v4range", "v6range"): if target in self.data["ranges"]: match = [ - (docname, anchor) + address_tuple(docname, anchor, ip_range) for ip_range, docname, anchor in [ range_nodes for range_nodes in self.data["ranges"][target] ] @@ -301,8 +310,9 @@ class IPDomain(Domain): if len(match) > 0: todocname = match[0][0] targ = match[0][1] + title = match[0][2] - return make_refnode(builder, fromdocname, todocname, targ, contnode, targ) + return make_refnode(builder, fromdocname, todocname, targ, contnode, title) else: logger.error("found no link target for %s", target) return None @@ -319,7 +329,7 @@ def process_ip_nodes(app, doctree, fromdocname): content = [] net = Network(node["range_spec"]) addresses = defaultdict(list) - for ip_address_sig, refs in ips.data["ips"].items(): + for ip_address_sig, refs in ips.data["ip_refs"].items(): for ip_address, todocname, anchor in refs: if ip_address in net: addresses[ip_address_sig].append((ip_address, todocname, anchor)) diff --git a/tests/test_ip.py b/tests/test_ip.py index 7c3cf7d..082ee67 100644 --- a/tests/test_ip.py +++ b/tests/test_ip.py @@ -32,7 +32,7 @@ class TestIPExtension(unittest.TestCase): self.assertIn("range_refs", ipdomdata) self.assertIn("range_nodes", ipdomdata) self.assertIn("ranges", ipdomdata) - self.assertIn("ips", ipdomdata) + self.assertIn("ip_dict", ipdomdata) def find_in_index(self, entry): indexentries = self.app.env.get_domain("index").entries @@ -43,14 +43,14 @@ class TestIPExtension(unittest.TestCase): self.fail("%s not found in index" % entry) def test_ip4_addresses(self): - ips = self.app.env.domaindata["ip"]["ips"] + ips = self.app.env.domaindata["ip"]["ip_refs"] for ip in IP4_ADDRESSES: self.assertIn(ip, ips) self.find_in_index("IPv4 address; %s" % ip) self.find_in_index("%s; Test page 2" % ip) def test_ip6_addresses(self): - ips = self.app.env.domaindata["ip"]["ips"] + ips = self.app.env.domaindata["ip"]["ip_refs"] for ip in IP6_ADDRESSES: self.assertIn(ip, ips) self.find_in_index("IPv6 address; %s" % ip)