Skip to content

Commit 5218c55

Browse files
committed
fix(#54): add 4-space indented deflists
1 parent 18a85b6 commit 5218c55

File tree

8 files changed

+352
-0
lines changed

8 files changed

+352
-0
lines changed

mdformat_mkdocs/mdit_plugins/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
MATERIAL_CONTENT_TAB_MARKERS,
66
material_content_tabs_plugin,
77
)
8+
from ._material_deflist import (
9+
escape_deflist,
10+
render_material_definition_body,
11+
render_material_definition_list,
12+
render_material_definition_term,
13+
)
814
from ._mkdocstrings_autorefs import (
915
MKDOCSTRINGS_AUTOREFS_PREFIX,
1016
MKDOCSTRINGS_HEADING_AUTOREFS_PREFIX,
@@ -33,6 +39,7 @@
3339
"PYMD_CAPTIONS_PREFIX",
3440
"PYMD_SNIPPET_PREFIX",
3541
"PYTHON_MARKDOWN_ATTR_LIST_PREFIX",
42+
"escape_deflist",
3643
"material_admon_plugin",
3744
"material_content_tabs_plugin",
3845
"mkdocstrings_autorefs_plugin",
@@ -42,4 +49,7 @@
4249
"pymd_captions_plugin",
4350
"pymd_snippet_plugin",
4451
"python_markdown_attr_list_plugin",
52+
"render_material_definition_body",
53+
"render_material_definition_list",
54+
"render_material_definition_term",
4555
)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""Material Definition Lists.
2+
3+
Based on
4+
[mdformat-deflist](https://github.com/executablebooks/mdformat-deflist/blob/bbcf9ed4f80847db58b6f932ed95e2c7a6c49ae5/mdformat_deflist/plugin.py),
5+
but modified for mkdocs-material conventions.
6+
7+
Example:
8+
```md
9+
`Lorem ipsum dolor sit amet`
10+
11+
: Sed sagittis eleifend rutrum. Donec vitae suscipit est. Nullam tempus
12+
tellus non sem sollicitudin, quis rutrum leo facilisis.
13+
14+
`Cras arcu libero`
15+
16+
: Aliquam metus eros, pretium sed nulla venenatis, faucibus auctor ex. Proin
17+
ut eros sed sapien ullamcorper consequat. Nunc ligula ante.
18+
19+
Duis mollis est eget nibh volutpat, fermentum aliquet dui mollis.
20+
Name vulputate tincidunt fringilla.
21+
Nullam dignissim ultrices urna non auctor.
22+
```
23+
24+
Docs:
25+
<https://squidfunk.github.io/mkdocs-material/reference/lists/#using-definition-lists>
26+
27+
"""
28+
29+
from __future__ import annotations
30+
31+
from mdformat.renderer import RenderContext, RenderTreeNode
32+
from mdformat.renderer.typing import Render
33+
34+
35+
def make_render_children(separator: str) -> Render:
36+
"""Create a renderer that joins child nodes with a separator."""
37+
38+
def render_children(
39+
node: RenderTreeNode,
40+
context: RenderContext,
41+
) -> str:
42+
return separator.join(child.render(context) for child in node.children)
43+
44+
return render_children
45+
46+
47+
def render_material_definition_list() -> str:
48+
"""Render Material Definition List."""
49+
return make_render_children("\n")
50+
51+
52+
def render_material_definition_term() -> str:
53+
"""Render Material Definition Term."""
54+
return make_render_children("\n")
55+
56+
57+
def render_material_definition_body(
58+
node: RenderTreeNode,
59+
context: RenderContext,
60+
) -> str:
61+
"""Render the definition body."""
62+
tight_list = all(
63+
child.type != "paragraph" or child.hidden for child in node.children
64+
)
65+
marker = ": " # FYI: increased for material
66+
indent_width = len(marker)
67+
context.env["indent_width"] += indent_width
68+
try:
69+
text = make_render_children("\n\n")(node, context)
70+
lines = text.splitlines()
71+
if not lines:
72+
return ":"
73+
indented_lines = [f"{marker}{lines[0]}"] + [
74+
f"{' ' * indent_width}{line}" if line else "" for line in lines[1:]
75+
]
76+
indented_lines = ("" if tight_list else "\n") + "\n".join(indented_lines)
77+
next_sibling = node.next_sibling
78+
return indented_lines + (
79+
"\n" if (next_sibling and next_sibling.type == "dt") else ""
80+
)
81+
finally:
82+
context.env["indent_width"] -= indent_width
83+
84+
85+
def escape_deflist(
86+
text: str,
87+
node: RenderTreeNode, # noqa: ARG001
88+
context: RenderContext, # noqa: ARG001
89+
) -> str:
90+
"""Escape line starting ":" which would otherwise be parsed as a definition list."""
91+
return "\n".join(
92+
"\\" + line if line.startswith(":") else line for line in text.split("\n")
93+
)

mdformat_mkdocs/plugin.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import TYPE_CHECKING
88

99
from mdformat.renderer import DEFAULT_RENDERERS, RenderContext, RenderTreeNode
10+
from mdit_py_plugins.deflist import deflist_plugin
1011

1112
from ._helpers import ContextOptions, get_conf
1213
from ._normalize_list import normalize_list as unbounded_normalize_list
@@ -28,6 +29,9 @@
2829
pymd_captions_plugin,
2930
pymd_snippet_plugin,
3031
python_markdown_attr_list_plugin,
32+
render_material_definition_body,
33+
render_material_definition_list,
34+
render_material_definition_term,
3135
)
3236

3337
if TYPE_CHECKING:
@@ -82,6 +86,7 @@ def update_mdit(mdit: MarkdownIt) -> None:
8286
mdit.use(material_admon_plugin)
8387
mdit.use(pymd_captions_plugin)
8488
mdit.use(material_content_tabs_plugin)
89+
mdit.use(deflist_plugin) # TODO: convert material_deflist to normal plugin
8590
mdit.use(mkdocstrings_autorefs_plugin)
8691
mdit.use(pymd_abbreviations_plugin)
8792
mdit.use(pymd_admon_plugin)
@@ -205,6 +210,9 @@ def render_pymd_caption(node: RenderTreeNode, context: RenderContext) -> str:
205210
"admonition_mkdocs_title": render_admon_title,
206211
"content_tab_mkdocs": add_extra_admon_newline,
207212
"content_tab_mkdocs_title": render_admon_title,
213+
"dl": render_material_definition_list,
214+
"dt": render_material_definition_term,
215+
"dd": render_material_definition_body,
208216
PYMD_CAPTIONS_PREFIX: render_pymd_caption,
209217
MKDOCSTRINGS_AUTOREFS_PREFIX: _render_meta_content,
210218
MKDOCSTRINGS_CROSSREFERENCE_PREFIX: _render_cross_reference,
@@ -229,4 +237,5 @@ def render_pymd_caption(node: RenderTreeNode, context: RenderContext) -> str:
229237
"bullet_list": normalize_list,
230238
"inline": postprocess_list_wrap, # type: ignore[has-type]
231239
"ordered_list": normalize_list,
240+
"paragraph": escape_deflist,
232241
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
Pandoc (with slightly changed indents):
2+
.
3+
paragraph
4+
5+
Term 1
6+
7+
: Definition 1
8+
9+
Term 2 with *inline markup*
10+
11+
: Definition 2
12+
13+
{ some code, part of Definition 2 }
14+
15+
Third paragraph of definition 2.
16+
17+
paragraph
18+
.
19+
paragraph
20+
21+
Term 1
22+
23+
: Definition 1
24+
25+
Term 2 with *inline markup*
26+
27+
: Definition 2
28+
29+
```
30+
{ some code, part of Definition 2 }
31+
```
32+
33+
Third paragraph of definition 2.
34+
35+
paragraph
36+
.
37+
38+
Pandoc 2:
39+
40+
.
41+
Term 1
42+
43+
: Definition
44+
with lazy continuation.
45+
46+
Second paragraph of the definition.
47+
.
48+
Term 1
49+
50+
: Definition
51+
with lazy continuation.
52+
53+
Second paragraph of the definition.
54+
.
55+
56+
Pandoc 3
57+
.
58+
paragraph
59+
60+
Term 1
61+
~ Definition 1
62+
63+
Term 2
64+
~ Definition 2a
65+
~ Definition 2b
66+
67+
paragraph
68+
.
69+
paragraph
70+
71+
Term 1
72+
: Definition 1
73+
74+
Term 2
75+
: Definition 2a
76+
: Definition 2b
77+
78+
paragraph
79+
.
80+
81+
Spaces after a colon:
82+
.
83+
Term 1
84+
: paragraph
85+
86+
Term 2
87+
: code block
88+
.
89+
Term 1
90+
: paragraph
91+
92+
Term 2
93+
: ```
94+
code block
95+
```
96+
.
97+
98+
List is tight, only if all dts are tight:
99+
.
100+
Term 1
101+
: foo
102+
: bar
103+
104+
Term 2
105+
: foo
106+
107+
: bar
108+
.
109+
Term 1
110+
111+
: foo
112+
113+
: bar
114+
115+
Term 2
116+
117+
: foo
118+
119+
: bar
120+
.
121+
122+
123+
Regression test (first paragraphs shouldn't be tight):
124+
.
125+
Term 1
126+
: foo
127+
128+
bar
129+
130+
Term 2
131+
: foo
132+
.
133+
Term 1
134+
135+
: foo
136+
137+
bar
138+
139+
Term 2
140+
141+
: foo
142+
.
143+
144+
Nested definition lists:
145+
146+
.
147+
test
148+
: foo
149+
: bar
150+
: baz
151+
: bar
152+
: foo
153+
.
154+
test
155+
: foo
156+
: bar
157+
: baz
158+
: bar
159+
: foo
160+
.
161+
162+
Regression test (blockquote inside deflist)
163+
.
164+
foo
165+
: > bar
166+
: baz
167+
.
168+
foo
169+
: > bar
170+
: baz
171+
.
172+
173+
Escaped deflist
174+
175+
.
176+
Term 1
177+
\: Definition
178+
.
179+
Term 1
180+
\: Definition
181+
.

tests/format/test_format.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def flatten(nested_list: list[list[T]]) -> list[T]:
2222
read_fixture_file(Path(__file__).parent / "fixtures" / fixture_path)
2323
for fixture_path in (
2424
"material_content_tabs.md",
25+
"material_deflist.md",
2526
"mkdocstrings_autorefs.md",
2627
"pymd_abbreviations.md",
2728
"pymd_snippet.md",

tests/pre-commit-test.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,27 @@ graph TD;
332332
```
333333

334334
[external link]: https://github.com/czuli/github-markdown-example/tree/7326f19c94be992319394e5bfeaa07b30f858e46
335+
336+
______________________________________________________________________
337+
338+
# Deflist Test
339+
340+
From [`mdformat-deflist`](https://github.com/executablebooks/mdformat-deflist/blob/bbcf9ed4f80847db58b6f932ed95e2c7a6c49ae5/tests/pre-commit-test.md)
341+
342+
paragraph
343+
344+
Term 1
345+
346+
: Definition 1
347+
348+
Term 2 with *inline markup*
349+
350+
: Definition 2
351+
352+
```
353+
{ some code, part of Definition 2 }
354+
```
355+
356+
Third paragraph of definition 2.
357+
358+
paragraph

0 commit comments

Comments
 (0)