qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: John Snow <jsnow@redhat.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org, "Michael Roth" <michael.roth@amd.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Thomas Huth" <thuth@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>
Subject: Re: [PATCH 31/57] qapi: expand tags to all doc sections
Date: Wed, 5 Mar 2025 22:58:14 -0500	[thread overview]
Message-ID: <CAFn=p-bUtzo1dByK0k6kevNDqghcc15L1N8WFWNB_nm9kXvCbQ@mail.gmail.com> (raw)
In-Reply-To: <875xknok8w.fsf@pond.sub.org>

[-- Attachment #1: Type: text/plain, Size: 17710 bytes --]

On Wed, Mar 5, 2025 at 5:16 AM Markus Armbruster <armbru@redhat.com> wrote:

> Replaying review of a previous posting for your convenience...
>
> John Snow <jsnow@redhat.com> writes:
>
> > This patch adds an explicit section "kind" to all QAPIDoc
> > sections. Members/Features are now explicitly marked as such, with the
> > name now being stored in a dedicated "name" field (which qapidoc.py was
> > not actually using anyway.)
>
> I'm not sure what the parenthesis is trying to convey.
>

The old qapidoc.py doesn't actually use the name field, so there's nothing
to adjust for old callers.


>
> Before the patch, we have:
>
>               type        tag
>     untagged  Section     None
>     @foo:     ArgSection  'foo'
>     Returns:  Section     'Returns'
>     Errors:   Section     'Errors'
>     Since:    Section     'Since'
>     TODO:     Section     'TODO'
>
> Afterwards, I believe:
>
>               type         kind     name
>     untagged  Section      PLAIN
>     @foo:     ArgSection   MEMBER   'foo'   if member or argument
>               ArgSection   FEATURE  'foo'   if feature
>     Returns:  Section      RETURNS
>     Errors:   Section      ERRORS
>     Since:    Section      SINCE
>     TODO:     Section      TODO
>
> So, .tag is replaced by .kind and .name, member vs. feature vs. other
> tags is now obvious from .kind alone, i.e. there's no need to account
> for context or type.
>
> Fine print: why do we need to account for type before the patch?
> Consider @Since: ...
>

I'm not sure I follow...


>
> > The qapi-schema tests are updated to account for the new section names;
> > mostly "TODO" becomes "Todo" and `None` becomes "Plain".
> >
> > Signed-off-by: John Snow <jsnow@redhat.com>
> > ---
> >  docs/sphinx/qapidoc.py         |   7 ++-
> >  scripts/qapi/parser.py         | 109 ++++++++++++++++++++++++---------
> >  tests/qapi-schema/doc-good.out |  10 +--
> >  tests/qapi-schema/test-qapi.py |   2 +-
> >  4 files changed, 90 insertions(+), 38 deletions(-)
> >
> > diff --git a/docs/sphinx/qapidoc.py b/docs/sphinx/qapidoc.py
> > index 61997fd21af..d622398f1da 100644
> > --- a/docs/sphinx/qapidoc.py
> > +++ b/docs/sphinx/qapidoc.py
> > @@ -35,6 +35,7 @@
> >  from docutils.statemachine import ViewList
> >  from qapi.error import QAPIError, QAPISemError
> >  from qapi.gen import QAPISchemaVisitor
> > +from qapi.parser import QAPIDoc
> >  from qapi.schema import QAPISchema
> >
> >  from sphinx import addnodes
> > @@ -258,11 +259,11 @@ def _nodes_for_sections(self, doc):
> >          """Return list of doctree nodes for additional sections"""
> >          nodelist = []
> >          for section in doc.sections:
> > -            if section.tag and section.tag == 'TODO':
> > +            if section.kind == QAPIDoc.Kind.TODO:
> >                  # Hide TODO: sections
> >                  continue
> >
> > -            if not section.tag:
> > +            if section.kind == QAPIDoc.Kind.PLAIN:
> >                  # Sphinx cannot handle sectionless titles;
> >                  # Instead, just append the results to the prior section.
> >                  container = nodes.container()
> > @@ -270,7 +271,7 @@ def _nodes_for_sections(self, doc):
> >                  nodelist += container.children
> >                  continue
> >
> > -            snode = self._make_section(section.tag)
> > +            snode = self._make_section(section.kind.name.title())
> >              self._parse_text_into_node(dedent(section.text), snode)
> >              nodelist.append(snode)
> >          return nodelist
> > diff --git a/scripts/qapi/parser.py b/scripts/qapi/parser.py
> > index 36cb64a677a..c3004aa70c6 100644
> > --- a/scripts/qapi/parser.py
> > +++ b/scripts/qapi/parser.py
> > @@ -15,6 +15,7 @@
> >  # See the COPYING file in the top-level directory.
> >
> >  from collections import OrderedDict
> > +import enum
> >  import os
> >  import re
> >  from typing import (
> > @@ -575,7 +576,10 @@ def get_doc(self) -> 'QAPIDoc':
> >                          )
> >                          raise QAPIParseError(self, emsg)
> >
> > -                    doc.new_tagged_section(self.info, match.group(1))
> > +                    doc.new_tagged_section(
> > +                        self.info,
> > +                        QAPIDoc.Kind.from_string(match.group(1))
> > +                    )
> >                      text = line[match.end():]
> >                      if text:
> >                          doc.append_line(text)
> > @@ -586,7 +590,7 @@ def get_doc(self) -> 'QAPIDoc':
> >                          self,
> >                          "unexpected '=' markup in definition
> documentation")
> >                  else:
> > -                    # tag-less paragraph
> > +                    # plain paragraph(s)
>
> We're parsing a single pargraph here.  The plain section we add it to
> may have any number of paragraphs.  But for me, the comment is about
> what's being parsed.  Mind to drop (s)?
>

Anguish. I can't keep this straight in my head. OK. It wasn't obvious at a
glance where the break is if we get an empty newline ...


>
> >                      doc.ensure_untagged_section(self.info)
> >                      doc.append_line(line)
> >                      line = self.get_doc_paragraph(doc)
> > @@ -635,14 +639,37 @@ class QAPIDoc:
> >      Free-form documentation blocks consist only of a body section.
> >      """
> >
> > +    class Kind(enum.Enum):
> > +        PLAIN = 0
> > +        MEMBER = 1
> > +        FEATURE = 2
> > +        RETURNS = 3
> > +        ERRORS = 4
> > +        SINCE = 5
> > +        TODO = 6
> > +
> > +        @staticmethod
> > +        def from_string(kind: str) -> 'QAPIDoc.Kind':
>
> Remind me, why do we need to quote the type here?
>

It doesn't exist yet; it's a forward reference, basically. While we are in
the context of defining the class, we don't have access to variables scoped
within the class :)


>
> > +            return QAPIDoc.Kind[kind.upper()]
> > +
> > +        def text_required(self) -> bool:
> > +            # Only "plain" sections can be empty
> > +            return self.value not in (0,)
>
> Rather roundabout way to check for PLAIN, isn't it?
>

Vestigial from intro/details split. It can be removed here for now.


>
> There's just one caller (see below).  I doubt the method is worth its
> keep.
>

Vestigial again. Whether it's worth it once there are multiple such
sections, who knows. I thought it made the code read nicer in context. We
don't need it right now anyway...


>
> > +
> > +        def __str__(self) -> str:
> > +            return self.name.title()
> > +
>
> I wonder whether a simple StrEnum without methods would do.  Oh, StrEnum
> is new in 3.11.  Nevermind.
>
> Hmm.
>
>     >>> Kind = Enum('Kind', [('PLAIN', 'Plain'), ('TODO, 'TODO)])
>     >>> kind=Kind('Plain')
>     >>> kind.value
>     'Plain'
>
> What do you think?
>

Maybe, lemme play with it and see if it makes something else worse, I don't
know right away.


>
> >      class Section:
> >          # pylint: disable=too-few-public-methods
> > -        def __init__(self, info: QAPISourceInfo,
> > -                     tag: Optional[str] = None):
> > +        def __init__(
> > +            self,
> > +            info: QAPISourceInfo,
> > +            kind: 'QAPIDoc.Kind',
> > +        ):
> >              # section source info, i.e. where it begins
> >              self.info = info
> > -            # section tag, if any ('Returns', '@name', ...)
> > -            self.tag = tag
> > +            # section kind
> > +            self.kind = kind
> >              # section text without tag
> >              self.text = ''
> >
> > @@ -650,8 +677,14 @@ def append_line(self, line: str) -> None:
> >              self.text += line + '\n'
> >
> >      class ArgSection(Section):
> > -        def __init__(self, info: QAPISourceInfo, tag: str):
> > -            super().__init__(info, tag)
> > +        def __init__(
> > +            self,
> > +            info: QAPISourceInfo,
> > +            kind: 'QAPIDoc.Kind',
> > +            name: str
> > +        ):
> > +            super().__init__(info, kind)
> > +            self.name = name
> >              self.member: Optional['QAPISchemaMember'] = None
>
> Before the patch, use of a separate type for members, arguments and
> features was necessary to distinguish between '@TAG:' and 'TAG:' for the
> various TAGs.  This is no longer the case.  Fold ArgSection into
> Section?  Not sure.  If yes, separate patch to keep this one as
> mechanical as possible.
>

Possibly the case. I'll play with it. Do you want it in this series? (It's
pretty long as is...!)


>
> >
> >          def connect(self, member: 'QAPISchemaMember') -> None:
> > @@ -663,7 +696,9 @@ def __init__(self, info: QAPISourceInfo, symbol:
> Optional[str] = None):
> >          # definition doc's symbol, None for free-form doc
> >          self.symbol: Optional[str] = symbol
> >          # the sections in textual order
> > -        self.all_sections: List[QAPIDoc.Section] =
> [QAPIDoc.Section(info)]
> > +        self.all_sections: List[QAPIDoc.Section] = [
> > +            QAPIDoc.Section(info, QAPIDoc.Kind.PLAIN)
> > +        ]
> >          # the body section
> >          self.body: Optional[QAPIDoc.Section] = self.all_sections[0]
> >          # dicts mapping parameter/feature names to their description
> > @@ -680,12 +715,17 @@ def __init__(self, info: QAPISourceInfo, symbol:
> Optional[str] = None):
> >      def end(self) -> None:
> >          for section in self.all_sections:
> >              section.text = section.text.strip('\n')
> > -            if section.tag is not None and section.text == '':
> > +            if section.kind.text_required() and section.text == '':
>
> This is the only use of .text_required().  I believe checking for PLAIN
> would be clearer.
>
> >                  raise QAPISemError(
> > -                    section.info, "text required after '%s:'" %
> section.tag)
> > +                    section.info, "text required after '%s:'" %
> section.kind)
> >
> > -    def ensure_untagged_section(self, info: QAPISourceInfo) -> None:
> > -        if self.all_sections and not self.all_sections[-1].tag:
> > +    def ensure_untagged_section(
> > +        self,
> > +        info: QAPISourceInfo,
> > +    ) -> None:
>
> Accidental line breaking?
>

Something something something black autoformatter. I wonder why it did
this, though... I'll see if I can undo it.


>
> > +        kind = QAPIDoc.Kind.PLAIN
> > +
> > +        if self.all_sections and self.all_sections[-1].kind == kind:
>
> I'd prefer not to hide PLAIN behind a variable, but I'd also prefer
> the condition to fit on a line.  Hmm.
>

Also somewhat vestigial from when I had intro/details. When that split
comes, kind = becomes a conditional ternary.


>
> >              # extend current section
> >              section = self.all_sections[-1]
> >              if not section.text:
>
> Maybe
>
>            section = self.all_sections[-1] if self.all_sections else None
>
>            if second and section.kind = QAPIDoc.Kind.Plain:
>                # extend current section
>                if not section.text:
>

Could, but it's going to get rewritten when the inliner comes anyway, ...


>
> > @@ -693,46 +733,56 @@ def ensure_untagged_section(self, info:
> QAPISourceInfo) -> None:
> >                  section.info = info
> >              section.text += '\n'
> >              return
> > +
> >          # start new section
> > -        section = self.Section(info)
> > +        section = self.Section(info, kind)
> >          self.sections.append(section)
> >          self.all_sections.append(section)
> >
> > -    def new_tagged_section(self, info: QAPISourceInfo, tag: str) ->
> None:
> > -        section = self.Section(info, tag)
> > -        if tag == 'Returns':
> > +    def new_tagged_section(
> > +        self,
> > +        info: QAPISourceInfo,
> > +        kind: 'QAPIDoc.Kind',
> > +    ) -> None:
> > +        section = self.Section(info, kind)
> > +        if kind == QAPIDoc.Kind.RETURNS:
> >              if self.returns:
> >                  raise QAPISemError(
> > -                    info, "duplicated '%s' section" % tag)
> > +                    info, "duplicated '%s' section" % kind)
> >              self.returns = section
> > -        elif tag == 'Errors':
> > +        elif kind == QAPIDoc.Kind.ERRORS:
> >              if self.errors:
> >                  raise QAPISemError(
> > -                    info, "duplicated '%s' section" % tag)
> > +                    info, "duplicated '%s' section" % kind)
> >              self.errors = section
> > -        elif tag == 'Since':
> > +        elif kind == QAPIDoc.Kind.SINCE:
> >              if self.since:
> >                  raise QAPISemError(
> > -                    info, "duplicated '%s' section" % tag)
> > +                    info, "duplicated '%s' section" % kind)
> >              self.since = section
> >          self.sections.append(section)
> >          self.all_sections.append(section)
> >
> > -    def _new_description(self, info: QAPISourceInfo, name: str,
> > -                         desc: Dict[str, ArgSection]) -> None:
> > +    def _new_description(
> > +        self,
> > +        info: QAPISourceInfo,
> > +        name: str,
> > +        kind: 'QAPIDoc.Kind',
> > +        desc: Dict[str, ArgSection]
> > +    ) -> None:
> >          if not name:
> >              raise QAPISemError(info, "invalid parameter name")
> >          if name in desc:
> >              raise QAPISemError(info, "'%s' parameter name duplicated" %
> name)
> > -        section = self.ArgSection(info, '@' + name)
> > +        section = self.ArgSection(info, kind, name)
> >          self.all_sections.append(section)
> >          desc[name] = section
> >
> >      def new_argument(self, info: QAPISourceInfo, name: str) -> None:
> > -        self._new_description(info, name, self.args)
> > +        self._new_description(info, name, QAPIDoc.Kind.MEMBER,
> self.args)
> >
> >      def new_feature(self, info: QAPISourceInfo, name: str) -> None:
> > -        self._new_description(info, name, self.features)
> > +        self._new_description(info, name, QAPIDoc.Kind.FEATURE,
> self.features)
>
> QAPIDoc.Kind.FOO is a mouthful, and it tends to result in long lines,
> like here.  Can't see an easy and clean way to reduce the verbosity.
>

Yeah...


>
> >
> >      def append_line(self, line: str) -> None:
> >          self.all_sections[-1].append_line(line)
> > @@ -744,8 +794,9 @@ def connect_member(self, member: 'QAPISchemaMember')
> -> None:
> >                  raise QAPISemError(member.info,
> >                                     "%s '%s' lacks documentation"
> >                                     % (member.role, member.name))
> > -            self.args[member.name] = QAPIDoc.ArgSection(
> > -                self.info, '@' + member.name)
> > +            section = QAPIDoc.ArgSection(
> > +                self.info, QAPIDoc.Kind.MEMBER, member.name)
> > +            self.args[member.name] = section
>
> Why the extra variable?
>

Wish I remembered. I can undo it and see if anything barks.


>
> >          self.args[member.name].connect(member)
> >
> >      def connect_feature(self, feature: 'QAPISchemaFeature') -> None:
> > diff --git a/tests/qapi-schema/doc-good.out
> b/tests/qapi-schema/doc-good.out
> > index 0a9da3efdeb..5773f1dd6d6 100644
> > --- a/tests/qapi-schema/doc-good.out
> > +++ b/tests/qapi-schema/doc-good.out
> > @@ -113,7 +113,7 @@ The _one_ {and only}, description on the same line
> >  Also _one_ {and only}
> >      feature=enum-member-feat
> >  a member feature
> > -    section=None
> > +    section=Plain
> >  @two is undocumented
> >  doc symbol=Base
> >      body=
> > @@ -171,15 +171,15 @@ description starts on the same line
> >  a feature
> >      feature=cmd-feat2
> >  another feature
> > -    section=None
> > +    section=Plain
> >  .. note:: @arg3 is undocumented
> >      section=Returns
> >  @Object
> >      section=Errors
> >  some
> > -    section=TODO
> > +    section=Todo
>
> With the method-less Enum I suggested, this hunk would go away.  Not
> that it matters :)
>
> >  frobnicate
> > -    section=None
> > +    section=Plain
> >  .. admonition:: Notes
> >
> >   - Lorem ipsum dolor sit amet
> > @@ -212,7 +212,7 @@ If you're bored enough to read this, go see a video
> of boxed cats
> >  a feature
> >      feature=cmd-feat2
> >  another feature
> > -    section=None
> > +    section=Plain
> >  .. qmp-example::
> >
> >     -> "this example"
> > diff --git a/tests/qapi-schema/test-qapi.py
> b/tests/qapi-schema/test-qapi.py
> > index 7e3f9f4aa1f..bca924309be 100755
> > --- a/tests/qapi-schema/test-qapi.py
> > +++ b/tests/qapi-schema/test-qapi.py
> > @@ -131,7 +131,7 @@ def test_frontend(fname):
> >          for feat, section in doc.features.items():
> >              print('    feature=%s\n%s' % (feat, section.text))
> >          for section in doc.sections:
> > -            print('    section=%s\n%s' % (section.tag, section.text))
> > +            print('    section=%s\n%s' % (section.kind, section.text))
> >
> >
> >  def open_test_result(dir_name, file_name, update):
>
>

[-- Attachment #2: Type: text/html, Size: 25512 bytes --]

  reply	other threads:[~2025-03-06  4:04 UTC|newest]

Thread overview: 129+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-05  3:45 [PATCH 00/57] docs: Add new QAPI transmogrifier John Snow
2025-03-05  3:45 ` [PATCH 01/57] do-not-merge John Snow
2025-03-05  3:45 ` [PATCH 02/57] qapi: shush pylint up John Snow
2025-03-05  6:28   ` Markus Armbruster
2025-03-05 15:31     ` John Snow
2025-03-05  3:45 ` [PATCH 03/57] docs/sphinx: create QAPI domain extension stub John Snow
2025-03-05  3:45 ` [PATCH 04/57] docs/sphinx: add compat.py module and nested_parse helper John Snow
2025-03-07  5:46   ` Markus Armbruster
2025-03-07 20:08     ` John Snow
2025-03-05  3:45 ` [PATCH 05/57] docs/qapi-domain: add qapi:module directive John Snow
2025-03-05  3:45 ` [PATCH 06/57] docs/qapi-domain: add QAPI domain object registry John Snow
2025-03-05  3:45 ` [PATCH 07/57] docs/qapi-domain: add QAPI index John Snow
2025-03-05  3:45 ` [PATCH 08/57] docs/qapi-domain: add resolve_any_xref() John Snow
2025-03-05  3:45 ` [PATCH 09/57] docs/qapi-domain: add QAPI xref roles John Snow
2025-03-07 10:08   ` Markus Armbruster
2025-03-07 21:23     ` John Snow
2025-03-05  3:45 ` [PATCH 10/57] docs/qapi-domain: add compatibility node classes John Snow
2025-03-05  3:45 ` [PATCH 11/57] docs/qapi-domain: add qapi:command directive John Snow
2025-03-07  6:33   ` Markus Armbruster
2025-03-07 22:39     ` John Snow
2025-03-05  3:45 ` [PATCH 12/57] docs/qapi-domain: add :since: directive option John Snow
2025-03-07  6:59   ` Markus Armbruster
2025-03-07 22:43     ` John Snow
2025-03-05  3:45 ` [PATCH 13/57] docs/qapi-domain: add "Arguments:" field lists John Snow
2025-03-07  7:46   ` Markus Armbruster
2025-03-07 22:48     ` John Snow
2025-03-05  3:45 ` [PATCH 14/57] docs/qapi-domain: add "Features:" " John Snow
2025-03-05  3:45 ` [PATCH 15/57] docs/qapi-domain: add "Errors:" " John Snow
2025-03-07  7:48   ` Markus Armbruster
2025-03-07 22:50     ` John Snow
2025-03-08  6:49       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 16/57] docs/qapi-domain: add "Returns:" " John Snow
2025-03-07  7:58   ` Markus Armbruster
2025-03-07 22:58     ` John Snow
2025-03-08  6:57       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 17/57] docs/qapi-domain: add qapi:enum directive John Snow
2025-03-05  3:45 ` [PATCH 18/57] docs/qapi-domain: add qapi:alternate directive John Snow
2025-03-07 10:18   ` Markus Armbruster
2025-03-07 23:02     ` John Snow
2025-03-08  6:58       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 19/57] docs/qapi-domain: add qapi:event directive John Snow
2025-03-07 10:26   ` Markus Armbruster
2025-03-07 23:06     ` John Snow
2025-03-08  7:00       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 20/57] docs/qapi-domain: add qapi:object directive John Snow
2025-03-05  3:45 ` [PATCH 21/57] docs/qapi-domain: add :deprecated: directive option John Snow
2025-03-05  9:13   ` Markus Armbruster
2025-03-05 15:34     ` John Snow
2025-03-06  7:22       ` Markus Armbruster
2025-03-07 10:47   ` Markus Armbruster
2025-03-08 18:24     ` John Snow
2025-03-05  3:45 ` [PATCH 22/57] docs/qapi-domain: add :unstable: " John Snow
2025-03-05  3:45 ` [PATCH 23/57] docs/qapi-domain: add :ifcond: " John Snow
2025-03-07 10:57   ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 24/57] docs/qapi-domain: add warnings for malformed field lists John Snow
2025-03-05  3:45 ` [PATCH 25/57] docs/qapi-domain: add type cross-refs to " John Snow
2025-03-05  3:45 ` [PATCH 26/57] docs/qapi-domain: add CSS styling John Snow
2025-03-05  3:45 ` [PATCH 27/57] docs/qapi-domain: add XREF compatibility goop for Sphinx < 4.1 John Snow
2025-03-05  3:45 ` [PATCH 28/57] docs/qapi-domain: warn when QAPI domain xrefs fail to resolve John Snow
2025-03-05  3:45 ` [PATCH 29/57] docs/qapi-domain: Fix error context reporting in Sphinx 5.x and 6.x John Snow
2025-03-05  3:45 ` [PATCH 30/57] qapi/parser: adjust info location for doc body section John Snow
2025-03-05 10:10   ` Markus Armbruster
2025-03-06  3:42     ` John Snow
2025-03-06  6:53       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 31/57] qapi: expand tags to all doc sections John Snow
2025-03-05 10:16   ` Markus Armbruster
2025-03-06  3:58     ` John Snow [this message]
2025-03-06  7:42       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 32/57] qapi/schema: add __repr__ to QAPIDoc.Section John Snow
2025-03-05  3:45 ` [PATCH 33/57] docs/qapidoc: add transmogrifier stub John Snow
2025-03-05  3:45 ` [PATCH 34/57] docs/qapidoc: split old implementation into qapidoc_legacy.py John Snow
2025-03-05  3:45 ` [PATCH 35/57] docs/qapidoc: Fix static typing on qapidoc.py John Snow
2025-03-07 11:59   ` Markus Armbruster
2025-03-08 18:32     ` John Snow
2025-03-09  5:37       ` Markus Armbruster
2025-03-09  6:46         ` John Snow
2025-03-05  3:45 ` [PATCH 36/57] do-not-merge John Snow
2025-03-05  3:45 ` [PATCH 37/57] docs/qapidoc: add transmogrifier class stub John Snow
2025-03-05  3:45 ` [PATCH 38/57] docs/qapidoc: add visit_module() method John Snow
2025-03-05  3:45 ` [PATCH 39/57] qapi/source: allow multi-line QAPISourceInfo advancing John Snow
2025-03-05 10:35   ` Markus Armbruster
2025-03-06  3:13     ` John Snow
2025-03-06  7:01       ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 40/57] docs/qapidoc: add visit_freeform() method John Snow
2025-03-07 12:10   ` Markus Armbruster
2025-03-08  8:02     ` John Snow
2025-03-05  3:45 ` [PATCH 41/57] docs/qapidoc: add preamble() method John Snow
2025-03-07 12:13   ` Markus Armbruster
2025-03-08  8:03     ` John Snow
2025-03-05  3:45 ` [PATCH 42/57] docs/qapidoc: add visit_paragraph() method John Snow
2025-03-05  3:45 ` [PATCH 43/57] docs/qapidoc: add visit_errors() method John Snow
2025-03-07 12:14   ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 44/57] docs/qapidoc: add format_type() method John Snow
2025-03-05  3:45 ` [PATCH 45/57] docs/qapidoc: add add_field() and generate_field() helper methods John Snow
2025-03-05  3:45 ` [PATCH 46/57] docs/qapidoc: add visit_feature() method John Snow
2025-03-07 12:16   ` Markus Armbruster
2025-03-05  3:45 ` [PATCH 47/57] docs/qapidoc: prepare to record entity being transmogrified John Snow
2025-03-05  3:45 ` [PATCH 48/57] docs/qapidoc: add visit_returns() method John Snow
2025-03-07 12:18   ` Markus Armbruster
2025-03-08  8:06     ` John Snow
2025-03-05  3:45 ` [PATCH 49/57] docs/qapidoc: add visit_member() method John Snow
2025-03-07 12:24   ` Markus Armbruster
2025-03-08  8:07     ` John Snow
2025-03-05  3:45 ` [PATCH 50/57] docs/qapidoc: add visit_sections() method John Snow
2025-03-07 12:25   ` Markus Armbruster
2025-03-08  8:10     ` John Snow
2025-03-08  9:20       ` Markus Armbruster
2025-03-05  3:46 ` [PATCH 51/57] docs/qapidoc: add visit_entity() John Snow
2025-03-07 12:26   ` Markus Armbruster
2025-03-08  8:12     ` John Snow
2025-03-05  3:46 ` [PATCH 52/57] docs/qapidoc: implement transmogrify() method John Snow
2025-03-05  3:46 ` [PATCH 53/57] docs: disambiguate cross-references John Snow
2025-03-05  3:46 ` [PATCH 54/57] docs/qapidoc: add transmogrifier test document John Snow
2025-03-09  7:19   ` Markus Armbruster
2025-03-05  3:46 ` [PATCH 55/57] docs/qapidoc: process @foo into ``foo`` John Snow
2025-03-05  3:46 ` [PATCH 56/57] docs/qapidoc: add intermediate output debugger John Snow
2025-03-07 12:34   ` Markus Armbruster
2025-03-08  8:13     ` John Snow
2025-03-08  9:21       ` Markus Armbruster
2025-03-05  3:46 ` [PATCH 57/57] docs/qapidoc: Add "the members of" pointers John Snow
2025-03-07 12:37   ` Markus Armbruster
2025-03-08  8:18     ` John Snow
2025-03-05 11:31 ` [PATCH 00/57] docs: Add new QAPI transmogrifier Markus Armbruster
2025-03-05 15:40   ` John Snow
2025-03-06  7:19     ` Markus Armbruster
2025-03-06 10:58   ` Markus Armbruster
2025-03-06 12:35 ` Markus Armbruster
2025-03-06 13:27   ` John Snow
2025-03-07 18:19 ` Markus Armbruster

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAFn=p-bUtzo1dByK0k6kevNDqghcc15L1N8WFWNB_nm9kXvCbQ@mail.gmail.com' \
    --to=jsnow@redhat.com \
    --cc=alex.bennee@linaro.org \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=michael.roth@amd.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).