generated from executablebooks/mdformat-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: reorganize to match mdformat-admon design and test rendering
- Loading branch information
Showing
8 changed files
with
255 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from ._factories import ( | ||
AlertData, | ||
gfm_alert_plugin_factory, | ||
new_token, | ||
parse_possible_blockquote_admon_factory, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
"""GitHub Alerts.""" | ||
|
||
from __future__ import annotations | ||
|
||
import re | ||
from collections.abc import Generator | ||
from contextlib import contextmanager | ||
from typing import TYPE_CHECKING, Callable, NamedTuple | ||
|
||
from markdown_it import MarkdownIt | ||
from markdown_it.rules_block import StateBlock | ||
from mdit_py_plugins.utils import is_code_block | ||
|
||
if TYPE_CHECKING: | ||
from markdown_it.token import Token | ||
|
||
PREFIX = "gfm_alert" | ||
"""Prefix used to differentiate the parsed output.""" | ||
|
||
|
||
# FYI: copied from mdformat_admon.factories | ||
@contextmanager | ||
def new_token(state: StateBlock, name: str, kind: str) -> Generator[Token, None, None]: | ||
"""Creates scoped token.""" | ||
yield state.push(f"{name}_open", kind, 1) | ||
state.push(f"{name}_close", kind, -1) | ||
|
||
|
||
# FYI: Adapted from mdformat_admon.factories._factories | ||
class AlertState(NamedTuple): | ||
"""Frozen state.""" | ||
|
||
parentType: str | ||
lineMax: int | ||
|
||
|
||
class AlertData(NamedTuple): | ||
"""AlertData data for rendering.""" | ||
|
||
old_state: AlertState | ||
meta_text: str | ||
inline_content: str | ||
next_line: int | ||
|
||
|
||
def parse_possible_blockquote_admon_factory( | ||
patterns: set[str], | ||
) -> Callable[[StateBlock, int, int, bool], AlertData | bool]: | ||
"""Generate the parser function. | ||
Accepts set of strings that will be compiled into regular expressions. | ||
They must have a capture group `title`. | ||
""" | ||
|
||
def parse_possible_blockquote_admon( | ||
state: StateBlock, | ||
start_line: int, | ||
end_line: int, | ||
silent: bool, | ||
) -> AlertData | bool: | ||
if is_code_block(state, start_line): | ||
return False | ||
|
||
start = state.bMarks[start_line] + state.tShift[start_line] | ||
|
||
# Exit if no match for any pattern | ||
text = state.src[start:] | ||
regexes = [ | ||
re.compile(rf"{pat}(?P<inline_content>(?: |<br>)[^\n]+)?") | ||
for pat in patterns | ||
] | ||
match = next((_m for rx in regexes if (_m := rx.match(text))), None) | ||
if not match: | ||
return False | ||
|
||
# Since start is found, we can report success here in validation mode | ||
if silent: | ||
return True | ||
|
||
old_state = AlertState( | ||
parentType=state.parentType, | ||
lineMax=state.lineMax, | ||
) | ||
state.parentType = "gfm_alert" | ||
|
||
return AlertData( | ||
old_state=old_state, | ||
meta_text=match["title"], | ||
inline_content=match["inline_content"] or "", | ||
next_line=end_line, | ||
) | ||
|
||
return parse_possible_blockquote_admon | ||
|
||
|
||
def gfm_alert_plugin_factory( | ||
prefix: str, | ||
logic: Callable[[StateBlock, int, int, bool], bool], | ||
) -> Callable[[MarkdownIt], None]: | ||
"""Generate the plugin function.""" | ||
|
||
def gfm_alert_plugin(md: MarkdownIt) -> None: | ||
md.block.ruler.before("fence", prefix, logic) | ||
|
||
return gfm_alert_plugin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from ._gfm_alert import format_gfm_alert_markup, gfm_alert_plugin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
"""GitHub Alerts.""" | ||
|
||
from __future__ import annotations | ||
|
||
from markdown_it.rules_block import StateBlock | ||
|
||
from ..factories import ( | ||
AlertData, | ||
gfm_alert_plugin_factory, | ||
new_token, | ||
parse_possible_blockquote_admon_factory, | ||
) | ||
|
||
PREFIX = "gfm_alert" | ||
"""Prefix used to differentiate the parsed output.""" | ||
|
||
PATTERNS = { | ||
# Note '> ' prefix is removed when parsing | ||
r"^\*\*(?P<title>Note|Warning)\*\*", | ||
r"^\\?\[!(?P<title>NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\?\]", | ||
} | ||
"""Patterns specific to GitHub Alerts.""" | ||
|
||
|
||
def format_gfm_alert_markup( | ||
state: StateBlock, | ||
start_line: int, | ||
admonition: AlertData, | ||
) -> None: | ||
"""Format markup.""" | ||
with new_token(state, PREFIX, "div") as token: | ||
token.block = True | ||
token.attrs = {"class": f"admonition {admonition.meta_text.lower()}"} | ||
token.info = f"[!{admonition.meta_text.upper()}]{admonition.inline_content}" | ||
token.map = [start_line, admonition.next_line] | ||
|
||
state.md.block.tokenize(state, start_line + 1, admonition.next_line) | ||
|
||
# Render as a div for accessibility rather than block quote | ||
# Which is because '>' is being misused (https://github.com/orgs/community/discussions/16925#discussioncomment-8729846) | ||
state.parentType = "div" | ||
state.lineMax = admonition.old_state.lineMax | ||
state.line = admonition.next_line | ||
|
||
|
||
def alert_logic( | ||
state: StateBlock, | ||
startLine: int, | ||
endLine: int, | ||
silent: bool, | ||
) -> bool: | ||
"""Parse GitHub Alerts.""" | ||
parser_func = parse_possible_blockquote_admon_factory(PATTERNS) | ||
result = parser_func(state, startLine, endLine, silent) | ||
if isinstance(result, AlertData): | ||
format_gfm_alert_markup(state, startLine, admonition=result) | ||
return True | ||
return result | ||
|
||
|
||
gfm_alert_plugin = gfm_alert_plugin_factory(PREFIX, alert_logic) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
2023 Syntax | ||
. | ||
> [!NOTE] | ||
> Useful information that users should know, even when skimming content. | ||
. | ||
<blockquote> | ||
<div class="admonition note"> | ||
<p>Useful information that users should know, even when skimming content.</p> | ||
</div> | ||
</blockquote> | ||
. | ||
|
||
Replaces 2022 with 2023 Syntax | ||
. | ||
> **Warning** | ||
> This is a warning | ||
. | ||
<blockquote> | ||
<div class="admonition warning"> | ||
<p>This is a warning</p> | ||
</div> | ||
</blockquote> | ||
. |
Oops, something went wrong.