##// END OF EJS Templates
minirst: combine list parsing in one function...
Martin Geisler -
r9737:5f101af4 default
parent child Browse files
Show More
@@ -106,6 +106,53 b' def findliteralblocks(blocks):'
106 i += 1
106 i += 1
107 return blocks
107 return blocks
108
108
109 _bulletre = re.compile(r'- ')
110 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
111 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):( +)(.*)')
112 _definitionre = re.compile(r'[^ ]')
113
114 def splitparagraphs(blocks):
115 """Split paragraphs into lists."""
116 # Tuples with (list type, item regexp, single line items?). Order
117 # matters: definition lists has the least specific regexp and must
118 # come last.
119 listtypes = [('bullet', _bulletre, True),
120 ('option', _optionre, True),
121 ('field', _fieldre, True),
122 ('definition', _definitionre, False)]
123
124 def match(lines, i, itemre, singleline):
125 """Does itemre match an item at line i?
126
127 A list item can be followed by an idented line or another list
128 item (but only if singleline is True).
129 """
130 line1 = lines[i]
131 line2 = i+1 < len(lines) and lines[i+1] or ''
132 if not itemre.match(line1):
133 return False
134 if singleline:
135 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
136 else:
137 return line2.startswith(' ')
138
139 i = 0
140 while i < len(blocks):
141 if blocks[i]['type'] == 'paragraph':
142 lines = blocks[i]['lines']
143 for type, itemre, singleline in listtypes:
144 if match(lines, 0, itemre, singleline):
145 items = []
146 for j, line in enumerate(lines):
147 if match(lines, j, itemre, singleline):
148 items.append(dict(type=type, lines=[],
149 indent=blocks[i]['indent']))
150 items[-1]['lines'].append(line)
151 blocks[i:i+1] = items
152 break
153 i += 1
154 return blocks
155
109
156
110 def findsections(blocks):
157 def findsections(blocks):
111 """Finds sections.
158 """Finds sections.
@@ -127,139 +174,6 b' def findsections(blocks):'
127 return blocks
174 return blocks
128
175
129
176
130 def findbulletlists(blocks):
131 """Finds bullet lists.
132
133 The blocks must have a 'type' field, i.e., they should have been
134 run through findliteralblocks first.
135 """
136 i = 0
137 while i < len(blocks):
138 # Searching for a paragraph that looks like this:
139 #
140 # +------+-----------------------+
141 # | "- " | list item |
142 # +------| (body elements)+ |
143 # +-----------------------+
144 if (blocks[i]['type'] == 'paragraph' and
145 blocks[i]['lines'][0].startswith('- ')):
146 items = []
147 for line in blocks[i]['lines']:
148 if line.startswith('- '):
149 items.append(dict(type='bullet', lines=[],
150 indent=blocks[i]['indent']))
151 line = line[2:]
152 items[-1]['lines'].append(line)
153 blocks[i:i+1] = items
154 i += len(items) - 1
155 i += 1
156 return blocks
157
158
159 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
160 def findoptionlists(blocks):
161 """Finds option lists.
162
163 The blocks must have a 'type' field, i.e., they should have been
164 run through findliteralblocks first.
165 """
166 i = 0
167 while i < len(blocks):
168 # Searching for a paragraph that looks like this:
169 #
170 # +----------------------------+-------------+
171 # | "--" option " " | description |
172 # +-------+--------------------+ |
173 # | (body elements)+ |
174 # +----------------------------------+
175 if (blocks[i]['type'] == 'paragraph' and
176 _optionre.match(blocks[i]['lines'][0])):
177 options = []
178 for line in blocks[i]['lines']:
179 m = _optionre.match(line)
180 if m:
181 option, arg, rest = m.groups()
182 width = len(option) + len(arg)
183 options.append(dict(type='option', lines=[],
184 indent=blocks[i]['indent'],
185 width=width))
186 options[-1]['lines'].append(line)
187 blocks[i:i+1] = options
188 i += len(options) - 1
189 i += 1
190 return blocks
191
192
193 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):( +)(.*)')
194 def findfieldlists(blocks):
195 """Finds fields lists.
196
197 The blocks must have a 'type' field, i.e., they should have been
198 run through findliteralblocks first.
199 """
200 i = 0
201 while i < len(blocks):
202 # Searching for a paragraph that looks like this:
203 #
204 #
205 # +--------------------+----------------------+
206 # | ":" field name ":" | field body |
207 # +-------+------------+ |
208 # | (body elements)+ |
209 # +-----------------------------------+
210 if (blocks[i]['type'] == 'paragraph' and
211 _fieldre.match(blocks[i]['lines'][0])):
212 indent = blocks[i]['indent']
213 fields = []
214 for line in blocks[i]['lines']:
215 m = _fieldre.match(line)
216 if m:
217 key, spaces, rest = m.groups()
218 width = 2 + len(key) + len(spaces)
219 fields.append(dict(type='field', lines=[],
220 indent=indent, width=width))
221 # Turn ":foo: bar" into "foo bar".
222 line = '%s %s%s' % (key, spaces, rest)
223 fields[-1]['lines'].append(line)
224 blocks[i:i+1] = fields
225 i += len(fields) - 1
226 i += 1
227 return blocks
228
229
230 def finddefinitionlists(blocks):
231 """Finds definition lists.
232
233 The blocks must have a 'type' field, i.e., they should have been
234 run through findliteralblocks first.
235 """
236 i = 0
237 while i < len(blocks):
238 # Searching for a paragraph that looks like this:
239 #
240 # +----------------------------+
241 # | term |
242 # +--+-------------------------+--+
243 # | definition |
244 # | (body elements)+ |
245 # +----------------------------+
246 if (blocks[i]['type'] == 'paragraph' and
247 len(blocks[i]['lines']) > 1 and
248 not blocks[i]['lines'][0].startswith(' ') and
249 blocks[i]['lines'][1].startswith(' ')):
250 definitions = []
251 for line in blocks[i]['lines']:
252 if not line.startswith(' '):
253 definitions.append(dict(type='definition', lines=[],
254 indent=blocks[i]['indent']))
255 definitions[-1]['lines'].append(line)
256 definitions[-1]['hang'] = len(line) - len(line.lstrip())
257 blocks[i:i+1] = definitions
258 i += len(definitions) - 1
259 i += 1
260 return blocks
261
262
263 def inlineliterals(blocks):
177 def inlineliterals(blocks):
264 for b in blocks:
178 for b in blocks:
265 if b['type'] == 'paragraph':
179 if b['type'] == 'paragraph':
@@ -298,19 +212,29 b' def formatblock(block, width):'
298 return indent + ('\n' + indent).join(block['lines'])
212 return indent + ('\n' + indent).join(block['lines'])
299 if block['type'] == 'definition':
213 if block['type'] == 'definition':
300 term = indent + block['lines'][0]
214 term = indent + block['lines'][0]
301 defindent = indent + block['hang'] * ' '
215 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
216 defindent = indent + hang * ' '
302 text = ' '.join(map(str.strip, block['lines'][1:]))
217 text = ' '.join(map(str.strip, block['lines'][1:]))
303 return "%s\n%s" % (term, textwrap.fill(text, width=width,
218 return "%s\n%s" % (term, textwrap.fill(text, width=width,
304 initial_indent=defindent,
219 initial_indent=defindent,
305 subsequent_indent=defindent))
220 subsequent_indent=defindent))
306 initindent = subindent = indent
221 initindent = subindent = indent
307 text = ' '.join(map(str.strip, block['lines']))
308 if block['type'] == 'bullet':
222 if block['type'] == 'bullet':
309 initindent = indent + '- '
310 subindent = indent + ' '
223 subindent = indent + ' '
311 elif block['type'] in ('option', 'field'):
224 elif block['type'] == 'field':
312 subindent = indent + block['width'] * ' '
225 m = _fieldre.match(block['lines'][0])
226 if m:
227 key, spaces, rest = m.groups()
228 # Turn ":foo: bar" into "foo bar".
229 block['lines'][0] = '%s %s%s' % (key, spaces, rest)
230 subindent = indent + (2 + len(key) + len(spaces)) * ' '
231 elif block['type'] == 'option':
232 m = _optionre.match(block['lines'][0])
233 if m:
234 option, arg, rest = m.groups()
235 subindent = indent + (len(option) + len(arg)) * ' '
313
236
237 text = ' '.join(map(str.strip, block['lines']))
314 return textwrap.fill(text, width=width,
238 return textwrap.fill(text, width=width,
315 initial_indent=initindent,
239 initial_indent=initindent,
316 subsequent_indent=subindent)
240 subsequent_indent=subindent)
@@ -323,11 +247,8 b' def format(text, width, indent=0):'
323 b['indent'] += indent
247 b['indent'] += indent
324 blocks = findliteralblocks(blocks)
248 blocks = findliteralblocks(blocks)
325 blocks = inlineliterals(blocks)
249 blocks = inlineliterals(blocks)
250 blocks = splitparagraphs(blocks)
326 blocks = findsections(blocks)
251 blocks = findsections(blocks)
327 blocks = findbulletlists(blocks)
328 blocks = findoptionlists(blocks)
329 blocks = findfieldlists(blocks)
330 blocks = finddefinitionlists(blocks)
331 blocks = addmargins(blocks)
252 blocks = addmargins(blocks)
332 return '\n'.join(formatblock(b, width) for b in blocks)
253 return '\n'.join(formatblock(b, width) for b in blocks)
333
254
@@ -345,10 +266,7 b' if __name__ == "__main__":'
345 text = open(sys.argv[1]).read()
266 text = open(sys.argv[1]).read()
346 blocks = debug(findblocks, text)
267 blocks = debug(findblocks, text)
347 blocks = debug(findliteralblocks, blocks)
268 blocks = debug(findliteralblocks, blocks)
269 blocks = debug(splitparagraphs, blocks)
348 blocks = debug(findsections, blocks)
270 blocks = debug(findsections, blocks)
349 blocks = debug(findbulletlists, blocks)
350 blocks = debug(findoptionlists, blocks)
351 blocks = debug(findfieldlists, blocks)
352 blocks = debug(finddefinitionlists, blocks)
353 blocks = debug(addmargins, blocks)
271 blocks = debug(addmargins, blocks)
354 print '\n'.join(formatblock(b, 30) for b in blocks)
272 print '\n'.join(formatblock(b, 30) for b in blocks)
General Comments 0
You need to be logged in to leave comments. Login now