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 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.append_node(self.region, 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 pattern = self.matching_pattern() 58 59 if pattern == "regionend": 60 break 61 62 elif pattern == "columnsep": 63 cell = TableCell([]) 64 row.append(cell) 65 66 elif pattern == "rowsep": 67 row = TableRow([]) 68 table.append(row) 69 cell = TableCell([]) 70 row.append(cell) 71 72 # Parser handler methods. 73 74 def parse_continuation(self, cell): 75 pass 76 77 def parse_table_end(self, cell): 78 79 "Handle the end of a region within 'cell'." 80 81 feature = self.match_group() 82 if self.region.have_end(feature): 83 raise StopIteration 84 else: 85 cell.append_inline(Text(feature)) 86 87 # Regular expressions. 88 89 syntax = {} 90 syntax.update(MoinParser.syntax) 91 syntax.update({ 92 # At start of line: 93 "rowsep" : r"^==(?!.*==\s*?$)(?=\N*?)", # == not-heading ws-excl-nl 94 "continuation" : r"^(\N*)\.\.(?!\.)(?=\N)", # .. ws-excl-nl or .. not-dot 95 96 # Within text: 97 "columnsep" : r"\|\|(?!\|)(?=\N)", # || ws-excl-nl or || not-pipe 98 }) 99 100 patterns = get_patterns(syntax) 101 102 103 104 # Pattern details. 105 106 table_region_pattern_names = MoinParser.region_pattern_names + [ 107 "columnsep", "continuation", "regionend", "rowsep", 108 ] 109 110 111 112 # Pattern handlers. 113 114 handlers = {} 115 handlers.update(MoinParser.handlers) 116 handlers.update({ 117 "columnsep" : MoinParser.end_region, 118 "continuation" : parse_continuation, 119 "rowsep" : MoinParser.end_region, 120 "regionend" : parse_table_end, 121 }) 122 123 parser = TableParser 124 125 # vim: tabstop=4 expandtab shiftwidth=4