MoinLight

Annotated moinformat/parsers/table.py

54:d517824d2df5
2018-07-15 Paul Boddie Renamed read_matching to matching_pattern, read_match to match_group, and changed match_groups to update the stream position.
paul@38 1
#!/usr/bin/env python
paul@38 2
paul@38 3
"""
paul@38 4
Moin wiki table parser.
paul@38 5
paul@54 6
Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
paul@38 7
paul@38 8
This program is free software; you can redistribute it and/or modify it under
paul@38 9
the terms of the GNU General Public License as published by the Free Software
paul@38 10
Foundation; either version 3 of the License, or (at your option) any later
paul@38 11
version.
paul@38 12
paul@38 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@38 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@38 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@38 16
details.
paul@38 17
paul@38 18
You should have received a copy of the GNU General Public License along with
paul@38 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@38 20
"""
paul@38 21
paul@42 22
from moinformat.parsers.common import get_patterns
paul@42 23
from moinformat.parsers.moin import MoinParser
paul@38 24
from moinformat.tree import Table, TableAttrs, TableCell, TableRow, Text
paul@38 25
paul@38 26
paul@38 27
paul@38 28
# Parser functionality.
paul@38 29
paul@42 30
class TableParser(MoinParser):
paul@38 31
paul@38 32
    "A parser for improved table syntax."
paul@38 33
paul@38 34
    # Principal parser methods.
paul@38 35
paul@38 36
    def parse_region_content(self, items, region):
paul@38 37
paul@38 38
        "Parse the data provided by 'items' to populate the given 'region'."
paul@38 39
paul@38 40
        self.set_region(items, region)
paul@38 41
        self.parse_table_region()
paul@38 42
paul@38 43
    def parse_table_region(self):
paul@38 44
paul@38 45
        # Start to populate table rows.
paul@38 46
paul@38 47
        cell = TableCell([])
paul@38 48
        row = TableRow([cell])
paul@38 49
        table = Table([row])
paul@43 50
        self.append_node(self.region, table)
paul@38 51
paul@38 52
        while True:
paul@38 53
            self.parse_region_details(cell, self.table_region_pattern_names)
paul@38 54
paul@38 55
            # Detect the end of the table.
paul@38 56
paul@54 57
            pattern = self.matching_pattern()
paul@54 58
paul@54 59
            if pattern == "regionend":
paul@38 60
                break
paul@38 61
paul@54 62
            elif pattern == "columnsep":
paul@38 63
                cell = TableCell([])
paul@38 64
                row.append(cell)
paul@38 65
paul@54 66
            elif pattern == "rowsep":
paul@38 67
                row = TableRow([])
paul@38 68
                table.append(row)
paul@38 69
                cell = TableCell([])
paul@38 70
                row.append(cell)
paul@38 71
paul@38 72
    # Parser handler methods.
paul@38 73
paul@38 74
    def parse_continuation(self, cell):
paul@38 75
        pass
paul@38 76
paul@38 77
    def parse_table_end(self, cell):
paul@38 78
paul@38 79
        "Handle the end of a region within 'cell'."
paul@38 80
paul@54 81
        feature = self.match_group()
paul@38 82
        if self.region.have_end(feature):
paul@38 83
            raise StopIteration
paul@38 84
        else:
paul@38 85
            cell.append_inline(Text(feature))
paul@38 86
paul@38 87
    # Regular expressions.
paul@38 88
paul@38 89
    syntax = {}
paul@42 90
    syntax.update(MoinParser.syntax)
paul@38 91
    syntax.update({
paul@38 92
        # At start of line:
paul@38 93
        "rowsep"        : r"^==(?!.*==\s*?$)(?=\N*?)",  # == not-heading ws-excl-nl
paul@38 94
        "continuation"  : r"^(\N*)\.\.(?!\.)(?=\N)",    # .. ws-excl-nl or .. not-dot
paul@38 95
paul@38 96
        # Within text:
paul@38 97
        "columnsep"     : r"\|\|(?!\|)(?=\N)",          # || ws-excl-nl or || not-pipe
paul@38 98
        })
paul@38 99
paul@38 100
    patterns = get_patterns(syntax)
paul@38 101
paul@38 102
paul@38 103
paul@38 104
    # Pattern details.
paul@38 105
paul@42 106
    table_region_pattern_names = MoinParser.region_pattern_names + [
paul@38 107
        "columnsep", "continuation", "regionend", "rowsep",
paul@38 108
        ]
paul@38 109
paul@38 110
paul@38 111
paul@38 112
    # Pattern handlers.
paul@38 113
paul@38 114
    handlers = {}
paul@42 115
    handlers.update(MoinParser.handlers)
paul@38 116
    handlers.update({
paul@42 117
        "columnsep" : MoinParser.end_region,
paul@38 118
        "continuation" : parse_continuation,
paul@42 119
        "rowsep" : MoinParser.end_region,
paul@38 120
        "regionend" : parse_table_end,
paul@38 121
        })
paul@38 122
paul@40 123
parser = TableParser
paul@40 124
paul@38 125
# vim: tabstop=4 expandtab shiftwidth=4