[rtems-central commit] sphinxcontent: Rework label handling

Sebastian Huber sebh at rtems.org
Tue May 9 13:45:26 UTC 2023


Module:    rtems-central
Branch:    master
Commit:    e38207f81d0da414e07d982ab17699e109d3f2e2
Changeset: http://git.rtems.org/rtems-central/commit/?id=e38207f81d0da414e07d982ab17699e109d3f2e2

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Fri May  5 14:41:18 2023 +0200

sphinxcontent: Rework label handling

Rename get_label() in make_label().  Add a label stack to SphinxContent.

---

 rtemsspec/interfacedoc.py              | 15 ++++----
 rtemsspec/membench.py                  | 13 +++----
 rtemsspec/specdoc.py                   | 13 ++++---
 rtemsspec/sphinxcontent.py             | 66 ++++++++++++++++++++++------------
 rtemsspec/tests/test_content_sphinx.py | 46 +++++++++---------------
 rtemsspec/tests/test_membench.py       |  2 +-
 6 files changed, 85 insertions(+), 70 deletions(-)

diff --git a/rtemsspec/interfacedoc.py b/rtemsspec/interfacedoc.py
index 335c4e85..f7da0adf 100644
--- a/rtemsspec/interfacedoc.py
+++ b/rtemsspec/interfacedoc.py
@@ -32,7 +32,7 @@ from typing import Any, Dict, List, Tuple
 
 from rtemsspec.content import CContent, get_value_compound, \
     get_value_forward_declaration, get_value_unspecified_type
-from rtemsspec.sphinxcontent import get_label, get_reference, sanitize_name, \
+from rtemsspec.sphinxcontent import make_label, get_reference, sanitize_name, \
     SphinxContent, SphinxInterfaceMapper
 from rtemsspec.items import Item, ItemCache, ItemGetValueContext, ItemMapper
 
@@ -40,7 +40,7 @@ ItemMap = Dict[str, Item]
 
 
 def _get_reference(name: str) -> str:
-    return get_reference(get_label(f"Interface {name}"))
+    return get_reference(make_label(f"Interface {name}"))
 
 
 def _get_code_param(ctx: ItemGetValueContext) -> Any:
@@ -67,9 +67,10 @@ def _generate_introduction(target: str, group: Item, group_uids: List[str],
     content = SphinxContent()
     content.register_license_and_copyrights_of_item(group)
     content.add_automatically_generated_warning()
-    group_name = group["name"]
     content.add(f".. Generated from spec:{group.uid}")
-    with content.section("Introduction", get_label(group_name)):
+    group_name = group["name"]
+    content.push_label(make_label(group_name))
+    with content.section("Introduction"):
         # This needs to be in front of the list since comment blocks have an
         # effect on the list layout in the HTML output
         content.add(".. The following list was generated from:")
@@ -180,7 +181,8 @@ def _generate_directives(target: str, group: Item, group_uids: List[str],
     content.register_license_and_copyrights_of_item(group)
     content.add_automatically_generated_warning()
     group_name = group["name"]
-    with content.section("Directives", get_label(group_name)):
+    content.push_label(make_label(group_name))
+    with content.section("Directives"):
         content.wrap([
             f"This section details the directives of the {group_name}.",
             "A subsection is dedicated to each of this manager's directives",
@@ -197,7 +199,8 @@ def _generate_directives(target: str, group: Item, group_uids: List[str],
                 content.add("\\clearpage")
             directive = f"{name}()"
             content.add_index_entries([directive] + item["index-entries"])
-            with content.section(directive, "Interface"):
+            with content.section(directive,
+                                 label=make_label(f"Interface {directive}")):
                 _generate_directive(content, mapper, code_mapper, item,
                                     enabled)
     content.add_licence_and_copyrights()
diff --git a/rtemsspec/membench.py b/rtemsspec/membench.py
index d7a554b5..993d17c9 100644
--- a/rtemsspec/membench.py
+++ b/rtemsspec/membench.py
@@ -32,7 +32,7 @@ import re
 from typing import Dict, List, Tuple
 
 from rtemsspec.items import Item, ItemMapper
-from rtemsspec.sphinxcontent import get_label, get_reference, SphinxContent
+from rtemsspec.sphinxcontent import make_label, get_reference, SphinxContent
 from rtemsspec.util import run_command
 
 _SECTION = re.compile(
@@ -118,8 +118,8 @@ def _get_sections(item: Item, path: str) -> Dict[str, Tuple[int, int]]:
     return sections
 
 
-def _get_label(item: Item) -> str:
-    return get_label(f"MemBenchmark {item.uid[1:]}")
+def _make_label(item: Item) -> str:
+    return make_label(f"MemBenchmark {item.uid[1:]}")
 
 
 def _generate_table(content: SphinxContent, items: List[Item],
@@ -127,7 +127,7 @@ def _generate_table(content: SphinxContent, items: List[Item],
     rows: List[Tuple[str, ...]] = []
     for index, item in enumerate(items):
         sections = _get_sections(item, path)
-        name = (get_reference(_get_label(item), item.uid), )
+        name = (get_reference(_make_label(item), item.uid), )
         if index == 0:
             keys = ("spec", ) + tuple(sections.keys())
             base = {key: info[1] - info[0] for key, info in sections.items()}
@@ -141,7 +141,8 @@ def _generate_table(content: SphinxContent, items: List[Item],
     section = f"Benchmarks Based on: {pivot.spec}"
     with content.section(section):
         content.wrap(f"""The following memory benchmarks are based on the
-memory benchmark defined by {get_reference(_get_label(pivot), pivot.spec)}.""")
+memory benchmark defined by
+{get_reference(_make_label(pivot), pivot.spec)}.""")
         content.add_simple_table(rows)
 
 
@@ -149,7 +150,7 @@ def _generate_paragraphs(content: SphinxContent, items: List[Item],
                          mapper: ItemMapper) -> None:
     for item in items:
         section = f"Benchmark: {item.spec}"
-        with content.section(section, label=_get_label(item)):
+        with content.section(section, label=_make_label(item)):
             content.wrap(mapper.substitute(item["test-brief"], item))
             content.wrap(mapper.substitute(item["test-description"], item))
 
diff --git a/rtemsspec/specdoc.py b/rtemsspec/specdoc.py
index 658da477..cbab0574 100644
--- a/rtemsspec/specdoc.py
+++ b/rtemsspec/specdoc.py
@@ -27,7 +27,7 @@
 import re
 from typing import Any, Dict, Iterator, List, Optional, Pattern, Set, Tuple
 
-from rtemsspec.sphinxcontent import get_reference, get_label, \
+from rtemsspec.sphinxcontent import get_reference, make_label, \
     SphinxContent, SphinxMapper
 from rtemsspec.items import Item, ItemCache, ItemGetValueContext
 from rtemsspec.specverify import NAME
@@ -275,7 +275,7 @@ class _Documenter:
 
     def _get_ref_specification_type(self, ctx: ItemGetValueContext) -> Any:
         return get_reference(self._label_prefix +
-                             get_label(ctx.value[ctx.key]))
+                             make_label(ctx.value[ctx.key]))
 
     def _substitute(self, text: str) -> str:
         if text:
@@ -284,7 +284,7 @@ class _Documenter:
 
     def get_section_reference(self) -> str:
         """ Returns the section reference. """
-        return get_reference(self._label_prefix + get_label(self.section))
+        return get_reference(self._label_prefix + make_label(self.section))
 
     def get_a_section_reference(self) -> str:
         """ Returns a section reference. """
@@ -440,7 +440,9 @@ class _Documenter:
         if self.get_list_element_type():
             return
         content.register_license_and_copyrights_of_item(self._item)
-        with content.section(self.section, self._label_prefix):
+        with content.section(
+                self.section,
+                label=f"{self._label_prefix}{make_label(self.section)}"):
             last = content.lines[-1]
             self._add_description(content)
             if len(self._info_map) == 1:
@@ -560,8 +562,9 @@ def document(config: dict, item_cache: ItemCache) -> None:
     for documenter in documenter_map.values():
         documenter.resolve_used_by()
     documenter_names = set(documenter_map)
-    content.section_label_prefix = config["section-label-prefix"]
+    content.push_label(config["section-label-prefix"])
     with content.section(config["section-name"]):
+        content.push_label(config["section-label-prefix"])
         with content.section(config["hierarchy-subsection-name"]):
             content.add(config["hierarchy-text"])
             root_documenter.hierarchy(content, ignore)
diff --git a/rtemsspec/sphinxcontent.py b/rtemsspec/sphinxcontent.py
index abec5553..42cf6430 100644
--- a/rtemsspec/sphinxcontent.py
+++ b/rtemsspec/sphinxcontent.py
@@ -45,7 +45,7 @@ def get_reference(label: str, name: Optional[str] = None) -> str:
     return f":ref:`{label}`"
 
 
-def get_label(name: str) -> str:
+def make_label(name: str) -> str:
     """ Returns the label for the specified name. """
     return to_camel_case(name.strip())
 
@@ -77,7 +77,36 @@ class SphinxContent(Content):
         super().__init__("CC-BY-SA-4.0", True)
         self._tab = "    "
         self._section_level = section_level
-        self.section_label_prefix = "Section"
+        self._label_stack = [""]
+
+    @property
+    def label(self) -> str:
+        """ This is the top of the label stack. """
+        return self._label_stack[-1]
+
+    def get_label(self, label_tail: str = "") -> str:
+        """
+        Returns the concatenation of the top of the label stack and the label
+        tail.
+        """
+        return f"{self.label}{label_tail}"
+
+    def push_label(self, label: str) -> None:
+        """ Pushes the label to the label stack. """
+        self._label_stack.append(label)
+
+    def push_label_tail(self, label_tail: str) -> str:
+        """
+        Makes a label from the concatenation of the top of the label stack and
+        the label tail.  Pushes this label to the label stack and returns it.
+        """
+        label = self.get_label(label_tail)
+        self.push_label(label)
+        return label
+
+    def pop_label(self) -> None:
+        """ Pops the top from the label stack. """
+        self._label_stack.pop()
 
     def add_label(self, label: str) -> None:
         """ Adds a label. """
@@ -88,20 +117,6 @@ class SphinxContent(Content):
         name = name.strip()
         self.add([name, _HEADER_LEVELS[level] * len(name)])
 
-    def add_header_with_label(self,
-                              name: str,
-                              level: int = 2,
-                              label_prefix: Optional[str] = None,
-                              label: Optional[str] = None) -> str:
-        """ Adds a header with label. """
-        if label is None:
-            if label_prefix is None:
-                label_prefix = self.section_label_prefix
-            label = label_prefix + get_label(name)
-        self.add_label(label)
-        self.add_header(name, level)
-        return label
-
     def add_rubric(self, name: str) -> None:
         """ Adds a rubric. """
         self.add(f".. rubric:: {name}")
@@ -175,25 +190,32 @@ class SphinxContent(Content):
 
     def open_section(self,
                      name: str,
-                     label_prefix: Optional[str] = None,
+                     label_tail: Optional[str] = None,
                      label: Optional[str] = None) -> str:
         """ Opens a section. """
-        label = self.add_header_with_label(name, self._section_level,
-                                           label_prefix, label)
+        if label is None:
+            if label_tail is None:
+                label_tail = make_label(name)
+            label = self.push_label_tail(label_tail)
+        else:
+            self.push_label(label)
+        self.add_label(label)
+        self.add_header(name, self._section_level)
         self._section_level += 1
         return label
 
     def close_section(self) -> None:
         """ Closes a section. """
         self._section_level -= 1
+        self.pop_label()
 
     @contextmanager
     def section(self,
                 name: str,
-                label_prefix: Optional[str] = None,
+                label_tail: Optional[str] = None,
                 label: Optional[str] = None) -> Iterator[str]:
         """ Opens a section context. """
-        yield self.open_section(name, label_prefix, label)
+        yield self.open_section(name, label_tail, label)
         self.close_section()
 
     def open_latex_tiny(self, size: str = "tiny") -> None:
@@ -427,7 +449,7 @@ class SphinxInterfaceMapper(SphinxMapper):
         name = ctx.value[ctx.key]
         for group in ctx.item.parents("interface-ingroup"):
             if group.uid in self._group_uids:
-                return get_reference(get_label(f"Interface {name}"))
+                return get_reference(make_label(f"Interface {name}"))
         return f":c:func:`{name}`"
 
     def _get_group(self, ctx: ItemGetValueContext) -> Any:
diff --git a/rtemsspec/tests/test_content_sphinx.py b/rtemsspec/tests/test_content_sphinx.py
index 59903283..07724c30 100644
--- a/rtemsspec/tests/test_content_sphinx.py
+++ b/rtemsspec/tests/test_content_sphinx.py
@@ -26,7 +26,7 @@
 
 import pytest
 
-from rtemsspec.sphinxcontent import get_reference, get_label, \
+from rtemsspec.sphinxcontent import get_reference, make_label, \
     SphinxContent, SphinxMapper
 from rtemsspec.items import Item, ItemCache, ItemMapper
 from rtemsspec.tests.util import create_item_cache_config_and_copy_spec
@@ -76,36 +76,13 @@ yz
 """
 
 
-def test_add_header_with_label():
-    content = SphinxContent()
-    label = content.add_header_with_label("x", 1)
-    assert label == "SectionX"
-    assert str(content) == """.. _SectionX:
-
-x
-*
-"""
-    label = content.add_header_with_label("yz w", 2)
-    assert label == "SectionYzW"
-    assert str(content) == """.. _SectionX:
-
-x
-*
-
-.. _SectionYzW:
-
-yz w
-====
-"""
-
-
 def test_get_reference():
     assert get_reference("a") == ":ref:`a`"
     assert get_reference("a", "b") == ":ref:`b <a>`"
 
 
-def test_get_label():
-    assert get_label("ab cd") == "AbCd"
+def test_make_label():
+    assert make_label("ab cd") == "AbCd"
 
 
 def test_section():
@@ -114,19 +91,28 @@ def test_section():
         content.add(label)
         with content.section("ef gh") as label2:
             content.add(label2)
-    assert str(content) == """.. _SectionAbCd:
+            with content.section("ij kl", "mn") as label2:
+                content.add(label2)
+    assert str(content) == """.. _AbCd:
 
 ab cd
 =====
 
-SectionAbCd
+AbCd
 
-.. _SectionEfGh:
+.. _AbCdEfGh:
 
 ef gh
 -----
 
-SectionEfGh
+AbCdEfGh
+
+.. _AbCdEfGhmn:
+
+ij kl
+^^^^^
+
+AbCdEfGhmn
 """
 
 
diff --git a/rtemsspec/tests/test_membench.py b/rtemsspec/tests/test_membench.py
index 3bc5ecb5..ffbe2aea 100644
--- a/rtemsspec/tests/test_membench.py
+++ b/rtemsspec/tests/test_membench.py
@@ -49,7 +49,7 @@ def test_membench(tmpdir, monkeypatch):
     root = item_cache["/r0"]
     content = SphinxContent()
     generate(content, root, ItemMapper(root), ["/r0"], "path")
-    assert str(content) == """.. _SectionBenchmarksBasedOnSpecT0:
+    assert str(content) == """.. _BenchmarksBasedOnSpecT0:
 
 Benchmarks Based on: spec:/t0
 =============================



More information about the vc mailing list