# HG changeset patch # User Paul Boddie # Date 1532429923 -7200 # Node ID 5cfbebeefb65e0191d6ed490366531b7aeaf5374 # Parent 8a6729123c708c329d6d45cc80ae0ce48d8a5226 Introduced separate modules for format-specific document tree nodes. diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/parsers/common.py --- a/moinformat/parsers/common.py Tue Jul 24 10:47:29 2018 +0200 +++ b/moinformat/parsers/common.py Tue Jul 24 12:58:43 2018 +0200 @@ -20,7 +20,7 @@ """ from collections import defaultdict -from moinformat.tree import Block, Region, Text +from moinformat.tree.moin import Block, Region, Text import re # Pattern management. diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/parsers/moin.py --- a/moinformat/parsers/moin.py Tue Jul 24 10:47:29 2018 +0200 +++ b/moinformat/parsers/moin.py Tue Jul 24 12:58:43 2018 +0200 @@ -20,13 +20,15 @@ """ from moinformat.parsers.common import ParserBase, get_patterns, \ - excl, expect, group, optional, recur, repeat + excl, expect, group, optional, recur, \ + repeat from moinformat.serialisers import serialise -from moinformat.tree import Break, DefItem, DefTerm, FontStyle, Heading, \ - Larger, Link, List, ListItem, Macro, Monospace, \ - Region, Rule, Smaller, Strikethrough, Subscript, \ - Superscript, Table, TableAttr, TableAttrs, \ - TableCell, TableRow, Text, Underline +from moinformat.tree.moin import Break, DefItem, DefTerm, FontStyle, Heading, \ + Larger, Link, List, ListItem, Macro, \ + Monospace, Region, Rule, Smaller, \ + Strikethrough, Subscript, Superscript, Table, \ + TableAttr, TableAttrs, TableCell, TableRow, \ + Text, Underline join = "".join diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/parsers/table.py --- a/moinformat/parsers/table.py Tue Jul 24 10:47:29 2018 +0200 +++ b/moinformat/parsers/table.py Tue Jul 24 12:58:43 2018 +0200 @@ -22,8 +22,8 @@ from moinformat.parsers.common import get_patterns, \ excl, expect, group from moinformat.parsers.moin import MoinParser -from moinformat.tree import Continuation, Table, TableAttrs, TableCell, \ - TableRow, Text +from moinformat.tree.moin import Table, TableAttrs, TableCell, TableRow, Text +from moinformat.tree.table import Continuation join = "".join diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/tree.py --- a/moinformat/tree.py Tue Jul 24 10:47:29 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,621 +0,0 @@ -#!/usr/bin/env python - -""" -Moin wiki format document tree nodes. - -Copyright (C) 2017, 2018 Paul Boddie - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; either version 3 of the License, or (at your option) any later -version. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -details. - -You should have received a copy of the GNU General Public License along with -this program. If not, see . -""" - -class Container: - - "A container of document nodes." - - 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) - - 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 - - def node(self, index): - try: - return self.nodes[index] - except IndexError: - return None - - def normalise(self): - - "Combine adjacent text nodes." - - nodes = self.nodes - self.nodes = [] - text = None - - for node in nodes: - - # Open a text node or merge text into an open node. - - if isinstance(node, Text): - if not text: - text = node - else: - text.merge(node) - - # Close any open text node and append the current node. - - else: - if text: - self.append(text) - text = None - self.append(node) - - # Add any open text node. - - if text: - self.append(text) - - def __str__(self): - return self.prettyprint() - - def _prettyprint(self, l, indent=""): - for node in self.nodes: - l.append(node.prettyprint(indent + " ")) - return "\n".join(l) - - def _to_string(self, out): - for node in self.nodes: - node.to_string(out) - -class Region(Container): - - "A region of the page." - - 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) - if last and last.empty(): - self.nodes[-1] = node - else: - self.append(node) - - def append_inline(self, node): - if self.transparent: - self.nodes[-1].append(node) - else: - self.append(node) - - def have_end(self, s): - return self.level and s.startswith("}") and self.level == len(s) - - def __repr__(self): - 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 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, self.extra) - - # Obtain a serialiser for the region, if appropriate. - - serialiser = out.formats and out.formats.get(self.type) - region_out = serialiser and serialiser(out.out, out.formats) or out - - # Serialise the region. - - self._to_string(region_out) - - out.end_region(self.level, self.indent, self.type, self.extra) - - - -# Block nodes. - -class Block(Container): - - "A block in the page." - - def __repr__(self): - return "Block(%r)" % self.nodes - - def prettyprint(self, indent=""): - l = ["%sBlock" % indent] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_block() - self._to_string(out) - out.end_block() - -class DefItem(Container): - - "A definition item." - - def __init__(self, nodes, pad, extra): - Container.__init__(self, nodes) - self.pad = pad - self.extra = extra - - def __repr__(self): - return "DefItem(%r, %r, %r)" % (self.nodes, self.pad, self.extra) - - def prettyprint(self, indent=""): - l = ["%sDefItem: pad=%r extra=%r" % (indent, self.pad, self.extra)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_defitem(self.pad, self.extra) - self._to_string(out) - out.end_defitem(self.pad, self.extra) - -class DefTerm(Container): - - "A definition term." - - def __init__(self, nodes, pad): - Container.__init__(self, nodes) - self.pad = pad - - def __repr__(self): - return "DefTerm(%r, %r)" % (self.nodes, self.pad) - - def prettyprint(self, indent=""): - l = ["%sDefTerm: pad=%r" % (indent, self.pad)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_defterm(self.pad) - self._to_string(out) - out.end_defterm(self.pad) - -class FontStyle(Container): - - "Emphasised and/or strong text." - - def __init__(self, nodes, emphasis=False, strong=False): - Container.__init__(self, nodes) - self.emphasis = emphasis - self.strong = strong - - def close_emphasis(self): - if self.strong: - span = FontStyle(self.nodes, emphasis=True) - self.nodes = [span] - self.emphasis = False - return self.strong - - def close_strong(self): - if self.emphasis: - span = FontStyle(self.nodes, strong=True) - self.nodes = [span] - self.strong = False - return self.emphasis - - def __repr__(self): - return "FontStyle(%r, %r, %r)" % (self.nodes, self.emphasis, self.strong) - - def prettyprint(self, indent=""): - l = ["%sFontStyle: emphasis=%r strong=%r" % (indent, self.emphasis, self.strong)] - return self._prettyprint(l, indent) - - def to_string(self, out): - if self.emphasis: - out.start_emphasis() - elif self.strong: - out.start_strong() - self._to_string(out) - if self.emphasis: - out.end_emphasis() - elif self.strong: - out.end_strong() - -class Heading(Container): - - "A heading." - - def __init__(self, nodes, level, start_extra="", start_pad="", end_pad="", end_extra=""): - Container.__init__(self, nodes) - self.level = level - self.start_extra = start_extra - self.start_pad = start_pad - self.end_pad = end_pad - self.end_extra = end_extra - - def __repr__(self): - return "Heading(%r, %d, %r, %r, %r, %r)" % ( - self.nodes, self.level, self.start_extra, self.start_pad, self.end_pad, self.end_extra) - - def prettyprint(self, indent=""): - l = ["%sHeading: level=%d start_extra=%r start_pad=%r end_pad=%r end_extra=%r" % ( - indent, self.level, self.start_extra, self.start_pad, self.end_pad, self.end_extra)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_heading(self.level, self.start_extra, self.start_pad) - self._to_string(out) - out.end_heading(self.level, self.end_pad, self.end_extra) - -class List(Container): - - "A list." - - def __init__(self, nodes, indent, marker, num): - Container.__init__(self, nodes) - self.indent = indent - self.marker = marker - self.num = num - - def __repr__(self): - return "List(%r, %r, %r, %r)" % (self.nodes, self.indent, self.marker, self.num) - - def prettyprint(self, indent=""): - l = ["%sList: indent=%d marker=%r num=%r" % (indent, self.indent, self.marker, self.num)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_list(self.indent, self.marker, self.num) - self._to_string(out) - out.end_list(self.indent, self.marker, self.num) - -class ListItem(Container): - - "A list item." - - def __init__(self, nodes, indent, marker, space, num): - Container.__init__(self, nodes) - self.indent = indent - self.marker = marker - 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) - - def prettyprint(self, indent=""): - l = ["%sListItem: indent=%d marker=%r space=%r num=%r" % (indent, self.indent, self.marker, self.space, self.num)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_listitem(self.indent, self.marker, self.space, self.num) - self._to_string(out) - out.end_listitem(self.indent, self.marker, self.space, self.num) - -class TableAttrs(Container): - - "A collection of table attributes." - - def __repr__(self): - return "TableAttrs(%r)" % self.nodes - - def prettyprint(self, indent=""): - l = ["%sTableAttrs:" % indent] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_table_attrs() - self._to_string(out) - out.end_table_attrs() - -class Table(Container): - - "A table." - - def __repr__(self): - return "Table(%r)" % self.nodes - - def prettyprint(self, indent=""): - l = ["%sTable:" % indent] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_table() - self._to_string(out) - out.end_table() - -class TableCell(Container): - - "A table cell." - - def __init__(self, nodes, attrs=None): - Container.__init__(self, nodes) - self.attrs = attrs - - def __repr__(self): - return "TableCell(%r, %r)" % (self.nodes, self.attrs) - - def prettyprint(self, indent=""): - l = ["%sTableCell:" % indent] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_table_cell(self.attrs) - for node in self.nodes: - if node is not self.attrs: - node.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) - - - -# Inline nodes with children. - -class Inline(Container): - - "Generic inline formatting." - - def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self.nodes) - - def prettyprint(self, indent=""): - l = ["%s%s" % (indent, self.__class__.__name__)] - return self._prettyprint(l, indent) - -class Larger(Inline): - - "Larger text." - - def to_string(self, out): - out.start_larger() - self._to_string(out) - out.end_larger() - -class Link(Container): - - "Link details." - - def __init__(self, nodes, target): - Container.__init__(self, nodes) - self.target = target - - def __repr__(self): - return "Link(%r, %r)" % (self.nodes, self.target) - - def prettyprint(self, indent=""): - l = ["%sLink: target=%r" % (indent, self.target)] - return self._prettyprint(l, indent) - - def to_string(self, out): - out.start_link(self.target) - if self.nodes: - out.start_linktext() - self._to_string(out) - out.end_linktext() - out.end_link() - -class Monospace(Inline): - - "Monospaced text." - - def to_string(self, out): - out.start_monospace() - self._to_string(out) - out.end_monospace() - -class Smaller(Inline): - - "Smaller text." - - def to_string(self, out): - out.start_smaller() - self._to_string(out) - out.end_smaller() - -class Strikethrough(Inline): - - "Crossed-out text." - - def to_string(self, out): - out.start_strikethrough() - self._to_string(out) - out.end_strikethrough() - -class Subscript(Inline): - - "Subscripted text." - - def to_string(self, out): - out.start_subscript() - self._to_string(out) - out.end_subscript() - -class Superscript(Inline): - - "Superscripted text." - - def to_string(self, out): - out.start_superscript() - self._to_string(out) - out.end_superscript() - -class Underline(Inline): - - "Underlined text." - - def to_string(self, out): - out.start_underline() - self._to_string(out) - out.end_underline() - - - -# Nodes without children. - -class Node: - - "A document node without children." - - def empty(self): - return False - -class Break(Node): - - "A paragraph break." - - def __repr__(self): - return "Break()" - - def prettyprint(self, indent=""): - return "%sBreak" % indent - - def to_string(self, out): - out.break_() - -class Continuation(Node): - - "Continuation padding for table content." - - def __init__(self, text): - self.text = text - - def __repr__(self): - return "Continuation(%r)" % self.text - - def prettyprint(self, indent=""): - return "%sContinuation: %r" % (indent, self.text) - - def to_string(self, out): - out.continuation(self.text) - -class Macro(Node): - - "Macro details." - - def __init__(self, name, args): - self.name = name - self.args = args - - def __repr__(self): - return "Macro(%r, %r)" % (self.name, self.args) - - def prettyprint(self, indent=""): - return "%sMacro: name=%r args=%r" % (indent, self.name, self.args) - - def to_string(self, out): - out.macro(self.name, self.args) - -class Rule(Node): - - "A horizontal rule." - - def __init__(self, length): - self.length = length - - def __repr__(self): - return "Rule(%d)" % self.length - - def prettyprint(self, indent=""): - return "%sRule: length=%d" % (indent, self.length) - - def to_string(self, out): - out.rule(self.length) - -class TableAttr(Node): - - "A table attribute." - - def __init__(self, name, value=None, concise=False, quote=None): - self.name = name - self.value = value - self.concise = concise - self.quote = quote - - def __repr__(self): - return "TableAttr(%r, %r, %r, %r)" % (self.name, self.value, self.concise, self.quote) - - def prettyprint(self, indent=""): - return "%sTableAttr: name=%r value=%r concise=%r quote=%r" % (indent, self.name, self.value, self.concise, self.quote) - - def to_string(self, out): - out.table_attr(self.name, self.value, self.concise, self.quote) - -class Text(Node): - - "A text node." - - def __init__(self, s): - self.s = s - - def empty(self): - return not self.s - - def multiline(self): - return "\n" in self.s - - def merge(self, text): - self.s += text.s - - def __repr__(self): - return "Text(%r)" % self.s - - def prettyprint(self, indent=""): - return "%sText: %r" % (indent, self.s) - - def to_string(self, out): - out.text(self.s) - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/tree/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/tree/__init__.py Tue Jul 24 12:58:43 2018 +0200 @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +""" +A package of modules containing document tree nodes. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/tree/moin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/tree/moin.py Tue Jul 24 12:58:43 2018 +0200 @@ -0,0 +1,605 @@ +#!/usr/bin/env python + +""" +Moin wiki format document tree nodes. + +Copyright (C) 2017, 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +class Container: + + "A container of document nodes." + + 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) + + 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 + + def node(self, index): + try: + return self.nodes[index] + except IndexError: + return None + + def normalise(self): + + "Combine adjacent text nodes." + + nodes = self.nodes + self.nodes = [] + text = None + + for node in nodes: + + # Open a text node or merge text into an open node. + + if isinstance(node, Text): + if not text: + text = node + else: + text.merge(node) + + # Close any open text node and append the current node. + + else: + if text: + self.append(text) + text = None + self.append(node) + + # Add any open text node. + + if text: + self.append(text) + + def __str__(self): + return self.prettyprint() + + def _prettyprint(self, l, indent=""): + for node in self.nodes: + l.append(node.prettyprint(indent + " ")) + return "\n".join(l) + + def _to_string(self, out): + for node in self.nodes: + node.to_string(out) + +class Region(Container): + + "A region of the page." + + 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) + if last and last.empty(): + self.nodes[-1] = node + else: + self.append(node) + + def append_inline(self, node): + if self.transparent: + self.nodes[-1].append(node) + else: + self.append(node) + + def have_end(self, s): + return self.level and s.startswith("}") and self.level == len(s) + + def __repr__(self): + 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 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, self.extra) + + # Obtain a serialiser for the region, if appropriate. + + serialiser = out.formats and out.formats.get(self.type) + region_out = serialiser and serialiser(out.out, out.formats) or out + + # Serialise the region. + + self._to_string(region_out) + + out.end_region(self.level, self.indent, self.type, self.extra) + + + +# Block nodes. + +class Block(Container): + + "A block in the page." + + def __repr__(self): + return "Block(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sBlock" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_block() + self._to_string(out) + out.end_block() + +class DefItem(Container): + + "A definition item." + + def __init__(self, nodes, pad, extra): + Container.__init__(self, nodes) + self.pad = pad + self.extra = extra + + def __repr__(self): + return "DefItem(%r, %r, %r)" % (self.nodes, self.pad, self.extra) + + def prettyprint(self, indent=""): + l = ["%sDefItem: pad=%r extra=%r" % (indent, self.pad, self.extra)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_defitem(self.pad, self.extra) + self._to_string(out) + out.end_defitem(self.pad, self.extra) + +class DefTerm(Container): + + "A definition term." + + def __init__(self, nodes, pad): + Container.__init__(self, nodes) + self.pad = pad + + def __repr__(self): + return "DefTerm(%r, %r)" % (self.nodes, self.pad) + + def prettyprint(self, indent=""): + l = ["%sDefTerm: pad=%r" % (indent, self.pad)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_defterm(self.pad) + self._to_string(out) + out.end_defterm(self.pad) + +class FontStyle(Container): + + "Emphasised and/or strong text." + + def __init__(self, nodes, emphasis=False, strong=False): + Container.__init__(self, nodes) + self.emphasis = emphasis + self.strong = strong + + def close_emphasis(self): + if self.strong: + span = FontStyle(self.nodes, emphasis=True) + self.nodes = [span] + self.emphasis = False + return self.strong + + def close_strong(self): + if self.emphasis: + span = FontStyle(self.nodes, strong=True) + self.nodes = [span] + self.strong = False + return self.emphasis + + def __repr__(self): + return "FontStyle(%r, %r, %r)" % (self.nodes, self.emphasis, self.strong) + + def prettyprint(self, indent=""): + l = ["%sFontStyle: emphasis=%r strong=%r" % (indent, self.emphasis, self.strong)] + return self._prettyprint(l, indent) + + def to_string(self, out): + if self.emphasis: + out.start_emphasis() + elif self.strong: + out.start_strong() + self._to_string(out) + if self.emphasis: + out.end_emphasis() + elif self.strong: + out.end_strong() + +class Heading(Container): + + "A heading." + + def __init__(self, nodes, level, start_extra="", start_pad="", end_pad="", end_extra=""): + Container.__init__(self, nodes) + self.level = level + self.start_extra = start_extra + self.start_pad = start_pad + self.end_pad = end_pad + self.end_extra = end_extra + + def __repr__(self): + return "Heading(%r, %d, %r, %r, %r, %r)" % ( + self.nodes, self.level, self.start_extra, self.start_pad, self.end_pad, self.end_extra) + + def prettyprint(self, indent=""): + l = ["%sHeading: level=%d start_extra=%r start_pad=%r end_pad=%r end_extra=%r" % ( + indent, self.level, self.start_extra, self.start_pad, self.end_pad, self.end_extra)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_heading(self.level, self.start_extra, self.start_pad) + self._to_string(out) + out.end_heading(self.level, self.end_pad, self.end_extra) + +class List(Container): + + "A list." + + def __init__(self, nodes, indent, marker, num): + Container.__init__(self, nodes) + self.indent = indent + self.marker = marker + self.num = num + + def __repr__(self): + return "List(%r, %r, %r, %r)" % (self.nodes, self.indent, self.marker, self.num) + + def prettyprint(self, indent=""): + l = ["%sList: indent=%d marker=%r num=%r" % (indent, self.indent, self.marker, self.num)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_list(self.indent, self.marker, self.num) + self._to_string(out) + out.end_list(self.indent, self.marker, self.num) + +class ListItem(Container): + + "A list item." + + def __init__(self, nodes, indent, marker, space, num): + Container.__init__(self, nodes) + self.indent = indent + self.marker = marker + 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) + + def prettyprint(self, indent=""): + l = ["%sListItem: indent=%d marker=%r space=%r num=%r" % (indent, self.indent, self.marker, self.space, self.num)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_listitem(self.indent, self.marker, self.space, self.num) + self._to_string(out) + out.end_listitem(self.indent, self.marker, self.space, self.num) + +class TableAttrs(Container): + + "A collection of table attributes." + + def __repr__(self): + return "TableAttrs(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sTableAttrs:" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_table_attrs() + self._to_string(out) + out.end_table_attrs() + +class Table(Container): + + "A table." + + def __repr__(self): + return "Table(%r)" % self.nodes + + def prettyprint(self, indent=""): + l = ["%sTable:" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_table() + self._to_string(out) + out.end_table() + +class TableCell(Container): + + "A table cell." + + def __init__(self, nodes, attrs=None): + Container.__init__(self, nodes) + self.attrs = attrs + + def __repr__(self): + return "TableCell(%r, %r)" % (self.nodes, self.attrs) + + def prettyprint(self, indent=""): + l = ["%sTableCell:" % indent] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_table_cell(self.attrs) + for node in self.nodes: + if node is not self.attrs: + node.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) + + + +# Inline nodes with children. + +class Inline(Container): + + "Generic inline formatting." + + def __repr__(self): + return "%s(%r)" % (self.__class__.__name__, self.nodes) + + def prettyprint(self, indent=""): + l = ["%s%s" % (indent, self.__class__.__name__)] + return self._prettyprint(l, indent) + +class Larger(Inline): + + "Larger text." + + def to_string(self, out): + out.start_larger() + self._to_string(out) + out.end_larger() + +class Link(Container): + + "Link details." + + def __init__(self, nodes, target): + Container.__init__(self, nodes) + self.target = target + + def __repr__(self): + return "Link(%r, %r)" % (self.nodes, self.target) + + def prettyprint(self, indent=""): + l = ["%sLink: target=%r" % (indent, self.target)] + return self._prettyprint(l, indent) + + def to_string(self, out): + out.start_link(self.target) + if self.nodes: + out.start_linktext() + self._to_string(out) + out.end_linktext() + out.end_link() + +class Monospace(Inline): + + "Monospaced text." + + def to_string(self, out): + out.start_monospace() + self._to_string(out) + out.end_monospace() + +class Smaller(Inline): + + "Smaller text." + + def to_string(self, out): + out.start_smaller() + self._to_string(out) + out.end_smaller() + +class Strikethrough(Inline): + + "Crossed-out text." + + def to_string(self, out): + out.start_strikethrough() + self._to_string(out) + out.end_strikethrough() + +class Subscript(Inline): + + "Subscripted text." + + def to_string(self, out): + out.start_subscript() + self._to_string(out) + out.end_subscript() + +class Superscript(Inline): + + "Superscripted text." + + def to_string(self, out): + out.start_superscript() + self._to_string(out) + out.end_superscript() + +class Underline(Inline): + + "Underlined text." + + def to_string(self, out): + out.start_underline() + self._to_string(out) + out.end_underline() + + + +# Nodes without children. + +class Node: + + "A document node without children." + + def empty(self): + return False + +class Break(Node): + + "A paragraph break." + + def __repr__(self): + return "Break()" + + def prettyprint(self, indent=""): + return "%sBreak" % indent + + def to_string(self, out): + out.break_() + +class Macro(Node): + + "Macro details." + + def __init__(self, name, args): + self.name = name + self.args = args + + def __repr__(self): + return "Macro(%r, %r)" % (self.name, self.args) + + def prettyprint(self, indent=""): + return "%sMacro: name=%r args=%r" % (indent, self.name, self.args) + + def to_string(self, out): + out.macro(self.name, self.args) + +class Rule(Node): + + "A horizontal rule." + + def __init__(self, length): + self.length = length + + def __repr__(self): + return "Rule(%d)" % self.length + + def prettyprint(self, indent=""): + return "%sRule: length=%d" % (indent, self.length) + + def to_string(self, out): + out.rule(self.length) + +class TableAttr(Node): + + "A table attribute." + + def __init__(self, name, value=None, concise=False, quote=None): + self.name = name + self.value = value + self.concise = concise + self.quote = quote + + def __repr__(self): + return "TableAttr(%r, %r, %r, %r)" % (self.name, self.value, self.concise, self.quote) + + def prettyprint(self, indent=""): + return "%sTableAttr: name=%r value=%r concise=%r quote=%r" % (indent, self.name, self.value, self.concise, self.quote) + + def to_string(self, out): + out.table_attr(self.name, self.value, self.concise, self.quote) + +class Text(Node): + + "A text node." + + def __init__(self, s): + self.s = s + + def empty(self): + return not self.s + + def multiline(self): + return "\n" in self.s + + def merge(self, text): + self.s += text.s + + def __repr__(self): + return "Text(%r)" % self.s + + def prettyprint(self, indent=""): + return "%sText: %r" % (indent, self.s) + + def to_string(self, out): + out.text(self.s) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 8a6729123c70 -r 5cfbebeefb65 moinformat/tree/table.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/moinformat/tree/table.py Tue Jul 24 12:58:43 2018 +0200 @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +""" +Extended table syntax document tree nodes. + +Copyright (C) 2018 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from moinformat.tree.moin import Node + +class Continuation(Node): + + "Continuation padding for table content." + + def __init__(self, text): + self.text = text + + def __repr__(self): + return "Continuation(%r)" % self.text + + def prettyprint(self, indent=""): + return "%sContinuation: %r" % (indent, self.text) + + def to_string(self, out): + out.continuation(self.text) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 8a6729123c70 -r 5cfbebeefb65 tests/test_parser.py --- a/tests/test_parser.py Tue Jul 24 10:47:29 2018 +0200 +++ b/tests/test_parser.py Tue Jul 24 12:58:43 2018 +0200 @@ -13,7 +13,7 @@ sys.path.append(parent) from moinformat import all_parsers, all_serialisers, parse, serialise -from moinformat.tree import Container +from moinformat.tree.moin import Container from glob import glob def test_input(d, s):