@@ -482,56 +482,84 @@ def _toctree_add_classes(node: Element, depth: int, docname: str) -> None:
482
482
subnode = subnode .parent
483
483
484
484
485
- ET = TypeVar ('ET ' , bound = Element )
485
+ _ET = TypeVar ('_ET ' , bound = Element )
486
486
487
487
488
488
def _toctree_copy (
489
- node : ET , depth : int , maxdepth : int , collapse : bool , tags : Tags
490
- ) -> ET :
489
+ node : _ET , depth : int , maxdepth : int , collapse : bool , tags : Tags
490
+ ) -> _ET :
491
491
"""Utility: Cut and deep-copy a TOC at a specified depth."""
492
- keep_bullet_list_sub_nodes = depth <= 1 or (
493
- (depth <= maxdepth or maxdepth <= 0 ) and (not collapse or 'iscurrent' in node )
494
- )
492
+ assert not isinstance (node , addnodes .only )
493
+ depth = max (depth - 1 , 1 )
494
+ copied = _toctree_copy_seq (node , depth , maxdepth , collapse , tags , initial_call = True )
495
+ assert len (copied ) == 1
496
+ return copied [0 ] # type: ignore[return-value]
495
497
496
- copy = node .copy ()
497
- for subnode in node .children :
498
- if isinstance (subnode , addnodes .compact_paragraph | nodes .list_item ):
499
- # for <p> and <li>, just recurse
500
- copy .append (_toctree_copy (subnode , depth , maxdepth , collapse , tags ))
501
- elif isinstance (subnode , nodes .bullet_list ):
502
- # for <ul>, copy if the entry is top-level
503
- # or, copy if the depth is within bounds and;
504
- # collapsing is disabled or the sub-entry's parent is 'current'.
505
- # The boolean is constant so is calculated outwith the loop.
506
- if keep_bullet_list_sub_nodes :
507
- copy .append (_toctree_copy (subnode , depth + 1 , maxdepth , collapse , tags ))
508
- elif isinstance (subnode , addnodes .toctree ):
509
- # copy sub toctree nodes for later processing
510
- copy .append (subnode .copy ())
511
- elif isinstance (subnode , addnodes .only ):
512
- # only keep children if the only node matches the tags
513
- if _only_node_keep_children (subnode , tags ):
514
- for child in subnode .children :
515
- copy .append (
516
- _toctree_copy (
517
- child ,
518
- depth ,
519
- maxdepth ,
520
- collapse ,
521
- tags , # type: ignore[type-var]
522
- )
523
- )
524
- elif isinstance (subnode , nodes .reference | nodes .title ):
525
- # deep copy references and captions
526
- sub_node_copy = subnode .copy ()
527
- sub_node_copy .children = [child .deepcopy () for child in subnode .children ]
528
- for child in sub_node_copy .children :
529
- child .parent = sub_node_copy
530
- copy .append (sub_node_copy )
531
- else :
532
- msg = f'Unexpected node type { subnode .__class__ .__name__ !r} !'
533
- raise ValueError (msg ) # NoQA: TRY004
534
- return copy
498
+
499
+ def _toctree_copy_seq (
500
+ node : Node ,
501
+ depth : int ,
502
+ maxdepth : int ,
503
+ collapse : bool ,
504
+ tags : Tags ,
505
+ * ,
506
+ initial_call : bool = False ,
507
+ is_current : bool = False ,
508
+ ) -> list [Element ]:
509
+ copy : Element
510
+ if isinstance (node , addnodes .compact_paragraph | nodes .list_item ):
511
+ # for <p> and <li>, just recurse
512
+ copy = node .copy ()
513
+ for subnode in node .children :
514
+ copy += _toctree_copy_seq ( # type: ignore[assignment,operator]
515
+ subnode , depth , maxdepth , collapse , tags , is_current = 'iscurrent' in node
516
+ )
517
+ return [copy ]
518
+
519
+ if isinstance (node , nodes .bullet_list ):
520
+ # for <ul>, copy if the entry is top-level
521
+ # or, copy if the depth is within bounds and;
522
+ # collapsing is disabled or the sub-entry's parent is 'current'.
523
+ # The boolean is constant so is calculated outwith the loop.
524
+ keep_bullet_list_sub_nodes = depth <= 1 or (
525
+ (depth <= maxdepth or maxdepth <= 0 )
526
+ and (not collapse or is_current or 'iscurrent' in node )
527
+ )
528
+ if not keep_bullet_list_sub_nodes and not initial_call :
529
+ return []
530
+ depth += 1
531
+ copy = node .copy ()
532
+ for subnode in node .children :
533
+ copy += _toctree_copy_seq (
534
+ subnode , depth , maxdepth , collapse , tags , is_current = 'iscurrent' in node
535
+ )
536
+ return [copy ]
537
+
538
+ if isinstance (node , addnodes .toctree ):
539
+ # copy sub toctree nodes for later processing
540
+ return [node .copy ()]
541
+
542
+ if isinstance (node , addnodes .only ):
543
+ # only keep children if the only node matches the tags
544
+ if not _only_node_keep_children (node , tags ):
545
+ return []
546
+ copied : list [Element ] = []
547
+ for subnode in node .children :
548
+ copied += _toctree_copy_seq (
549
+ subnode , depth , maxdepth , collapse , tags , is_current = 'iscurrent' in node
550
+ )
551
+ return copied
552
+
553
+ if isinstance (node , nodes .reference | nodes .title ):
554
+ # deep copy references and captions
555
+ sub_node_copy = node .copy ()
556
+ sub_node_copy .children = [child .deepcopy () for child in node .children ]
557
+ for child in sub_node_copy .children :
558
+ child .parent = sub_node_copy
559
+ return [sub_node_copy ]
560
+
561
+ msg = f'Unexpected node type { node .__class__ .__name__ !r} !'
562
+ raise ValueError (msg )
535
563
536
564
537
565
def _get_toctree_ancestors (
0 commit comments