1.1 --- a/moinformat/__init__.py Mon May 01 23:36:31 2017 +0200
1.2 +++ b/moinformat/__init__.py Tue May 02 16:39:30 2017 +0200
1.3 @@ -21,7 +21,8 @@
1.4
1.5 from moinformat.tree import Block, Break, DefItem, DefTerm, FontStyle, Heading, \
1.6 Larger, ListItem, Monospace, Region, Rule, Smaller, \
1.7 - Subscript, Superscript, Text, Underline
1.8 + Subscript, Superscript, TableCell, TableRow, Text, \
1.9 + Underline
1.10 import re
1.11
1.12 # Regular expressions.
1.13 @@ -52,6 +53,8 @@
1.14 "listitem_roman": r"^(\s+)([iI]\.)(\s+)",
1.15 # ws... dot-item [ws...]
1.16 "listitem_dot" : r"^(\s+)(\.)(\s*)",
1.17 + # ||
1.18 + "tablerow" : r"^\|\|",
1.19
1.20 # Region contents:
1.21 # Inline patterns:
1.22 @@ -79,6 +82,10 @@
1.23 "deftermend" : r"::(\s*?\n)",
1.24 "deftermsep" : r"::(\s+)",
1.25 "listitemend" : r"^", # next line
1.26 +
1.27 + # Table contents:
1.28 + "tablecell" : r"\|\|",
1.29 + "tableend" : r"(\s*?)^", # [ws...] next line
1.30 }
1.31
1.32 # Define inline pattern details.
1.33 @@ -220,6 +227,7 @@
1.34 "listitem_roman",
1.35 "regionstart", "regionend",
1.36 "rule",
1.37 + "tablerow",
1.38 ])
1.39
1.40 def parse_region_opaque(items, region):
1.41 @@ -408,6 +416,52 @@
1.42 else:
1.43 region.append_inline(Text(feature))
1.44
1.45 +def parse_table_row(items, region):
1.46 +
1.47 + "Handle the start of a table row within 'region'."
1.48 +
1.49 + row = TableRow([])
1.50 +
1.51 + while True:
1.52 + cell = TableCell([])
1.53 + parse_region_details(items, cell, ["tablecell", "tableend"])
1.54 +
1.55 + # Handle the end of the row.
1.56 +
1.57 + if items.matching == "tableend":
1.58 + trailing = items.read_match()
1.59 +
1.60 + # If the cell was started but not finished, convert the row into text.
1.61 +
1.62 + if not row.nodes or not cell.empty():
1.63 + region.append_inline(Text("||"))
1.64 +
1.65 + # Convert all cells.
1.66 +
1.67 + for node in row.nodes:
1.68 + region.append_inline_many(node.nodes)
1.69 + region.append_inline(Text("||"))
1.70 +
1.71 + region.append_inline_many(cell.nodes)
1.72 + region.append_inline(Text(trailing))
1.73 +
1.74 + new_block(region)
1.75 + return
1.76 +
1.77 + # Append the final cell, if not empty.
1.78 +
1.79 + else:
1.80 + row.trailing = trailing
1.81 +
1.82 + if not cell.empty():
1.83 + row.append(cell)
1.84 + break
1.85 +
1.86 + row.append(cell)
1.87 +
1.88 + region.add(row)
1.89 + new_block(region)
1.90 +
1.91 # Inline formatting handlers.
1.92
1.93 def parse_inline(items, region, cls, pattern_name):
1.94 @@ -456,6 +510,9 @@
1.95 "subend" : end_region,
1.96 "super" : parse_super,
1.97 "superend" : end_region,
1.98 + "tablerow" : parse_table_row,
1.99 + "tablecell" : end_region,
1.100 + "tableend" : end_region,
1.101 "underline" : parse_underline,
1.102 "underlineend" : end_region,
1.103 }
2.1 --- a/moinformat/serialisers.py Mon May 01 23:36:31 2017 +0200
2.2 +++ b/moinformat/serialisers.py Tue May 02 16:39:30 2017 +0200
2.3 @@ -116,6 +116,18 @@
2.4 def end_superscript(self):
2.5 self.out("^")
2.6
2.7 + def start_table_cell(self):
2.8 + pass
2.9 +
2.10 + def end_table_cell(self):
2.11 + self.out("||")
2.12 +
2.13 + def start_table_row(self):
2.14 + self.out("||")
2.15 +
2.16 + def end_table_row(self, trailing):
2.17 + self.out(trailing)
2.18 +
2.19 def start_underline(self):
2.20 self.out("__")
2.21
2.22 @@ -226,6 +238,18 @@
2.23 def end_superscript(self):
2.24 self.out("</sup>")
2.25
2.26 + def start_table_cell(self):
2.27 + self.out("<td>")
2.28 +
2.29 + def end_table_cell(self):
2.30 + self.out("</td>")
2.31 +
2.32 + def start_table_row(self):
2.33 + self.out("<tr>")
2.34 +
2.35 + def end_table_row(self, trailing):
2.36 + self.out("</tr>")
2.37 +
2.38 def start_underline(self):
2.39 self.out("<span style='text-decoration: underline'>")
2.40
3.1 --- a/moinformat/tree.py Mon May 01 23:36:31 2017 +0200
3.2 +++ b/moinformat/tree.py Tue May 02 16:39:30 2017 +0200
3.3 @@ -29,10 +29,18 @@
3.4 def append(self, node):
3.5 self.nodes.append(node)
3.6
3.7 + def append_many(self, nodes):
3.8 + for node in nodes:
3.9 + self.append(node)
3.10 +
3.11 add = append
3.12
3.13 append_inline = append
3.14
3.15 + def append_inline_many(self, nodes):
3.16 + for node in nodes:
3.17 + self.append_inline(node)
3.18 +
3.19 def empty(self):
3.20 return not self.nodes
3.21
3.22 @@ -104,11 +112,11 @@
3.23 else:
3.24 self.append(node)
3.25
3.26 - def append_inline(self, s):
3.27 + def append_inline(self, node):
3.28 if self.is_transparent():
3.29 - self.nodes[-1].append(s)
3.30 + self.nodes[-1].append(node)
3.31 else:
3.32 - self.append(s)
3.33 + self.append(node)
3.34
3.35 def have_end(self, s):
3.36 return self.level and s.startswith("}") and self.level == len(s)
3.37 @@ -276,6 +284,42 @@
3.38 self._to_string(out)
3.39 out.end_listitem(self.indent, self.marker)
3.40
3.41 +class TableCell(Container):
3.42 +
3.43 + "A table cell."
3.44 +
3.45 + def __repr__(self):
3.46 + return "TableCell(%r)" % self.nodes
3.47 +
3.48 + def prettyprint(self, indent=""):
3.49 + l = ["%sTableCell:" % indent]
3.50 + return self._prettyprint(l, indent)
3.51 +
3.52 + def to_string(self, out):
3.53 + out.start_table_cell()
3.54 + self._to_string(out)
3.55 + out.end_table_cell()
3.56 +
3.57 +class TableRow(Container):
3.58 +
3.59 + "A table row."
3.60 +
3.61 + def __init__(self, nodes, trailing=""):
3.62 + Container.__init__(self, nodes)
3.63 + self.trailing = trailing
3.64 +
3.65 + def __repr__(self):
3.66 + return "TableRow(%r, %r)" % (self.nodes, self.trailing)
3.67 +
3.68 + def prettyprint(self, indent=""):
3.69 + l = ["%sTableRow: trailing=%r" % (indent, self.trailing)]
3.70 + return self._prettyprint(l, indent)
3.71 +
3.72 + def to_string(self, out):
3.73 + out.start_table_row()
3.74 + self._to_string(out)
3.75 + out.end_table_row(self.trailing)
3.76 +
3.77
3.78
3.79 class Inline(Container):
4.1 --- a/tests/test_parser.py Mon May 01 23:36:31 2017 +0200
4.2 +++ b/tests/test_parser.py Tue May 02 16:39:30 2017 +0200
4.3 @@ -111,6 +111,16 @@
4.4 ~+Larger...+~ and ~-smaller-~
4.5 """)
4.6
4.7 +sl.append("""\
4.8 +|| Cell 1 || Cell 2 ||
4.9 +|| Cell 3 || Cell 4 ||
4.10 +
4.11 +|| Not a table
4.12 + || Also not a table
4.13 +|| Almost a table || ...
4.14 +|| A table, trailing space ||
4.15 +""")
4.16 +
4.17 dl = map(parse, sl)
4.18 nl = map(serialise, dl)
4.19