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