# HG changeset patch # User Paul Boddie # Date 1493735970 -7200 # Node ID e35326be8a028bb0244267295bf4e96bed85dd83 # Parent 3630b0946d2fb4f779449202c70ff7310dca3e67 Added initial support for table elements. diff -r 3630b0946d2f -r e35326be8a02 moinformat/__init__.py --- a/moinformat/__init__.py Mon May 01 23:36:31 2017 +0200 +++ b/moinformat/__init__.py Tue May 02 16:39:30 2017 +0200 @@ -21,7 +21,8 @@ from moinformat.tree import Block, Break, DefItem, DefTerm, FontStyle, Heading, \ Larger, ListItem, Monospace, Region, Rule, Smaller, \ - Subscript, Superscript, Text, Underline + Subscript, Superscript, TableCell, TableRow, Text, \ + Underline import re # Regular expressions. @@ -52,6 +53,8 @@ "listitem_roman": r"^(\s+)([iI]\.)(\s+)", # ws... dot-item [ws...] "listitem_dot" : r"^(\s+)(\.)(\s*)", + # || + "tablerow" : r"^\|\|", # Region contents: # Inline patterns: @@ -79,6 +82,10 @@ "deftermend" : r"::(\s*?\n)", "deftermsep" : r"::(\s+)", "listitemend" : r"^", # next line + + # Table contents: + "tablecell" : r"\|\|", + "tableend" : r"(\s*?)^", # [ws...] next line } # Define inline pattern details. @@ -220,6 +227,7 @@ "listitem_roman", "regionstart", "regionend", "rule", + "tablerow", ]) def parse_region_opaque(items, region): @@ -408,6 +416,52 @@ else: region.append_inline(Text(feature)) +def parse_table_row(items, region): + + "Handle the start of a table row within 'region'." + + row = TableRow([]) + + while True: + cell = TableCell([]) + parse_region_details(items, cell, ["tablecell", "tableend"]) + + # Handle the end of the row. + + if items.matching == "tableend": + trailing = items.read_match() + + # If the cell was started but not finished, convert the row into text. + + if not row.nodes or not cell.empty(): + region.append_inline(Text("||")) + + # Convert all cells. + + for node in row.nodes: + region.append_inline_many(node.nodes) + region.append_inline(Text("||")) + + region.append_inline_many(cell.nodes) + region.append_inline(Text(trailing)) + + new_block(region) + return + + # Append the final cell, if not empty. + + else: + row.trailing = trailing + + if not cell.empty(): + row.append(cell) + break + + row.append(cell) + + region.add(row) + new_block(region) + # Inline formatting handlers. def parse_inline(items, region, cls, pattern_name): @@ -456,6 +510,9 @@ "subend" : end_region, "super" : parse_super, "superend" : end_region, + "tablerow" : parse_table_row, + "tablecell" : end_region, + "tableend" : end_region, "underline" : parse_underline, "underlineend" : end_region, } diff -r 3630b0946d2f -r e35326be8a02 moinformat/serialisers.py --- a/moinformat/serialisers.py Mon May 01 23:36:31 2017 +0200 +++ b/moinformat/serialisers.py Tue May 02 16:39:30 2017 +0200 @@ -116,6 +116,18 @@ def end_superscript(self): self.out("^") + def start_table_cell(self): + pass + + def end_table_cell(self): + self.out("||") + + def start_table_row(self): + self.out("||") + + def end_table_row(self, trailing): + self.out(trailing) + def start_underline(self): self.out("__") @@ -226,6 +238,18 @@ def end_superscript(self): self.out("") + def start_table_cell(self): + self.out("") + + def end_table_cell(self): + self.out("") + + def start_table_row(self): + self.out("") + + def end_table_row(self, trailing): + self.out("") + def start_underline(self): self.out("") diff -r 3630b0946d2f -r e35326be8a02 moinformat/tree.py --- a/moinformat/tree.py Mon May 01 23:36:31 2017 +0200 +++ b/moinformat/tree.py Tue May 02 16:39:30 2017 +0200 @@ -29,10 +29,18 @@ def append(self, node): self.nodes.append(node) + def append_many(self, nodes): + for node in nodes: + self.append(node) + add = append append_inline = append + def append_inline_many(self, nodes): + for node in nodes: + self.append_inline(node) + def empty(self): return not self.nodes @@ -104,11 +112,11 @@ else: self.append(node) - def append_inline(self, s): + def append_inline(self, node): if self.is_transparent(): - self.nodes[-1].append(s) + self.nodes[-1].append(node) else: - self.append(s) + self.append(node) def have_end(self, s): return self.level and s.startswith("}") and self.level == len(s) @@ -276,6 +284,42 @@ self._to_string(out) out.end_listitem(self.indent, self.marker) +class TableCell(Container): + + "A table cell." + + def __repr__(self): + return "TableCell(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sTableCell:" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_table_cell() + self._to_string(out) + out.end_table_cell() + +class TableRow(Container): + + "A table row." + + def __init__(self, nodes, trailing=""): + Container.__init__(self, nodes) + self.trailing = trailing + + def __repr__(self): + return "TableRow(%r, %r)" % (self.nodes, self.trailing) + + def prettyprint(self, indent=""): + l = ["%sTableRow: trailing=%r" % (indent, self.trailing)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_table_row() + self._to_string(out) + out.end_table_row(self.trailing) + class Inline(Container): diff -r 3630b0946d2f -r e35326be8a02 tests/test_parser.py --- a/tests/test_parser.py Mon May 01 23:36:31 2017 +0200 +++ b/tests/test_parser.py Tue May 02 16:39:30 2017 +0200 @@ -111,6 +111,16 @@ ~+Larger...+~ and ~-smaller-~ """) +sl.append("""\ +|| Cell 1 || Cell 2 || +|| Cell 3 || Cell 4 || + +|| Not a table + || Also not a table +|| Almost a table || ... +|| A table, trailing space || +""") + dl = map(parse, sl) nl = map(serialise, dl)