aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2024-07-16 22:13:05 -0400
committerMarkus Armbruster <armbru@redhat.com>2024-07-17 10:20:53 +0200
commit547864f9d4cead4fe70981d2c4ffa5905b40e671 (patch)
treebea3f30fd8d9717c3c96c9d16e9313784e7d457b /docs
parenta7d07ccd208dc1a8dbd0b03d95761a6424ccb375 (diff)
docs/qapidoc: create qmp-example directive
This is a directive that creates a syntactic sugar for creating "Example" boxes very similar to the ones already used in the bitmaps.rst document, please see e.g. https://www.qemu.org/docs/master/interop/bitmaps.html#creation-block-dirty-bitmap-add In its simplest form, when a custom title is not needed or wanted, and the example body is *solely* a QMP example: ``` .. qmp-example:: {body} ``` is syntactic sugar for: ``` .. admonition:: Example: .. code-block:: QMP {body} ``` When a custom, plaintext title that describes the example is desired, this form: ``` .. qmp-example:: :title: Defrobnification {body} ``` Is syntactic sugar for: ``` .. admonition:: Example: Defrobnification .. code-block:: QMP {body} ``` Lastly, when Examples are multi-step processes that require non-QMP exposition, have lengthy titles, or otherwise involve prose with rST markup (lists, cross-references, etc), the most complex form: ``` .. qmp-example:: :annotated: This example shows how to use `foo-command`:: {body} For more information, please see `frobnozz`. ``` Is desugared to: ``` .. admonition:: Example: This example shows how to use `foo-command`:: {body} For more information, please see `frobnozz`. ``` Note that :annotated: and :title: options can be combined together, if desired. The primary benefit here being documentation source consistently using the same directive for all forms of examples to ensure consistent visual styling, and ensuring all relevant prose is visually grouped alongside the code literal block. Note that as of this commit, the code-block rST syntax "::" does not apply QMP highlighting; you would need to use ".. code-block:: QMP". The very next commit changes this behavior to assume all "::" code blocks within this directive are QMP blocks. Signed-off-by: John Snow <jsnow@redhat.com> Acked-by: Markus Armbruster <armbru@redhat.com> Message-ID: <20240717021312.606116-4-jsnow@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'docs')
-rw-r--r--docs/sphinx/qapidoc.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index b3be82998a..11defcfa3f 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -27,6 +27,7 @@ https://www.sphinx-doc.org/en/master/development/index.html
import os
import re
import textwrap
+from typing import List
from docutils import nodes
from docutils.parsers.rst import Directive, directives
@@ -35,6 +36,7 @@ from qapi.error import QAPIError, QAPISemError
from qapi.gen import QAPISchemaVisitor
from qapi.schema import QAPISchema
+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
@@ -538,10 +540,63 @@ class QAPIDocDirective(NestedDirective):
raise ExtensionError(str(err)) from err
+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 instead. 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 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]:
+ content_node: nodes.Element = nodes.section()
+ self.do_parse(self.content, content_node)
+ 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__,