1 #!/usr/bin/env python 2 3 """ 4 Moin wiki table parser. 5 6 Copyright (C) 2017, 2018 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 format = "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 pattern == "regionend": 65 break 66 67 elif pattern == "columnsep": 68 cell = TableCell([]) 69 row.append(cell) 70 71 elif pattern == "rowsep": 72 row = TableRow([]) 73 table.append(row) 74 cell = TableCell([]) 75 row.append(cell) 76 77 # Parser handler methods. 78 79 def parse_continuation(self, cell): 80 81 "Handle continuation padding." 82 83 feature = self.match_group("feature") 84 cell.append(Continuation(feature)) 85 86 87 88 # Regular expressions. 89 90 syntax = {} 91 syntax.update(MoinParser.syntax) 92 syntax.update({ 93 # At start of line: 94 95 "rowsep" : join(("^==", # == 96 excl(r".*==\s*?$"), # not-heading 97 expect(r"\N*?"))), # ws-excl-nl 98 99 "continuation" : group("feature", 100 join(("^", 101 group("indent", r"\N*"), # ws... (optional) 102 r"\.\.", # .. 103 excl(r"\.")))), # not-. 104 105 # Within text: 106 107 "columnsep" : join((r"\|\|", # || 108 excl(r"\|"))), # not-| 109 }) 110 111 patterns = get_patterns(syntax) 112 113 114 115 # Pattern details. 116 117 region_pattern_names = [ 118 "columnsep", "continuation", "rowsep", "tableattrs", 119 ] + MoinParser.region_without_table_pattern_names 120 121 122 123 # Pattern handlers. 124 125 end_region = MoinParser.end_region 126 parse_table_end = MoinParser.parse_region_end 127 128 handlers = {} 129 handlers.update(MoinParser.handlers) 130 handlers.update({ 131 "columnsep" : end_region, 132 "continuation" : parse_continuation, 133 "rowsep" : end_region, 134 "regionend" : parse_table_end, 135 }) 136 137 parser = TableParser 138 139 # vim: tabstop=4 expandtab shiftwidth=4