docs/qapidoc: add visit_freeform() method

Add the transmogrifier implementation for converting freeform doc blocks
to rST.

Signed-off-by: John Snow <jsnow@redhat.com>
Message-ID: <20250311034303.75779-43-jsnow@redhat.com>
Acked-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
John Snow 2025-03-10 23:42:40 -04:00 committed by Markus Armbruster
parent 36e4182f40
commit f0b2fe99f6

View file

@ -29,6 +29,7 @@ from __future__ import annotations
from contextlib import contextmanager from contextlib import contextmanager
import os import os
from pathlib import Path from pathlib import Path
import re
import sys import sys
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -55,6 +56,8 @@ if TYPE_CHECKING:
Sequence, Sequence,
) )
from qapi.parser import QAPIDoc
from sphinx.application import Sphinx from sphinx.application import Sphinx
from sphinx.util.typing import ExtensionMetadata from sphinx.util.typing import ExtensionMetadata
@ -130,6 +133,47 @@ class Transmogrifier:
self.add_line_raw(f".. qapi:module:: {name}", path, 1) self.add_line_raw(f".. qapi:module:: {name}", path, 1)
self.ensure_blank_line() 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(" ")
# Implicit +1 for heading in the containing .rst doc
level = len(leader) + 1
# https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#sections
markers = ' #*=_^"'
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): class QAPISchemaGenDepVisitor(QAPISchemaVisitor):
"""A QAPI schema visitor which adds Sphinx dependencies each module """A QAPI schema visitor which adds Sphinx dependencies each module