Skip to content

Commit b653e01

Browse files
committed
chore: Reorganize code within modules
1 parent 3b769b7 commit b653e01

File tree

2 files changed

+422
-417
lines changed

2 files changed

+422
-417
lines changed

src/mkdocs_autorefs/_internal/plugin.py

Lines changed: 181 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,169 @@ def __init__(self) -> None:
152152
self._link_titles: bool | Literal["external"] = True
153153
self._strip_title_tags: bool = False
154154

155-
# YORE: Bump 2: Remove block.
156-
@property
157-
def get_fallback_anchor(self) -> Callable[[str], tuple[str, ...]] | None:
158-
"""Fallback anchors getter."""
159-
return self._get_fallback_anchor
155+
# ----------------------------------------------------------------------- #
156+
# MkDocs Hooks #
157+
# ----------------------------------------------------------------------- #
158+
def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
159+
"""Instantiate our Markdown extension.
160160
161-
# YORE: Bump 2: Remove block.
162-
@get_fallback_anchor.setter
163-
def get_fallback_anchor(self, value: Callable[[str], tuple[str, ...]] | None) -> None:
164-
"""Fallback anchors setter."""
165-
self._get_fallback_anchor = value
166-
if value is not None:
167-
warn(
168-
"Setting a fallback anchor function is deprecated and will be removed in a future release.",
169-
DeprecationWarning,
170-
stacklevel=2,
171-
)
161+
Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config).
162+
In this hook, we instantiate our [`AutorefsExtension`][mkdocs_autorefs.AutorefsExtension]
163+
and add it to the list of Markdown extensions used by `mkdocs`.
164+
165+
Arguments:
166+
config: The MkDocs config object.
167+
168+
Returns:
169+
The modified config.
170+
"""
171+
_log.debug("Adding AutorefsExtension to the list")
172+
config.markdown_extensions.append(AutorefsExtension(self)) # type: ignore[arg-type]
173+
174+
# YORE: Bump 2: Remove block.
175+
# mkdocstrings still uses the `page` attribute as a string.
176+
# Fortunately, it does so in f-strings, so we can simply patch the `__str__` method
177+
# to render the URL.
178+
Page.__str__ = lambda page: page.url # type: ignore[method-assign,attr-defined]
179+
180+
if self.config.link_titles == "auto":
181+
if getattr(config.theme, "name", None) == "material" and "navigation.instant.preview" in config.theme.get(
182+
"features",
183+
(),
184+
):
185+
self._link_titles = "external"
186+
else:
187+
self._link_titles = True
188+
else:
189+
self._link_titles = self.config.link_titles
190+
191+
if self.config.strip_title_tags == "auto":
192+
if getattr(config.theme, "name", None) == "material":
193+
self._strip_title_tags = False
194+
else:
195+
self._strip_title_tags = True
196+
else:
197+
self._strip_title_tags = self.config.strip_title_tags
198+
199+
return config
200+
201+
def on_page_markdown(self, markdown: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
202+
"""Remember which page is the current one.
203+
204+
Arguments:
205+
markdown: Input Markdown.
206+
page: The related MkDocs page instance.
207+
kwargs: Additional arguments passed by MkDocs.
208+
209+
Returns:
210+
The same Markdown. We only use this hook to keep a reference to the current page URL,
211+
used during Markdown conversion by the anchor scanner tree processor.
212+
"""
213+
# YORE: Bump 2: Remove line.
214+
self._url_to_page[page.url] = page
215+
self.current_page = page
216+
return markdown
217+
218+
def on_page_content(self, html: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
219+
"""Map anchors to URLs.
220+
221+
Hook for the [`on_page_content` event](https://www.mkdocs.org/user-guide/plugins/#on_page_content).
222+
In this hook, we map the IDs of every anchor found in the table of contents to the anchors absolute URLs.
223+
This mapping will be used later to fix unresolved reference of the form `[title][identifier]` or
224+
`[identifier][]`.
225+
226+
Arguments:
227+
html: HTML converted from Markdown.
228+
page: The related MkDocs page instance.
229+
kwargs: Additional arguments passed by MkDocs.
230+
231+
Returns:
232+
The same HTML. We only use this hook to map anchors to URLs.
233+
"""
234+
self.current_page = page
235+
# Collect `std`-domain URLs.
236+
if self.scan_toc:
237+
_log.debug("Mapping identifiers to URLs for page %s", page.file.src_path)
238+
for item in page.toc.items:
239+
self.map_urls(page, item)
240+
return html
241+
242+
@event_priority(-50) # Late, after mkdocstrings has finished loading inventories.
243+
def on_env(self, env: Environment, /, *, config: MkDocsConfig, files: Files) -> Environment: # noqa: ARG002
244+
"""Apply cross-references and collect backlinks.
245+
246+
Hook for the [`on_env` event](https://www.mkdocs.org/user-guide/plugins/#on_env).
247+
In this hook, we try to fix unresolved references of the form `[title][identifier]` or `[identifier][]`.
248+
Doing that allows the user of `autorefs` to cross-reference objects in their documentation strings.
249+
It uses the native Markdown syntax so it's easy to remember and use.
250+
251+
We log a warning for each reference that we couldn't map to an URL.
252+
253+
We also collect backlinks at the same time. We fix cross-refs and collect backlinks in a single pass
254+
for performance reasons (we don't want to run the regular expression on each page twice).
255+
256+
Arguments:
257+
env: The MkDocs environment.
258+
config: The MkDocs config object.
259+
files: The list of files in the MkDocs project.
260+
261+
Returns:
262+
The unmodified environment.
263+
"""
264+
for file in files:
265+
if file.page and file.page.content:
266+
_log.debug("Applying cross-refs in page %s", file.page.file.src_path)
267+
268+
# YORE: Bump 2: Replace `, fallback=self.get_fallback_anchor` with `` within line.
269+
url_mapper = functools.partial(
270+
self.get_item_url,
271+
from_url=file.page.url,
272+
fallback=self.get_fallback_anchor,
273+
)
274+
backlink_recorder = (
275+
functools.partial(self._record_backlink, page_url=file.page.url) if self.record_backlinks else None
276+
)
277+
# YORE: Bump 2: Replace `, _legacy_refs=self.legacy_refs` with `` within line.
278+
file.page.content, unmapped = fix_refs(
279+
file.page.content,
280+
url_mapper,
281+
record_backlink=backlink_recorder,
282+
link_titles=self._link_titles,
283+
strip_title_tags=self._strip_title_tags,
284+
_legacy_refs=self.legacy_refs,
285+
)
286+
287+
if unmapped and _log.isEnabledFor(logging.WARNING):
288+
for ref, context in unmapped:
289+
message = f"from {context.filepath}:{context.lineno}: ({context.origin}) " if context else ""
290+
_log.warning(
291+
f"{file.page.file.src_path}: {message}Could not find cross-reference target '{ref}'",
292+
)
293+
294+
return env
295+
296+
# ----------------------------------------------------------------------- #
297+
# Utilities #
298+
# ----------------------------------------------------------------------- #
299+
def map_urls(self, page: Page, anchor: AnchorLink) -> None:
300+
"""Recurse on every anchor to map its ID to its absolute URL.
301+
302+
This method populates `self._primary_url_map` by side-effect.
303+
304+
Arguments:
305+
page: The page containing the anchors.
306+
anchor: The anchor to process and to recurse on.
307+
"""
308+
# YORE: Bump 2: Remove block.
309+
if isinstance(page, str):
310+
try:
311+
page = self._url_to_page[page]
312+
except KeyError:
313+
page = self.current_page
314+
315+
self.register_anchor(page, anchor.id, title=anchor.title, primary=True)
316+
for child in anchor.children:
317+
self.map_urls(page, child)
172318

173319
def _record_backlink(self, identifier: str, backlink_type: str, backlink_anchor: str, page_url: str) -> None:
174320
"""Record a backlink.
@@ -366,160 +512,23 @@ def get_item_url(
366512
url = relative_url(from_url, url)
367513
return url, title
368514

369-
def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
370-
"""Instantiate our Markdown extension.
371-
372-
Hook for the [`on_config` event](https://www.mkdocs.org/user-guide/plugins/#on_config).
373-
In this hook, we instantiate our [`AutorefsExtension`][mkdocs_autorefs.AutorefsExtension]
374-
and add it to the list of Markdown extensions used by `mkdocs`.
375-
376-
Arguments:
377-
config: The MkDocs config object.
378-
379-
Returns:
380-
The modified config.
381-
"""
382-
_log.debug("Adding AutorefsExtension to the list")
383-
config.markdown_extensions.append(AutorefsExtension(self)) # type: ignore[arg-type]
384-
385-
# YORE: Bump 2: Remove block.
386-
# mkdocstrings still uses the `page` attribute as a string.
387-
# Fortunately, it does so in f-strings, so we can simply patch the `__str__` method
388-
# to render the URL.
389-
Page.__str__ = lambda page: page.url # type: ignore[method-assign,attr-defined]
390-
391-
if self.config.link_titles == "auto":
392-
if getattr(config.theme, "name", None) == "material" and "navigation.instant.preview" in config.theme.get(
393-
"features",
394-
(),
395-
):
396-
self._link_titles = "external"
397-
else:
398-
self._link_titles = True
399-
else:
400-
self._link_titles = self.config.link_titles
401-
402-
if self.config.strip_title_tags == "auto":
403-
if getattr(config.theme, "name", None) == "material":
404-
self._strip_title_tags = False
405-
else:
406-
self._strip_title_tags = True
407-
else:
408-
self._strip_title_tags = self.config.strip_title_tags
409-
410-
return config
411-
412-
def on_page_markdown(self, markdown: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
413-
"""Remember which page is the current one.
414-
415-
Arguments:
416-
markdown: Input Markdown.
417-
page: The related MkDocs page instance.
418-
kwargs: Additional arguments passed by MkDocs.
419-
420-
Returns:
421-
The same Markdown. We only use this hook to keep a reference to the current page URL,
422-
used during Markdown conversion by the anchor scanner tree processor.
423-
"""
424-
# YORE: Bump 2: Remove line.
425-
self._url_to_page[page.url] = page
426-
self.current_page = page
427-
return markdown
428-
429-
def on_page_content(self, html: str, page: Page, **kwargs: Any) -> str: # noqa: ARG002
430-
"""Map anchors to URLs.
431-
432-
Hook for the [`on_page_content` event](https://www.mkdocs.org/user-guide/plugins/#on_page_content).
433-
In this hook, we map the IDs of every anchor found in the table of contents to the anchors absolute URLs.
434-
This mapping will be used later to fix unresolved reference of the form `[title][identifier]` or
435-
`[identifier][]`.
436-
437-
Arguments:
438-
html: HTML converted from Markdown.
439-
page: The related MkDocs page instance.
440-
kwargs: Additional arguments passed by MkDocs.
441-
442-
Returns:
443-
The same HTML. We only use this hook to map anchors to URLs.
444-
"""
445-
self.current_page = page
446-
# Collect `std`-domain URLs.
447-
if self.scan_toc:
448-
_log.debug("Mapping identifiers to URLs for page %s", page.file.src_path)
449-
for item in page.toc.items:
450-
self.map_urls(page, item)
451-
return html
452-
453-
def map_urls(self, page: Page, anchor: AnchorLink) -> None:
454-
"""Recurse on every anchor to map its ID to its absolute URL.
455-
456-
This method populates `self._primary_url_map` by side-effect.
457-
458-
Arguments:
459-
page: The page containing the anchors.
460-
anchor: The anchor to process and to recurse on.
461-
"""
462-
# YORE: Bump 2: Remove block.
463-
if isinstance(page, str):
464-
try:
465-
page = self._url_to_page[page]
466-
except KeyError:
467-
page = self.current_page
468-
469-
self.register_anchor(page, anchor.id, title=anchor.title, primary=True)
470-
for child in anchor.children:
471-
self.map_urls(page, child)
472-
473-
@event_priority(-50) # Late, after mkdocstrings has finished loading inventories.
474-
def on_env(self, env: Environment, /, *, config: MkDocsConfig, files: Files) -> Environment: # noqa: ARG002
475-
"""Apply cross-references and collect backlinks.
476-
477-
Hook for the [`on_env` event](https://www.mkdocs.org/user-guide/plugins/#on_env).
478-
In this hook, we try to fix unresolved references of the form `[title][identifier]` or `[identifier][]`.
479-
Doing that allows the user of `autorefs` to cross-reference objects in their documentation strings.
480-
It uses the native Markdown syntax so it's easy to remember and use.
481-
482-
We log a warning for each reference that we couldn't map to an URL.
483-
484-
We also collect backlinks at the same time. We fix cross-refs and collect backlinks in a single pass
485-
for performance reasons (we don't want to run the regular expression on each page twice).
486-
487-
Arguments:
488-
env: The MkDocs environment.
489-
config: The MkDocs config object.
490-
files: The list of files in the MkDocs project.
491-
492-
Returns:
493-
The unmodified environment.
494-
"""
495-
for file in files:
496-
if file.page and file.page.content:
497-
_log.debug("Applying cross-refs in page %s", file.page.file.src_path)
498-
499-
# YORE: Bump 2: Replace `, fallback=self.get_fallback_anchor` with `` within line.
500-
url_mapper = functools.partial(
501-
self.get_item_url,
502-
from_url=file.page.url,
503-
fallback=self.get_fallback_anchor,
504-
)
505-
backlink_recorder = (
506-
functools.partial(self._record_backlink, page_url=file.page.url) if self.record_backlinks else None
507-
)
508-
# YORE: Bump 2: Replace `, _legacy_refs=self.legacy_refs` with `` within line.
509-
file.page.content, unmapped = fix_refs(
510-
file.page.content,
511-
url_mapper,
512-
record_backlink=backlink_recorder,
513-
link_titles=self._link_titles,
514-
strip_title_tags=self._strip_title_tags,
515-
_legacy_refs=self.legacy_refs,
516-
)
517-
518-
if unmapped and _log.isEnabledFor(logging.WARNING):
519-
for ref, context in unmapped:
520-
message = f"from {context.filepath}:{context.lineno}: ({context.origin}) " if context else ""
521-
_log.warning(
522-
f"{file.page.file.src_path}: {message}Could not find cross-reference target '{ref}'",
523-
)
515+
# YORE: Bump 2: Remove block.
516+
# ----------------------------------------------------------------------- #
517+
# Deprecated API #
518+
# ----------------------------------------------------------------------- #
519+
@property
520+
def get_fallback_anchor(self) -> Callable[[str], tuple[str, ...]] | None:
521+
"""Fallback anchors getter."""
522+
return self._get_fallback_anchor
524523

525-
return env
524+
# YORE: Bump 2: Remove block.
525+
@get_fallback_anchor.setter
526+
def get_fallback_anchor(self, value: Callable[[str], tuple[str, ...]] | None) -> None:
527+
"""Fallback anchors setter."""
528+
self._get_fallback_anchor = value
529+
if value is not None:
530+
warn(
531+
"Setting a fallback anchor function is deprecated and will be removed in a future release.",
532+
DeprecationWarning,
533+
stacklevel=2,
534+
)

0 commit comments

Comments
 (0)