@@ -659,10 +659,23 @@ class InsertIndexInfo:
659
659
PARAM_SYNONYMS = ("param " , "parameter " , "arg " , "argument " , "keyword " , "kwarg " , "kwparam " )
660
660
661
661
662
- def line_before_node (node : Node ) -> int :
663
- line = node .line
664
- assert line
665
- return line - 2
662
+ def node_line_no (node : Node ) -> int | None :
663
+ """
664
+ Get the 1-indexed line on which the node starts if possible. If not, return
665
+ None.
666
+
667
+ Descend through the first children until we locate one with a line number or
668
+ return None if None of them have one.
669
+
670
+ I'm not aware of any rst on which this returns None, to find out would
671
+ require a more detailed analysis of the docutils rst parser source code. An
672
+ example where the node doesn't have a line number but the first child does
673
+ is all `definition_list` nodes. It seems like bullet_list and option_list
674
+ get line numbers, but enum_list also doesn't. *shrug*.
675
+ """
676
+ while node .line is None and node .children :
677
+ node = node .children [0 ]
678
+ return node .line
666
679
667
680
668
681
def tag_name (node : Node ) -> str :
@@ -690,39 +703,29 @@ def get_insert_index(app: Sphinx, lines: list[str]) -> InsertIndexInfo | None:
690
703
# Find a top level child which is a field_list that contains a field whose
691
704
# name starts with one of the PARAM_SYNONYMS. This is the parameter list. We
692
705
# hope there is at most of these.
693
- for idx , child in enumerate ( doc .children ) :
706
+ for child in doc .children :
694
707
if tag_name (child ) != "field_list" :
695
708
continue
696
709
697
- if any (c .children [0 ].astext ().startswith (PARAM_SYNONYMS ) for c in child .children ):
698
- idx = idx
699
- break
700
- else :
701
- idx = - 1
710
+ if not any (c .children [0 ].astext ().startswith (PARAM_SYNONYMS ) for c in child .children ):
711
+ continue
702
712
703
- if idx == - 1 :
704
- # No parameters
705
- pass
706
- elif idx + 1 < len ( doc . children ):
707
- # Unfortunately docutils only tells us the line numbers that nodes start on,
708
- # not the range (boo!). So insert before the line before the next sibling.
709
- at = line_before_node ( doc . children [ idx + 1 ] )
713
+ # Found it! Try to insert before the next sibling. If there is no next
714
+ # sibling, insert at end.
715
+ # If there is a next sibling but we can't locate a line number, insert
716
+ # at end. (I don't know of any input where this happens.)
717
+ next_sibling = child . next_node ( descend = False , siblings = True )
718
+ line_no = node_line_no ( next_sibling ) if next_sibling else None
719
+ at = line_no - 2 if line_no else len ( lines )
710
720
return InsertIndexInfo (insert_index = at , found_param = True )
711
- else :
712
- # No next sibling, insert at end
713
- return InsertIndexInfo (insert_index = len (lines ), found_param = True )
714
721
715
722
# 4. Insert before examples
716
723
# TODO: Maybe adjust which tags to insert ahead of
717
- for idx , child in enumerate (doc .children ):
718
- if tag_name (child ) not in ["literal_block" , "paragraph" , "field_list" ]:
719
- idx = idx
720
- break
721
- else :
722
- idx = - 1
723
-
724
- if idx != - 1 :
725
- at = line_before_node (doc .children [idx ])
724
+ for child in doc .children :
725
+ if tag_name (child ) in ["literal_block" , "paragraph" , "field_list" ]:
726
+ continue
727
+ line_no = node_line_no (child )
728
+ at = line_no - 2 if line_no else len (lines )
726
729
return InsertIndexInfo (insert_index = at , found_directive = True )
727
730
728
731
# 5. Otherwise, insert at end
0 commit comments