import re __all__ = ['plugin_table'] TABLE_PATTERN = re.compile( r' {0,3}\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*' ) NP_TABLE_PATTERN = re.compile( r' {0,3}(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*' ) HEADER_SUB = re.compile(r'\| *$') HEADER_SPLIT = re.compile(r' *\| *') ALIGN_SPLIT = re.compile(r' *\| *') def parse_table(self, m, state): header = HEADER_SUB.sub('', m.group(1)).strip() align = HEADER_SUB.sub('', m.group(2)) thead, aligns = _process_table(header, align) text = re.sub(r'(?: *\| *)?\n$', '', m.group(3)) rows = [] for i, v in enumerate(text.split('\n')): v = re.sub(r'^ *\| *| *\| *$', '', v) rows.append(_process_row(v, aligns)) children = [thead, {'type': 'table_body', 'children': rows}] return {'type': 'table', 'children': children} def parse_nptable(self, m, state): thead, aligns = _process_table(m.group(1), m.group(2)) text = re.sub(r'\n$', '', m.group(3)) rows = [] for i, v in enumerate(text.split('\n')): rows.append(_process_row(v, aligns)) children = [thead, {'type': 'table_body', 'children': rows}] return {'type': 'table', 'children': children} def _process_table(header, align): headers = HEADER_SPLIT.split(header) aligns = ALIGN_SPLIT.split(align) if header.endswith('|'): headers.append('') cells = [] for i, v in enumerate(aligns): if re.search(r'^ *-+: *$', v): aligns[i] = 'right' elif re.search(r'^ *:-+: *$', v): aligns[i] = 'center' elif re.search(r'^ *:-+ *$', v): aligns[i] = 'left' else: aligns[i] = None if len(headers) > i: cells.append({ 'type': 'table_cell', 'text': headers[i], 'params': (aligns[i], True) }) i += 1 while i + 1 < len(headers): cells.append({ 'type': 'table_cell', 'text': headers[i], 'params': (None, True) }) aligns.append(None) i += 1 thead = {'type': 'table_head', 'children': cells} return thead, aligns def _process_row(row, aligns): cells = [] for i, s in enumerate(re.split(r' *(?\n' + text + '\n' def render_html_table_head(text): return '\n\n' + text + '\n\n' def render_html_table_body(text): return '\n' + text + '\n' def render_html_table_row(text): return '\n' + text + '\n' def render_html_table_cell(text, align=None, is_head=False): if is_head: tag = 'th' else: tag = 'td' html = ' <' + tag if align: html += ' style="text-align:' + align + '"' return html + '>' + text + '\n' def render_ast_table_cell(children, align=None, is_head=False): return { 'type': 'table_cell', 'children': children, 'align': align, 'is_head': is_head } def plugin_table(md): md.block.register_rule('table', TABLE_PATTERN, parse_table) md.block.register_rule('nptable', NP_TABLE_PATTERN, parse_nptable) md.block.rules.append('table') md.block.rules.append('nptable') if md.renderer.NAME == 'html': md.renderer.register('table', render_html_table) md.renderer.register('table_head', render_html_table_head) md.renderer.register('table_body', render_html_table_body) md.renderer.register('table_row', render_html_table_row) md.renderer.register('table_cell', render_html_table_cell) elif md.renderer.NAME == 'ast': md.renderer.register('table_cell', render_ast_table_cell)