Skip to content

Commit

Permalink
Ensure lines after heading in loose list are properly detabbed
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
waylan authored Jan 29, 2024
1 parent ea92856 commit c334a3e
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
1 change: 1 addition & 0 deletions .spell-dict
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ customizable
dedent
deliminators
deregister
detabbed
Dmitry
docdata
ElementTree
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

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

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

Expand Down
5 changes: 5 additions & 0 deletions markdown/blockprocessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ def run(self, parent: etree.Element, blocks: list[str]) -> None:
h.text = m.group('header').strip()
if after:
# Insert remaining lines as first block for future parsing.
if self.parser.state.isstate('looselist'):
# This is a weird edge case where a header is a child of a loose list
# and there is no blank line after the header. To ensure proper
# parsing, the line(s) after need to be detabbed. See #1443.
after = self.looseDetab(after)
blocks.insert(0, after)
else: # pragma: no cover
# This should never happen, but just in case...
Expand Down
137 changes: 137 additions & 0 deletions tests/test_syntax/blocks/test_ul.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"""
Python Markdown
A Python implementation of John Gruber's Markdown.
Documentation: https://python-markdown.github.io/
GitHub: https://github.com/Python-Markdown/markdown/
PyPI: https://pypi.org/project/Markdown/
Started by Manfred Stienstra (http://www.dwerg.net/).
Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
Currently maintained by Waylan Limberg (https://github.com/waylan),
Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
Copyright 2007-2024 The Python Markdown Project (v. 1.7 and later)
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
Copyright 2004 Manfred Stienstra (the original version)
License: BSD (see LICENSE.md for details).
"""

import unittest
from markdown.test_tools import TestCase


class TestUnorderedLists(TestCase):

# TODO: Move legacy tests here

def test_header_and_paragraph_no_blank_line_loose_list(self):
self.assertMarkdownRenders(
self.dedent(
"""
- ### List 1
Entry 1.1
- ### List 2
Entry 2.1
"""
),
self.dedent(
"""
<ul>
<li>
<h3>List 1</h3>
<p>Entry 1.1</p>
</li>
<li>
<h3>List 2</h3>
<p>Entry 2.1</p>
</li>
</ul>
"""
)
)

# Note: This is strange. Any other element on first line of list item would get very
# different behavior. However, as a heading can only ever be one line, this is the
# correct behavior. In fact, `markdown.pl` behaves this way with no indentation.
def test_header_and_paragraph_no_blank_line_loose_list_no_indent(self):
self.assertMarkdownRenders(
self.dedent(
"""
- ### List 1
Entry 1.1
- ### List 2
Entry 2.1
"""
),
self.dedent(
"""
<ul>
<li>
<h3>List 1</h3>
<p>Entry 1.1</p>
</li>
<li>
<h3>List 2</h3>
<p>Entry 2.1</p>
</li>
</ul>
"""
)
)

# TODO: Possibly change this behavior. While this test follows the behavior
# of `markdown.pl`, it is likely surprising to most users. In fact, actual
# behavior is to return the same results as for a loose list.
@unittest.skip('This behaves as a loose list in Python-Markdown')
def test_header_and_paragraph_no_blank_line_tight_list(self):
self.assertMarkdownRenders(
self.dedent(
"""
- ### List 1
Entry 1.1
- ### List 2
Entry 2.1
"""
),
self.dedent(
"""
<ul>
<li>### List 1
Entry 1.1</li>
<li>### List 2
Entry 2.1</li>
</ul>
"""
)
)

# TODO: Possibly change this behavior. While this test follows the behavior
# of `markdown.pl`, it is likely surprising to most users. In fact, actual
# behavior is to return the same results as for a loose list.
@unittest.skip('This behaves as a loose list in Python-Markdown')
def test_header_and_paragraph_no_blank_line_tight_list_no_indent(self):
self.assertMarkdownRenders(
self.dedent(
"""
- ### List 1
Entry 1.1
- ### List 2
Entry 2.1
"""
),
self.dedent(
"""
<ul>
<li>### List 1
Entry 1.1</li>
<li>### List 2
Entry 2.1</li>
</ul>
"""
)
)

0 comments on commit c334a3e

Please sign in to comment.