Skip to content

Commit 08a4137

Browse files
committed
Better handling of one-liner Block HTML
Fixes Python-Markdown#1074
1 parent 0c9a459 commit 08a4137

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

docs/changelog.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
### Fixed
1818

1919
* Backslash Unescape IDs set via `attr_list` on `toc` (#1493).
20-
* `md_in_html` should now process content inside "markdown" blocks a similar way
20+
* `md_in_html` will process content inside "markdown" blocks a similar way
2121
as they are parsed outside of "markdown" blocks giving a more consistent
2222
expectation to external extensions (#1503).
23-
* `md_in_html` should not handle tags within inline code blocks better (#1075).
23+
* `md_in_html` handle tags within inline code blocks better (#1075).
24+
* `md_in_html` fix handling of one-liner block HTML handling (#1074)
2425

2526
## [3.7] -- 2024-08-16
2627

markdown/extensions/md_in_html.py

+20
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def reset(self):
6161
self.mdstack: list[str] = [] # When markdown=1, stack contains a list of tags
6262
self.treebuilder = etree.TreeBuilder()
6363
self.mdstate: list[Literal['block', 'span', 'off', None]] = []
64+
self.mdstarted: list[bool] = []
6465
super().reset()
6566

6667
def close(self):
@@ -126,8 +127,24 @@ def handle_starttag(self, tag, attrs):
126127
self.handle_endtag('p')
127128
self.mdstate.append(state)
128129
self.mdstack.append(tag)
130+
self.mdstarted.append(True)
129131
attrs['markdown'] = state
130132
self.treebuilder.start(tag, attrs)
133+
134+
elif not self.inraw and tag in self.block_level_tags and self.mdstarted and self.mdstarted[-1]:
135+
# Nested one-liner block tags `<tag><tag>...`
136+
attrs = {key: value if value is not None else key for key, value in attrs}
137+
state = self.get_state(tag, attrs)
138+
if 'p' in self.mdstack and tag in self.block_level_tags:
139+
# Close unclosed 'p' tag
140+
self.handle_endtag('p')
141+
self.mdstate.append(state)
142+
self.mdstack.append(tag)
143+
self.mdstarted.append(True)
144+
attrs['markdown'] = state
145+
self.treebuilder.start(tag, attrs)
146+
return
147+
131148
else:
132149
# Span level tag
133150
if self.inraw:
@@ -151,6 +168,7 @@ def handle_endtag(self, tag):
151168
while self.mdstack:
152169
item = self.mdstack.pop()
153170
self.mdstate.pop()
171+
self.mdstarted.pop()
154172
self.treebuilder.end(item)
155173
if item == tag:
156174
break
@@ -247,6 +265,8 @@ def handle_data(self, data):
247265
if self.inraw or not self.mdstack:
248266
super().handle_data(data)
249267
else:
268+
for i in range(len(self.mdstarted)):
269+
self.mdstarted[i] = False
250270
self.treebuilder.data(data)
251271

252272
def handle_empty_tag(self, data, is_block):

tests/test_syntax/extensions/test_md_in_html.py

+101
Original file line numberDiff line numberDiff line change
@@ -1274,6 +1274,107 @@ def test_md1_code_void_tag_multiline(self):
12741274
extensions=['md_in_html']
12751275
)
12761276

1277+
def test_md1_oneliner_block(self):
1278+
self.assertMarkdownRenders(
1279+
self.dedent(
1280+
'<div class="outer" markdown="block"><div class="inner" markdown="block">*foo*</div></div>'
1281+
),
1282+
'<div class="outer">\n'
1283+
'<div class="inner">\n'
1284+
'<p><em>foo</em></p>\n'
1285+
'</div>\n'
1286+
'</div>',
1287+
extensions=['md_in_html']
1288+
)
1289+
1290+
def test_md1_oneliner_block_mixed(self):
1291+
self.assertMarkdownRenders(
1292+
self.dedent(
1293+
"""
1294+
<div class="a" markdown="block"><div class="b" markdown="block">
1295+
1296+
<div class="c" markdown="block"><div class="d" markdown="block">
1297+
*foo*
1298+
</div></div>
1299+
1300+
</div></div>
1301+
"""
1302+
),
1303+
'<div class="a">\n'
1304+
'<div class="b">\n'
1305+
'<div class="c">\n'
1306+
'<div class="d">\n'
1307+
'<p><em>foo</em></p>\n'
1308+
'</div>\n'
1309+
'</div>\n'
1310+
'</div>\n'
1311+
'</div>',
1312+
extensions=['md_in_html']
1313+
)
1314+
1315+
def test_md1_oneliner_block_start(self):
1316+
self.assertMarkdownRenders(
1317+
self.dedent(
1318+
"""
1319+
<div class="outer" markdown="block"><div class="inner" markdown="block">
1320+
*foo*
1321+
</div></div>
1322+
"""
1323+
),
1324+
'<div class="outer">\n'
1325+
'<div class="inner">\n'
1326+
'<p><em>foo</em></p>\n'
1327+
'</div>\n'
1328+
'</div>',
1329+
extensions=['md_in_html']
1330+
)
1331+
1332+
def test_md1_oneliner_block_span(self):
1333+
self.assertMarkdownRenders(
1334+
self.dedent(
1335+
'<div class="outer" markdown="block"><div class="inner" markdown="span">*foo*</div></div>'
1336+
),
1337+
'<div class="outer">\n'
1338+
'<div class="inner"><em>foo</em></div>\n'
1339+
'</div>',
1340+
extensions=['md_in_html']
1341+
)
1342+
1343+
def test_md1_oneliner_block_span_start(self):
1344+
self.assertMarkdownRenders(
1345+
self.dedent(
1346+
"""
1347+
<div class="outer" markdown="block"><div class="inner" markdown="span">
1348+
*foo*
1349+
</div></div>
1350+
"""
1351+
),
1352+
'<div class="outer">\n'
1353+
'<div class="inner">\n'
1354+
'<em>foo</em>\n'
1355+
'</div>\n'
1356+
'</div>',
1357+
extensions=['md_in_html']
1358+
)
1359+
1360+
def test_md1_oneliner_span_block_start(self):
1361+
self.assertMarkdownRenders(
1362+
self.dedent(
1363+
"""
1364+
<div class="outer" markdown="span"><div class="inner" markdown="block">
1365+
*foo*
1366+
</div>
1367+
*foo*
1368+
</div>
1369+
"""
1370+
),
1371+
'<div class="outer">\n'
1372+
'<div class="inner">\n'
1373+
'<em>foo</em>\n'
1374+
'</div>\n\n'
1375+
'<em>foo</em></div>',
1376+
extensions=['md_in_html']
1377+
)
12771378

12781379
def test_md1_code_comment(self):
12791380

0 commit comments

Comments
 (0)