diff --git a/docs/index.rst b/docs/index.rst index 0173bb5..f5e2c65 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,9 @@ Introduction .. ADDITIONAL CONTENT START +.. obj.embed:: Arthur + :type: dog + The extension provides a domain which allows user creates directive and roles to descibe, reference and index arbitrary object in documentation. It is a bit like :py:meth:`sphinx.application.Sphinx.add_object_type`, diff --git a/src/sphinxnotes/any/directives.py b/src/sphinxnotes/any/directives.py index 607699d..49f3a8c 100644 --- a/src/sphinxnotes/any/directives.py +++ b/src/sphinxnotes/any/directives.py @@ -186,3 +186,77 @@ def run(self) -> list[Node]: else: # Else, create Sphinx ObjectDescription(sphinx.addnodes.dsec_*) return self._run_objdesc(obj) + + +class ObjEmbedDirective(SphinxDirective): + """ + """ + schema: Schema + + # Member of parent + has_content:bool = False + required_arguments:int = 1 + optional_arguments:int = 0 + final_argument_whitespace:bool = True + option_spec:dict[str,callable] = { + 'type' : directives.unchanged, + } + + def run(self) -> list[Node]: + domainname, _ = self.name.split(':', 1) + domain = self.env.get_domain(domainname) + objid = self.arguments[0] + objtype = self.options['type'] + logger.warning('keys: %s' % domain.data['objects'].keys()) + self.schema = domain._schemas[objtype] + _, _, obj = domain.data['objects'][objtype, objid] + + return self._run_objdesc(obj) + + def _run_objdesc(self, obj:Object) -> list[Node]: + descnode = addnodes.desc() + + # Generate signature node + title = self.schema.title_of(obj) + if title is None: + # Use non-generated object ID as replacement of title + idfield, objid = self.schema.identifier_of(obj) + title = objid if idfield is not None else None + if title is not None: + signode = addnodes.desc_signature(title, '') + signode += addnodes.desc_name(title, title) + descnode.append(signode) + else: + signode = None + + # Generate content node + contnode = addnodes.desc_content() + descnode.append(contnode) + self._setup_nodes(obj, descnode, signode, contnode) + return [descnode] + + def _setup_nodes(self, obj:Object, sectnode:Element, _:Element|None, contnode:Element) -> None: + """ + Attach necessary informations to nodes and note them. + + The necessary information contains: domain info, basic attributes for nodes + (ids, names, classes...), name of anchor, description content and so on. + + :param sectnode: Section node, used as container of the whole object description + :param ahrnode: Anchor node, used to mark the location of object description + :param contnode: Content node, which contains the description content + """ + domainname, objtype = self.name.split(':', 1) + domain = self.env.get_domain(domainname) + + # Attach domain related info to section node + sectnode['domain'] = domain.name + # 'desctype' is a backwards compatible attribute + sectnode['objtype'] = sectnode['desctype'] = objtype + sectnode['classes'].append(domain.name) + + # Parse description + nested_parse_with_titles(self.state, + StringList(self.schema.render_description(obj)), + contnode) + diff --git a/src/sphinxnotes/any/domain.py b/src/sphinxnotes/any/domain.py index 1a08aa6..9bc683d 100644 --- a/src/sphinxnotes/any/domain.py +++ b/src/sphinxnotes/any/domain.py @@ -14,12 +14,12 @@ from docutils.nodes import Element, literal, Text from sphinx.addnodes import pending_xref -from sphinx.domains import Domain, ObjType +from sphinx.domains import Domain, ObjType, Index from sphinx.util import logging from sphinx.util.nodes import make_refnode from .schema import Schema, Object -from .directives import AnyDirective +from .directives import AnyDirective, ObjEmbedDirective from .roles import AnyRole from .indices import AnyIndex @@ -28,6 +28,7 @@ from sphinx.builders import Builder from sphinx.environment import BuildEnvironment from sphinx.util.typing import RoleFunction + from docutils.parsers.rst import Directive logger = logging.getLogger(__name__) @@ -44,11 +45,13 @@ class AnyDomain(Domain): #: Type (usually directive) name -> ObjType instance object_types:dict[str,ObjType]= {} #: Directive name -> directive class - directives:dict[str,type[AnyDirective]] = {} + directives:dict[str,type[Directive]] = { + 'obj.embed': ObjEmbedDirective, + } #: Role name -> role callable roles:dict[str,RoleFunction] = {} #: A list of Index subclasses - indices:list[type[AnyIndex]] = [] + indices:list[type[Index]] = [] #: AnyDomain specific: type -> index class _indices_for_reftype:dict[str,type[AnyIndex]] = {} #: AnyDomain specific: type -> Schema instance