[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 15/21] docs/qapidoc: create qmp-example directive
From: |
John Snow |
Subject: |
[PATCH v2 15/21] docs/qapidoc: create qmp-example directive |
Date: |
Wed, 26 Jun 2024 18:21:21 -0400 |
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}
```
Is desugared to:
```
.. admonition:: Example:
This example shows how to use `foo-command`::
{body}
For more information, please see `frobnozz`.
```
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>
---
docs/sphinx/qapidoc.py | 60 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
index 43dd99e21e6..a2fa05fc491 100644
--- a/docs/sphinx/qapidoc.py
+++ b/docs/sphinx/qapidoc.py
@@ -27,16 +27,19 @@
import os
import re
import textwrap
+from typing import List
from docutils import nodes
-from docutils.parsers.rst import Directive, directives
+from docutils.parsers.rst import directives
from docutils.statemachine import ViewList
from qapi.error import QAPIError, QAPISemError
from qapi.gen import QAPISchemaVisitor
from qapi.schema import QAPISchema
import sphinx
+from sphinx.directives.code import CodeBlock
from sphinx.errors import ExtensionError
+from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import nested_parse_with_titles
@@ -494,7 +497,7 @@ def visit_module(self, name):
super().visit_module(name)
-class NestedDirective(Directive):
+class NestedDirective(SphinxDirective):
def run(self):
raise NotImplementedError
@@ -567,10 +570,63 @@ def run(self):
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__,
--
2.45.0
- [PATCH v2 11/21] qapi: update prose in note blocks, (continued)
- [PATCH v2 11/21] qapi: update prose in note blocks, John Snow, 2024/06/26
- [PATCH v2 10/21] qapi: convert "Note" sections to plain rST, John Snow, 2024/06/26
- [PATCH v2 12/21] qapi: add markup to note blocks, John Snow, 2024/06/26
- [PATCH v2 13/21] qapi/parser: don't parse rST markup as section headers, John Snow, 2024/06/26
- [PATCH v2 14/21] docs/qapidoc: factor out do_parse(), John Snow, 2024/06/26
- [PATCH v2 15/21] docs/qapidoc: create qmp-example directive,
John Snow <=
- [PATCH v2 18/21] qapi: convert "Example" sections without titles, John Snow, 2024/06/26
- [PATCH v2 19/21] qapi: convert "Example" sections with titles, John Snow, 2024/06/26
- [PATCH v2 17/21] docs/sphinx: add CSS styling for qmp-example directive, John Snow, 2024/06/26
- [PATCH v2 20/21] qapi: convert "Example" sections with longer prose, John Snow, 2024/06/26
- [PATCH v2 16/21] docs/qapidoc: add QMP highlighting to annotated qmp-example blocks, John Snow, 2024/06/26
- [PATCH v2 21/21] qapi: remove "Example" doc section, John Snow, 2024/06/26