From 14f9581ab7bf8fc6797757cf5addfd31a127c8f2 Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Mon, 19 Oct 2020 10:30:57 -0300 Subject: [PATCH 1/7] Update compound parser to better support xrefitem When xrefitem, or its specializations, is used some extra XML elements are generated which were not properly parsed; this commit adds the extra parsing required. * properly parses a variable list element, which consists of a set of varlistentry + listitem elements * docTitleTypeSub was extended to to parse the "ref" and "anchor" elements which exist inside a varlistentry. Signed-off-by: Fabio Utzig --- breathe/parser/compound.py | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/breathe/parser/compound.py b/breathe/parser/compound.py index 16750187..a1f0c5cf 100644 --- a/breathe/parser/compound.py +++ b/breathe/parser/compound.py @@ -642,6 +642,12 @@ class docVarListEntryTypeSub(supermod.docVarListEntryType): def __init__(self, term=None): supermod.docVarListEntryType.__init__(self, term) + def buildChildren(self, child_, nodeName_): + if child_.nodeType == Node.ELEMENT_NODE and nodeName_ == 'term': + obj_ = supermod.docTitleType.factory() + obj_.build(child_) + self.set_term(obj_) + supermod.docVarListEntryType.subclass = docVarListEntryTypeSub # end class docVarListEntryTypeSub @@ -858,6 +864,33 @@ def __init__(self, id=None, xreftitle=None, xrefdescription=None): # end class docXRefSectTypeSub +class docVariableListTypeSub(supermod.docVariableListType): + + node_type = "docvariablelist" + + def __init__(self, valueOf_=''): + supermod.docVariableListType.__init__(self, valueOf_) + + self.varlistentries = [] + self.listitems = [] + + def buildChildren(self, child_, nodeName_): + supermod.docVariableListType.buildChildren(self, child_, nodeName_) + + if child_.nodeType == Node.ELEMENT_NODE and nodeName_ == "varlistentry": + obj_ = supermod.docVarListEntryType.factory() + obj_.build(child_) + self.varlistentries.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and nodeName_ == "listitem": + obj_ = supermod.docListItemType.factory() + obj_.build(child_) + self.listitems.append(obj_) + + +supermod.docVariableListType.subclass = docVariableListTypeSub +# end class docVariableListTypeSub + + class docCopyTypeSub(supermod.docCopyType): node_type = "doccopy" @@ -1009,6 +1042,10 @@ def buildChildren(self, child_, nodeName_): obj_ = supermod.docXRefSectType.factory() obj_.build(child_) self.content.append(obj_) + elif child_.nodeType == Node.ELEMENT_NODE and nodeName_ == "variablelist": + obj_ = supermod.docVariableListType.factory() + obj_.build(child_) + self.content.append(obj_) supermod.docParaType.subclass = docParaTypeSub @@ -1052,6 +1089,19 @@ def __init__(self, valueOf_='', mixedclass_=None, content_=None): supermod.docTitleType.__init__(self, valueOf_, mixedclass_, content_) self.type_ = None + def buildChildren(self, child_, nodeName_): + supermod.docTitleType.buildChildren(self, child_, nodeName_) + + if child_.nodeType == Node.ELEMENT_NODE and nodeName_ == "ref": + obj_ = supermod.docRefTextType.factory() + obj_.build(child_) + self.content_.append(obj_) + self.valueOf_ += obj_.valueOf_ + elif child_.nodeType == Node.ELEMENT_NODE and nodeName_ == "anchor": + obj_ = supermod.docAnchorType.factory() + obj_.build(child_) + self.content_.append(obj_) + supermod.docTitleType.subclass = docTitleTypeSub # end class docTitleTypeSub From 7fb9366331380108dbe5f87ca871587dbaa5867b Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 09:16:16 -0300 Subject: [PATCH 2/7] Add support for Doxygen "page" block and directive When xrefitem or any of its specializations is used, Doxygen generates a new file of kind="page"; this is very similar to a "group" or "namespace" file. This commit adds proper filter handling and a new directive, doxygenpage, that can be used to include documentation from a page block. Signed-off-by: Fabio Utzig --- breathe/directives.py | 9 +++++++++ breathe/renderer/filter.py | 10 ++++++++-- documentation/source/directives.rst | 22 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/breathe/directives.py b/breathe/directives.py index 40b0dac9..da175b9a 100644 --- a/breathe/directives.py +++ b/breathe/directives.py @@ -412,6 +412,14 @@ class DoxygenGroupDirective(_DoxygenContentBlockDirective): } +class DoxygenPageDirective(_DoxygenContentBlockDirective): + kind = "page" + option_spec = { + "path": unchanged_required, + "project": unchanged_required, + } + + # TODO: is this comment still relevant? # This class was the same as the DoxygenBaseDirective above, except that it # wraps the output in a definition_list before passing it back. This should be @@ -557,6 +565,7 @@ def setup(app: Sphinx) -> None: "doxygengroup": DoxygenGroupDirective, "doxygenfile": DoxygenFileDirective, "autodoxygenfile": AutoDoxygenFileDirective, + "doxygenpage": DoxygenPageDirective, } # note: the parser factory contains a cache of the parsed XML diff --git a/breathe/renderer/filter.py b/breathe/renderer/filter.py index 0ba742f9..d9ef3ff9 100644 --- a/breathe/renderer/filter.py +++ b/breathe/renderer/filter.py @@ -577,7 +577,7 @@ def __init__(self, app: Sphinx) -> None: def create_render_filter(self, kind: str, options: Dict[str, Any]) -> Filter: """Render filter for group & namespace blocks""" - if kind not in ['group', 'namespace']: + if kind not in ['group', 'page', 'namespace']: raise UnrecognisedKindError(kind) # Generate new dictionary from defaults @@ -933,7 +933,7 @@ def create_content_filter(self, kind: str, options: Dict[str, Any]) -> Filter: As a finder/content filter we only need to match exactly what we're interested in. """ - if kind not in ['group', 'namespace']: + if kind not in ['group', 'page', 'namespace']: raise UnrecognisedKindError(kind) node = Node() @@ -1063,6 +1063,12 @@ def create_finder_filter(self, kind: str, name: str) -> Filter: InFilter(KindAccessor(Node()), ["group"]), InFilter(NameAccessor(Node()), [name]) ) + elif kind == 'page': + filter_ = AndFilter( + InFilter(NodeTypeAccessor(Node()), ["compound"]), + InFilter(KindAccessor(Node()), ["page"]), + InFilter(NameAccessor(Node()), [name]) + ) else: # Assume kind == 'namespace' filter_ = AndFilter( diff --git a/documentation/source/directives.rst b/documentation/source/directives.rst index dcf24025..cd81c6ec 100644 --- a/documentation/source/directives.rst +++ b/documentation/source/directives.rst @@ -387,6 +387,28 @@ It behaves the same as the doxygenstruct directive. Checkout the :ref:`example ` to see it in action. +doxygenpage +~~~~~~~~~~~ + +This directive generates the appropriate output for the contents of a doxygen +page. A doxygen page is created for each "key" of every \\xrefitem command used +for markup in the source comments. For more information check the +`doxygen xrefitem documentation`_. + +It takes the standard ``project`` and ``path`` options. + +:: + + .. doxygenpage:: + :project: ... + :path: ... + +Checkout the :ref:`doxygenpage documentation ` for more details +and to see it in action. + +.. _doxygen xrefitem documentation: https://www.doxygen.nl/manual/commands.html#cmdxrefitem + + Config Values ------------- From 3f47df55cca02f23be5c27591cea4634f3c18580 Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 11:21:17 -0300 Subject: [PATCH 3/7] Fix link to Doxygen grouping documentation Signed-off-by: Fabio Utzig --- documentation/source/directives.rst | 4 ++-- documentation/source/group.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/source/directives.rst b/documentation/source/directives.rst index cd81c6ec..3cb39d4c 100644 --- a/documentation/source/directives.rst +++ b/documentation/source/directives.rst @@ -193,7 +193,7 @@ doxygengroup This directive generates the appropriate output for the contents of a doxygen group. A doxygen group can be declared with specific doxygen markup in the -source comments as covered in the `doxygen documentation`_. +source comments as covered in the `doxygen grouping documentation`_. It takes the standard ``project``, ``path``, ``outline`` and ``no-link`` options and additionally the ``content-only``, ``members``, ``protected-members``, @@ -216,7 +216,7 @@ and additionally the ``content-only``, ``members``, ``protected-members``, Checkout the :ref:`doxygengroup documentation ` for more details and to see it in action. -.. _doxygen documentation: http://www.stack.nl/~dimitri/doxygen/manual/grouping.html +.. _doxygen grouping documentation: https://www.doxygen.nl/manual/grouping.html .. _doxygenindex: diff --git a/documentation/source/group.rst b/documentation/source/group.rst index bf8b7202..6e006827 100644 --- a/documentation/source/group.rst +++ b/documentation/source/group.rst @@ -6,7 +6,7 @@ doxygengroup Directive This directive generates the appropriate output for the contents of a doxygen group. A doxygen group can be declared with specific doxygen markup in the -source comments as cover in the `doxygen documentation`_. +source comments as cover in the `doxygen grouping documentation`_. It takes the standard ``project``, ``path``, ``outline`` and ``no-link`` options and additionally the ``content-only``, ``members``, ``protected-members``, @@ -47,7 +47,7 @@ variable to set it in the ``conf.py``. defining them inside the scope of another group, or by using the Doxygen \ingroup command, are also parsed and loaded. -.. _doxygen documentation: http://www.stack.nl/~dimitri/doxygen/manual/grouping.html +.. _doxygen grouping documentation: https://www.doxygen.nl/manual/grouping.html .. contents:: From f20b539f139577079ebee322d7f019fb8631f6ba Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 09:17:01 -0300 Subject: [PATCH 4/7] Fix message when content element is not found When a content block was not found, the message would imply it is of type "namespace"; fix it so that the proper "kind" is displayed ("namespace", or "group", or "page"). Signed-off-by: Fabio Utzig --- breathe/directives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/breathe/directives.py b/breathe/directives.py index da175b9a..bb56e9a7 100644 --- a/breathe/directives.py +++ b/breathe/directives.py @@ -358,7 +358,7 @@ def run(self) -> List[Node]: if not matches: warning = create_warning(project_info, self.state, self.lineno, name=name, kind=self.kind) - return warning.warn('doxygen{kind}: Cannot find namespace "{name}" {tail}') + return warning.warn('doxygen{kind}: Cannot find {kind} "{name}" {tail}') if 'content-only' in self.options: # Unpack the single entry in the matches list From fca973205e4fa670cabd0e16ffff86984cce5e36 Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 09:17:59 -0300 Subject: [PATCH 5/7] Add proper rendering for xrefitem's elements The elements "docvariablelist", "docvarlistentry" and "docanchor" are used whenever an xrefitem is used in a project, and the proper compound of kind="page" is generated. This commits adds rendering of the elements in a definition block, and properly adds a target to anchor elements so they can be referenced later. Signed-off-by: Fabio Utzig --- breathe/renderer/sphinxrenderer.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 9f313d3f..3f557077 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1556,6 +1556,27 @@ def visit_docxrefsect(self, node) -> List[Node]: return [descnode] + def visit_docvariablelist(self, node) -> List[Node]: + output = [] + for varlistentry, listitem in zip(node.varlistentries, node.listitems): + descnode = addnodes.desc() + descnode['objtype'] = 'varentry' + signode = addnodes.desc_signature() + signode += self.render_optional(varlistentry) + descnode += signode + contentnode = addnodes.desc_content() + contentnode += self.render_iterable(listitem.para) + descnode += contentnode + output.append(descnode) + return output + + def visit_docvarlistentry(self, node) -> List[Node]: + content = node.term.content_ + return self.render_iterable(content) + + def visit_docanchor(self, node) -> List[None]: + return self.create_doxygen_target(node) + def visit_mixedcontainer(self, node) -> List[Node]: return self.render_optional(node.getValue()) @@ -1932,6 +1953,9 @@ def dispatch_memberdef(self, node) -> List[Node]: "docparamname": visit_docparamname, "templateparamlist": visit_templateparamlist, "docxrefsect": visit_docxrefsect, + "docvariablelist": visit_docvariablelist, + "docvarlistentry": visit_docvarlistentry, + "docanchor": visit_docanchor, } def render(self, node, context: Optional[RenderContext] = None) -> List[Node]: From ca6243a78465ccd3f06f1fc7a8c9cbc4cb93593a Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 09:18:51 -0300 Subject: [PATCH 6/7] Allow reference from xrefitem title Mimic Doxygen html output, by adding a pending_xref to xrefitem titles, which can later be resolved to the generated xrefsect page, if it was added to the project. Signed-off-by: Fabio Utzig --- breathe/renderer/sphinxrenderer.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 3f557077..7c7b0f7c 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1543,7 +1543,15 @@ def visit_docxrefsect(self, node) -> List[Node]: signode = addnodes.desc_signature() title = node.xreftitle[0] + ':' titlenode = nodes.emphasis(text=title) - signode += titlenode + ref = addnodes.pending_xref( + "", + reftype="ref", + refdomain="std", + refexplicit=True, + reftarget=node.id, + refdoc=self.app.env.docname, + *[titlenode]) + signode += ref nodelist = self.render(node.xrefdescription) contentnode = addnodes.desc_content() From 6830f3fc3a8353a119c51394d3b3fb2a7df916b3 Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Thu, 5 Nov 2020 11:52:16 -0300 Subject: [PATCH 7/7] Add documentation page for doxygenpage directive Add initial documentation with "doxygenpage" usage relying on previously added xrefsect examples. Signed-off-by: Fabio Utzig --- documentation/source/directives.rst | 1 + documentation/source/page.rst | 60 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 documentation/source/page.rst diff --git a/documentation/source/directives.rst b/documentation/source/directives.rst index 3cb39d4c..de83fb47 100644 --- a/documentation/source/directives.rst +++ b/documentation/source/directives.rst @@ -18,6 +18,7 @@ Directives & Config Variables file group autofile + page .. contents:: Table of Contents diff --git a/documentation/source/page.rst b/documentation/source/page.rst new file mode 100644 index 00000000..66a3cafb --- /dev/null +++ b/documentation/source/page.rst @@ -0,0 +1,60 @@ + +.. _page-example: + +doxygenpage Directive +===================== + +This directive generates the appropriate output for the contents of a doxygen +page. A doxygen page is created for each "key" of every \\xrefitem command used +for markup in the source comments. For more information check the +`doxygen documentation`_. + +It takes the standard ``project`` and ``path`` options. + +:: + + .. doxygenpage:: + :project: ... + :path: ... + +.. _doxygen documentation: https://www.doxygen.nl/manual/commands.html#cmdxrefitem + +.. contents:: + + +Basic Example +------------- + +.. cpp:namespace:: @ex_page_basic + +The plain ``doxygenpage`` directive will output the page name and description +and any variable entries which were defined to be part of this page (with an +\xrefitem usage). + +.. code-block:: rst + + .. doxygenpage:: xrefsample + :project: xrefsect + +It produces this output: + +.. doxygenpage:: xrefsample + :project: xrefsect + + +Failing Example +--------------- + +.. cpp:namespace:: @ex_page_failing + +This intentionally fails: + +.. code-block:: rst + + .. doxygengroup:: madeuppage + :project: xrefsect + +It produces the following warning message: + +.. warning:: Cannot find file "madeuppage" in doxygen xml output for project + "xrefsect" from directory: ../../examples/specific/xrefsect/xml/