Skip to content

Commit ab9f4c2

Browse files
facelessuserwaylan
authored andcommitted
Fix regression of single column tables (#540)
Single column tables are valid tables, so add back in the accidentally removed functionality of allowing single column tables, but with one exception -- table bodies should not render empty (an empty `<tbody>` is invalid HTML. Fixes #539.
1 parent 13c8897 commit ab9f4c2

File tree

3 files changed

+169
-11
lines changed

3 files changed

+169
-11
lines changed

markdown/extensions/tables.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
from ..blockprocessors import BlockProcessor
2222
from ..util import etree
2323
import re
24+
PIPE_NONE = 0
25+
PIPE_LEFT = 1
26+
PIPE_RIGHT = 2
2427

2528

2629
class TableProcessor(BlockProcessor):
@@ -41,17 +44,33 @@ def test(self, parent, block):
4144
Keep border check and separator row do avoid repeating the work.
4245
"""
4346
is_table = False
44-
header = [row.strip() for row in block.split('\n')[0:2]]
45-
if len(header) == 2:
46-
self.border = header[0].startswith('|')
47-
row = self._split_row(header[0])
48-
is_table = len(row) > 1
47+
rows = [row.strip() for row in block.split('\n')]
48+
if len(rows) > 1:
49+
header0 = rows[0]
50+
self.border = PIPE_NONE
51+
if header0.startswith('|'):
52+
self.border |= PIPE_LEFT
53+
if self.RE_END_BORDER.search(header0) is not None:
54+
self.border |= PIPE_RIGHT
55+
row = self._split_row(header0)
56+
row0_len = len(row)
57+
is_table = row0_len > 1
58+
59+
# Each row in a single column table needs at least one pipe.
60+
if not is_table and row0_len == 1 and self.border:
61+
for index in range(1, len(rows)):
62+
is_table = rows[index].startswith('|')
63+
if not is_table:
64+
is_table = self.RE_END_BORDER.search(rows[index]) is not None
65+
if not is_table:
66+
break
4967

5068
if is_table:
51-
row = self._split_row(header[1])
52-
is_table = len(row) > 1 and set(''.join(row)) <= set('|:- ')
69+
row = self._split_row(rows[1])
70+
is_table = (len(row) == row0_len) and set(''.join(row)) <= set('|:- ')
5371
if is_table:
5472
self.separator = row
73+
5574
return is_table
5675

5776
def run(self, parent, blocks):
@@ -78,8 +97,20 @@ def run(self, parent, blocks):
7897
thead = etree.SubElement(table, 'thead')
7998
self._build_row(header, thead, align)
8099
tbody = etree.SubElement(table, 'tbody')
81-
for row in rows:
82-
self._build_row(row.strip(), tbody, align)
100+
if len(rows) == 0:
101+
# Handle empty table
102+
self._build_empty_row(tbody, align)
103+
else:
104+
for row in rows:
105+
self._build_row(row.strip(), tbody, align)
106+
107+
def _build_empty_row(self, parent, align):
108+
"""Build an empty row."""
109+
tr = etree.SubElement(parent, 'tr')
110+
count = len(align)
111+
while count:
112+
etree.SubElement(tr, 'td')
113+
count -= 1
83114

84115
def _build_row(self, row, parent, align):
85116
""" Given a row of text, build table cells. """

tests/extensions/extra/tables.html

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,12 @@ <h2>Table Tests</h2>
167167
<th>Second Header</th>
168168
</tr>
169169
</thead>
170-
<tbody></tbody>
170+
<tbody>
171+
<tr>
172+
<td></td>
173+
<td></td>
174+
</tr>
175+
</tbody>
171176
</table>
172177
<p>More inline code block tests</p>
173178
<table>
@@ -375,4 +380,87 @@ <h2>Table Tests</h2>
375380
<td>\\<code>code</code></td>
376381
</tr>
377382
</tbody>
378-
</table>
383+
</table>
384+
<p>Single column tables</p>
385+
<table>
386+
<thead>
387+
<tr>
388+
<th>Is a Table</th>
389+
</tr>
390+
</thead>
391+
<tbody>
392+
<tr>
393+
<td></td>
394+
</tr>
395+
</tbody>
396+
</table>
397+
<table>
398+
<thead>
399+
<tr>
400+
<th>Is a Table</th>
401+
</tr>
402+
</thead>
403+
<tbody>
404+
<tr>
405+
<td></td>
406+
</tr>
407+
</tbody>
408+
</table>
409+
<table>
410+
<thead>
411+
<tr>
412+
<th>Is a Table</th>
413+
</tr>
414+
</thead>
415+
<tbody>
416+
<tr>
417+
<td></td>
418+
</tr>
419+
</tbody>
420+
</table>
421+
<table>
422+
<thead>
423+
<tr>
424+
<th>Is a Table</th>
425+
</tr>
426+
</thead>
427+
<tbody>
428+
<tr>
429+
<td>row</td>
430+
</tr>
431+
</tbody>
432+
</table>
433+
<table>
434+
<thead>
435+
<tr>
436+
<th>Is a Table</th>
437+
</tr>
438+
</thead>
439+
<tbody>
440+
<tr>
441+
<td>row</td>
442+
</tr>
443+
</tbody>
444+
</table>
445+
<table>
446+
<thead>
447+
<tr>
448+
<th>Is a Table</th>
449+
</tr>
450+
</thead>
451+
<tbody>
452+
<tr>
453+
<td>row</td>
454+
</tr>
455+
</tbody>
456+
</table>
457+
<h2>| Is not a Table</h2>
458+
<p>| row</p>
459+
<h2>Is not a Table |</h2>
460+
<p>row |</p>
461+
<p>| Is not a Table
462+
| --------------
463+
row</p>
464+
<p>Is not a Table |
465+
-------------- |
466+
row</p>

tests/extensions/extra/tables.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,42 @@ Should not be code | Should be code
128128
------------------ | --------------
129129
\`Not code\` | \\`code`
130130
\\\`Not code\\\` | \\\\`code`
131+
132+
Single column tables
133+
134+
| Is a Table |
135+
| ---------- |
136+
137+
| Is a Table
138+
| ----------
139+
140+
Is a Table |
141+
---------- |
142+
143+
| Is a Table |
144+
| ---------- |
145+
| row |
146+
147+
| Is a Table
148+
| ----------
149+
| row
150+
151+
Is a Table |
152+
---------- |
153+
row |
154+
155+
| Is not a Table
156+
--------------
157+
| row
158+
159+
Is not a Table |
160+
--------------
161+
row |
162+
163+
| Is not a Table
164+
| --------------
165+
row
166+
167+
Is not a Table |
168+
-------------- |
169+
row

0 commit comments

Comments
 (0)