Skip to content

Commit 677a863

Browse files
authored
Fix some corner cases with Blocks and nested lists (#2651)
Fixes #2650
1 parent f655468 commit 677a863

File tree

3 files changed

+94
-11
lines changed

3 files changed

+94
-11
lines changed

docs/src/markdown/about/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Unreleased
44

5+
- **FIX**: Blocks: Fix some corner cases of nested blocks with lists.
56
- **FIX**: Tab and Tabbed: Fix a case where tabs could fail if `combine_header_slug` was enabled and there was no
67
header.
78

pymdownx/blocks/__init__.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -338,10 +338,11 @@ def get_parent(self, parent):
338338

339339
temp = parent
340340
while temp is not None:
341-
for entry in self.stack:
342-
if entry.hungry and entry.parent is temp:
343-
self.cached_parent = temp
344-
return temp
341+
if not self.stack:
342+
break
343+
if self.stack[-1].hungry and self.stack[-1].parent is temp:
344+
self.cached_parent = temp
345+
return temp
345346
if temp is not None:
346347
temp = self.lastChild(temp)
347348
return None
@@ -356,7 +357,7 @@ def is_block(self, tag):
356357

357358
return tag.tag in self.block_tags
358359

359-
def parse_blocks(self, blocks):
360+
def parse_blocks(self, blocks, current_parent):
360361
"""Parse the blocks."""
361362

362363
# Get the target element and parse
@@ -372,9 +373,19 @@ def parse_blocks(self, blocks):
372373
# has not fully adjusted list indentation, so look at how many
373374
# list item parents we have on the stack and adjust the content
374375
# accordingly.
375-
li = [e.parent.tag in ('li', 'dd') for e in self.stack[:-1]]
376-
length = len(li) * self.tab_length
377-
b, a = self.detab_by_length(b, length)
376+
parent_map = {c: p for p in current_parent.iter() for c in p}
377+
# Only need to count lists between nested blocks
378+
parent = self.stack[-1].el if len(self.stack) > 1 else None
379+
li = 0
380+
while parent is not None:
381+
parent = parent_map.get(parent, None)
382+
if parent is not None:
383+
if parent.tag in ('li', 'dd'):
384+
li += 1
385+
continue
386+
break
387+
388+
b, a = self.detab_by_length(b, li * self.tab_length)
378389
if a:
379390
blocks.insert(0, a)
380391

@@ -468,15 +479,15 @@ def run(self, parent, blocks):
468479
self.stack.append(BlockEntry(generic_block, el, parent))
469480

470481
# Parse the text blocks under the Block
471-
self.parse_blocks(blocks)
482+
self.parse_blocks(blocks, parent)
472483

473484
else:
474485
for r in range(len(self.stack)):
475486
entry = self.stack[r]
476487
if entry.hungry and parent is entry.parent:
477488
# Get the target element and parse
478489
entry.hungry = False
479-
self.parse_blocks(blocks)
490+
self.parse_blocks(blocks, parent)
480491

481492
break
482493

tests/test_extensions/test_blocks/test_general_blocks.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,78 @@ def test_bad_attributes(self):
384384
)
385385

386386

387+
class TestNestedBlocksAndLists(util.MdCase):
388+
"""Test Nested blocks and lists."""
389+
390+
extension = ['pymdownx.blocks.tab', 'pymdownx.blocks.html']
391+
extension_configs = {
392+
'pymdownx.blocks.tab': {'alternate_style': True}
393+
}
394+
395+
def test_nested_blocks_in_lists(self):
396+
"""Test a nested blocks case with lists."""
397+
398+
self.check_markdown(
399+
R"""
400+
//// html | div.my-div
401+
402+
- List
403+
404+
- List
405+
406+
/// tab | TEST1
407+
408+
Content
409+
410+
///
411+
412+
/// tab | TEST2
413+
414+
- A list
415+
416+
Paragraph
417+
418+
Code
419+
420+
///
421+
422+
////
423+
""",
424+
"""
425+
<div class="my-div">
426+
<ul>
427+
<li>
428+
<p>List</p>
429+
<ul>
430+
<li>
431+
<p>List</p>
432+
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">TEST1</label><label for="__tabbed_1_2">TEST2</label></div>
433+
<div class="tabbed-content">
434+
<div class="tabbed-block">
435+
<p>Content</p>
436+
</div>
437+
<div class="tabbed-block">
438+
<ul>
439+
<li>
440+
<p>A list</p>
441+
<p>Paragraph</p>
442+
<pre><code>Code
443+
</code></pre>
444+
</li>
445+
</ul>
446+
</div>
447+
</div>
448+
</div>
449+
</li>
450+
</ul>
451+
</li>
452+
</ul>
453+
</div>
454+
""", # noqa: E501
455+
True
456+
)
457+
458+
387459
class TestBlocksMdInHTML(util.MdCase):
388460
"""Test blocks with `md_in_html`."""
389461

@@ -392,7 +464,6 @@ class TestBlocksMdInHTML(util.MdCase):
392464
'pymdownx.blocks.tab': {'alternate_style': True}
393465
}
394466

395-
396467
def test_md_in_html_inserted_correctly(self):
397468
"""Test that `md_in_html` inserts under the correct target."""
398469

0 commit comments

Comments
 (0)