aboutsummaryrefslogtreecommitdiff
path: root/docs/sphinx/qapi_domain.py
diff options
context:
space:
mode:
authorJohn Snow <jsnow@redhat.com>2025-03-10 23:42:03 -0400
committerMarkus Armbruster <armbru@redhat.com>2025-03-11 10:07:02 +0100
commit36ceafad9e4e61138b08dc371c42248dc5289a57 (patch)
tree7c1dce9219a01bafcec7b31ca5e589e142096985 /docs/sphinx/qapi_domain.py
parentabf6bedc38aea51ecce988a499a0b277bbd3c267 (diff)
downloadqemu-36ceafad9e4e61138b08dc371c42248dc5289a57.zip
qemu-36ceafad9e4e61138b08dc371c42248dc5289a57.tar.gz
qemu-36ceafad9e4e61138b08dc371c42248dc5289a57.tar.bz2
docs/qapi-domain: add QAPI domain object registry
This is the first step towards QAPI domain cross-references and a QAPI reference index. This patch just creates the object registry, and updates the merge_domaindata stub method now that we have actual data we may need to merge. Note that how to handle merge conflict resolution is unhandled, as the Sphinx python domain itself does not handle it either. I do not know how to intentionally trigger it, so I've left an assertion instead if it should ever come up ... Signed-off-by: John Snow <jsnow@redhat.com> Message-ID: <20250311034303.75779-6-jsnow@redhat.com> Acked-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com>
Diffstat (limited to 'docs/sphinx/qapi_domain.py')
-rw-r--r--docs/sphinx/qapi_domain.py77
1 files changed, 75 insertions, 2 deletions
diff --git a/docs/sphinx/qapi_domain.py b/docs/sphinx/qapi_domain.py
index a1983d9..f3ece42b 100644
--- a/docs/sphinx/qapi_domain.py
+++ b/docs/sphinx/qapi_domain.py
@@ -9,10 +9,12 @@ from typing import (
AbstractSet,
Any,
Dict,
+ NamedTuple,
Tuple,
)
from sphinx.domains import Domain, ObjType
+from sphinx.locale import __
from sphinx.util import logging
@@ -22,22 +24,93 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
+class ObjectEntry(NamedTuple):
+ docname: str
+ node_id: str
+ objtype: str
+ aliased: bool
+
+
class QAPIDomain(Domain):
"""QAPI language domain."""
name = "qapi"
label = "QAPI"
+ # This table associates cross-reference object types (key) with an
+ # ObjType instance, which defines the valid cross-reference roles
+ # for each object type.
+
+ # Actual table entries for module, command, event, etc will come in
+ # forthcoming commits.
object_types: Dict[str, ObjType] = {}
+
directives = {}
roles = {}
- initial_data: Dict[str, Dict[str, Tuple[Any]]] = {}
+
+ # Moved into the data property at runtime;
+ # this is the internal index of reference-able objects.
+ initial_data: Dict[str, Dict[str, Tuple[Any]]] = {
+ "objects": {}, # fullname -> ObjectEntry
+ }
+
indices = []
+ @property
+ def objects(self) -> Dict[str, ObjectEntry]:
+ ret = self.data.setdefault("objects", {})
+ return ret # type: ignore[no-any-return]
+
+ def note_object(
+ self,
+ name: str,
+ objtype: str,
+ node_id: str,
+ aliased: bool = False,
+ location: Any = None,
+ ) -> None:
+ """Note a QAPI object for cross reference."""
+ if name in self.objects:
+ other = self.objects[name]
+ if other.aliased and aliased is False:
+ # The original definition found. Override it!
+ pass
+ elif other.aliased is False and aliased:
+ # The original definition is already registered.
+ return
+ else:
+ # duplicated
+ logger.warning(
+ __(
+ "duplicate object description of %s, "
+ "other instance in %s, use :no-index: for one of them"
+ ),
+ name,
+ other.docname,
+ location=location,
+ )
+ self.objects[name] = ObjectEntry(
+ self.env.docname, node_id, objtype, aliased
+ )
+
+ def clear_doc(self, docname: str) -> None:
+ for fullname, obj in list(self.objects.items()):
+ if obj.docname == docname:
+ del self.objects[fullname]
+
def merge_domaindata(
self, docnames: AbstractSet[str], otherdata: Dict[str, Any]
) -> None:
- pass
+ for fullname, obj in otherdata["objects"].items():
+ if obj.docname in docnames:
+ # Sphinx's own python domain doesn't appear to bother to
+ # check for collisions. Assert they don't happen and
+ # we'll fix it if/when the case arises.
+ assert fullname not in self.objects, (
+ "bug - collision on merge?"
+ f" {fullname=} {obj=} {self.objects[fullname]=}"
+ )
+ self.objects[fullname] = obj
def resolve_any_xref(self, *args: Any, **kwargs: Any) -> Any:
# pylint: disable=unused-argument