1# markdown is released under the BSD license
2# Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
3# Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
4# Copyright 2004 Manfred Stienstra (the original version)
5#
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions are met:
10#
11# *   Redistributions of source code must retain the above copyright
12#     notice, this list of conditions and the following disclaimer.
13# *   Redistributions in binary form must reproduce the above copyright
14#     notice, this list of conditions and the following disclaimer in the
15#     documentation and/or other materials provided with the distribution.
16# *   Neither the name of the <organization> nor the
17#     names of its contributors may be used to endorse or promote products
18#     derived from this software without specific prior written permission.
19#
20# THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
21# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23# DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
24# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30# POSSIBILITY OF SUCH DAMAGE.
31
32
33"""
34Tables Extension for Python-Markdown
35====================================
36
37Added parsing of tables to Python-Markdown.
38
39A simple example:
40
41    First Header  | Second Header
42    ------------- | -------------
43    Content Cell  | Content Cell
44    Content Cell  | Content Cell
45
46Copyright 2009 - [Waylan Limberg](http://achinghead.com)
47"""
48
49from __future__ import absolute_import
50from __future__ import unicode_literals
51from . import Extension
52from ..blockprocessors import BlockProcessor
53from ..util import etree
54
55class TableProcessor(BlockProcessor):
56    """ Process Tables. """
57
58    def test(self, parent, block):
59        rows = block.split('\n')
60        return (len(rows) > 2 and '|' in rows[0] and
61                '|' in rows[1] and '-' in rows[1] and
62                rows[1].strip()[0] in ['|', ':', '-'])
63
64    def run(self, parent, blocks):
65        """ Parse a table block and build table. """
66        block = blocks.pop(0).split('\n')
67        header = block[0].strip()
68        seperator = block[1].strip()
69        rows = block[2:]
70        # Get format type (bordered by pipes or not)
71        border = False
72        if header.startswith('|'):
73            border = True
74        # Get alignment of columns
75        align = []
76        for c in self._split_row(seperator, border):
77            if c.startswith(':') and c.endswith(':'):
78                align.append('center')
79            elif c.startswith(':'):
80                align.append('left')
81            elif c.endswith(':'):
82                align.append('right')
83            else:
84                align.append(None)
85        # Build table
86        table = etree.SubElement(parent, 'table')
87        thead = etree.SubElement(table, 'thead')
88        self._build_row(header, thead, align, border)
89        tbody = etree.SubElement(table, 'tbody')
90        for row in rows:
91            self._build_row(row.strip(), tbody, align, border)
92
93    def _build_row(self, row, parent, align, border):
94        """ Given a row of text, build table cells. """
95        tr = etree.SubElement(parent, 'tr')
96        tag = 'td'
97        if parent.tag == 'thead':
98            tag = 'th'
99        cells = self._split_row(row, border)
100        # We use align here rather than cells to ensure every row
101        # contains the same number of columns.
102        for i, a in enumerate(align):
103            c = etree.SubElement(tr, tag)
104            try:
105                c.text = cells[i].strip()
106            except IndexError:
107                c.text = ""
108            if a:
109                c.set('align', a)
110
111    def _split_row(self, row, border):
112        """ split a row of text into list of cells. """
113        if border:
114            if row.startswith('|'):
115                row = row[1:]
116            if row.endswith('|'):
117                row = row[:-1]
118        return row.split('|')
119
120
121class TableExtension(Extension):
122    """ Add tables to Markdown. """
123
124    def extendMarkdown(self, md, md_globals):
125        """ Add an instance of TableProcessor to BlockParser. """
126        md.parser.blockprocessors.add('table',
127                                      TableProcessor(md.parser),
128                                      '<hashheader')
129
130
131def makeExtension(configs={}):
132    return TableExtension(configs=configs)
133