From 9904ae00f86c79936d20b561a5b5cd660bf40ab9 Mon Sep 17 00:00:00 2001
From: Oleh Prypin
Date: Fri, 23 Feb 2024 13:51:34 +0100
Subject: [PATCH 1/3] feat: Support [`identifier`][] with pymdownx.inlinehilite
enabled
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Timothée Mazzucotelli
---
pyproject.toml | 2 ++
src/mkdocs_autorefs/references.py | 5 ++++-
tests/test_references.py | 25 ++++++++++++++++++++++++-
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index eec6329..691dd27 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -34,6 +34,7 @@ classifiers = [
]
dependencies = [
"Markdown>=3.3",
+ "markupsafe>=2.0.1",
"mkdocs>=1.1",
]
@@ -90,6 +91,7 @@ tests = [
"pytest-cov>=4.1",
"pytest-randomly>=3.15",
"pytest-xdist>=3.3",
+ "pymdown-extensions>=10.0",
]
typing = [
"mypy>=1.5",
diff --git a/src/mkdocs_autorefs/references.py b/src/mkdocs_autorefs/references.py
index 66b4931..78d9b82 100644
--- a/src/mkdocs_autorefs/references.py
+++ b/src/mkdocs_autorefs/references.py
@@ -8,9 +8,10 @@
from urllib.parse import urlsplit
from xml.etree.ElementTree import Element
+import markupsafe
from markdown.extensions import Extension
from markdown.inlinepatterns import REFERENCE_RE, ReferenceInlineProcessor
-from markdown.util import INLINE_PLACEHOLDER_RE
+from markdown.util import HTML_PLACEHOLDER_RE, INLINE_PLACEHOLDER_RE
if TYPE_CHECKING:
from markdown import Markdown
@@ -88,6 +89,8 @@ def evalId(self, data: str, index: int, text: str) -> EvalIDType: # noqa: N802
# https://github.com/Python-Markdown/markdown/blob/1858c1b601ead62ed49646ae0d99298f41b1a271/markdown/inlinepatterns.py#L78
if INLINE_PLACEHOLDER_RE.fullmatch(identifier):
identifier = self.unescape(identifier)
+ if match := HTML_PLACEHOLDER_RE.fullmatch(identifier):
+ identifier = markupsafe.Markup(self.md.htmlStash.rawHtmlBlocks[int(match.group(1))]).striptags()
end = m.end(0)
return identifier, end, True
diff --git a/tests/test_references.py b/tests/test_references.py
index 5a25844..37937fb 100644
--- a/tests/test_references.py
+++ b/tests/test_references.py
@@ -2,6 +2,8 @@
from __future__ import annotations
+from typing import Mapping
+
import markdown
import pytest
@@ -44,6 +46,7 @@ def run_references_test(
output: str,
unmapped: list[str] | None = None,
from_url: str = "page.html",
+ extensions: Mapping = {},
) -> None:
"""Help running tests about references.
@@ -54,7 +57,7 @@ def run_references_test(
unmapped: The expected unmapped list.
from_url: The source page URL.
"""
- md = markdown.Markdown(extensions=[AutorefsExtension()])
+ md = markdown.Markdown(extensions=[AutorefsExtension(), *extensions], extension_configs=extensions)
content = md.convert(source)
def url_mapper(identifier: str) -> str:
@@ -92,6 +95,26 @@ def test_reference_implicit_with_code() -> None:
)
+def test_reference_implicit_with_code_inlinehilite_plain() -> None:
+ """Check implicit references (identifier in backticks, wrapped by inlinehilite)."""
+ run_references_test(
+ extensions={"pymdownx.inlinehilite": {}},
+ url_map={"pathlib.Path": "pathlib.html#Path"},
+ source="This [`pathlib.Path`][].",
+ output='This pathlib.Path
.
',
+ )
+
+
+def test_reference_implicit_with_code_inlinehilite_python() -> None:
+ """Check implicit references (identifier in backticks, syntax-highlighted by inlinehilite)."""
+ run_references_test(
+ extensions={"pymdownx.inlinehilite": {"style_plain_text": "python"}},
+ url_map={"pathlib.Path": "pathlib.html#Path"},
+ source="This [`pathlib.Path`][].",
+ output='This pathlib
.Path.
',
+ )
+
+
def test_reference_with_punctuation() -> None:
"""Check references with punctuation."""
run_references_test(
From 1ecd2a36d819f81bde16c56364f7f06dd996e4ae Mon Sep 17 00:00:00 2001
From: Oleh Prypin
Date: Fri, 23 Feb 2024 14:09:45 +0100
Subject: [PATCH 2/3] fixup! feat: Support [`identifier`][] with
pymdownx.inlinehilite enabled
---
pyproject.toml | 3 ++-
tests/test_references.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/pyproject.toml b/pyproject.toml
index 691dd27..d341542 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -87,11 +87,12 @@ quality = [
"ruff>=0.0",
]
tests = [
+ "pygments>=2.16",
+ "pymdown-extensions>=10.0",
"pytest>=7.4",
"pytest-cov>=4.1",
"pytest-randomly>=3.15",
"pytest-xdist>=3.3",
- "pymdown-extensions>=10.0",
]
typing = [
"mypy>=1.5",
diff --git a/tests/test_references.py b/tests/test_references.py
index 37937fb..9b29ede 100644
--- a/tests/test_references.py
+++ b/tests/test_references.py
@@ -108,7 +108,7 @@ def test_reference_implicit_with_code_inlinehilite_plain() -> None:
def test_reference_implicit_with_code_inlinehilite_python() -> None:
"""Check implicit references (identifier in backticks, syntax-highlighted by inlinehilite)."""
run_references_test(
- extensions={"pymdownx.inlinehilite": {"style_plain_text": "python"}},
+ extensions={"pymdownx.inlinehilite": {"style_plain_text": "python"}, "pymdownx.highlight": {}},
url_map={"pathlib.Path": "pathlib.html#Path"},
source="This [`pathlib.Path`][].",
output='This pathlib
.Path.
',
From 15ace7c0d9cb618e4c98184fe9fd8128e7f5cba6 Mon Sep 17 00:00:00 2001
From: Oleh Prypin
Date: Fri, 23 Feb 2024 15:50:30 +0100
Subject: [PATCH 3/3] fixup! fixup! feat: Support [`identifier`][] with
pymdownx.inlinehilite enabled
---
src/mkdocs_autorefs/references.py | 29 +++++++++++++++++------------
tests/test_references.py | 2 +-
2 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/src/mkdocs_autorefs/references.py b/src/mkdocs_autorefs/references.py
index 78d9b82..a4d2ab6 100644
--- a/src/mkdocs_autorefs/references.py
+++ b/src/mkdocs_autorefs/references.py
@@ -4,7 +4,7 @@
import re
from html import escape, unescape
-from typing import TYPE_CHECKING, Any, Callable, Match, Tuple
+from typing import TYPE_CHECKING, Any, Callable, Match
from urllib.parse import urlsplit
from xml.etree.ElementTree import Element
@@ -25,8 +25,6 @@
in the [`on_post_page` hook][mkdocs_autorefs.plugin.AutorefsPlugin.on_post_page].
"""
-EvalIDType = Tuple[Any, Any, Any]
-
class AutoRefInlineProcessor(ReferenceInlineProcessor):
"""A Markdown extension."""
@@ -37,7 +35,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: D107
# Code based on
# https://github.com/Python-Markdown/markdown/blob/8e7528fa5c98bf4652deb13206d6e6241d61630b/markdown/inlinepatterns.py#L780
- def handleMatch(self, m: Match[str], data: Any) -> Element | EvalIDType: # type: ignore[override] # noqa: N802
+ def handleMatch(self, m: Match[str], data: str) -> tuple[Element | None, int | None, int | None]: # type: ignore[override] # noqa: N802
"""Handle an element that matched.
Arguments:
@@ -52,7 +50,7 @@ def handleMatch(self, m: Match[str], data: Any) -> Element | EvalIDType: # type
return None, None, None
identifier, end, handled = self.evalId(data, index, text)
- if not handled:
+ if not handled or identifier is None:
return None, None, None
if re.search(r"[/ \x00-\x1f]", identifier):
@@ -62,9 +60,9 @@ def handleMatch(self, m: Match[str], data: Any) -> Element | EvalIDType: # type
# but references with Markdown formatting are not possible anyway.
return None, m.start(0), end
- return self.makeTag(identifier, text), m.start(0), end
+ return self._make_tag(identifier, text), m.start(0), end
- def evalId(self, data: str, index: int, text: str) -> EvalIDType: # noqa: N802 (parent's casing)
+ def evalId(self, data: str, index: int, text: str) -> tuple[str | None, int, bool]: # noqa: N802 (parent's casing)
"""Evaluate the id portion of `[ref][id]`.
If `[ref][]` use `[ref]`.
@@ -87,15 +85,22 @@ def evalId(self, data: str, index: int, text: str) -> EvalIDType: # noqa: N802
# Allow the entire content to be one placeholder, with the intent of catching things like [`Foo`][].
# It doesn't catch [*Foo*][] though, just due to the priority order.
# https://github.com/Python-Markdown/markdown/blob/1858c1b601ead62ed49646ae0d99298f41b1a271/markdown/inlinepatterns.py#L78
- if INLINE_PLACEHOLDER_RE.fullmatch(identifier):
- identifier = self.unescape(identifier)
- if match := HTML_PLACEHOLDER_RE.fullmatch(identifier):
- identifier = markupsafe.Markup(self.md.htmlStash.rawHtmlBlocks[int(match.group(1))]).striptags()
+ if match := INLINE_PLACEHOLDER_RE.fullmatch(identifier):
+ stashed_nodes: dict[str, Element | str] = self.md.treeprocessors["inline"].stashed_nodes # type: ignore[attr-defined]
+ el = stashed_nodes.get(match[1])
+ if isinstance(el, Element) and el.tag == "code":
+ identifier = "".join(el.itertext())
+ # Special case: allow pymdownx.inlinehilite raw snippets but strip them back to unhighlighted.
+ if match := HTML_PLACEHOLDER_RE.fullmatch(identifier):
+ stash_index = int(match.group(1))
+ html = self.md.htmlStash.rawHtmlBlocks[stash_index]
+ identifier = markupsafe.Markup(html).striptags()
+ self.md.htmlStash.rawHtmlBlocks[stash_index] = escape(identifier)
end = m.end(0)
return identifier, end, True
- def makeTag(self, identifier: str, text: str) -> Element: # type: ignore[override] # noqa: N802
+ def _make_tag(self, identifier: str, text: str) -> Element:
"""Create a tag that can be matched by `AUTO_REF_RE`.
Arguments:
diff --git a/tests/test_references.py b/tests/test_references.py
index 9b29ede..02b3f50 100644
--- a/tests/test_references.py
+++ b/tests/test_references.py
@@ -111,7 +111,7 @@ def test_reference_implicit_with_code_inlinehilite_python() -> None:
extensions={"pymdownx.inlinehilite": {"style_plain_text": "python"}, "pymdownx.highlight": {}},
url_map={"pathlib.Path": "pathlib.html#Path"},
source="This [`pathlib.Path`][].",
- output='This pathlib
.Path
.
',
+ output='This pathlib.Path
.
',
)