1 #!/usr/bin/env python 2 3 """ 4 Moin wiki table parser. 5 6 Copyright (C) 2017 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 from moinformat.parsers.moin import MoinParser 24 from moinformat.tree import Table, TableAttrs, TableCell, TableRow, Text 25 26 27 28 # Parser functionality. 29 30 class TableParser(MoinParser): 31 32 "A parser for improved table syntax." 33 34 # Principal parser methods. 35 36 def parse_region_content(self, items, region): 37 38 "Parse the data provided by 'items' to populate the given 'region'." 39 40 self.set_region(items, region) 41 self.parse_table_region() 42 43 def parse_table_region(self): 44 45 # Start to populate table rows. 46 47 cell = TableCell([]) 48 row = TableRow([cell]) 49 table = Table([row]) 50 self.region.append(table) 51 52 while True: 53 self.parse_region_details(cell, self.table_region_pattern_names) 54 55 # Detect the end of the table. 56 57 if self.read_matching() == "regionend": 58 break 59 60 if self.read_matching() == "columnsep": 61 cell = TableCell([]) 62 row.append(cell) 63 64 elif self.read_matching() == "rowsep": 65 row = TableRow([]) 66 table.append(row) 67 cell = TableCell([]) 68 row.append(cell) 69 70 # Parser handler methods. 71 72 def parse_continuation(self, cell): 73 pass 74 75 def parse_table_end(self, cell): 76 77 "Handle the end of a region within 'cell'." 78 79 feature = self.read_match() 80 if self.region.have_end(feature): 81 raise StopIteration 82 else: 83 cell.append_inline(Text(feature)) 84 85 # Regular expressions. 86 87 syntax = {} 88 syntax.update(MoinParser.syntax) 89 syntax.update({ 90 # At start of line: 91 "rowsep" : r"^==(?!.*==\s*?$)(?=\N*?)", # == not-heading ws-excl-nl 92 "continuation" : r"^(\N*)\.\.(?!\.)(?=\N)", # .. ws-excl-nl or .. not-dot 93 94 # Within text: 95 "columnsep" : r"\|\|(?!\|)(?=\N)", # || ws-excl-nl or || not-pipe 96 }) 97 98 patterns = get_patterns(syntax) 99 100 101 102 # Pattern details. 103 104 table_region_pattern_names = MoinParser.region_pattern_names + [ 105 "columnsep", "continuation", "regionend", "rowsep", 106 ] 107 108 109 110 # Pattern handlers. 111 112 handlers = {} 113 handlers.update(MoinParser.handlers) 114 handlers.update({ 115 "columnsep" : MoinParser.end_region, 116 "continuation" : parse_continuation, 117 "rowsep" : MoinParser.end_region, 118 "regionend" : parse_table_end, 119 }) 120 121 parser = TableParser 122 123 # vim: tabstop=4 expandtab shiftwidth=4