[PATCH 40/57] docs/qapidoc: add visit_freeform() method

John Snow posted 57 patches 4 weeks ago
There is a newer version of this series
[PATCH 40/57] docs/qapidoc: add visit_freeform() method
Posted by John Snow 4 weeks ago
Signed-off-by: John Snow <jsnow@redhat.com>
---
 docs/sphinx/qapidoc.py | 50 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 6de8c900543..cf5dbb0133d 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -29,6 +29,7 @@
 from contextlib import contextmanager
 import os
 from pathlib import Path
+import re
 import sys
 from typing import TYPE_CHECKING
 
@@ -55,6 +56,8 @@
         Sequence,
     )
 
+    from qapi.parser import QAPIDoc
+
     from sphinx.application import Sphinx
     from sphinx.util.typing import ExtensionMetadata
 
@@ -130,6 +133,53 @@ def visit_module(self, path: str) -> None:
         self.add_line_raw(f".. qapi:module:: {name}", path, 1)
         self.ensure_blank_line()
 
+    def visit_freeform(self, doc: QAPIDoc) -> None:
+        # TODO: Once the old qapidoc transformer is deprecated, freeform
+        # sections can be updated to pure rST, and this transformed removed.
+        #
+        # For now, translate our micro-format into rST. Code adapted
+        # from Peter Maydell's freeform().
+
+        assert len(doc.all_sections) == 1, doc.all_sections
+        body = doc.all_sections[0]
+        text = body.text
+        info = doc.info
+
+        if re.match(r"=+ ", text):
+            # Section/subsection heading (if present, will always be the
+            # first line of the block)
+            (heading, _, text) = text.partition("\n")
+            (leader, _, heading) = heading.partition(" ")
+            level = len(leader) + 1  # Implicit +1 for heading in .rST stub
+
+            # https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
+            markers = {
+                1: "#",
+                2: "*",
+                3: "=",
+                4: "-",
+                5: "^",
+                6: '"',
+            }
+            overline = level <= 2
+            marker = markers[level]
+
+            self.ensure_blank_line()
+            # This credits all 2 or 3 lines to the single source line.
+            if overline:
+                self.add_line(marker * len(heading), info)
+            self.add_line(heading, info)
+            self.add_line(marker * len(heading), info)
+            self.ensure_blank_line()
+
+            # Eat blank line(s) and advance info
+            trimmed = text.lstrip("\n")
+            text = trimmed
+            info = info.next_line(len(text) - len(trimmed) + 1)
+
+        self.add_lines(text, info)
+        self.ensure_blank_line()
+
 
 class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
     """A QAPI schema visitor which adds Sphinx dependencies each module
-- 
2.48.1
Re: [PATCH 40/57] docs/qapidoc: add visit_freeform() method
Posted by Markus Armbruster 3 weeks, 5 days ago
John Snow <jsnow@redhat.com> writes:

> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  docs/sphinx/qapidoc.py | 50 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
>
> diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
> index 6de8c900543..cf5dbb0133d 100644
> --- a/docs/sphinx/qapidoc.py
> +++ b/docs/sphinx/qapidoc.py
> @@ -29,6 +29,7 @@
>  from contextlib import contextmanager
>  import os
>  from pathlib import Path
> +import re
>  import sys
>  from typing import TYPE_CHECKING
>  
> @@ -55,6 +56,8 @@
>          Sequence,
>      )
>  
> +    from qapi.parser import QAPIDoc
> +
>      from sphinx.application import Sphinx
>      from sphinx.util.typing import ExtensionMetadata
>  
> @@ -130,6 +133,53 @@ def visit_module(self, path: str) -> None:
>          self.add_line_raw(f".. qapi:module:: {name}", path, 1)
>          self.ensure_blank_line()
>  
> +    def visit_freeform(self, doc: QAPIDoc) -> None:
> +        # TODO: Once the old qapidoc transformer is deprecated, freeform
> +        # sections can be updated to pure rST, and this transformed removed.
> +        #
> +        # For now, translate our micro-format into rST. Code adapted
> +        # from Peter Maydell's freeform().
> +
> +        assert len(doc.all_sections) == 1, doc.all_sections
> +        body = doc.all_sections[0]
> +        text = body.text
> +        info = doc.info
> +
> +        if re.match(r"=+ ", text):
> +            # Section/subsection heading (if present, will always be the
> +            # first line of the block)
> +            (heading, _, text) = text.partition("\n")
> +            (leader, _, heading) = heading.partition(" ")



> +            level = len(leader) + 1  # Implicit +1 for heading in .rST stub

What is the ".rST stub"?

> +
> +            # https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
> +            markers = {
> +                1: "#",
> +                2: "*",
> +                3: "=",
> +                4: "-",
> +                5: "^",
> +                6: '"',
> +            }

I'd be tempted to use markers = '#*=-^".  Matter of taste, yours takes
precedence here.

> +            overline = level <= 2
> +            marker = markers[level]
> +
> +            self.ensure_blank_line()
> +            # This credits all 2 or 3 lines to the single source line.
> +            if overline:
> +                self.add_line(marker * len(heading), info)
> +            self.add_line(heading, info)
> +            self.add_line(marker * len(heading), info)
> +            self.ensure_blank_line()
> +
> +            # Eat blank line(s) and advance info
> +            trimmed = text.lstrip("\n")
> +            text = trimmed
> +            info = info.next_line(len(text) - len(trimmed) + 1)
> +
> +        self.add_lines(text, info)
> +        self.ensure_blank_line()
> +
>  
>  class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
>      """A QAPI schema visitor which adds Sphinx dependencies each module
Re: [PATCH 40/57] docs/qapidoc: add visit_freeform() method
Posted by John Snow 3 weeks, 4 days ago
On Fri, Mar 7, 2025 at 7:10 AM Markus Armbruster <armbru@redhat.com> wrote:

> John Snow <jsnow@redhat.com> writes:
>
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > ---
> >  docs/sphinx/qapidoc.py | 50 ++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 50 insertions(+)
> >
> > diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
> > index 6de8c900543..cf5dbb0133d 100644
> > --- a/docs/sphinx/qapidoc.py
> > +++ b/docs/sphinx/qapidoc.py
> > @@ -29,6 +29,7 @@
> >  from contextlib import contextmanager
> >  import os
> >  from pathlib import Path
> > +import re
> >  import sys
> >  from typing import TYPE_CHECKING
> >
> > @@ -55,6 +56,8 @@
> >          Sequence,
> >      )
> >
> > +    from qapi.parser import QAPIDoc
> > +
> >      from sphinx.application import Sphinx
> >      from sphinx.util.typing import ExtensionMetadata
> >
> > @@ -130,6 +133,53 @@ def visit_module(self, path: str) -> None:
> >          self.add_line_raw(f".. qapi:module:: {name}", path, 1)
> >          self.ensure_blank_line()
> >
> > +    def visit_freeform(self, doc: QAPIDoc) -> None:
> > +        # TODO: Once the old qapidoc transformer is deprecated, freeform
> > +        # sections can be updated to pure rST, and this transformed
> removed.
> > +        #
> > +        # For now, translate our micro-format into rST. Code adapted
> > +        # from Peter Maydell's freeform().
> > +
> > +        assert len(doc.all_sections) == 1, doc.all_sections
> > +        body = doc.all_sections[0]
> > +        text = body.text
> > +        info = doc.info
> > +
> > +        if re.match(r"=+ ", text):
> > +            # Section/subsection heading (if present, will always be the
> > +            # first line of the block)
> > +            (heading, _, text) = text.partition("\n")
> > +            (leader, _, heading) = heading.partition(" ")
>
>
>
> > +            level = len(leader) + 1  # Implicit +1 for heading in .rST
> stub
>
> What is the ".rST stub"?
>

sorry, I meant the .rst document in-tree that invokes the qapidoc
directive. that document inherently has a title, so I treat everything in
the generated doc as a sub-heading of some kind.

(i.e., only one <h1>)


>
> > +
> > +            #
> https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
> > +            markers = {
> > +                1: "#",
> > +                2: "*",
> > +                3: "=",
> > +                4: "-",
> > +                5: "^",
> > +                6: '"',
> > +            }
>
> I'd be tempted to use markers = '#*=-^".  Matter of taste, yours takes
> precedence here.
>

Oh, yeah. I think I need a vacation from Python.


>
> > +            overline = level <= 2
> > +            marker = markers[level]
> > +
> > +            self.ensure_blank_line()
> > +            # This credits all 2 or 3 lines to the single source line.
> > +            if overline:
> > +                self.add_line(marker * len(heading), info)
> > +            self.add_line(heading, info)
> > +            self.add_line(marker * len(heading), info)
> > +            self.ensure_blank_line()
> > +
> > +            # Eat blank line(s) and advance info
> > +            trimmed = text.lstrip("\n")
> > +            text = trimmed
> > +            info = info.next_line(len(text) - len(trimmed) + 1)
> > +
> > +        self.add_lines(text, info)
> > +        self.ensure_blank_line()
> > +
> >
> >  class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
> >      """A QAPI schema visitor which adds Sphinx dependencies each module
>
>