From nobody Sat Apr 11 19:55:06 2026 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1775677967; cv=none; d=zohomail.com; s=zohoarc; b=CXJo05Aw1hQ5TfNOHWeCTdEUKVFhuZeVrPXu/aoG2NcfuN/ycY4Ta8+h35gr0cn+vDEO3Jeq16yEhZXdYhBF4Kbug6nusNrIkAfXa57G4O2O92b2S8M0RcjrJPah5LNZtx4Rhkn7VY0nWNniJInH11OrQM77SFqbMkN+OgwA+j8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775677967; 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=zQNiTfcBvXKXQ+Z+lV3PoOjT3444LniGV6uuOZJ1Zbs=; b=MY/HcBO9avrcW1jKo19jm++ohYMAV/c1rWmrRgL+JjJ7nrTJ7PRUi44vVYcnyrKsshxGCweHwGafSQA1nPRqVrinxYCBUT4BRdo8YzfdM2w31Upi1s0h6LMiI0I0R73LR/1UkueR1z1AMb9YQHtNLKjAHtJFVdV4Q+PCh6aeKV0= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 177567796739281.64350187617072; Wed, 8 Apr 2026 12:52:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wAYWD-0006RB-Ss; Wed, 08 Apr 2026 15:24:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wAY6p-0007Ci-W5 for qemu-devel@nongnu.org; Wed, 08 Apr 2026 14:58:40 -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 1wAKxL-0005Tc-Ov for qemu-devel@nongnu.org; Wed, 08 Apr 2026 00:56:01 -0400 Received: from mx-prod-mc-05.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-52-UGhLi6MbMiaOvoMH2xKW4w-1; Wed, 08 Apr 2026 00:55:55 -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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id ABED21956080; Wed, 8 Apr 2026 04:55:52 +0000 (UTC) Received: from jsnow-thinkpadp16vgen1.westford.csb (unknown [10.22.88.7]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6D3791955F2B; Wed, 8 Apr 2026 04:55:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775624159; 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=zQNiTfcBvXKXQ+Z+lV3PoOjT3444LniGV6uuOZJ1Zbs=; b=imHieWAQxhh9EbcJ5a+RmoaR8CkxoWRwaO9MKcqhwd+f63BUCZkc2jVcNsEzyVtb/CABRL Kf+5ZpDyNQZXksepPrPIzuinnbNFh+4PcAc9cRH1b7UdsPO0uk2ldfTWUsUSBDuNvTwENj N5+3+yWTy7pbUvLDOf7PcfxrS7CezQE= X-MC-Unique: UGhLi6MbMiaOvoMH2xKW4w-1 X-Mimecast-MFC-AGG-ID: UGhLi6MbMiaOvoMH2xKW4w_1775624153 From: John Snow To: qemu-devel@nongnu.org Cc: Kashyap Chamarthy , Stefan Berger , Mauro Carvalho Chehab , Michael Roth , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , qemu-block@nongnu.org, Pierrick Bouvier , Yanan Wang , Hanna Reitz , Peter Xu , Igor Mammedov , "Michael S. Tsirkin" , Kevin Wolf , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Stefano Garzarella , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Lukas Straub , Jason Wang , Alex Williamson , Paolo Bonzini , Fabiano Rosas , Zhao Liu , Richard Henderson , =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= , Stefan Hajnoczi , Peter Maydell , Eric Blake , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Kostiantyn Kostiuk , Jiri Pirko , Markus Armbruster , John Snow , Ani Sinha , Marcel Apfelbaum Subject: [PATCH v2 01/10] qapi: differentiate "intro" and "details" sections Date: Wed, 8 Apr 2026 00:55:22 -0400 Message-ID: <20260408045531.3006678-2-jsnow@redhat.com> In-Reply-To: <20260408045531.3006678-1-jsnow@redhat.com> References: <20260408045531.3006678-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: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development 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: 1775677968983158500 Content-Type: text/plain; charset="utf-8" This patch begins distinguishing "Plain" sections as being either "Intro" or "Details" sections for the purpose of, in the forthcoming documentation inliner, knowing when/where/how to inline those sections. i.e. "Intro" sections will not be inlined, but "Details" sections will be. The intent is for "Intro" sections to describe (briefly) only the specific entity, but for details sections to describe information in greater detail that would be relevant to include in inlined documentation. The Intro section is always the first section of any doc block. It may be empty or any number of paragraphs. It is interrupted by any other non-plaintext section, i.e.; Members, Features, Errors, Returns, Since, and TODO. The details section, as of this patch, is any plaintext section after the initial section. (It cannot appear immediately following the INTRO section, because it would then simply be part of that intro section.) Signed-off-by: John Snow --- [Review note: .ir files remain unchanged before and after this patch, it should be completely inert with regards to the rendered output. --js] Signed-off-by: John Snow --- docs/sphinx/qapidoc.py | 2 +- scripts/qapi/parser.py | 35 +++++++++++++++++++++++----------- tests/qapi-schema/doc-good.out | 8 ++++---- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py index c2f09bac16c..e359836f110 100644 --- a/docs/sphinx/qapidoc.py +++ b/docs/sphinx/qapidoc.py @@ -368,7 +368,7 @@ def visit_sections(self, ent: QAPISchemaDefinition) -> = None: for i, section in enumerate(sections): section.text =3D self.reformat_arobase(section.text) =20 - if section.kind =3D=3D QAPIDoc.Kind.PLAIN: + if section.kind.name in ("INTRO", "DETAILS"): self.visit_paragraph(section) elif section.kind =3D=3D QAPIDoc.Kind.MEMBER: assert isinstance(section, QAPIDoc.ArgSection) diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py index c3cf33904ef..da0ac32ad89 100644 --- a/scripts/qapi/parser.py +++ b/scripts/qapi/parser.py @@ -544,7 +544,7 @@ def get_doc(self) -> 'QAPIDoc': doc =3D QAPIDoc(info, symbol) self.accept(False) line =3D self.get_doc_line() - no_more_args =3D False + have_tagged =3D False =20 while line is not None: # Blank lines @@ -573,10 +573,10 @@ def get_doc(self) -> 'QAPIDoc': if not doc.features: raise QAPIParseError( self, 'feature descriptions expected') - no_more_args =3D True + have_tagged =3D True elif match :=3D self._match_at_name_colon(line): # description - if no_more_args: + if have_tagged: raise QAPIParseError( self, "description of '@%s:' follows a section" @@ -588,7 +588,7 @@ def get_doc(self) -> 'QAPIDoc': if text: doc.append_line(text) line =3D self.get_doc_indented(doc) - no_more_args =3D True + have_tagged =3D True elif match :=3D re.match( r'(Returns|Errors|Since|Notes?|Examples?|TODO)' r'(?!::): *', @@ -629,10 +629,14 @@ def get_doc(self) -> 'QAPIDoc': if text: doc.append_line(text) line =3D self.get_doc_indented(doc) - no_more_args =3D True + have_tagged =3D True else: # plain paragraph - doc.ensure_untagged_section(self.info) + + # Paragraphs before tagged sections are "intro" paragr= aphs. + # Any appearing after are "detail" paragraphs. + intro =3D not have_tagged + doc.ensure_untagged_section(self.info, intro) doc.append_line(line) line =3D self.get_doc_paragraph(doc) else: @@ -674,13 +678,14 @@ class QAPIDoc: """ =20 class Kind(enum.Enum): - PLAIN =3D 0 + INTRO =3D 0 MEMBER =3D 1 FEATURE =3D 2 RETURNS =3D 3 ERRORS =3D 4 SINCE =3D 5 TODO =3D 6 + DETAILS =3D 7 =20 @staticmethod def from_string(kind: str) -> 'QAPIDoc.Kind': @@ -730,7 +735,7 @@ def __init__(self, info: QAPISourceInfo, symbol: Option= al[str] =3D None): self.symbol: Optional[str] =3D symbol # the sections in textual order self.all_sections: List[QAPIDoc.Section] =3D [ - QAPIDoc.Section(info, QAPIDoc.Kind.PLAIN) + QAPIDoc.Section(info, QAPIDoc.Kind.INTRO) ] # the body section self.body: Optional[QAPIDoc.Section] =3D self.all_sections[0] @@ -748,12 +753,20 @@ def __init__(self, info: QAPISourceInfo, symbol: Opti= onal[str] =3D None): def end(self) -> None: for section in self.all_sections: section.text =3D section.text.strip('\n') - if section.kind !=3D QAPIDoc.Kind.PLAIN and section.text =3D= =3D '': + if ( + section.kind not in ( + QAPIDoc.Kind.INTRO, QAPIDoc.Kind.DETAILS + ) and section.text =3D=3D '' + ): raise QAPISemError( section.info, "text required after '%s:'" % section.ki= nd) =20 - def ensure_untagged_section(self, info: QAPISourceInfo) -> None: - kind =3D QAPIDoc.Kind.PLAIN + def ensure_untagged_section( + self, + info: QAPISourceInfo, + intro: bool =3D True, + ) -> None: + kind =3D QAPIDoc.Kind.INTRO if intro else QAPIDoc.Kind.DETAILS =20 if self.all_sections and self.all_sections[-1].kind =3D=3D kind: # extend current section diff --git a/tests/qapi-schema/doc-good.out b/tests/qapi-schema/doc-good.out index 04a55072646..04e29e8d50f 100644 --- a/tests/qapi-schema/doc-good.out +++ b/tests/qapi-schema/doc-good.out @@ -116,7 +116,7 @@ The _one_ {and only}, description on the same line Also _one_ {and only} feature=3Denum-member-feat a member feature - section=3DPlain + section=3DDetails @two is undocumented doc symbol=3DBase body=3D @@ -175,7 +175,7 @@ description starts on the same line a feature feature=3Dcmd-feat2 another feature - section=3DPlain + section=3DDetails .. note:: @arg3 is undocumented section=3DReturns @Object @@ -183,7 +183,7 @@ another feature some section=3DTodo frobnicate - section=3DPlain + section=3DDetails .. admonition:: Notes =20 - Lorem ipsum dolor sit amet @@ -216,7 +216,7 @@ If you're bored enough to read this, go see a video of = boxed cats a feature feature=3Dcmd-feat2 another feature - section=3DPlain + section=3DDetails .. qmp-example:: =20 -> "this example" --=20 2.53.0