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