Skip to content

Commit

Permalink
feat: add priority option
Browse files Browse the repository at this point in the history
  • Loading branch information
percevalw committed Jun 8, 2023
1 parent 4a45c3b commit e19b9fa
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ plugins:
- autorefs
```
If a heading title that appears several times throughout the site, set the priority parameter to decide which page will be linked. The priority list follows the gitignore syntax and is tested in reverse: each anchor will be assigned the lowest priority amongst all of its matches.
```yaml
# mkdocs.yml
plugins:
- search
- autorefs:
priority:
- '*' # priority to all files
- reference # except reference/... files
```
In one of your Markdown files (e.g. `doc1.md`) create some headings:

```markdown
Expand All @@ -48,8 +60,6 @@ This works the same as [a normal link to that heading](../doc1.md#hello-world).

Linking to a heading without needing to know the destination page can be useful if specifying that path is cumbersome, e.g. when the pages have deeply nested paths, are far apart, or are moved around frequently. And the issue is somewhat exacerbated by the fact that [MkDocs supports only *relative* links between pages](https://github.com/mkdocs/mkdocs/issues/1592).

Note that this plugin's behavior is undefined when trying to link to a heading title that appears several times throughout the site. Currently it arbitrarily chooses one of the pages.

## Requirements

mkdocs-autorefs requires Python 3.7 or above.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ classifiers = [
dependencies = [
"Markdown>=3.3",
"mkdocs>=1.1",
"pathspec>=0.11.1"
]

[project.urls]
Expand Down
34 changes: 33 additions & 1 deletion src/mkdocs_autorefs/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,21 @@
import contextlib
import functools
import logging
from typing import Callable, Dict, Optional, Sequence
from typing import Callable, Dict, List, Optional, Sequence
from urllib.parse import urlsplit
from pathlib import Path
import pathspec

import mkdocs
from mkdocs.config import Config
from mkdocs.config.defaults import MkDocsConfig
from mkdocs.plugins import BasePlugin
from mkdocs.structure.pages import Page
from mkdocs.structure.toc import AnchorLink
from mkdocs.utils import warning_filter

from mkdocs_autorefs.references import AutorefsExtension, fix_refs, relative_url
from mkdocs.config import config_options as c

log = logging.getLogger(f"mkdocs.plugins.{__name__}")
log.addFilter(warning_filter)
Expand All @@ -43,13 +48,26 @@ class AutorefsPlugin(BasePlugin):

scan_toc: bool = True
current_page: Optional[str] = None
config_scheme = (
('priority', c.ListOfItems(c.Type(str), default=[])),
)

def __init__(self) -> None:
"""Initialize the object."""
super().__init__()
self._url_map: Dict[str, str] = {}
self._abs_url_map: Dict[str, str] = {}
self.get_fallback_anchor: Optional[Callable[[str], Optional[str]]] = None # noqa: WPS234
self._priority_patterns = None

@property
def priority_patterns(self):
if self._priority_patterns is None:
self._priority_patterns = [
pathspec.patterns.GitWildMatchPattern(pat)
for pat in self.config.get('priority')
]
return self._priority_patterns

def register_anchor(self, page: str, identifier: str):
"""Register that an anchor corresponding to an identifier was encountered when rendering the page.
Expand All @@ -58,6 +76,20 @@ def register_anchor(self, page: str, identifier: str):
page: The relative URL of the current page. Examples: `'foo/bar/'`, `'foo/index.html'`
identifier: The HTML anchor (without '#') as a string.
"""
if identifier in self._url_map:
rev_patterns = list(enumerate(self.priority_patterns))[::-1]
old_priority_idx = next(
(i for i, pat in rev_patterns
if pat.match_file(self._url_map[identifier])),
len(rev_patterns),
)
new_priority_idx = next(
(i for i, pat in rev_patterns
if pat.match_file(page)),
len(rev_patterns),
)
if new_priority_idx >= old_priority_idx:
return
self._url_map[identifier] = f"{page}#{identifier}"

def register_url(self, identifier: str, url: str):
Expand Down
12 changes: 11 additions & 1 deletion tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Tests for the plugin module."""
import pytest

from mkdocs_autorefs.plugin import AutorefsPlugin


Expand Down Expand Up @@ -57,3 +56,14 @@ def test_dont_make_relative_urls_relative_again():
plugin.get_item_url("hello", from_url="baz/bar/foo.html", fallback=lambda _: ("foo.bar.baz",))
== "../../foo/bar/baz.html#foo.bar.baz"
)


def test_priority_config():
"""Check that URLs are not made relative more than once."""
plugin = AutorefsPlugin()
plugin.config = {"priority": ["*", "reference", "foo"]}
plugin.register_anchor(identifier="bar.baz", page="reference/baz.html")
plugin.register_anchor(identifier="bar.baz", page="baz.html")
plugin.register_anchor(identifier="bar.baz", page="foo/bar/baz.html")

assert plugin.get_item_url("bar.baz") == "baz.html#bar.baz"

0 comments on commit e19b9fa

Please sign in to comment.