@@ -229,6 +229,24 @@ def _parse_param_list(self, content):
229
229
230
230
return params
231
231
232
+ _role = r":(?P<role>\w+):"
233
+ _funcbacktick = r"`(?P<name>(?:~\w+\.)?[a-zA-Z0-9_.-]+)`"
234
+ _funcplain = r"(?P<name2>[a-zA-Z0-9_.-]+)"
235
+ _funcname = r"(" + _role + _funcbacktick + r"|" + _funcplain + r")"
236
+ _funcnamenext = _funcname .replace ('role' , 'rolenext' ).replace ('name' , 'namenext' )
237
+ _description = r"(?P<description>\s*:(\s+(?P<desc>\S+.*))?)?\s*$"
238
+ _func_rgx = re .compile (r"^\s*" + _funcname + r"\s*" , re .X )
239
+ # _funcs_rgx = re.compile(r"^\s*" + _funcname + r"(?P<morefuncs>([,\s]\s*" + _funcnamenext + r")*)" + r"\s*", re.X)
240
+ _line_rgx = re .compile (r"^\s*"
241
+ + r"(?P<allfuncs>" # group for all function names
242
+ + _funcname
243
+ + r"(?P<morefuncs>([,]\s+"
244
+ + _funcnamenext + r")*)"
245
+ + r")" # end of "allfuncs"
246
+ + r"(\s*,)?" # Some function lists have a trailing comma
247
+ + _description ,
248
+ re .X )
249
+
232
250
_name_rgx = re .compile (r"^\s*(:(?P<role>\w+):"
233
251
r"`(?P<name>(?:~\w+\.)?[a-zA-Z0-9_.-]+)`|"
234
252
r" (?P<name2>[a-zA-Z0-9_.-]+))\s*" , re .X )
@@ -245,48 +263,62 @@ def _parse_see_also(self, content):
245
263
246
264
def parse_item_name (text ):
247
265
"""Match ':role:`name`' or 'name'"""
248
- m = self ._name_rgx .match (text )
249
- if m :
250
- g = m .groups ()
251
- if g [1 ] is None :
252
- return g [3 ], None
253
- else :
254
- return g [2 ], g [1 ]
255
- raise ParseError ("%s is not a item name" % text )
266
+ m = self ._func_rgx .match (text )
267
+ if not m :
268
+ raise ParseError ("%s is not a item name" % text )
269
+ role = m .groupdict ().get ('role' )
270
+ if role :
271
+ name = m .group ('name' )
272
+ else :
273
+ name = m .group ('name2' )
274
+ return name , role , m
256
275
257
276
def push_item (name , rest ):
258
277
if not name :
259
278
return
260
- name , role = parse_item_name (name )
279
+ name , role , m2 = parse_item_name (name )
261
280
items .append ((name , list (rest ), role ))
262
281
del rest [:]
263
282
264
- current_func = None
265
283
rest = []
266
284
267
285
for line in content :
268
286
if not line .strip ():
269
287
continue
270
288
271
- m = self ._name_rgx .match (line )
272
- if m and line [m .end ():].strip ().startswith (':' ):
273
- push_item (current_func , rest )
274
- current_func , line = line [:m .end ()], line [m .end ():]
275
- rest = [line .split (':' , 1 )[1 ].strip ()]
276
- if not rest [0 ]:
277
- rest = []
278
- elif not line .startswith (' ' ):
279
- push_item (current_func , rest )
280
- current_func = None
281
- if ',' in line :
282
- for func in line .split (',' ):
283
- if func .strip ():
284
- push_item (func , [])
285
- elif line .strip ():
286
- current_func = line
287
- elif current_func is not None :
289
+ ml = self ._line_rgx .match (line )
290
+ description = None
291
+ if ml :
292
+ if 'description' in ml .groupdict ():
293
+ description = ml .groupdict ().get ('desc' )
294
+ if not description and line .startswith (' ' ):
288
295
rest .append (line .strip ())
289
- push_item (current_func , rest )
296
+ elif ml :
297
+ funcs = []
298
+ text = ml .group ('allfuncs' )
299
+ while True :
300
+ if not text .strip ():
301
+ break
302
+ name , role , m2 = parse_item_name (text )
303
+ # m2 = self._func_rgx.match(text)
304
+ # if not m2:
305
+ # raise ParseError("%s is not a item name" % line)
306
+ # role = m2.groupdict().get('role')
307
+ # if role:
308
+ # name = m2.group('name')
309
+ # else:
310
+ # name = m2.group('name2')
311
+ funcs .append ((name , role ))
312
+ text = text [m2 .end ():].strip ()
313
+ if text and text [0 ] == ',' :
314
+ text = text [1 :].strip ()
315
+ if description :
316
+ rest = [description ]
317
+ else :
318
+ rest = []
319
+ items .append ((funcs , rest ))
320
+ else :
321
+ raise ParseError ("%s is not a item name" % line )
290
322
return items
291
323
292
324
def _parse_index (self , section , content ):
@@ -432,25 +464,35 @@ def _str_see_also(self, func_role):
432
464
return []
433
465
out = []
434
466
out += self ._str_header ("See Also" )
467
+ out += ['' ]
435
468
last_had_desc = True
436
- for func , desc , role in self ['See Also' ]:
437
- if role :
438
- link = ':%s:`%s`' % (role , func )
439
- elif func_role :
440
- link = ':%s:`%s`' % (func_role , func )
441
- else :
442
- link = "`%s`_" % func
443
- if desc or last_had_desc :
444
- out += ['' ]
445
- out += [link ]
446
- else :
447
- out [- 1 ] += ", %s" % link
469
+ for funcs , desc in self ['See Also' ]:
470
+ assert isinstance (funcs , (list , tuple ))
471
+ links = []
472
+ for func , role in funcs :
473
+ if role :
474
+ link = ':%s:`%s`' % (role , func )
475
+ elif func_role :
476
+ link = ':%s:`%s`' % (func_role , func )
477
+ else :
478
+ link = "`%s`_" % func
479
+ links .append (link )
480
+ link = ', ' .join (links )
481
+ out += [link ]
448
482
if desc :
449
483
out += self ._str_indent ([' ' .join (desc )])
450
484
last_had_desc = True
451
485
else :
452
486
last_had_desc = False
487
+ out += ['' ]
488
+ if last_had_desc :
489
+ out += ['' ]
453
490
out += ['' ]
491
+ # if 1:
492
+ # print()
493
+ # for l in out:
494
+ # print(repr(l))
495
+ # # print(out)
454
496
return out
455
497
456
498
def _str_index (self ):
0 commit comments