SF.net SVN: docutils:[10229 ] trunk/docutils

milde--- via Docutils-checkins <[email protected]> Tue, 09 Sep 2025 09:54:20 +0000
Newsgroups gmane.text.docutils.cvs
Message-ID <[email protected]>
Revision: 10229
          http://sourceforge.net/p/docutils/code/10229
Author:   milde
Date:     2025-09-09 09:54:18 +0000 (Tue, 09 Sep 2025)
Log Message:
-----------
rST parser: Use `section_level_offset` instead of `memo.section_level`.

Keeping record of the current section level in the state machine's "memo"
is cumbersome and error prone because it needs to be updated with every switch
of the current node.

Store the difference between the intended start level of nested parsing and the
number of parents of the base node in the new attribute `section_level_offset`.
Use it to correct the section level determined via `node.section_hierarchy()`.

Modified Paths:
--------------
    trunk/docutils/docutils/parsers/rst/states.py
    trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py

Modified: trunk/docutils/docutils/parsers/rst/states.py
===================================================================
--- trunk/docutils/docutils/parsers/rst/states.py	2025-09-08 13:44:23 UTC (rev 10228)
+++ trunk/docutils/docutils/parsers/rst/states.py	2025-09-09 09:54:18 UTC (rev 10229)
@@ -141,7 +141,16 @@
 
     The entry point to reStructuredText parsing is the `run()` method.
     """
+    section_level_offset: int = 0
+    """Correction term for section level determination in nested parsing.
 
+    Updated by `RSTState.nested_parse()` and used in
+    `RSTState.check_subsection()` to compensate differences when
+    nested parsing uses a detached base node with a document-wide
+    section title style hierarchy or the current node with a new,
+    independent title style hierarchy.
+    """
+
     def run(self, input_lines, document, input_offset=0, match_titles=True,
             inliner=None) -> None:
         """
@@ -157,13 +166,13 @@
             inliner = Inliner()
         inliner.init_customizations(document.settings)
         # A collection of objects to share with nested parsers.
-        # The attributes `reporter` and `section_bubble_up_kludge`
-        # will be removed in Docutils 2.0
+        # The attributes `reporter`, `section_level`, and
+        # `section_bubble_up_kludge` will be removed in Docutils 2.0
         self.memo = Struct(document=document,
                            reporter=document.reporter,  # ignored
                            language=self.language,
                            title_styles=[],
-                           section_level=0,  # (0 document, 1 section, ...)
+                           section_level=0,  # ignored
                            section_bubble_up_kludge=False,  # ignored
                            inliner=inliner)
         self.document = document
@@ -176,7 +185,7 @@
         self.node = self.memo = None    # remove unneeded references
 
 
-class NestedStateMachine(StateMachineWS):
+class NestedStateMachine(RSTStateMachine):
     """
     StateMachine run from within other StateMachine runs, to parse nested
     document structures.
@@ -333,6 +342,15 @@
         if (node == self.state_machine.node
                 and not isinstance(node, (nodes.document, nodes.section))):
             match_titles = False  # avoid invalid sections
+        if match_titles:
+            # Compensate mismatch of known title styles and number of
+            # parent sections of the base node if the document wide
+            # title styles are used with a detached base node or
+            # a new list of title styles with the current parent node:
+            l_node = len(node.section_hierarchy())
+            l_start = min(len(self.parent.section_hierarchy()),
+                          len(self.memo.title_styles))
+            my_state_machine.section_level_offset = l_start - l_node
 
         # run the state machine and populate `node`:
         block_length = len(block)
@@ -349,10 +367,6 @@
                         sm = sm.parent_state_machine
                 except AttributeError:
                     pass
-            # set section level
-            # (fails with Sphinx's `_fresh_title_style_context`)
-            self.memo.section_level = len(
-                self.state_machine.node.section_hierarchy())
         # clean up
         new_offset = my_state_machine.abs_line_offset()
         if use_default == 2:
@@ -423,8 +437,10 @@
         (or the root node if the new section is a top-level section).
         """
         title_styles = self.memo.title_styles
+        parent_sections = self.parent.section_hierarchy()
         # current section level: (0 root, 1 section, 2 subsection, ...)
-        oldlevel = self.memo.section_level
+        oldlevel = (len(parent_sections)
+                    + self.state_machine.section_level_offset)
         # new section level:
         try:  # check for existing title style
             newlevel = title_styles.index(style) + 1
@@ -443,7 +459,6 @@
             return False
         if newlevel <= oldlevel:
             # new section is sibling or higher up in the section hierarchy
-            parent_sections = self.parent.section_hierarchy()
             try:
                 new_parent = parent_sections[newlevel-oldlevel-1].parent
             except IndexError:

Modified: trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py
===================================================================
--- trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py	2025-09-08 13:44:23 UTC (rev 10228)
+++ trunk/docutils/test/test_parsers/test_rst/test_nested_parsing.py	2025-09-09 09:54:18 UTC (rev 10229)
@@ -71,9 +71,6 @@
                 sm.node = self.state_machine.node
         except AttributeError:
             pass
-        # Update section level:
-        self.state_machine.memo.section_level = len(
-            self.state_machine.node.section_hierarchy())
         return []  # node already attached to document
 
 
@@ -126,9 +123,6 @@
         with _fresh_title_style_context(self.state):
             self.state.nested_parse(self.content, self.content_offset,
                                     match_titles=True)
-        # update section level
-        self.state_machine.memo.section_level = len(
-            self.state_machine.node.section_hierarchy())
         return []  # node already attached to document
 
 
@@ -137,7 +131,6 @@
     # copied from sphinx/sphinx/util/parsing.py
     memo = state.memo
     surrounding_title_styles = memo.title_styles
-    surrounding_section_level = memo.section_level
     memo.title_styles = []
     memo.section_level = 0
     try:
@@ -144,7 +137,6 @@
         yield
     finally:
         memo.title_styles = surrounding_title_styles
-        memo.section_level = surrounding_section_level
 
 
 class ParserTestCase(unittest.TestCase):

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.