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 # Principal parser methods. 37 38 def parse_region_content(self, items, region): 39 40 """ 41 Parse the data provided by 'items' to populate the given 'region'. For 42 table regions, normal region handling is wrapped by management of the 43 table structure. 44 """ 45 46 self.set_region(items, region) 47 48 # Start to populate table rows. 49 50 cell = TableCell([]) 51 row = TableRow([cell]) 52 table = Table([row]) 53 self.append_node(self.region, table) 54 55 while True: 56 self.parse_region_details(cell, self.region_pattern_names) 57 58 # Detect the end of the table. 59 60 pattern = self.matching_pattern() 61 62 if pattern == "regionend": 63 break 64 65 elif pattern == "columnsep": 66 cell = TableCell([]) 67 row.append(cell) 68 69 elif pattern == "rowsep": 70 row = TableRow([]) 71 table.append(row) 72 cell = TableCell([]) 73 row.append(cell) 74 75 # Parser handler methods. 76 77 def parse_continuation(self, cell): 78 79 "Handle continuation padding." 80 81 feature = self.match_group("feature") 82 cell.append(Continuation(feature)) 83 84 85 86 # Regular expressions. 87 88 syntax = {} 89 syntax.update(MoinParser.syntax) 90 syntax.update({ 91 # At start of line: 92 93 "rowsep" : join(("^==", # == 94 excl(r".*==\s*?$"), # not-heading 95 expect(r"\N*?"))), # ws-excl-nl 96 97 "continuation" : group("feature", 98 join(("^", 99 group("indent", r"\N*"), # ws... (optional) 100 r"\.\.", # .. 101 excl(r"\.")))), # not-. 102 103 # Within text: 104 105 "columnsep" : join((r"\|\|", # || 106 excl(r"\|"))), # not-| 107 }) 108 109 patterns = get_patterns(syntax) 110 111 112 113 # Pattern details. 114 115 region_pattern_names = [ 116 "columnsep", "continuation", "rowsep", 117 ] + MoinParser.region_without_table_pattern_names 118 119 120 121 # Pattern handlers. 122 123 end_region = MoinParser.end_region 124 parse_table_end = MoinParser.parse_region_end 125 126 handlers = {} 127 handlers.update(MoinParser.handlers) 128 handlers.update({ 129 "columnsep" : end_region, 130 "continuation" : parse_continuation, 131 "rowsep" : end_region, 132 "regionend" : parse_table_end, 133 }) 134 135 parser = TableParser 136 137 # vim: tabstop=4 expandtab shiftwidth=4