markdown_convert 1.2.46__py3-none-any.whl → 1.2.47__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- markdown_convert/default.css +23 -3
- markdown_convert/modules/convert.py +3 -6
- markdown_convert/modules/transform.py +65 -63
- {markdown_convert-1.2.46.dist-info → markdown_convert-1.2.47.dist-info}/METADATA +1 -1
- {markdown_convert-1.2.46.dist-info → markdown_convert-1.2.47.dist-info}/RECORD +8 -8
- {markdown_convert-1.2.46.dist-info → markdown_convert-1.2.47.dist-info}/WHEEL +0 -0
- {markdown_convert-1.2.46.dist-info → markdown_convert-1.2.47.dist-info}/entry_points.txt +0 -0
- {markdown_convert-1.2.46.dist-info → markdown_convert-1.2.47.dist-info}/licenses/LICENSE +0 -0
markdown_convert/default.css
CHANGED
|
@@ -181,7 +181,7 @@ p > img + em {
|
|
|
181
181
|
font-style: italic;
|
|
182
182
|
color: var(--color-text-light);
|
|
183
183
|
display: block;
|
|
184
|
-
margin:
|
|
184
|
+
margin: 0 auto;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/* Image alt text attributes */
|
|
@@ -212,6 +212,22 @@ img[alt*="::wide::"] {
|
|
|
212
212
|
max-width: 100vw;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
p:has(> img[alt*="::left::"]) {
|
|
216
|
+
display: flex;
|
|
217
|
+
flex-direction: column;
|
|
218
|
+
width: fit-content;
|
|
219
|
+
margin-right: auto;
|
|
220
|
+
align-items: center;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
p:has(> img[alt*="::right::"]) {
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
width: fit-content;
|
|
227
|
+
margin-left: auto;
|
|
228
|
+
align-items: center;
|
|
229
|
+
}
|
|
230
|
+
|
|
215
231
|
p:has(> img[alt*="::inline::"]) {
|
|
216
232
|
display: inline-block;
|
|
217
233
|
width: min-content;
|
|
@@ -391,8 +407,7 @@ math {
|
|
|
391
407
|
.keyboard,
|
|
392
408
|
.key {
|
|
393
409
|
font-family:
|
|
394
|
-
"Segoe UI Symbol", "DejaVu Sans", "Liberation Sans", "Arial",
|
|
395
|
-
"sans-serif";
|
|
410
|
+
"Segoe UI Symbol", "DejaVu Sans", "Liberation Sans", "Arial", "sans-serif";
|
|
396
411
|
font-size: 0.9rem;
|
|
397
412
|
background-color: var(--color-text-background);
|
|
398
413
|
border: 1px solid var(--color-border);
|
|
@@ -400,3 +415,8 @@ math {
|
|
|
400
415
|
padding: 0.1em 0.4em;
|
|
401
416
|
box-shadow: rgba(100, 100, 100, 0.4) 0px 2px 4px 0px;
|
|
402
417
|
}
|
|
418
|
+
|
|
419
|
+
.center {
|
|
420
|
+
display: block;
|
|
421
|
+
text-align: center;
|
|
422
|
+
}
|
|
@@ -18,8 +18,7 @@ from .transform import (
|
|
|
18
18
|
create_sections,
|
|
19
19
|
render_mermaid_diagrams,
|
|
20
20
|
create_html_document,
|
|
21
|
-
|
|
22
|
-
create_spans,
|
|
21
|
+
render_extra_features,
|
|
23
22
|
)
|
|
24
23
|
from .utils import drop_duplicates
|
|
25
24
|
|
|
@@ -135,8 +134,7 @@ def convert(
|
|
|
135
134
|
html = markdown2.markdown_path(markdown_path, extras=MARKDOWN_EXTENSIONS)
|
|
136
135
|
html = create_sections(html)
|
|
137
136
|
html = render_mermaid_diagrams(html, nonce=nonce)
|
|
138
|
-
html =
|
|
139
|
-
html = create_spans(html)
|
|
137
|
+
html = render_extra_features(html)
|
|
140
138
|
|
|
141
139
|
_generate_pdf_with_playwright(
|
|
142
140
|
html,
|
|
@@ -207,8 +205,7 @@ def convert_text(markdown_text, css_text=None, *, extend_default_css=True):
|
|
|
207
205
|
html = markdown2.markdown(markdown_text, extras=MARKDOWN_EXTENSIONS)
|
|
208
206
|
html = create_sections(html)
|
|
209
207
|
html = render_mermaid_diagrams(html, nonce=nonce)
|
|
210
|
-
html =
|
|
211
|
-
html = create_spans(html)
|
|
208
|
+
html = render_extra_features(html)
|
|
212
209
|
|
|
213
210
|
return _generate_pdf_with_playwright(
|
|
214
211
|
html,
|
|
@@ -44,15 +44,11 @@ def create_sections(html_string):
|
|
|
44
44
|
"""
|
|
45
45
|
soup = BeautifulSoup(html_string, "html.parser")
|
|
46
46
|
|
|
47
|
-
# Change 1: Search for both h2 and h3 tags
|
|
48
47
|
for header in soup.find_all(["h2", "h3"]):
|
|
49
|
-
# Create the new section
|
|
50
48
|
new_section = soup.new_tag("section")
|
|
51
49
|
header.insert_before(new_section)
|
|
52
50
|
|
|
53
51
|
current = header
|
|
54
|
-
|
|
55
|
-
# Change 2: Update loop to stop if it hits an h2 OR h3 (that isn't the current one)
|
|
56
52
|
while current is not None and (
|
|
57
53
|
current == header or current.name not in ["h2", "h3"]
|
|
58
54
|
):
|
|
@@ -91,79 +87,85 @@ def render_mermaid_diagrams(html, *, nonce):
|
|
|
91
87
|
return html
|
|
92
88
|
|
|
93
89
|
|
|
94
|
-
def
|
|
90
|
+
def render_extra_features(html):
|
|
95
91
|
"""
|
|
96
|
-
Renders
|
|
92
|
+
Renders extra features like checkboxes, highlights, and custom spans in the HTML content.
|
|
93
|
+
|
|
97
94
|
Args:
|
|
98
95
|
html (str): HTML content.
|
|
99
96
|
Returns:
|
|
100
|
-
str: HTML content with rendered
|
|
97
|
+
str: HTML content with extra features rendered.
|
|
101
98
|
"""
|
|
102
|
-
unchecked = "[ ]"
|
|
103
|
-
checked = "[x]"
|
|
104
99
|
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
def _create_checkbox(soup, match):
|
|
101
|
+
tag = soup.new_tag("input", type="checkbox")
|
|
102
|
+
if "[x]" in match.group("checkbox"):
|
|
103
|
+
tag["checked"] = ""
|
|
104
|
+
return tag
|
|
107
105
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if not parts[part_index].startswith("<code>"):
|
|
113
|
-
parts[part_index] = parts[part_index].replace(unchecked, unchecked_html)
|
|
114
|
-
parts[part_index] = parts[part_index].replace(checked, checked_html)
|
|
106
|
+
def _create_highlight(soup, match):
|
|
107
|
+
tag = soup.new_tag("span", attrs={"class": "highlight"})
|
|
108
|
+
tag.string = match.group("hl_content")
|
|
109
|
+
return tag
|
|
115
110
|
|
|
116
|
-
|
|
111
|
+
def _create_custom_span(soup, match):
|
|
112
|
+
tag = soup.new_tag("span", attrs={"class": match.group("cls")})
|
|
113
|
+
tag.string = match.group("sp_content")
|
|
114
|
+
return tag
|
|
117
115
|
|
|
116
|
+
handlers = {
|
|
117
|
+
"checkbox": _create_checkbox,
|
|
118
|
+
"highlight": _create_highlight,
|
|
119
|
+
"span": _create_custom_span,
|
|
120
|
+
}
|
|
118
121
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
Returns:
|
|
125
|
-
str: HTML content with rendered custom spans.
|
|
126
|
-
"""
|
|
127
|
-
soup = BeautifulSoup(html, "html.parser")
|
|
122
|
+
master_pattern = re.compile(
|
|
123
|
+
r"(?P<checkbox>\[\s\]|\[x\])|"
|
|
124
|
+
r"(?P<highlight>==(?P<hl_content>.*?)==)|"
|
|
125
|
+
r"(?P<span>(?P<cls>[a-zA-Z0-9_-]+)\{\{\s*(?P<sp_content>.*?)\s*\}\})"
|
|
126
|
+
)
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
# It captures the class name and the content
|
|
131
|
-
pattern = re.compile(r"([a-zA-Z0-9_-]+){{\s*(.*?)\s*}}")
|
|
128
|
+
ignored_tags = {"code", "pre", "script", "style"}
|
|
132
129
|
|
|
133
|
-
|
|
130
|
+
soup = BeautifulSoup(html, "html.parser")
|
|
134
131
|
for text_node in soup.find_all(string=True):
|
|
135
|
-
#
|
|
136
|
-
if text_node.parent.name in
|
|
132
|
+
# Ignore text nodes within certain tags
|
|
133
|
+
if text_node.parent.name in ignored_tags:
|
|
137
134
|
continue
|
|
138
135
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
136
|
+
# If no match, skip processing
|
|
137
|
+
content = text_node.string
|
|
138
|
+
if not master_pattern.search(content):
|
|
139
|
+
continue
|
|
140
|
+
|
|
141
|
+
new_nodes = []
|
|
142
|
+
last_end = 0
|
|
143
|
+
for match in master_pattern.finditer(content):
|
|
144
|
+
start, end = match.span()
|
|
145
|
+
|
|
146
|
+
# Append text before the match
|
|
147
|
+
if start > last_end:
|
|
148
|
+
new_nodes.append(content[last_end:start])
|
|
149
|
+
|
|
150
|
+
kind = match.lastgroup
|
|
151
|
+
|
|
152
|
+
# Call the appropriate handler
|
|
153
|
+
handler = handlers.get(kind)
|
|
154
|
+
if handler:
|
|
155
|
+
try:
|
|
156
|
+
tag = handler(soup, match)
|
|
157
|
+
new_nodes.append(tag)
|
|
158
|
+
except Exception as exc:
|
|
159
|
+
print(f"Warning: Handler for '{kind}' failed with exception: {exc}")
|
|
160
|
+
new_nodes.append(match.group(0))
|
|
161
|
+
|
|
162
|
+
last_end = end
|
|
163
|
+
|
|
164
|
+
# Append any remaining text after the last match
|
|
165
|
+
if new_nodes:
|
|
166
|
+
if last_end < len(content):
|
|
167
|
+
new_nodes.append(content[last_end:])
|
|
168
|
+
|
|
169
|
+
text_node.replace_with(*new_nodes)
|
|
168
170
|
|
|
169
171
|
return str(soup)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: markdown_convert
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.47
|
|
4
4
|
Summary: Convert Markdown files to PDF from your command line.
|
|
5
5
|
Project-URL: homepage, https://github.com/Julynx/markdown_convert
|
|
6
6
|
Author-email: Julio Cabria <juliocabria@tutanota.com>
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
markdown_convert/__init__.py,sha256=ysW3pXsDGGK4PzZHcIBTpfVW58IkDUwHffDkf_GM6UU,303
|
|
2
2
|
markdown_convert/__main__.py,sha256=w6sHfJcJQpMOERPqiNoKgoRM38YUwK22eGBmVkpZj1g,2807
|
|
3
3
|
markdown_convert/code.css,sha256=Wt4FqFqJcpT-jwY3GN-o4ZRCCXU8DQj-9lqKdGiuoyw,4935
|
|
4
|
-
markdown_convert/default.css,sha256=
|
|
4
|
+
markdown_convert/default.css,sha256=7yajQ662BwtQcZfhY1De8uWvRyFOd25gJLzBw2bVRko,6265
|
|
5
5
|
markdown_convert/modules/__init__.py,sha256=PFPgiQhMXgyfjD8BkfLC_X8AR1jz-dCxfif2qmNofJs,65
|
|
6
6
|
markdown_convert/modules/constants.py,sha256=eUeIFRxZerP3E0Rgp_Nsl0Q38IBELwca5UO3fbUcxRA,1280
|
|
7
|
-
markdown_convert/modules/convert.py,sha256=
|
|
7
|
+
markdown_convert/modules/convert.py,sha256=4UEZhx_v4lqcgTYeCiQ3V4Bkxz4siHCKQIHGvHICHuI,8888
|
|
8
8
|
markdown_convert/modules/resources.py,sha256=tnW8JmCrJNBRbzOcaOVG6GX5jPC8Kzj3dA7gX0B935A,2488
|
|
9
|
-
markdown_convert/modules/transform.py,sha256=
|
|
9
|
+
markdown_convert/modules/transform.py,sha256=_Pz-t_7g_n_IwtHtc386WDugkw6CfDpdgw_aFgiSM4Q,4796
|
|
10
10
|
markdown_convert/modules/utils.py,sha256=NX0WegM8e8MPKNNmweTujAWO8ZghdB8LSGDx20K2E44,655
|
|
11
11
|
markdown_convert/modules/validate.py,sha256=XV_k7cHeifEKDaltF26tCmabs2-Me5msP3enI_eVwfA,1517
|
|
12
|
-
markdown_convert-1.2.
|
|
13
|
-
markdown_convert-1.2.
|
|
14
|
-
markdown_convert-1.2.
|
|
15
|
-
markdown_convert-1.2.
|
|
16
|
-
markdown_convert-1.2.
|
|
12
|
+
markdown_convert-1.2.47.dist-info/METADATA,sha256=VQnb25PlCwzKr-ByEnsZ_lTyODbmjafw0AUtG_CBOzk,4077
|
|
13
|
+
markdown_convert-1.2.47.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
markdown_convert-1.2.47.dist-info/entry_points.txt,sha256=RCmzC7C0sX-SpzIP2Cr34rhg3lMd7BRx-exaZPfK8bU,68
|
|
15
|
+
markdown_convert-1.2.47.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
|
16
|
+
markdown_convert-1.2.47.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|