1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - ImprovedTableParser library 4 5 @copyright: 2012 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from MoinMoin import wikiutil 10 from shlex import shlex 11 from StringIO import StringIO 12 import re 13 14 # Regular expressions. 15 16 syntax = { 17 # At start of line: 18 "rows" : (r"^==", re.MULTILINE), # == 19 # Within text: 20 "columns" : (r"\|\|[ \t]*", 0), # || whitespace 21 # At start of column text: 22 "column" : (r"^\s*<(.*?)>\s*(.*)", re.DOTALL), # whitespace < attributes > whitespace 23 } 24 25 patterns = {} 26 for name, (value, flags) in syntax.items(): 27 patterns[name] = re.compile(value, re.UNICODE | flags) 28 29 # Functions. 30 31 def parse(s): 32 33 "Parse 's', returning a table definition." 34 35 rows = [] 36 table_attrs = {} 37 38 # Extract each row from the definition. 39 40 for row_text in patterns["rows"].split(s): 41 columns = [] 42 43 # Extract each column from the row. 44 45 for text in patterns["columns"].split(row_text): 46 47 # Extract the attribute and text sections. 48 49 match = patterns["column"].search(text) 50 if match: 51 attribute_text, text = match.groups() 52 columns.append((parseAttributes(attribute_text, True), text)) 53 else: 54 columns.append(({}, text)) 55 56 # Extract row- and table-level attributes. 57 58 row_attrs = {} 59 60 if columns: 61 attrs, column = columns[0] 62 63 for name, value in attrs.items(): 64 if name.startswith("row"): 65 row_attrs[name] = value 66 del attrs[name] 67 elif name.startswith("table"): 68 table_attrs[name] = value 69 del attrs[name] 70 71 rows.append((row_attrs, columns)) 72 73 return table_attrs, rows 74 75 def parseAttributes(s, escape=True): 76 77 """ 78 Parse the table attributes string 's', returning a mapping of names to 79 values. If 'escape' is set to a true value, the attributes will be suitable 80 for use with the formatter API. 81 """ 82 83 attrs = {} 84 f = StringIO(s) 85 name = None 86 need_value = False 87 88 for token in shlex(f): 89 90 # Capture the name if needed. 91 92 if name is None: 93 name = escape and wikiutil.escape(token) or token 94 95 # Detect either an equals sign or another name. 96 97 elif not need_value: 98 if token == "=": 99 need_value = True 100 else: 101 attrs[name.lower()] = escape and "true" or True 102 name = wikiutil.escape(token) 103 104 # Otherwise, capture a value. 105 106 else: 107 # Quoting of attributes done similarly to parseAttributes. 108 109 if escape and token: 110 if token[0] in ("'", '"'): 111 token = wikiutil.escape(token) 112 else: 113 token = '"%s"' % wikiutil.escape(token, 1) 114 115 attrs[name.lower()] = token 116 name = None 117 need_value = False 118 119 return attrs 120 121 # Formatting of embedded content. 122 # NOTE: Borrowed from EventAggregator. 123 124 def getParserClass(request, format): 125 126 """ 127 Return a parser class using the 'request' for the given 'format', returning 128 a plain text parser if no parser can be found for the specified 'format'. 129 """ 130 131 try: 132 return wikiutil.searchAndImportPlugin(request.cfg, "parser", format or "plain") 133 except wikiutil.PluginMissingError: 134 return wikiutil.searchAndImportPlugin(request.cfg, "parser", "plain") 135 136 def formatText(text, request, fmt): 137 138 "Format the given 'text' using the specified 'request' and formatter 'fmt'." 139 140 parser_cls = getParserClass(request, request.page.pi["format"]) 141 parser = parser_cls(text, request, line_anchors=False) 142 return request.redirectedOutput(parser.format, fmt, inhibit_p=True) 143 144 # Common formatting functions. 145 146 def formatTable(text, request, fmt): 147 148 "Format the given 'text' using the specified 'request' and formatter 'fmt'." 149 150 attrs, table = parse(text) 151 152 request.write(fmt.table(1, attrs)) 153 154 for row_attrs, columns in table: 155 request.write(fmt.table_row(1, row_attrs)) 156 157 for column_attrs, column_text in columns: 158 request.write(fmt.table_cell(1, column_attrs)) 159 request.write(formatText(column_text, request, fmt)) 160 request.write(fmt.table_cell(0)) 161 162 request.write(fmt.table_row(0)) 163 164 request.write(fmt.table(0)) 165 166 # vim: tabstop=4 expandtab shiftwidth=4