mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-27 04:13:53 -06:00
docs/qapidoc: Add "the members of" pointers
Add "the members of ..." pointers to Members and Arguments lists where appropriate, with clickable cross-references - so it's a slight improvement over the old system :) This patch is meant to be a temporary solution until we can review and merge the inliner. The implementation of this patch is a little bit of a hack: Sphinx is not designed to allow you to mix fields of different "type"; i.e. mixing member descriptions and free-form text under the same heading. To accomplish this with a minimum of hackery, we technically document a "dummy field" and then just strip off the documentation for that dummy field in a post-processing step. We use the "q_dummy" variable for this purpose, then strip it back out before final processing. If this processing step should fail, you'll see warnings for a bad cross-reference. (So if you don't see any, it must be working!) Signed-off-by: John Snow <jsnow@redhat.com> Message-ID: <20250311034303.75779-58-jsnow@redhat.com> Acked-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
This commit is contained in:
parent
7f6f24aaf5
commit
1884492e64
2 changed files with 77 additions and 3 deletions
|
@ -433,6 +433,24 @@ class QAPIObject(QAPIDescription):
|
|||
self._validate_field(field)
|
||||
|
||||
|
||||
class SpecialTypedField(CompatTypedField):
|
||||
def make_field(self, *args: Any, **kwargs: Any) -> nodes.field:
|
||||
ret = super().make_field(*args, **kwargs)
|
||||
|
||||
# Look for the characteristic " -- " text node that Sphinx
|
||||
# inserts for each TypedField entry ...
|
||||
for node in ret.traverse(lambda n: str(n) == " -- "):
|
||||
par = node.parent
|
||||
if par.children[0].astext() != "q_dummy":
|
||||
continue
|
||||
|
||||
# If the first node's text is q_dummy, this is a dummy
|
||||
# field we want to strip down to just its contents.
|
||||
del par.children[:-1]
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class QAPICommand(QAPIObject):
|
||||
"""Description of a QAPI Command."""
|
||||
|
||||
|
@ -440,7 +458,7 @@ class QAPICommand(QAPIObject):
|
|||
doc_field_types.extend(
|
||||
[
|
||||
# :arg TypeName ArgName: descr
|
||||
CompatTypedField(
|
||||
SpecialTypedField(
|
||||
"argument",
|
||||
label=_("Arguments"),
|
||||
names=("arg",),
|
||||
|
@ -508,7 +526,7 @@ class QAPIObjectWithMembers(QAPIObject):
|
|||
doc_field_types.extend(
|
||||
[
|
||||
# :member type name: descr
|
||||
CompatTypedField(
|
||||
SpecialTypedField(
|
||||
"member",
|
||||
label=_("Members"),
|
||||
names=("memb",),
|
||||
|
|
|
@ -47,8 +47,10 @@ from qapi.schema import (
|
|||
QAPISchemaCommand,
|
||||
QAPISchemaDefinition,
|
||||
QAPISchemaEnumMember,
|
||||
QAPISchemaEvent,
|
||||
QAPISchemaFeature,
|
||||
QAPISchemaMember,
|
||||
QAPISchemaObjectType,
|
||||
QAPISchemaObjectTypeMember,
|
||||
QAPISchemaType,
|
||||
QAPISchemaVisitor,
|
||||
|
@ -298,11 +300,61 @@ class Transmogrifier:
|
|||
|
||||
self.ensure_blank_line()
|
||||
|
||||
def _insert_member_pointer(self, ent: QAPISchemaDefinition) -> None:
|
||||
|
||||
def _get_target(
|
||||
ent: QAPISchemaDefinition,
|
||||
) -> Optional[QAPISchemaDefinition]:
|
||||
if isinstance(ent, (QAPISchemaCommand, QAPISchemaEvent)):
|
||||
return ent.arg_type
|
||||
if isinstance(ent, QAPISchemaObjectType):
|
||||
return ent.base
|
||||
return None
|
||||
|
||||
target = _get_target(ent)
|
||||
if target is not None and not target.is_implicit():
|
||||
assert ent.info
|
||||
self.add_field(
|
||||
self.member_field_type,
|
||||
"q_dummy",
|
||||
f"The members of :qapi:type:`{target.name}`.",
|
||||
ent.info,
|
||||
"q_dummy",
|
||||
)
|
||||
|
||||
if isinstance(ent, QAPISchemaObjectType) and ent.branches is not None:
|
||||
for variant in ent.branches.variants:
|
||||
if variant.type.name == "q_empty":
|
||||
continue
|
||||
assert ent.info
|
||||
self.add_field(
|
||||
self.member_field_type,
|
||||
"q_dummy",
|
||||
f" When ``{ent.branches.tag_member.name}`` is "
|
||||
f"``{variant.name}``: "
|
||||
f"The members of :qapi:type:`{variant.type.name}`.",
|
||||
ent.info,
|
||||
"q_dummy",
|
||||
)
|
||||
|
||||
def visit_sections(self, ent: QAPISchemaDefinition) -> None:
|
||||
sections = ent.doc.all_sections if ent.doc else []
|
||||
|
||||
# Determine the index location at which we should generate
|
||||
# documentation for "The members of ..." pointers. This should
|
||||
# go at the end of the members section(s) if any. Note that
|
||||
# index 0 is assumed to be a plain intro section, even if it is
|
||||
# empty; and that a members section if present will always
|
||||
# immediately follow the opening PLAIN section.
|
||||
gen_index = 1
|
||||
if len(sections) > 1:
|
||||
while sections[gen_index].kind == QAPIDoc.Kind.MEMBER:
|
||||
gen_index += 1
|
||||
if gen_index >= len(sections):
|
||||
break
|
||||
|
||||
# Add sections in source order:
|
||||
for section in sections:
|
||||
for i, section in enumerate(sections):
|
||||
# @var is translated to ``var``:
|
||||
section.text = re.sub(r"@([\w-]+)", r"``\1``", section.text)
|
||||
|
||||
|
@ -324,6 +376,10 @@ class Transmogrifier:
|
|||
else:
|
||||
assert False
|
||||
|
||||
# Generate "The members of ..." entries if necessary:
|
||||
if i == gen_index - 1:
|
||||
self._insert_member_pointer(ent)
|
||||
|
||||
self.ensure_blank_line()
|
||||
|
||||
# Transmogrification core methods
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue