Skip to content

Commit

Permalink
Merge pull request #556 from utzig/add-innergroup-support
Browse files Browse the repository at this point in the history
Add support for innergroup
  • Loading branch information
vermeeren authored Aug 19, 2020
2 parents 7b79a78 + 70fcda1 commit 762ee42
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 15 deletions.
4 changes: 4 additions & 0 deletions breathe/directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ class DoxygenNamespaceDirective(_DoxygenContentBlockDirective):

class DoxygenGroupDirective(_DoxygenContentBlockDirective):
kind = "group"
option_spec = {
**_DoxygenContentBlockDirective.option_spec,
"inner": flag,
}


# TODO: is this comment still relevant?
Expand Down
6 changes: 6 additions & 0 deletions breathe/renderer/sphinxrenderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,12 @@ def render_derivedcompoundref(node):
addnode('innerclass', lambda: self.render_iterable(node.innerclass))
addnode('innernamespace', lambda: self.render_iterable(node.innernamespace))

if 'inner' in options:
for node in node.innergroup:
file_data = self.compound_parser.parse(node.refid)
inner = file_data.compounddef
addnode('innergroup', lambda: self.visit_compounddef(inner))

nodelist = []
for i, nodes_ in sorted(nodemap.items()):
nodelist += nodes_
Expand Down
28 changes: 27 additions & 1 deletion documentation/source/group.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ source comments as cover in the `doxygen documentation`_.

It takes the standard ``project``, ``path``, ``outline`` and ``no-link`` options
and additionally the ``content-only``, ``members``, ``protected-members``,
``private-members`` and ``undoc-members`` options.
``private-members``, ``undoc-members`` and ``inner`` options.

``content-only``
If this flag is specified, then the directive does not output the name of the
Expand Down Expand Up @@ -42,6 +42,11 @@ If you would like to always specify some combination of ``members``,
use the :ref:`breathe_default_members <breathe-default-members>` configuration
variable to set it in the ``conf.py``.

``inner``
If specified, the groups that were defined inside this group, by either
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

.. contents::
Expand Down Expand Up @@ -190,6 +195,27 @@ Produces this output:
issue. Please post an issue on github if you would like this resolved.


Inner Example
-------------

.. cpp:namespace:: @ex_group_inner

The ``inner`` option changes the output to include groups that are defined
inside other groups.

.. code-block:: rst
.. doxygengroup:: mygroup
:project: group
:inner:
Produces this output:

.. doxygengroup:: mygroup
:project: group
:inner:


Outline Example
---------------

Expand Down
22 changes: 22 additions & 0 deletions examples/specific/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,28 @@ void groupedFunction();

/** @} */ // end of mygroup

/** @defgroup innergroup Inner Group
* @ingroup mygroup
* This is an inner group
* @{
*/

//! \brief inner class inside of namespace
class InnerGroupClassTest {

public:
//! \brief inner namespaced class function
void function() {};

private:

//! A private function
void innerGroupPrivateFunction() {};

class PrivateClass {};
};

/** @} */ // end of innergroup

//! \brief second class inside of namespace
class UngroupedClassTest {
Expand Down
82 changes: 68 additions & 14 deletions tests/test_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import sphinx.addnodes
import sphinx.environment
from breathe.parser.compound import linkedTextTypeSub, memberdefTypeSub, paramTypeSub, MixedContainer
from breathe.parser.compound import (
compounddefTypeSub, linkedTextTypeSub, memberdefTypeSub, paramTypeSub,
refTypeSub, MixedContainer
)
from breathe.renderer.sphinxrenderer import SphinxRenderer
from breathe.renderer.filter import OpenFilter
from docutils import frontend, nodes, parsers, utils
Expand Down Expand Up @@ -44,9 +47,9 @@ class WrappedDoxygenNode:
A base class for test wrappers of Doxygen nodes. It allows setting all attributes via keyword arguments
in the constructor.
"""
def __init__(self, cls, **kwargs):
def __init__(self, cls, *args, **kwargs):
if cls:
cls.__init__(self)
cls.__init__(self, args)
for name, value in kwargs.items():
if not hasattr(self, name):
raise AttributeError('invalid attribute ' + name)
Expand Down Expand Up @@ -78,6 +81,18 @@ def __init__(self, **kwargs):
WrappedDoxygenNode.__init__(self, paramTypeSub, **kwargs)


class WrappedRef(refTypeSub, WrappedDoxygenNode):
"""A test wrapper of Doxygen ref."""
def __init__(self, node_name, **kwargs):
WrappedDoxygenNode.__init__(self, refTypeSub, node_name, **kwargs)


class WrappedCompoundDef(compounddefTypeSub, WrappedDoxygenNode):
"""A test wrapper of Doxygen compound definition."""
def __init__(self, **kwargs):
WrappedDoxygenNode.__init__(self, compounddefTypeSub, **kwargs)


class MockState:
def __init__(self, app):
env = sphinx.environment.BuildEnvironment(app)
Expand Down Expand Up @@ -120,17 +135,17 @@ def mask(self, node):


class MockContext:
def __init__(self, app, node_stack, domain=None):
def __init__(self, app, node_stack, domain=None, options=[]):
self.domain = domain
self.node_stack = node_stack
self.directive_args = [
None, # name
None, # arguments
[], # options
None, # content
None, # lineno
None, # content_offset
None, # block_text
None, # name
None, # arguments
options, # options
None, # content
None, # lineno
None, # content_offset
None, # block_text
MockState(app), MockStateMachine()]
self.child = None
self.mask_factory = MockMaskFactory()
Expand All @@ -152,6 +167,23 @@ def __init__(self):
self.reporter = MockReporter()


class MockCompoundParser:
"""
A compound parser reads a doxygen XML file from disk; this mock implements
a mapping of what would be the file name on disk to data using a dict.
"""
def __init__(self, compound_dict):
self.compound_dict = compound_dict

class MockFileData:
def __init__(self, compounddef):
self.compounddef = compounddef

def parse(self, compoundname):
compounddef = self.compound_dict[compoundname]
return self.MockFileData(compounddef)


class NodeFinder(nodes.NodeVisitor):
"""Find node with specified class name."""
def __init__(self, name, document):
Expand Down Expand Up @@ -224,7 +256,8 @@ def test_find_node():
'the number of nodes Text is 2')


def render(app, member_def, domain=None, show_define_initializer=False):
def render(app, member_def, domain=None, show_define_initializer=False,
compound_parser=None, options=[]):
"""Render Doxygen *member_def* with *renderer_class*."""

app.config.breathe_use_project_refids = False
Expand All @@ -238,9 +271,9 @@ def render(app, member_def, domain=None, show_define_initializer=False):
None, # state
None, # document
MockTargetHandler(),
None, # compound_parser
compound_parser,
OpenFilter())
renderer.context = MockContext(app, [member_def], domain)
renderer.context = MockContext(app, [member_def], domain, options)
return renderer.render(member_def)


Expand Down Expand Up @@ -346,3 +379,24 @@ def test_render_define_no_initializer(app):
member_def = WrappedMemberDef(kind='define', name='USE_MILK')
signature = find_node(render(app, member_def), 'desc_signature')
assert signature.astext() == 'USE_MILK'


def test_render_innergroup(app):
refid = 'group__innergroup'
mock_compound_parser = MockCompoundParser({
refid: WrappedCompoundDef(kind='group',
compoundname='InnerGroup',
briefdescription='InnerGroup')
})
ref = WrappedRef('InnerGroup', refid=refid)
compound_def = WrappedCompoundDef(kind='group',
compoundname='OuterGroup',
briefdescription='OuterGroup',
innergroup=[ref])
assert all(el.astext() != 'InnerGroup'
for el in render(app, compound_def,
compound_parser=mock_compound_parser))
assert any(el.astext() == 'InnerGroup'
for el in render(app, compound_def,
compound_parser=mock_compound_parser,
options=['inner']))

0 comments on commit 762ee42

Please sign in to comment.