comparison mercurial/minirst.py @ 10065:a1ae0ed78d1a

minirst: improve layout of field lists Before, we used the padding following the key to compute where to wrap the text. Long keys would thus give a big indentation. It also required careful alignment of the source text, making it cumbersome to items to the list. We now compute the maximum key length and use that for all items in the list. We also put a cap on the indentation: keys longer than 10 characters are put on their own line. This is similar to how rst2html handles large keys: it uses 14 as the cutoff point, but I felt that 10 was better for monospaced text in the console.
author Martin Geisler <mg@lazybytes.net>
date Sun, 13 Dec 2009 23:49:53 +0100
parents 6f30c35766d6
children d6512b3e9ac0
comparison
equal deleted inserted replaced
10064:6f30c35766d6 10065:a1ae0ed78d1a
111 i += 1 111 i += 1
112 return blocks 112 return blocks
113 113
114 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)) ') 114 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)) ')
115 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$') 115 _optionre = re.compile(r'^(--[a-z-]+)((?:[ =][a-zA-Z][\w-]*)? +)(.*)$')
116 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):( +)(.*)') 116 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
117 _definitionre = re.compile(r'[^ ]') 117 _definitionre = re.compile(r'[^ ]')
118 118
119 def splitparagraphs(blocks): 119 def splitparagraphs(blocks):
120 """Split paragraphs into lists.""" 120 """Split paragraphs into lists."""
121 # Tuples with (list type, item regexp, single line items?). Order 121 # Tuples with (list type, item regexp, single line items?). Order
154 indent=blocks[i]['indent'])) 154 indent=blocks[i]['indent']))
155 items[-1]['lines'].append(line) 155 items[-1]['lines'].append(line)
156 blocks[i:i+1] = items 156 blocks[i:i+1] = items
157 break 157 break
158 i += 1 158 i += 1
159 return blocks
160
161
162 _fieldwidth = 12
163
164 def updatefieldlists(blocks):
165 """Find key and maximum key width for field lists."""
166 i = 0
167 while i < len(blocks):
168 if blocks[i]['type'] != 'field':
169 i += 1
170 continue
171
172 keywidth = 0
173 j = i
174 while j < len(blocks) and blocks[j]['type'] == 'field':
175 m = _fieldre.match(blocks[j]['lines'][0])
176 key, rest = m.groups()
177 blocks[j]['lines'][0] = rest
178 blocks[j]['key'] = key
179 keywidth = max(keywidth, len(key))
180 j += 1
181
182 for block in blocks[i:j]:
183 block['keywidth'] = keywidth
184 i = j + 1
185
159 return blocks 186 return blocks
160 187
161 188
162 def findsections(blocks): 189 def findsections(blocks):
163 """Finds sections. 190 """Finds sections.
226 initindent = subindent = indent 253 initindent = subindent = indent
227 if block['type'] == 'bullet': 254 if block['type'] == 'bullet':
228 m = _bulletre.match(block['lines'][0]) 255 m = _bulletre.match(block['lines'][0])
229 subindent = indent + m.end() * ' ' 256 subindent = indent + m.end() * ' '
230 elif block['type'] == 'field': 257 elif block['type'] == 'field':
231 m = _fieldre.match(block['lines'][0]) 258 keywidth = block['keywidth']
232 key, spaces, rest = m.groups() 259 key = block['key']
233 # Turn ":foo: bar" into "foo bar". 260
234 block['lines'][0] = '%s %s%s' % (key, spaces, rest) 261 subindent = indent + _fieldwidth * ' '
235 subindent = indent + (2 + len(key) + len(spaces)) * ' ' 262 if len(key) + 2 > _fieldwidth:
263 # key too large, use full line width
264 key = key.ljust(width)
265 elif keywidth + 2 < _fieldwidth:
266 # all keys are small, add only two spaces
267 key = key.ljust(keywidth + 2)
268 subindent = indent + (keywidth + 2) * ' '
269 else:
270 # mixed sizes, use fieldwidth for this one
271 key = key.ljust(_fieldwidth)
272 block['lines'][0] = key + block['lines'][0]
236 elif block['type'] == 'option': 273 elif block['type'] == 'option':
237 m = _optionre.match(block['lines'][0]) 274 m = _optionre.match(block['lines'][0])
238 option, arg, rest = m.groups() 275 option, arg, rest = m.groups()
239 subindent = indent + (len(option) + len(arg)) * ' ' 276 subindent = indent + (len(option) + len(arg)) * ' '
240 277
250 for b in blocks: 287 for b in blocks:
251 b['indent'] += indent 288 b['indent'] += indent
252 blocks = findliteralblocks(blocks) 289 blocks = findliteralblocks(blocks)
253 blocks = inlineliterals(blocks) 290 blocks = inlineliterals(blocks)
254 blocks = splitparagraphs(blocks) 291 blocks = splitparagraphs(blocks)
292 blocks = updatefieldlists(blocks)
255 blocks = findsections(blocks) 293 blocks = findsections(blocks)
256 blocks = addmargins(blocks) 294 blocks = addmargins(blocks)
257 return '\n'.join(formatblock(b, width) for b in blocks) 295 return '\n'.join(formatblock(b, width) for b in blocks)
258 296
259 297
270 text = open(sys.argv[1]).read() 308 text = open(sys.argv[1]).read()
271 blocks = debug(findblocks, text) 309 blocks = debug(findblocks, text)
272 blocks = debug(findliteralblocks, blocks) 310 blocks = debug(findliteralblocks, blocks)
273 blocks = debug(inlineliterals, blocks) 311 blocks = debug(inlineliterals, blocks)
274 blocks = debug(splitparagraphs, blocks) 312 blocks = debug(splitparagraphs, blocks)
313 blocks = debug(updatefieldlists, blocks)
275 blocks = debug(findsections, blocks) 314 blocks = debug(findsections, blocks)
276 blocks = debug(addmargins, blocks) 315 blocks = debug(addmargins, blocks)
277 print '\n'.join(formatblock(b, 30) for b in blocks) 316 print '\n'.join(formatblock(b, 30) for b in blocks)