Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.12
rev: v0.16.6
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.20.2
rev: v2.3.1
hooks:
- id: mypy
additional_dependencies: [mdurl, typing-extensions]
Expand Down
22 changes: 12 additions & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,9 @@ from __future__ import annotations

from typing import Sequence


def parse_blocks(
state: StateBlock,
start_line: int,
end_line: int,
silent: bool = False
state: StateBlock, start_line: int, end_line: int, silent: bool = False
) -> bool:
"""Parse block-level content.

Expand Down Expand Up @@ -293,18 +291,20 @@ HTML Output
import pytest
from markdown_it import MarkdownIt


def test_basic_parsing():
md = MarkdownIt()
result = md.render("# Heading\n\nParagraph")
assert "<h1>Heading</h1>" in result
assert "<p>Paragraph</p>" in result


@pytest.mark.parametrize(
"input_text,expected",
[
("**bold**", "<strong>bold</strong>"),
("*italic*", "<em>italic</em>"),
]
],
)
def test_emphasis(input_text, expected):
md = MarkdownIt()
Expand Down Expand Up @@ -389,7 +389,7 @@ for token in tokens:
print(md.get_all_rules())

# Enable/disable specific rules
md.disable(['emphasis'])
md.disable(["emphasis"])
result = md.render("*text*") # Won't be emphasized
```

Expand All @@ -401,13 +401,13 @@ result = md.render("*text*") # Won't be emphasized
2. Create rule function in appropriate `rules_*/` directory
3. Rule signature for block rules:
```python
def rule_name(state: StateBlock, startLine: int, endLine: int, silent: bool) -> bool:
...
def rule_name(
state: StateBlock, startLine: int, endLine: int, silent: bool
) -> bool: ...
```
4. Rule signature for inline rules:
```python
def rule_name(state: StateInline, silent: bool) -> bool:
...
def rule_name(state: StateInline, silent: bool) -> bool: ...
```
5. Register the rule in the appropriate parser's `__init__` method
6. Add tests for the new rule
Expand All @@ -434,11 +434,13 @@ result = md.render("*text*") # Won't be emphasized
```python
from markdown_it import MarkdownIt


def render_custom_link(self, tokens, idx, options, env):
tokens[idx].attrSet("target", "_blank")
tokens[idx].attrSet("rel", "noopener noreferrer")
return self.renderToken(tokens, idx, options, env)


md = MarkdownIt()
md.add_render_rule("link_open", render_custom_link)
```
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ It can then be activated by:

```python
from markdown_it import MarkdownIt

md = MarkdownIt().enable("linkify")
md.options["linkify"] = True
```
Expand All @@ -284,6 +285,7 @@ It can be activated by:

```python
from markdown_it import MarkdownIt

md = MarkdownIt().enable("smartquotes")
md.options["typographer"] = True
```
Expand All @@ -304,6 +306,7 @@ This plugin can be activated by:
```python
from markdown_it import MarkdownIt
from markdown_it.extensions.tasklists import tasklists_plugin

md = MarkdownIt().use(tasklists_plugin)
```

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ from mdit_py_plugins.front_matter import front_matter_plugin
from mdit_py_plugins.footnote import footnote_plugin

md = (
MarkdownIt('commonmark', {'breaks':True,'html':True})
MarkdownIt("commonmark", {"breaks": True, "html": True})
.use(front_matter_plugin)
.use(footnote_plugin)
.enable('table')
.enable("table")
)
text = ("""
text = """
---
a: 1
---
Expand All @@ -86,7 +86,7 @@ a | b
A footnote [^1]

[^1]: some details
""")
"""
tokens = md.parse(text)
html_text = md.render(text)

Expand Down
21 changes: 14 additions & 7 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,31 +105,36 @@ with the same signature:

```python
def function(renderer, tokens, idx, options, env):
return htmlResult
return htmlResult
```

In many cases that allows easy output change even without parser intrusion.
For example, let's replace images with vimeo links to player's iframe:

```python
import re

md = MarkdownIt("commonmark")

vimeoRE = re.compile(r'^https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)')
vimeoRE = re.compile(r"^https?:\/\/(www\.)?vimeo.com\/(\d+)($|\/)")


def render_vimeo(self, tokens, idx, options, env):
token = tokens[idx]

if vimeoRE.match(token.attrs["src"]):

ident = vimeoRE.match(token.attrs["src"])[2]

return ('<div class="embed-responsive embed-responsive-16by9">\n' +
' <iframe class="embed-responsive-item" src="//player.vimeo.com/video/' +
ident + '"></iframe>\n' +
'</div>\n')
return (
'<div class="embed-responsive embed-responsive-16by9">\n'
+ ' <iframe class="embed-responsive-item" src="//player.vimeo.com/video/'
+ ident
+ '"></iframe>\n'
+ "</div>\n"
)
return self.image(tokens, idx, options, env)


md = MarkdownIt("commonmark")
md.add_render_rule("image", render_vimeo)
print(md.render("![](https://www.vimeo.com/123)"))
Expand All @@ -140,12 +145,14 @@ Here is another example, how to add `target="_blank"` to all links:
```python
from markdown_it import MarkdownIt


def render_blank_link(self, tokens, idx, options, env):
tokens[idx].attrSet("target", "_blank")

# pass token to default renderer.
return self.renderToken(tokens, idx, options, env)


md = MarkdownIt("commonmark")
md.add_render_rule("link_open", render_blank_link)
print(md.render("[a]\n\n[a]: b"))
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"Path",
"Ellipsis",
"NotRequired",
"Self",
)
]

Expand Down
7 changes: 5 additions & 2 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ These can be enabled individually:

```python
from markdown_it import MarkdownIt
md = MarkdownIt("commonmark").enable('table')

md = MarkdownIt("commonmark").enable("table")
```

or as part of a configuration:

```python
from markdown_it import MarkdownIt
md = MarkdownIt("gfm-like") # tables, strikethrough, linkify

md = MarkdownIt("gfm-like") # tables, strikethrough, linkify
md = MarkdownIt("gfm-like2") # + task lists, alerts, single-tilde strikethrough
```

Expand Down Expand Up @@ -48,6 +50,7 @@ They can be chained and loaded *via*:
```python
from markdown_it import MarkdownIt
from mdit_py_plugins import plugin1, plugin2

md = MarkdownIt().use(plugin1, keyword=value).use(plugin2, keyword=value)
html_string = md.render("some *Markdown*")
```
2 changes: 1 addition & 1 deletion docs/using.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ with the same signature:

```python
def function(renderer, tokens, idx, options, env):
return htmlResult
return htmlResult
```

+++
Expand Down
1 change: 0 additions & 1 deletion markdown_it/cli/parse.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
"""
CLI interface to markdown-it-py

Expand Down
2 changes: 1 addition & 1 deletion markdown_it/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def replaceEntityPattern(match: str, name: str) -> str:
if name in entities:
return entities[name]

code: None | int = None
code: int | None = None
if pat := DIGITAL_ENTITY_BASE10_RE.fullmatch(name):
code = int(pat.group(1), 10)
elif pat := DIGITAL_ENTITY_BASE16_RE.fullmatch(name):
Expand Down
2 changes: 1 addition & 1 deletion markdown_it/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(self, parser: Any = None):
self.rules = {
k: v
for k, v in inspect.getmembers(self, predicate=inspect.ismethod)
if not (k.startswith("render") or k.startswith("_"))
if not k.startswith(("render", "_"))
}

def render(
Expand Down
4 changes: 2 additions & 2 deletions markdown_it/rules_block/fence.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ def make_fence_rule(
closing_matcher: Callable[[int, int], bool]
if exact_match:
# closing code fence must have exactly the same number of markers as the opening one
closing_matcher = lambda opening_len, closing_len: closing_len == opening_len # noqa: E731
closing_matcher = lambda opening_len, closing_len: closing_len == opening_len
else:
# closing code fence must be at least as long as the opening one
closing_matcher = lambda opening_len, closing_len: closing_len >= opening_len # noqa: E731
closing_matcher = lambda opening_len, closing_len: closing_len >= opening_len

def _fence_rule(
state: StateBlock, startLine: int, endLine: int, silent: bool
Expand Down
2 changes: 1 addition & 1 deletion markdown_it/rules_block/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def reference(state: StateBlock, startLine: int, _endLine: int, silent: bool) ->
return True


def getNextLine(state: StateBlock, nextLine: int) -> None | str:
def getNextLine(state: StateBlock, nextLine: int) -> str | None:
endLine = state.lineMax

if nextLine >= endLine or state.isEmpty(nextLine):
Expand Down
4 changes: 2 additions & 2 deletions markdown_it/rules_core/smartquotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def process_inlines(tokens: list[Token], state: StateCore) -> None:

# Find previous character,
# default to space if it's the beginning of the line
lastChar: None | int = 0x20
lastChar: int | None = 0x20

if t.start(0) + lastIndex - 1 >= 0:
lastChar = charCodeAt(text, t.start(0) + lastIndex - 1)
Expand All @@ -75,7 +75,7 @@ def process_inlines(tokens: list[Token], state: StateCore) -> None:

# Find next character,
# default to space if it's the end of the line
nextChar: None | int = 0x20
nextChar: int | None = 0x20

if pos < maximum:
nextChar = charCodeAt(text, pos)
Expand Down
4 changes: 2 additions & 2 deletions markdown_it/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ def attrPush(self, attrData: tuple[str, str | int | float]) -> None:
name, value = attrData
self.attrSet(name, value)

def attrSet(self, name: str, value: str | int | float) -> None:
def attrSet(self, name: str, value: str | float) -> None:
"""Set `name` attribute to `value`. Override old value if exists."""
self.attrs[name] = value

def attrGet(self, name: str) -> None | str | int | float:
def attrGet(self, name: str) -> str | int | float | None:
"""Get the value of attribute `name`, or null if it does not exist."""
return self.attrs.get(name, None)

Expand Down
Loading
Loading