55import logging
66import re
77import warnings
8+ from abc import ABC , abstractmethod
9+ from dataclasses import dataclass
810from functools import lru_cache
911from html import escape , unescape
1012from html .parser import HTMLParser
2022from markdown .util import HTML_PLACEHOLDER_RE , INLINE_PLACEHOLDER_RE
2123
2224if TYPE_CHECKING :
25+ from pathlib import Path
26+
2327 from markdown import Markdown
2428
2529 from mkdocs_autorefs .plugin import AutorefsPlugin
@@ -59,10 +63,56 @@ def __getattr__(name: str) -> Any:
5963"""
6064
6165
66+ class AutorefsHookInterface (ABC ):
67+ """An interface for hooking into how AutoRef handles inline references."""
68+
69+ @dataclass
70+ class Context :
71+ """The context around an auto-reference."""
72+
73+ domain : str
74+ role : str
75+ origin : str
76+ filepath : str | Path
77+ lineno : int
78+
79+ def as_dict (self ) -> dict [str , str ]:
80+ """Convert the context to a dictionary of HTML attributes."""
81+ return {
82+ "domain" : self .domain ,
83+ "role" : self .role ,
84+ "origin" : self .origin ,
85+ "filepath" : str (self .filepath ),
86+ "lineno" : str (self .lineno ),
87+ }
88+
89+ @abstractmethod
90+ def expand_identifier (self , identifier : str ) -> str :
91+ """Expand an identifier in a given context.
92+
93+ Parameters:
94+ identifier: The identifier to expand.
95+
96+ Returns:
97+ The expanded identifier.
98+ """
99+ raise NotImplementedError
100+
101+ @abstractmethod
102+ def get_context (self ) -> AutorefsHookInterface .Context :
103+ """Get the current context.
104+
105+ Returns:
106+ The current context.
107+ """
108+ raise NotImplementedError
109+
110+
62111class AutorefsInlineProcessor (ReferenceInlineProcessor ):
63112 """A Markdown extension to handle inline references."""
64113
65114 name : str = "mkdocs-autorefs"
115+ hook : AutorefsHookInterface | None = None
66116
67117 def __init__ (self , * args : Any , ** kwargs : Any ) -> None : # noqa: D107
68118 super ().__init__ (REFERENCE_RE , * args , ** kwargs )
@@ -145,6 +195,9 @@ def _make_tag(self, identifier: str, text: str) -> Element:
145195 A new element.
146196 """
147197 el = Element ("autoref" )
198+ if self .hook :
199+ identifier = self .hook .expand_identifier (identifier )
200+ el .attrib .update (self .hook .get_context ().as_dict ())
148201 el .set ("identifier" , identifier )
149202 el .text = text
150203 return el
@@ -177,7 +230,10 @@ def relative_url(url_a: str, url_b: str) -> str:
177230
178231
179232# YORE: Bump 2: Remove block.
180- def _legacy_fix_ref (url_mapper : Callable [[str ], str ], unmapped : list [str ]) -> Callable :
233+ def _legacy_fix_ref (
234+ url_mapper : Callable [[str ], str ],
235+ unmapped : list [tuple [str , AutorefsHookInterface .Context | None ]],
236+ ) -> Callable :
181237 """Return a `repl` function for [`re.sub`](https://docs.python.org/3/library/re.html#re.sub).
182238
183239 In our context, we match Markdown references and replace them with HTML links.
@@ -210,7 +266,7 @@ def inner(match: Match) -> str:
210266 return title
211267 if kind == "autorefs-optional-hover" :
212268 return f'<span title="{ identifier } ">{ title } </span>'
213- unmapped .append (identifier )
269+ unmapped .append (( identifier , None ) )
214270 if title == identifier :
215271 return f"[{ identifier } ][]"
216272 return f"[{ title } ][{ identifier } ]"
@@ -233,7 +289,30 @@ def inner(match: Match) -> str:
233289
234290
235291class _AutorefsAttrs (dict ):
236- _handled_attrs : ClassVar [set [str ]] = {"identifier" , "optional" , "hover" , "class" }
292+ _handled_attrs : ClassVar [set [str ]] = {
293+ "identifier" ,
294+ "optional" ,
295+ "hover" ,
296+ "class" ,
297+ "domain" ,
298+ "role" ,
299+ "origin" ,
300+ "filepath" ,
301+ "lineno" ,
302+ }
303+
304+ @property
305+ def context (self ) -> AutorefsHookInterface .Context | None :
306+ try :
307+ return AutorefsHookInterface .Context (
308+ domain = self ["domain" ],
309+ role = self ["role" ],
310+ origin = self ["origin" ],
311+ filepath = self ["filepath" ],
312+ lineno = int (self ["lineno" ]),
313+ )
314+ except KeyError :
315+ return None
237316
238317 @property
239318 def remaining (self ) -> str :
@@ -257,7 +336,10 @@ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None
257336_html_attrs_parser = _HTMLAttrsParser ()
258337
259338
260- def fix_ref (url_mapper : Callable [[str ], str ], unmapped : list [str ]) -> Callable :
339+ def fix_ref (
340+ url_mapper : Callable [[str ], str ],
341+ unmapped : list [tuple [str , AutorefsHookInterface .Context | None ]],
342+ ) -> Callable :
261343 """Return a `repl` function for [`re.sub`](https://docs.python.org/3/library/re.html#re.sub).
262344
263345 In our context, we match Markdown references and replace them with HTML links.
@@ -290,7 +372,7 @@ def inner(match: Match) -> str:
290372 if hover :
291373 return f'<span title="{ identifier } ">{ title } </span>'
292374 return title
293- unmapped .append (identifier )
375+ unmapped .append (( identifier , attrs . context ) )
294376 if title == identifier :
295377 return f"[{ identifier } ][]"
296378 return f"[{ title } ][{ identifier } ]"
@@ -310,7 +392,12 @@ def inner(match: Match) -> str:
310392
311393
312394# YORE: Bump 2: Replace `, *, _legacy_refs: bool = True` with `` within line.
313- def fix_refs (html : str , url_mapper : Callable [[str ], str ], * , _legacy_refs : bool = True ) -> tuple [str , list [str ]]:
395+ def fix_refs (
396+ html : str ,
397+ url_mapper : Callable [[str ], str ],
398+ * ,
399+ _legacy_refs : bool = True ,
400+ ) -> tuple [str , list [tuple [str , AutorefsHookInterface .Context | None ]]]:
314401 """Fix all references in the given HTML text.
315402
316403 Arguments:
@@ -319,9 +406,9 @@ def fix_refs(html: str, url_mapper: Callable[[str], str], *, _legacy_refs: bool
319406 such as [mkdocs_autorefs.plugin.AutorefsPlugin.get_item_url][].
320407
321408 Returns:
322- The fixed HTML.
409+ The fixed HTML, and a list of unmapped identifiers (string and optional context) .
323410 """
324- unmapped : list [str ] = []
411+ unmapped : list [tuple [ str , AutorefsHookInterface . Context | None ] ] = []
325412 html = AUTOREF_RE .sub (fix_ref (url_mapper , unmapped ), html )
326413
327414 # YORE: Bump 2: Remove block.
0 commit comments