@samitouri / QOSamiQemu / commits / a5635d6181

qapi/qapidoc: add rendering for INTRO sections

Amend the qapidoc generator to handle and render INTRO sections. The only real difference here from other sections is that we need to dedent the text so it renders correctly. Members and Features are also indented, but do not require a dedent() because they are always used in tandem with an rST construct that forms the start of a new indented block; there is coincidental harmony. Plaintext sections, however, do not start their own block and thus need to be dedented to prevent accidentally rendering them as a blockquote or a syntax error. This dedent transformation on the text does not reflow the text, so source line information remains accurate, and the "blame" chain of custody for sphinx rST parsing error messages continues to be correct even through this transformation. Signed-off-by: John Snow <jsnow@redhat.com> Message-ID: <20260611042332.482979-13-jsnow@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [Commit message tweaked] Signed-off-by: Markus Armbruster <armbru@redhat.com>

John Snow committed Jun 11, 2026 at 00:23 UTC a5635d61812cb08291ca7a0a7addff11fbb6511b
1 file changed +14 -3
docs/sphinx/qapidoc.py
+14 -3
@@ -35,6 +35,7 @@ import os
35 from pathlib import Path
36 import re
37 import sys
38 +import textwrap
39 from typing import TYPE_CHECKING
40
41 from docutils import nodes
@@ -150,8 +151,15 @@ class Transmogrifier:
151 self,
152 content: str,
153 info: QAPISourceInfo,
154 + dedent: bool = False,
155 ) -> None:
156 lines = content.splitlines(True)
157 +
158 + if dedent:
159 + lines = textwrap.dedent(content).splitlines(True)
160 + else:
161 + lines = content.splitlines(True)
162 +
163 for i, line in enumerate(lines):
164 self.add_line_raw(line, info.fname, info.line + i)
165
@@ -223,13 +231,16 @@ class Transmogrifier:
231
232 # Transmogrification helpers
233
226 - def visit_paragraph(self, section: QAPIDoc.Section) -> None:
234 + def visit_plaintext(self, section: QAPIDoc.Section) -> None:
235 # Squelch empty paragraphs.
236 if not section.text:
237 return
238
239 + # Intro sections, which are indented in QAPI source, need to
240 + # be dedented to avoid accidental block quotes in ReST syntax.
241 + dedent = bool(section.kind == QAPIDoc.Kind.INTRO)
242 self.ensure_blank_line()
232 - self.add_lines(section.text, section.info)
243 + self.add_lines(section.text, section.info, dedent)
244 self.ensure_blank_line()
245
246 def visit_member(self, section: QAPIDoc.ArgSection) -> None:
@@ -373,7 +384,7 @@ class Transmogrifier:
384 section.text = self.reformat_arobase(section.text)
385
386 if section.kind.name in ("PLAIN", "INTRO"):
376 - self.visit_paragraph(section)
387 + self.visit_plaintext(section)
388 elif section.kind == QAPIDoc.Kind.MEMBER:
389 assert isinstance(section, QAPIDoc.ArgSection)
390 if section.name == "q_dummy":