# HG changeset patch # User Paul Boddie # Date 1531847999 -7200 # Node ID 602ab3fbb29cfaa988108dd359d758347d7fe7dd # Parent c4440c1768b191f3bf00d1f62fc5b83f1aff99f7 Add inline regions within blocks instead of as separate blocks. Added feature pattern groups to better support the re-serialisation of certain patterns, such as region end markers that do not apply to the current region. Store trailing whitespace in region nodes. Store table attributes as conventional nodes within table cells. Coalesce trailing whitespace with re-serialised table cells. Avoid creating blocks inside certain nodes such as list items. diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/parsers/common.py --- a/moinformat/parsers/common.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/parsers/common.py Tue Jul 17 19:19:59 2018 +0200 @@ -407,7 +407,7 @@ # Obtain any feature. - feature = self.match_group() + feature = self.match_group("feature") or self.match_group() handler = self.handlers.get(self.matching_pattern()) # Handle each feature or add text to the region. diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/parsers/moin.py --- a/moinformat/parsers/moin.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/parsers/moin.py Tue Jul 17 19:19:59 2018 +0200 @@ -275,15 +275,30 @@ indent = len(self.match_group("indent")) level = len(self.match_group("level")) - self.add_node(region, self.parse_region(level, indent, "inline")) - self.new_block(region) + + section = self.parse_region(level, indent, "inline") + + # If the section is inline, treat it like any other inline element. + + if section.type == "inline": + region.append_inline(section) + + # Otherwise, add it as a new block element. + + else: + self.add_node(region, section) + if region.allow_blocks: + self.new_block(region) def parse_section_end(self, region): "Handle the end of a new section within 'region'." - feature = self.match_group("level") - if region.have_end(feature): + level = self.match_group("level") + feature = self.match_group("feature") + region.extra = self.match_group("extra") + + if region.have_end(level): raise StopIteration else: region.append_inline(Text(feature)) @@ -317,6 +332,9 @@ # All nodes were valid: preserve the collection. else: + # Add the attributes as a node, also recording their presence. + + cell.append(attrs) cell.attrs = attrs return @@ -354,8 +372,7 @@ if not row.nodes or not cell.empty(): for node in row.nodes: region.append_inline(Text(serialise(node))) - region.append_inline(Text(serialise(cell))) - region.append_inline(Text(trailing)) + region.append_inline(Text(serialise(cell) + trailing)) self.new_block(region) return @@ -463,7 +480,10 @@ group("level", repeat("[{]", 3)))), # {{{... "regionend" : join((r"\N*", # ws... (optional) - group("level", repeat("[}]", 3)))), # }}}... + group("feature", join(( + group("level", repeat("[}]", 3)), # }}}... + group("extra", r"\n"), + "?"))))), # nl (optional) "header" : join(("#!", # #! group("args", ".*?"), "\n")), # text-excl-nl diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/parsers/table.py --- a/moinformat/parsers/table.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/parsers/table.py Tue Jul 17 19:19:59 2018 +0200 @@ -79,8 +79,11 @@ "Handle the end of a region within 'cell'." - feature = self.match_group("level") - if self.region.have_end(feature): + level = self.match_group("level") + feature = self.match_group("feature") + self.region.extra = self.match_group("extra") + + if self.region.have_end(level): raise StopIteration else: cell.append_inline(Text(feature)) diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/serialisers/html.py --- a/moinformat/serialisers/html.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/serialisers/html.py Tue Jul 17 19:19:59 2018 +0200 @@ -38,7 +38,7 @@ else: return "span" - def start_region(self, level, indent, type): + def start_region(self, level, indent, type, extra): l = [] out = l.append if level: @@ -54,7 +54,7 @@ tag = self._region_tag(type) self.out("<%s class='%s'>" % (tag, " ".join(l))) - def end_region(self, level, indent, type): + def end_region(self, level, indent, type, extra): tag = self._region_tag(type) self.out("" % tag) diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/serialisers/moin.py --- a/moinformat/serialisers/moin.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/serialisers/moin.py Tue Jul 17 19:19:59 2018 +0200 @@ -25,7 +25,7 @@ "Serialisation of the page." - def start_region(self, level, indent, type): + def start_region(self, level, indent, type, extra): out = self.out if level: out(" " * indent + "{" * level) @@ -35,10 +35,10 @@ if type and type != "inline" and level: out("#!%s\n" % type) - def end_region(self, level, indent, type): + def end_region(self, level, indent, type, extra): out = self.out if level: - out("}" * level) + out("%s%s" % ("}" * level, extra or "")) def start_block(self): pass diff -r c4440c1768b1 -r 602ab3fbb29c moinformat/tree.py --- a/moinformat/tree.py Mon Jul 16 19:19:31 2018 +0200 +++ b/moinformat/tree.py Tue Jul 17 19:19:59 2018 +0200 @@ -26,6 +26,11 @@ def __init__(self, nodes): self.nodes = nodes + # In principle, allow blocks within containers. Some nodes may forbid + # them to simplify the document structure. + + self.allow_blocks = True + def append(self, node): self.nodes.append(node) @@ -97,12 +102,13 @@ "A region of the page." - def __init__(self, nodes, level=0, indent=0, type=None, transparent=True): + def __init__(self, nodes, level=0, indent=0, type=None, transparent=True, extra=None): Container.__init__(self, nodes) self.level = level self.indent = indent self.type = type self.transparent = transparent + self.extra = extra def add(self, node): last = self.node(-1) @@ -121,14 +127,16 @@ return self.level and s.startswith("}") and self.level == len(s) def __repr__(self): - return "Region(%r, %r, %r, %r)" % (self.nodes, self.level, self.indent, self.type) + return "Region(%r, %r, %r, %r, %r, %r)" % (self.nodes, self.level, + self.indent, self.type, self.transparent, self.extra) def prettyprint(self, indent=""): - l = ["%sRegion: level=%d indent=%d type=%s" % (indent, self.level, self.indent, self.type)] + l = ["%sRegion: level=%d indent=%d type=%s extra=%r" % (indent, + self.level, self.indent, self.type, self.extra)] return self._prettyprint(l, indent) def to_string(self, out): - out.start_region(self.level, self.indent, self.type) + out.start_region(self.level, self.indent, self.type, self.extra) # Obtain a serialiser for the region, if appropriate. @@ -139,7 +147,7 @@ self._to_string(region_out) - out.end_region(self.level, self.indent, self.type) + out.end_region(self.level, self.indent, self.type, self.extra) @@ -300,6 +308,10 @@ self.space = space self.num = num + # Forbid blocks within list items for simpler structure. + + self.allow_blocks = False + def __repr__(self): return "ListItem(%r, %r, %r, %r, %r)" % (self.nodes, self.indent, self.marker, self.space, self.num) @@ -353,17 +365,17 @@ self.attrs = attrs def __repr__(self): - return "TableCell(%r, %f)" % (self.nodes, self.attrs) + return "TableCell(%r, %r)" % (self.nodes, self.attrs) def prettyprint(self, indent=""): l = ["%sTableCell:" % indent] - if self.attrs: - l.append(self.attrs.prettyprint(indent + " ")) return self._prettyprint(l, indent) def to_string(self, out): out.start_table_cell(self.attrs) - self._to_string(out) + for node in self.nodes: + if node is not self.attrs: + node.to_string(out) out.end_table_cell() class TableRow(Container):