Skip to content

Commit c334a3e

Browse files
authored
Ensure lines after heading in loose list are properly detabbed
This is a weird edge case. Normally, detabbing would be handled by the `ListIndentProcessor`. However, in this one case, that class's `get_level` method would need to return a different result than in any other case. As there is no way to easily determine this specific case from that class, we make the adjustment directly in the `HashHeaderProcessor` class. Fixes #1433.
1 parent ea92856 commit c334a3e

File tree

4 files changed

+144
-0
lines changed

4 files changed

+144
-0
lines changed

Diff for: .spell-dict

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ customizable
3232
dedent
3333
deliminators
3434
deregister
35+
detabbed
3536
Dmitry
3637
docdata
3738
ElementTree

Diff for: docs/changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
### Fixed
1414

1515
* Include `scripts/*.py` in the generated source tarballs (#1430).
16+
* Ensure lines after heading in loose list are properly detabbed (#1443).
1617

1718
## [3.5.2] -- 2024-01-10
1819

Diff for: markdown/blockprocessors.py

+5
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,11 @@ def run(self, parent: etree.Element, blocks: list[str]) -> None:
479479
h.text = m.group('header').strip()
480480
if after:
481481
# Insert remaining lines as first block for future parsing.
482+
if self.parser.state.isstate('looselist'):
483+
# This is a weird edge case where a header is a child of a loose list
484+
# and there is no blank line after the header. To ensure proper
485+
# parsing, the line(s) after need to be detabbed. See #1443.
486+
after = self.looseDetab(after)
482487
blocks.insert(0, after)
483488
else: # pragma: no cover
484489
# This should never happen, but just in case...

Diff for: tests/test_syntax/blocks/test_ul.py

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
"""
2+
Python Markdown
3+
4+
A Python implementation of John Gruber's Markdown.
5+
6+
Documentation: https://python-markdown.github.io/
7+
GitHub: https://github.com/Python-Markdown/markdown/
8+
PyPI: https://pypi.org/project/Markdown/
9+
10+
Started by Manfred Stienstra (http://www.dwerg.net/).
11+
Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
12+
Currently maintained by Waylan Limberg (https://github.com/waylan),
13+
Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
14+
15+
Copyright 2007-2024 The Python Markdown Project (v. 1.7 and later)
16+
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
17+
Copyright 2004 Manfred Stienstra (the original version)
18+
19+
License: BSD (see LICENSE.md for details).
20+
"""
21+
22+
import unittest
23+
from markdown.test_tools import TestCase
24+
25+
26+
class TestUnorderedLists(TestCase):
27+
28+
# TODO: Move legacy tests here
29+
30+
def test_header_and_paragraph_no_blank_line_loose_list(self):
31+
self.assertMarkdownRenders(
32+
self.dedent(
33+
"""
34+
- ### List 1
35+
Entry 1.1
36+
37+
- ### List 2
38+
Entry 2.1
39+
"""
40+
),
41+
self.dedent(
42+
"""
43+
<ul>
44+
<li>
45+
<h3>List 1</h3>
46+
<p>Entry 1.1</p>
47+
</li>
48+
<li>
49+
<h3>List 2</h3>
50+
<p>Entry 2.1</p>
51+
</li>
52+
</ul>
53+
"""
54+
)
55+
)
56+
57+
# Note: This is strange. Any other element on first line of list item would get very
58+
# different behavior. However, as a heading can only ever be one line, this is the
59+
# correct behavior. In fact, `markdown.pl` behaves this way with no indentation.
60+
def test_header_and_paragraph_no_blank_line_loose_list_no_indent(self):
61+
self.assertMarkdownRenders(
62+
self.dedent(
63+
"""
64+
- ### List 1
65+
Entry 1.1
66+
67+
- ### List 2
68+
Entry 2.1
69+
"""
70+
),
71+
self.dedent(
72+
"""
73+
<ul>
74+
<li>
75+
<h3>List 1</h3>
76+
<p>Entry 1.1</p>
77+
</li>
78+
<li>
79+
<h3>List 2</h3>
80+
<p>Entry 2.1</p>
81+
</li>
82+
</ul>
83+
"""
84+
)
85+
)
86+
87+
# TODO: Possibly change this behavior. While this test follows the behavior
88+
# of `markdown.pl`, it is likely surprising to most users. In fact, actual
89+
# behavior is to return the same results as for a loose list.
90+
@unittest.skip('This behaves as a loose list in Python-Markdown')
91+
def test_header_and_paragraph_no_blank_line_tight_list(self):
92+
self.assertMarkdownRenders(
93+
self.dedent(
94+
"""
95+
- ### List 1
96+
Entry 1.1
97+
- ### List 2
98+
Entry 2.1
99+
"""
100+
),
101+
self.dedent(
102+
"""
103+
<ul>
104+
<li>### List 1
105+
Entry 1.1</li>
106+
<li>### List 2
107+
Entry 2.1</li>
108+
</ul>
109+
"""
110+
)
111+
)
112+
113+
# TODO: Possibly change this behavior. While this test follows the behavior
114+
# of `markdown.pl`, it is likely surprising to most users. In fact, actual
115+
# behavior is to return the same results as for a loose list.
116+
@unittest.skip('This behaves as a loose list in Python-Markdown')
117+
def test_header_and_paragraph_no_blank_line_tight_list_no_indent(self):
118+
self.assertMarkdownRenders(
119+
self.dedent(
120+
"""
121+
- ### List 1
122+
Entry 1.1
123+
- ### List 2
124+
Entry 2.1
125+
"""
126+
),
127+
self.dedent(
128+
"""
129+
<ul>
130+
<li>### List 1
131+
Entry 1.1</li>
132+
<li>### List 2
133+
Entry 2.1</li>
134+
</ul>
135+
"""
136+
)
137+
)

0 commit comments

Comments
 (0)