1.1 --- a/moinformat/__init__.py Tue May 02 16:39:30 2017 +0200
1.2 +++ b/moinformat/__init__.py Wed May 03 00:32:46 2017 +0200
1.3 @@ -21,8 +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, TableCell, TableRow, Text, \
1.8 - Underline
1.9 + Subscript, Superscript, TableAttr, TableAttrs, \
1.10 + TableCell, TableRow, Text, Underline
1.11 import re
1.12
1.13 # Regular expressions.
1.14 @@ -84,11 +84,25 @@
1.15 "listitemend" : r"^", # next line
1.16
1.17 # Table contents:
1.18 + "tableattrs" : r"<",
1.19 "tablecell" : r"\|\|",
1.20 "tableend" : r"(\s*?)^", # [ws...] next line
1.21 +
1.22 + # Table attributes:
1.23 + "tableattrsend" : r">",
1.24 + "halign" : r"([(:)])",
1.25 + "valign" : r"([v^])",
1.26 + "colour" : r"(\#[0-9A-F]{6})",
1.27 + "colspan" : r"\|(\d+)",
1.28 + "rowspan" : r"-(\d+)",
1.29 + "width" : r"(\d+%)",
1.30 + "attrname" : r"((?![-\d])[-\w]+)", # not-dash-or-digit dash-or-word-char...
1.31 + "attrvalue" : r"""=(?P<x>['"])(.*?)(?P=x)""",
1.32 }
1.33
1.34 -# Define inline pattern details.
1.35 +# Define pattern details.
1.36 +
1.37 +table_pattern_names = ["attrname", "colour", "colspan", "halign", "rowspan", "tableattrsend", "valign", "width"]
1.38
1.39 inline_pattern_names = ["fontstyle", "larger", "monospace", "smaller", "sub", "super", "underline"]
1.40
1.41 @@ -277,6 +291,19 @@
1.42
1.43 raise StopIteration
1.44
1.45 +def parse_attrname(items, attrs):
1.46 +
1.47 + "Handle an attribute name within 'attrs'."
1.48 +
1.49 + name = items.read_match()
1.50 + attr = TableAttr(name)
1.51 +
1.52 + preceding = items.read_until(["attrvalue"], False)
1.53 + if preceding == "":
1.54 + attr.value = items.read_match(2)
1.55 +
1.56 + attrs.append(attr)
1.57 +
1.58 def parse_break(items, region):
1.59
1.60 "Handle a paragraph break within 'region'."
1.61 @@ -352,6 +379,14 @@
1.62 parse_region_details(items, span, inline_pattern_names)
1.63 region.append_inline(span)
1.64
1.65 +def parse_halign(items, attrs):
1.66 +
1.67 + "Handle horizontal alignment within 'attrs'."
1.68 +
1.69 + value = items.read_match()
1.70 + attr = TableAttr("halign", value == "(" and "left" or value == ")" and "right" or "center", True)
1.71 + attrs.append(attr)
1.72 +
1.73 def parse_heading(items, region):
1.74
1.75 "Handle a heading."
1.76 @@ -416,6 +451,14 @@
1.77 else:
1.78 region.append_inline(Text(feature))
1.79
1.80 +def parse_table_attrs(items, cell):
1.81 +
1.82 + "Handle the start of table attributes within 'cell'."
1.83 +
1.84 + attrs = TableAttrs([])
1.85 + parse_region_details(items, attrs, table_pattern_names)
1.86 + cell.attrs = attrs
1.87 +
1.88 def parse_table_row(items, region):
1.89
1.90 "Handle the start of a table row within 'region'."
1.91 @@ -424,7 +467,7 @@
1.92
1.93 while True:
1.94 cell = TableCell([])
1.95 - parse_region_details(items, cell, ["tablecell", "tableend"])
1.96 + parse_region_details(items, cell, ["tableattrs", "tablecell", "tableend"])
1.97
1.98 # Handle the end of the row.
1.99
1.100 @@ -457,11 +500,21 @@
1.101 row.append(cell)
1.102 break
1.103
1.104 + # A cell separator has been found.
1.105 +
1.106 row.append(cell)
1.107
1.108 region.add(row)
1.109 new_block(region)
1.110
1.111 +def parse_valign(items, attrs):
1.112 +
1.113 + "Handle vertical alignment within 'attrs'."
1.114 +
1.115 + value = items.read_match()
1.116 + attr = TableAttr("valign", value == "^" and "top" or "bottom", True)
1.117 + attrs.append(attr)
1.118 +
1.119 # Inline formatting handlers.
1.120
1.121 def parse_inline(items, region, cls, pattern_name):
1.122 @@ -479,16 +532,34 @@
1.123 parse_super = lambda items, region: parse_inline(items, region, Superscript, "super")
1.124 parse_underline = lambda items, region: parse_inline(items, region, Underline, "underline")
1.125
1.126 +# Table attribute handlers.
1.127 +
1.128 +def parse_table_attr(items, attrs, pattern_name):
1.129 +
1.130 + "Handle a table attribute."
1.131 +
1.132 + value = items.read_match()
1.133 + attrs.append(TableAttr(pattern_name, value, True))
1.134 +
1.135 +parse_colour = lambda items, cell: parse_table_attr(items, cell, "colour")
1.136 +parse_colspan = lambda items, cell: parse_table_attr(items, cell, "colspan")
1.137 +parse_rowspan = lambda items, cell: parse_table_attr(items, cell, "rowspan")
1.138 +parse_width = lambda items, cell: parse_table_attr(items, cell, "width")
1.139 +
1.140 # Pattern handlers.
1.141
1.142 handlers = {
1.143 None : end_region,
1.144 + "attrname" : parse_attrname,
1.145 "break" : parse_break,
1.146 + "colour" : parse_colour,
1.147 + "colspan" : parse_colspan,
1.148 "defterm" : parse_defterm,
1.149 "defterm_empty" : parse_defterm_empty,
1.150 "deftermend" : end_region,
1.151 "deftermsep" : end_region,
1.152 "fontstyle" : parse_fontstyle,
1.153 + "halign" : parse_halign,
1.154 "heading" : parse_heading,
1.155 "headingend" : parse_heading_end,
1.156 "larger" : parse_larger,
1.157 @@ -503,6 +574,7 @@
1.158 "monospaceend" : end_region,
1.159 "regionstart" : parse_section,
1.160 "regionend" : parse_section_end,
1.161 + "rowspan" : parse_rowspan,
1.162 "rule" : parse_rule,
1.163 "smaller" : parse_smaller,
1.164 "smallerend" : end_region,
1.165 @@ -510,11 +582,15 @@
1.166 "subend" : end_region,
1.167 "super" : parse_super,
1.168 "superend" : end_region,
1.169 + "tableattrs" : parse_table_attrs,
1.170 + "tableattrsend" : end_region,
1.171 "tablerow" : parse_table_row,
1.172 "tablecell" : end_region,
1.173 "tableend" : end_region,
1.174 "underline" : parse_underline,
1.175 "underlineend" : end_region,
1.176 + "valign" : parse_valign,
1.177 + "width" : parse_width,
1.178 }
1.179
1.180 def new_block(region):