From nobody Mon Nov 25 02:06:22 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1719440818; cv=none; d=zohomail.com; s=zohoarc; b=FR4Hv91+CtNm7yvHR4uiEdokneOKRJmTkzm4eIPsU01wl5LlPmv6vaB/QirkZQofgKvE6AzNXShpdLiNUi+MSXD+NVj0fLP6LSaGrkNOe93P2sd7FEv4MEADc0tcTHVYo7r5bccboDUoK0SdOtAllgcrK4ioa4VMl1BFnOJEGpQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1719440818; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=GNSWdN9cWTKZDPj5/a/oNtSmKd3EdNCt0RiP98EW2Y4=; b=cWKGe5bodq6JEn7HEuY2Lg9heBUdboROttWB4GB737ojhVeRWw3Uwon2iUNcI70wrHNaJ40DqOcbqzfhmCJP5iuLoxtRZcG5x8/HtgSmLRm/KShrz9aHP9saVnFSpCgt6Lvi0fTSRYPOApaMufflHW2T9LGgdFVPedS/Cy9FRMA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1719440818062331.2385578869065; Wed, 26 Jun 2024 15:26:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sMb49-0000Fp-Q2; Wed, 26 Jun 2024 18:24:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sMb3a-0007d3-8h for qemu-devel@nongnu.org; Wed, 26 Jun 2024 18:24:06 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sMb3X-0002rl-R7 for qemu-devel@nongnu.org; Wed, 26 Jun 2024 18:24:01 -0400 Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-96-FMFYq9CsOOu1LrRPIbBy2Q-1; Wed, 26 Jun 2024 18:23:52 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 99D8A19560AB; Wed, 26 Jun 2024 22:23:46 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.8.67]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 478BE1955F2D; Wed, 26 Jun 2024 22:23:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1719440636; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=GNSWdN9cWTKZDPj5/a/oNtSmKd3EdNCt0RiP98EW2Y4=; b=Ol+U1lOq2VF/jJ4eqW0XUXSF9dP9JJSV/GQDw9JRJu+tj8WL+3jmR4OSSZ9ay4j3b0wjgJ Fd83nYozJ0eoykyCePqvliTI9/da1mfAf9H1F+UV5k9jVbmG2VE5GzhY4Y/56T0FSEmHss iVPilBMbx3Voyru3EOV+/MSUwIQDwUg= X-MC-Unique: FMFYq9CsOOu1LrRPIbBy2Q-1 From: John Snow To: qemu-devel@nongnu.org Cc: Mads Ynddal , Jiri Pirko , Stefan Hajnoczi , Eric Blake , Peter Maydell , Michael Roth , "Michael S. Tsirkin" , Alex Williamson , Pavel Dovgalyuk , Victor Toso de Carvalho , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , qemu-block@nongnu.org, Ani Sinha , Fabiano Rosas , Marcel Apfelbaum , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Gerd Hoffmann , Paolo Bonzini , Kevin Wolf , Peter Xu , Eduardo Habkost , Markus Armbruster , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Lukas Straub , Igor Mammedov , Jason Wang , Yanan Wang , Hanna Reitz , Konstantin Kostiuk , Stefan Berger , John Snow Subject: [PATCH v2 15/21] docs/qapidoc: create qmp-example directive Date: Wed, 26 Jun 2024 18:21:21 -0400 Message-ID: <20240626222128.406106-16-jsnow@redhat.com> In-Reply-To: <20240626222128.406106-1-jsnow@redhat.com> References: <20240626222128.406106-1-jsnow@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -22 X-Spam_score: -2.3 X-Spam_bar: -- X-Spam_report: (-2.3 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.207, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1719440819959100005 Content-Type: text/plain; charset="utf-8" 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 --- 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 =20 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 =20 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 =20 =20 @@ -494,7 +497,7 @@ def visit_module(self, name): super().visit_module(name) =20 =20 -class NestedDirective(Directive): +class NestedDirective(SphinxDirective): def run(self): raise NotImplementedError =20 @@ -567,10 +570,63 @@ def run(self): raise ExtensionError(str(err)) from err =20 =20 +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 =3D 0 + optional_arguments =3D 0 + has_content =3D True + option_spec =3D { + "annotated": directives.flag, + "title": directives.unchanged, + } + + def admonition_wrap(self, *content) -> List[nodes.Node]: + title =3D "Example:" + if "title" in self.options: + title =3D f"{title} {self.options['title']}" + + admon =3D nodes.admonition( + "", + nodes.title("", title), + *content, + classes=3D["admonition", "admonition-example"], + ) + return [admon] + + def run_annotated(self) -> List[nodes.Node]: + content_node: nodes.Element =3D nodes.section() + self.do_parse(self.content, content_node) + return content_node.children + + def run(self) -> List[nodes.Node]: + annotated =3D "annotated" in self.options + + if annotated: + content_nodes =3D self.run_annotated() + else: + self.arguments =3D ["QMP"] + content_nodes =3D 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) =20 return { "version": __version__, --=20 2.45.0