diff options
-rw-r--r-- | markdown/extensions/tables.py | 132 | ||||
-rw-r--r-- | tests/extensions-x-tables/tables.html | 21 | ||||
-rw-r--r-- | tests/extensions-x-tables/tables.txt | 39 |
3 files changed, 116 insertions, 76 deletions
diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py index 8ee1ce2..1d3c920 100644 --- a/markdown/extensions/tables.py +++ b/markdown/extensions/tables.py @@ -1,69 +1,97 @@ -#!/usr/bin/env python - -""" -Table extension for Python-Markdown +#!/usr/bin/env Python """ +Tables Extension for Python-Markdown +==================================== + +Added parsing of tables to Python-Markdown. + +A simple example: + First Header | Second Header + ------------- | ------------- + Content Cell | Content Cell + Content Cell | Content Cell + +Copyright 2009 - [Waylan Limberg](http://achinghead.com) +""" import markdown from markdown import etree -class TablePattern(markdown.inlinepatterns.Pattern): - def __init__ (self, md): - markdown.inlinepatterns.Pattern.__init__(self, r'(^|\n)\|([^\n]*)\|') - self.md = md - def handleMatch(self, m): +class TableProcessor(markdown.blockprocessors.BlockProcessor): + """ Process Tables. """ - # a single line represents a row - tr = etree.Element('tr') - - # chunks between pipes represent cells + def test(self, parent, block): + rows = block.split('\n') + return (len(rows) > 2 and '|' in rows[0] and + '|' in rows[1] and '-' in rows[1] and + rows[1][0] in ['|', ':', '-']) - for t in m.group(3).split('|'): - - if len(t) >= 2 and t.startswith('*') and t.endswith('*'): - # if a cell is bounded by asterisks, it is a <th> - td = etree.Element('th') - t = t[1:-1] + def run(self, parent, blocks): + """ Parse a table block and build table. """ + block = blocks.pop(0).split('\n') + header = block[:2] + rows = block[2:] + # Get format type (bordered by pipes or not) + border = False + if header[0].startswith('|'): + border = True + # Get alignment of columns + align = [] + for c in self._split_row(header[1], border): + if c.startswith(':') and c.endswith(':'): + align.append('center') + elif c.startswith(':'): + align.append('left') + elif c.endswith(':'): + align.append('right') else: - # otherwise it is a <td> - td = etree.Element('td') - - # add text ot inline section, later it will be - # processed by core + align.append(None) + # Build table + table = etree.SubElement(parent, 'table') + thead = etree.SubElement(table, 'thead') + self._build_row(header[0], thead, align, border) + tbody = etree.SubElement(table, 'tbody') + for row in rows: + self._build_row(row, tbody, align, border) - td.text = t - tr.append(td) - tr.tail = "\n" - - return tr + def _build_row(self, row, parent, align, border): + """ Given a row of text, build table cells. """ + tr = etree.SubElement(parent, 'tr') + tag = 'td' + if parent.tag == 'thead': + tag = 'th' + cells = self._split_row(row, border) + # We use align here rather than cells to ensure every row + # contains the same number of columns. + for i, a in enumerate(align): + c = etree.SubElement(tr, tag) + try: + c.text = cells[i].strip() + except IndexError: + c.text = "" + if a: + c.set('align', a) -class TableTreeprocessor(markdown.treeprocessors.Treeprocessor): - - def _findElement(self, element, name): - result = [] - for child in element: - if child.tag == name: - result.append(child) - result += self._findElement(child, name) - return result - - def run(self, root): - for element in self._findElement(root, "p"): - for child in element: - if child.tag in ['tr', 'th', 'td']: - element.tag = "table" - break - - + def _split_row(self, row, border): + """ split a row of text into list of cells. """ + if border: + if row.startswith('|'): + row = row[1:] + if row.endswith('|'): + row = row[:-1] + return row.split('|') class TableExtension(markdown.Extension): - def extendMarkdown(self, md, md_globals): - md.inlinePatterns.add('table', TablePattern(md), "<backtick") - md.treeprocessors.add('table', TableTreeprocessor(), "<prettify") + """ Add tables to Markdown. """ + def extendMarkdown(self, md, md_globals): + """ Add an instance of TableProcessor to BlockParser. """ + md.parser.blockprocessors.add('table', + TableProcessor(md.parser), + '<hashheader') -def makeExtension(configs): - return TableExtension(configs) +def makeExtension(configs={}): + return TableExtension(configs=configs) diff --git a/tests/extensions-x-tables/tables.html b/tests/extensions-x-tables/tables.html index 3377315..0549bdf 100644 --- a/tests/extensions-x-tables/tables.html +++ b/tests/extensions-x-tables/tables.html @@ -1,14 +1,7 @@ -<p>Before</p> -<table> -<tr><td> a </td><th> b </th></tr> -<tr><td> <a href="#link">c</a> </td><td> <em>d</em> </td></tr> -</table> -<p><em>Another</em> <em>some inline markup</em></p> -<table> -<tr><td> a </td><td> b </td></tr> -<tr><td> <em>a</em> </td><td> b </td></tr> -<tr><td> a </td><td> b </td></tr> -<tr><td> a </td><td> b </td></tr> -<tr><td> c </td><td> <em>d</em> </td></tr> -</table> -<p>After</p>
\ No newline at end of file +<h2>Table Tests</h2> +<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td>Content Cell</td><td>Content Cell</td></tr><tr><td>Content Cell</td><td>Content Cell</td></tr></tbody></table> +<table><thead><tr><th>First Header</th><th>Second Header</th></tr></thead><tbody><tr><td>Content Cell</td><td>Content Cell</td></tr><tr><td>Content Cell</td><td>Content Cell</td></tr></tbody></table> +<table><thead><tr><th>Item</th><th align="right">Value</th></tr></thead><tbody><tr><td>Computer</td><td align="right">$1600</td></tr><tr><td>Phone</td><td align="right">$12</td></tr><tr><td>Pipe</td><td align="right">$1</td></tr></tbody></table> +<table><thead><tr><th>Function name</th><th>Description</th></tr></thead><tbody><tr><td><code>help()</code></td><td>Display the help window.</td></tr><tr><td><code>destroy()</code></td><td><strong>Destroy your computer!</strong></td></tr></tbody></table> +<table><thead><tr><th align="left">foo</th><th align="center">bar</th><th align="right">baz</th></tr></thead><tbody><tr><td align="left" /><td align="center">Q</td><td align="right" /></tr><tr><td align="left">W</td><td align="center" /><td align="right">W</td></tr></tbody></table> +<table><thead><tr><th>foo</th><th>bar</th><th>baz</th></tr></thead><tbody><tr><td /><td>Q</td><td /></tr><tr><td>W</td><td /><td>W</td></tr></tbody></table>
\ No newline at end of file diff --git a/tests/extensions-x-tables/tables.txt b/tests/extensions-x-tables/tables.txt index 60b34bd..64917ab 100644 --- a/tests/extensions-x-tables/tables.txt +++ b/tests/extensions-x-tables/tables.txt @@ -1,15 +1,34 @@ -Before +Table Tests +----------- -| a |* b *| -| [c](#link) | *d* | +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell -*Another* *some inline markup* +| First Header | Second Header | +| ------------- | ------------- | +| Content Cell | Content Cell | +| Content Cell | Content Cell | -| a | b | -| _a_ | b | -| a | b | -| a | b | -| c | *d* | +| Item | Value | +| :-------- | -----:| +| Computer | $1600 | +| Phone | $12 | +| Pipe | $1 | -After +| Function name | Description | +| ------------- | ------------------------------ | +| `help()` | Display the help window. | +| `destroy()` | **Destroy your computer!** | + +|foo|bar|baz| +|:--|:-:|--:| +| | Q | | +|W | | W| + +foo|bar|baz +---|---|--- + | Q | + W | | W |