diff options
| author | Richard Henderson <richard.henderson@linaro.org> | 2024-07-18 10:06:35 +1000 |
|---|---|---|
| committer | Richard Henderson <richard.henderson@linaro.org> | 2024-07-18 10:06:35 +1000 |
| commit | e6485190f77e6166cde8dc799e4e52e607b6f61d (patch) | |
| tree | f3c34b5f28f9ed0ce8d2e39b834ae388c2541321 /docs/sphinx/qapidoc.py | |
| parent | 58ee924b97d1c0898555647a31820c5a20d55a73 (diff) | |
| parent | 3c5f6114d9ffc70bc9b1a7cc0dddd72a911f966d (diff) | |
| download | focaccia-qemu-e6485190f77e6166cde8dc799e4e52e607b6f61d.tar.gz focaccia-qemu-e6485190f77e6166cde8dc799e4e52e607b6f61d.zip | |
Merge tag 'pull-qapi-2024-07-17' of https://repo.or.cz/qemu/armbru into staging
QAPI patches patches for 2024-07-17 # -----BEGIN PGP SIGNATURE----- # # iQJGBAABCAAwFiEENUvIs9frKmtoZ05fOHC0AOuRhlMFAmaXoUESHGFybWJydUBy # ZWRoYXQuY29tAAoJEDhwtADrkYZTatYP/jPlsmx8S6X397COQf6Wd4oEFQEMo/FS # tWFiHWenPUZ56U3O3lDNIw+5URbhF4aUpxhLGg6cmkrOwK0zPjARI2UNnUnZvPtN # EHf//KJOpYLsSdkIlIW2nYzB27ps0DRf5PgOGdOOdW32Nuq93FLx7ChDgbpmrijc # HzByyJIn1QEv/G0aOMLCuTPA7LpGjCAd2a/LjWYpSXB3WGizrS2Rrat7oJYUl8Rz # mAPgdiE0aH2yWHOTcWabKfN4AsIHCnv7qNOZkumoWpZ0XULbgyK1OO05ju3jRSrB # 0WiwiE8pEhHz7qstKGcjS1c7pPuId64ubm3RAZ1RUqVvA5TZGucwuYiuQHUVX6jH # BGzpfojISFzIfTiKemyfqBb1gjXjxT6OIlCtmlJSUCJohb70f0fhX3vniyhzyl1d # fFTM0jMbmBX89e/o3j6ZXa7anafYNDh5TjTK4BYeAXRqe+jZpvDJUrwu1OZIq1cd # Wr1RR8qaawpfjD5r9SXu1mX5MPCX4SmNVNoQ7N4ruWjpVojQNmuCRW9yLPIv3yTH # c5ESND4zdvceW5EF9f5GSIFwnIdGqnUwJyBMcULGoCxz1HougQmGR4bhqSkEl6RD # GRK+bj3pLdj9f/en62mE6+f5rkEJye3Y5fJ5dn9+Ld09PeUtY59YKnJGg896g55V # /pGOUWf3L4iY # =E0F5 # -----END PGP SIGNATURE----- # gpg: Signature made Wed 17 Jul 2024 08:47:29 PM AEST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] * tag 'pull-qapi-2024-07-17' of https://repo.or.cz/qemu/armbru: qapi: remove "Example" doc section qapi: convert "Example" sections with longer prose qapi: convert "Example" sections with titles qapi: convert "Example" sections without titles docs/sphinx: add CSS styling for qmp-example directive docs/qapidoc: add QMP highlighting to annotated qmp-example blocks docs/qapidoc: create qmp-example directive docs/qapidoc: factor out do_parse() qapi/ui: Drop note on naming of SpiceQueryMouseMode qapi/sockets: Move deprecation note out of SocketAddress doc comment qapi/machine: Clarify query-uuid value when none has been specified qapi/machine: Clean up documentation around CpuInstanceProperties qapi/pci: Clean up documentation around PciDeviceClass qapi/qom: Document feature unstable of @x-vfio-user-server Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'docs/sphinx/qapidoc.py')
| -rw-r--r-- | docs/sphinx/qapidoc.py | 128 |
1 files changed, 117 insertions, 11 deletions
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index 62b39833ca..738b2450fb 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -26,7 +26,9 @@ https://www.sphinx-doc.org/en/master/development/index.html import os import re +import sys import textwrap +from typing import List from docutils import nodes from docutils.parsers.rst import Directive, directives @@ -35,6 +37,8 @@ from qapi.error import QAPIError, QAPISemError from qapi.gen import QAPISchemaVisitor from qapi.schema import QAPISchema +from sphinx import addnodes +from sphinx.directives.code import CodeBlock from sphinx.errors import ExtensionError from sphinx.util.docutils import switch_source_input from sphinx.util.nodes import nested_parse_with_titles @@ -481,7 +485,25 @@ class QAPISchemaGenDepVisitor(QAPISchemaVisitor): super().visit_module(name) -class QAPIDocDirective(Directive): +class NestedDirective(Directive): + def run(self): + raise NotImplementedError + + def do_parse(self, rstlist, node): + """ + Parse rST source lines and add them to the specified node + + Take the list of rST source lines rstlist, parse them as + rST, and add the resulting docutils nodes as children of node. + The nodes are parsed in a way that allows them to include + subheadings (titles) without confusing the rendering of + anything else. + """ + with switch_source_input(self.state, rstlist): + nested_parse_with_titles(self.state, rstlist, node) + + +class QAPIDocDirective(NestedDirective): """Extract documentation from the specified QAPI .json file""" required_argument = 1 @@ -519,23 +541,107 @@ class QAPIDocDirective(Directive): # so they are displayed nicely to the user raise ExtensionError(str(err)) from err - def do_parse(self, rstlist, node): - """Parse rST source lines and add them to the specified node - Take the list of rST source lines rstlist, parse them as - rST, and add the resulting docutils nodes as children of node. - The nodes are parsed in a way that allows them to include - subheadings (titles) without confusing the rendering of - anything else. - """ - with switch_source_input(self.state, rstlist): - nested_parse_with_titles(self.state, rstlist, node) +class QMPExample(CodeBlock, NestedDirective): + """ + Custom admonition for QMP code examples. + + When the :annotated: option is present, the body of this directive + is parsed as normal rST, but with any '::' code blocks set to use + the QMP lexer. Code blocks must be explicitly written by the user, + but this allows for intermingling explanatory paragraphs with + arbitrary rST syntax and code blocks for more involved examples. + + When :annotated: is absent, the directive body is treated as a + simple standalone QMP code block literal. + """ + + required_argument = 0 + optional_arguments = 0 + has_content = True + option_spec = { + "annotated": directives.flag, + "title": directives.unchanged, + } + + def _highlightlang(self) -> addnodes.highlightlang: + """Return the current highlightlang setting for the document""" + node = None + doc = self.state.document + + if hasattr(doc, "findall"): + # docutils >= 0.18.1 + for node in doc.findall(addnodes.highlightlang): + pass + else: + for elem in doc.traverse(): + if isinstance(elem, addnodes.highlightlang): + node = elem + + if node: + return node + + # No explicit directive found, use defaults + node = addnodes.highlightlang( + lang=self.env.config.highlight_language, + force=False, + # Yes, Sphinx uses this value to effectively disable line + # numbers and not 0 or None or -1 or something. ¯\_(ツ)_/¯ + linenothreshold=sys.maxsize, + ) + return node + + def admonition_wrap(self, *content) -> List[nodes.Node]: + title = "Example:" + if "title" in self.options: + title = f"{title} {self.options['title']}" + + admon = nodes.admonition( + "", + nodes.title("", title), + *content, + classes=["admonition", "admonition-example"], + ) + return [admon] + + def run_annotated(self) -> List[nodes.Node]: + lang_node = self._highlightlang() + + content_node: nodes.Element = nodes.section() + + # Configure QMP highlighting for "::" blocks, if needed + if lang_node["lang"] != "QMP": + content_node += addnodes.highlightlang( + lang="QMP", + force=False, # "True" ignores lexing errors + linenothreshold=lang_node["linenothreshold"], + ) + + self.do_parse(self.content, content_node) + + # Restore prior language highlighting, if needed + if lang_node["lang"] != "QMP": + content_node += addnodes.highlightlang(**lang_node.attributes) + + return content_node.children + + def run(self) -> List[nodes.Node]: + annotated = "annotated" in self.options + + if annotated: + content_nodes = self.run_annotated() + else: + self.arguments = ["QMP"] + content_nodes = super().run() + + return self.admonition_wrap(*content_nodes) def setup(app): """Register qapi-doc directive with Sphinx""" app.add_config_value("qapidoc_srctree", None, "env") app.add_directive("qapi-doc", QAPIDocDirective) + app.add_directive("qmp-example", QMPExample) return { "version": __version__, |