Fix anchor links

This commit is contained in:
Jan Dittberner 2021-09-04 19:54:24 +02:00
parent 1451a5a1c0
commit d1a151f8bd
2 changed files with 40 additions and 30 deletions

View file

@ -62,12 +62,13 @@ class IPV4RangeDirective(IPRangeDirective):
title_prefix = _("IPv4 range") title_prefix = _("IPv4 range")
def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None: 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 = self.env.get_domain("ip")
ips.add_ip4_range(sig) ips.add_ip4_range(sig)
idx_text = "{}; {}".format(self.title_prefix, name) idx_text = "{}; {}".format(self.title_prefix, name)
self.indexnode["entries"] = [ self.indexnode["entries"] = [
("single", idx_text, name, "", None), ("single", idx_text, anchor, "", None),
] ]
@ -75,12 +76,13 @@ class IPV6RangeDirective(IPRangeDirective):
title_prefix = _("IPv6 range") title_prefix = _("IPv6 range")
def add_target_and_index(self, name: T, sig: str, signode: desc_signature) -> None: 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 = self.env.get_domain("ip")
ips.add_ip6_range(sig) ips.add_ip6_range(sig)
idx_text = "{}; {}".format(self.title_prefix, name) idx_text = "{}; {}".format(self.title_prefix, name)
self.indexnode["entries"] = [ 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) node_list, message = super().result_nodes(document, env, node, is_ref)
ip = env.get_domain("ip") 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 return node_list, message
if ( if (
self.reftype in ["v4range", "v6range"] self.reftype in ["v4range", "v6range"]
@ -130,7 +132,11 @@ class IPXRefRole(XRefRole):
return node_list, message return node_list, message
index_node = addnodes.index() 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]) target_node = nodes.target("", "", ids=[target_id])
doc_title = next(d for d in document.traverse(nodes.title)).astext() doc_title = next(d for d in document.traverse(nodes.title)).astext()
@ -175,10 +181,9 @@ class IPDomain(Domain):
initial_data = { initial_data = {
"range_nodes": [], "range_nodes": [],
"ip_refs": [], "ip_refs": defaultdict(list),
"range_refs": [], "range_refs": [],
"ranges": defaultdict(list), "ranges": defaultdict(list),
"ips": defaultdict(list),
"ip_dict": {}, "ip_dict": {},
} }
@ -218,23 +223,15 @@ class IPDomain(Domain):
self._add_ip_address_reference("v6", ip_address) self._add_ip_address_reference("v6", ip_address)
def _add_ip_address_reference(self, family, sig): def _add_ip_address_reference(self, family, sig):
name = "ip{}.{}".format(family, sig) try:
anchor = "ip-ip{}-{}".format(family, sig) 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: try:
ip = IP(sig) ip = IP(sig)
self.data["ip_refs"].append( self.data["ip_refs"][sig].append((ip, docname, anchor))
(
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
except ValueError as e: except ValueError as e:
logger.error("invalid ip address '%s': %s", sig, e) logger.error("invalid ip address '%s': %s", sig, e)
@ -276,13 +273,25 @@ class IPDomain(Domain):
contnode: nodes.Element, contnode: nodes.Element,
) -> Optional[nodes.Element]: ) -> Optional[nodes.Element]:
match = [] 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"): if typ in ("v4", "v6"):
# reference to IP range # reference to IP range
if target not in self.data["ip_dict"]: if target not in self.data["ip_dict"]:
# invalid ip address # invalid ip address
raise NoUri(target) raise NoUri(target)
match = [ match = [
(docname, anchor) address_tuple(docname, anchor, ip_range)
for ip_range, docname, anchor in [ for ip_range, docname, anchor in [
r r
for range_nodes in self.data["ranges"].values() for range_nodes in self.data["ranges"].values()
@ -293,7 +302,7 @@ class IPDomain(Domain):
elif typ in ("v4range", "v6range"): elif typ in ("v4range", "v6range"):
if target in self.data["ranges"]: if target in self.data["ranges"]:
match = [ match = [
(docname, anchor) address_tuple(docname, anchor, ip_range)
for ip_range, docname, anchor in [ for ip_range, docname, anchor in [
range_nodes for range_nodes in self.data["ranges"][target] range_nodes for range_nodes in self.data["ranges"][target]
] ]
@ -301,8 +310,9 @@ class IPDomain(Domain):
if len(match) > 0: if len(match) > 0:
todocname = match[0][0] todocname = match[0][0]
targ = match[0][1] 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: else:
logger.error("found no link target for %s", target) logger.error("found no link target for %s", target)
return None return None
@ -319,7 +329,7 @@ def process_ip_nodes(app, doctree, fromdocname):
content = [] content = []
net = Network(node["range_spec"]) net = Network(node["range_spec"])
addresses = defaultdict(list) 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: for ip_address, todocname, anchor in refs:
if ip_address in net: if ip_address in net:
addresses[ip_address_sig].append((ip_address, todocname, anchor)) addresses[ip_address_sig].append((ip_address, todocname, anchor))

View file

@ -32,7 +32,7 @@ class TestIPExtension(unittest.TestCase):
self.assertIn("range_refs", ipdomdata) self.assertIn("range_refs", ipdomdata)
self.assertIn("range_nodes", ipdomdata) self.assertIn("range_nodes", ipdomdata)
self.assertIn("ranges", ipdomdata) self.assertIn("ranges", ipdomdata)
self.assertIn("ips", ipdomdata) self.assertIn("ip_dict", ipdomdata)
def find_in_index(self, entry): def find_in_index(self, entry):
indexentries = self.app.env.get_domain("index").entries indexentries = self.app.env.get_domain("index").entries
@ -43,14 +43,14 @@ class TestIPExtension(unittest.TestCase):
self.fail("%s not found in index" % entry) self.fail("%s not found in index" % entry)
def test_ip4_addresses(self): 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: for ip in IP4_ADDRESSES:
self.assertIn(ip, ips) self.assertIn(ip, ips)
self.find_in_index("IPv4 address; %s" % ip) self.find_in_index("IPv4 address; %s" % ip)
self.find_in_index("%s; Test page 2" % ip) self.find_in_index("%s; Test page 2" % ip)
def test_ip6_addresses(self): 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: for ip in IP6_ADDRESSES:
self.assertIn(ip, ips) self.assertIn(ip, ips)
self.find_in_index("IPv6 address; %s" % ip) self.find_in_index("IPv6 address; %s" % ip)