Hello community, here is the log from the commit of package python-breathe for openSUSE:Factory checked in at 2020-10-29 09:48:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-breathe (Old) and /work/SRC/openSUSE:Factory/.python-breathe.new.3463 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-breathe" Thu Oct 29 09:48:01 2020 rev:10 rq:841649 version:4.22.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-breathe/python-breathe.changes 2020-06-28 23:05:53.862773261 +0200 +++ /work/SRC/openSUSE:Factory/.python-breathe.new.3463/python-breathe.changes 2020-10-29 09:48:03.076154173 +0100 @@ -1,0 +2,21 @@ +Wed Oct 14 01:38:22 UTC 2020 - Steve Kowalik <steven.kowa...@suse.com> + +- Update to 4.22.1: + * Fix anonymous struct/union usage in C domain. #585 + * New boolean breathe_show_enumvalue_initializer option specifying whether + value of enumvalue should be displayed. #581 + * Fix Read the Docs build. #567 + * Document doxygenclass template specialisation spacing. #570 + * Update upper Sphinx release to <3.4. #571 + * Reuse breathe.__version__ in setup.py. #572 + * Document :inner: for the doxygengroup section. #573 + * Add support for verbatim inline elements. #560 + * Fix wrong refid when Doxygen SEPARATE_MEMBER_PAGES is YES. #566 + * Allow Sphinx 3.2. #561 + * Update CI scripts with new Sphinx versions. #552 + * Add support for C# using sphinx-csharp. #550 + * Doc, fix typo, :source: -> :project:. #551 + * Add support for innergroup. #556 + * Avoid duplicate doxygen targets when debug tracing. #563 + +------------------------------------------------------------------- Old: ---- v4.19.2.tar.gz New: ---- v4.22.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-breathe.spec ++++++ --- /var/tmp/diff_new_pack.p3L8tN/_old 2020-10-29 09:48:03.712154774 +0100 +++ /var/tmp/diff_new_pack.p3L8tN/_new 2020-10-29 09:48:03.716154778 +0100 @@ -18,11 +18,10 @@ %define skip_python2 1 Name: python-breathe -Version: 4.19.2 +Version: 4.22.1 Release: 0 Summary: Sphinx Doxygen renderer License: BSD-3-Clause -Group: Development/Languages/Python URL: https://github.com/michaeljones/breathe Source: https://github.com/michaeljones/breathe/archive/v%{version}.tar.gz BuildRequires: %{python_module Sphinx >= 3.0.4} ++++++ v4.19.2.tar.gz -> v4.22.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/.github/workflows/unit_tests.yml new/breathe-4.22.1/.github/workflows/unit_tests.yml --- old/breathe-4.19.2/.github/workflows/unit_tests.yml 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/.github/workflows/unit_tests.yml 2020-09-26 21:27:40.000000000 +0200 @@ -8,9 +8,10 @@ matrix: python-version: [3.5, 3.6, 3.7, 3.8] sphinx-version: - - 3.0.0 - - 3.1.0 - - git+https://github.com/sphinx-doc/sphinx.git@3.1.x + - 3.0.4 + - 3.1.2 + - 3.2.0 + - git+https://github.com/sphinx-doc/sphinx.git@3.2.x - git+https://github.com/sphinx-doc/sphinx.git@3.x # master (Sphinx 4) will require at least Python 3.6, so disable it for now #- git+https://github.com/sphinx-doc/sphinx.git@master diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/.readthedocs.yaml new/breathe-4.22.1/.readthedocs.yaml --- old/breathe-4.19.2/.readthedocs.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/breathe-4.22.1/.readthedocs.yaml 2020-09-26 21:27:40.000000000 +0200 @@ -0,0 +1,13 @@ +version: 2 + +python: + version: 3 + install: + - requirements: requirements/development.txt + - method: pip + path: . + +sphinx: + builder: html + configuration: documentation/source/conf.py + fail_on_warning: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/.travis.yml new/breathe-4.22.1/.travis.yml --- old/breathe-4.19.2/.travis.yml 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/.travis.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,27 +0,0 @@ -language: python - -env: - - SPHINX_VERSION=3.0 TRAVIS_CI=True - -python: - - "3.5" - - "3.6" - -before_install: - - sudo apt-get update -qq - - sudo apt-get install -y doxygen texlive-latex-base texlive-latex-extra texlive-fonts-recommended latexmk - -install: - - pip install flake8 - - pip install pytest - - pip install Sphinx==$SPHINX_VERSION - - pip install . - -# Builds all examples & html documentation -# -# Provide definition for DOXYGEN variable to stop it trying -# to run `which doxygen` -script: - - make DOXYGEN=doxygen DEBUG="" - - make test - - make flake8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/README.rst new/breathe-4.22.1/README.rst --- old/breathe-4.19.2/README.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/README.rst 2020-09-26 21:27:40.000000000 +0200 @@ -2,9 +2,6 @@ Breathe ======= -.. image:: https://travis-ci.org/michaeljones/breathe.svg?branch=master - :target: https://travis-ci.org/michaeljones/breathe - .. image:: https://github.com/michaeljones/breathe/workflows/unit%20tests/badge.svg :target: https://github.com/michaeljones/breathe/actions?query=workflow%3A%22unit+tests%22 @@ -173,6 +170,36 @@ Inspired by `Keepachangelog.com <http://keepachangelog.com/>`__. +- 2020-09-26 - Breathe v4.22.1 + + - Fix anonymous struct/union usage in C domain. #585 + +- 2020-09-19 - Breathe v4.22.0 + + - Fix Read the Docs build (again). #576 + - New boolean `breathe_show_enumvalue_initializer` option specifying + whether value of enumvalue should be displayed. #581 + +- 2020-09-10 - Breathe v4.21.0 + + - Fix Read the Docs build. #567 + - Document doxygenclass template specialisation spacing. #570 + - Update upper Sphinx release to <3.4. #571 + - Reuse breathe.__version__ in setup.py. #572 + - Document :inner: for the doxygengroup section. #573 + - Add support for verbatim inline elements. #560 + - Fix wrong refid when Doxygen SEPARATE_MEMBER_PAGES is YES. #566 + +- 2020-08-19 - Breathe v4.20.0 + + - Allow Sphinx 3.2. #561 + - Update CI scripts with new Sphinx versions. #552 + - Add support for C# using sphinx-csharp. #550 + - Doc, fix typo, :source: -> :project:. #551 + - Add support for innergroup. #556 + - Avoid duplicate doxygen targets when debug tracing. #563 + - Remove Travis badge from README file. #564 + - 2020-06-17 - Breathe v4.19.2 - Fix crash when visiting typedef. #547 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/breathe/__init__.py new/breathe-4.22.1/breathe/__init__.py --- old/breathe-4.19.2/breathe/__init__.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/breathe/__init__.py 2020-09-26 21:27:40.000000000 +0200 @@ -4,7 +4,7 @@ from sphinx.application import Sphinx -__version__ = '4.19.2' +__version__ = '4.22.1' def setup(app: Sphinx): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/breathe/directives.py new/breathe-4.22.1/breathe/directives.py --- old/breathe-4.19.2/breathe/directives.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/breathe/directives.py 2020-09-26 21:27:40.000000000 +0200 @@ -406,6 +406,10 @@ class DoxygenGroupDirective(_DoxygenContentBlockDirective): kind = "group" + option_spec = { + **_DoxygenContentBlockDirective.option_spec, + "inner": flag, + } # TODO: is this comment still relevant? @@ -575,16 +579,19 @@ app.add_config_value("breathe_projects", {}, True) # Dict[str, str] app.add_config_value("breathe_default_project", "", True) # str # Provide reasonable defaults for domain_by_extension mapping. Can be overridden by users. - app.add_config_value("breathe_domain_by_extension", {'py': 'py'}, True) # Dict[str, str] + app.add_config_value("breathe_domain_by_extension", + {'py': 'py', 'cs': 'cs'}, True) # Dict[str, str] app.add_config_value("breathe_domain_by_file_pattern", {}, True) # Dict[str, str] app.add_config_value("breathe_projects_source", {}, True) app.add_config_value("breathe_build_directory", '', True) app.add_config_value("breathe_default_members", (), True) app.add_config_value("breathe_show_define_initializer", False, 'env') + app.add_config_value("breathe_show_enumvalue_initializer", False, 'env') app.add_config_value("breathe_implementation_filename_extensions", ['.c', '.cc', '.cpp'], True) app.add_config_value("breathe_doxygen_config_options", {}, True) app.add_config_value("breathe_use_project_refids", False, "env") app.add_config_value("breathe_order_parameters_first", False, 'env') + app.add_config_value("breathe_separate_member_pages", False, 'env') breathe_css = "breathe.css" if (os.path.exists(os.path.join(app.confdir, "_static", breathe_css))): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/breathe/process.py new/breathe-4.22.1/breathe/process.py --- old/breathe-4.19.2/breathe/process.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/breathe/process.py 2020-09-26 21:27:40.000000000 +0200 @@ -26,6 +26,7 @@ GENERATE_XML = YES ALIASES = "rst=\verbatim embed:rst" ALIASES += "endrst=\endverbatim" +ALIASES += "inlinerst=\verbatim embed:rst:inline" {extra} """.strip() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/breathe/renderer/sphinxrenderer.py new/breathe-4.22.1/breathe/renderer/sphinxrenderer.py --- old/breathe-4.19.2/breathe/renderer/sphinxrenderer.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/breathe/renderer/sphinxrenderer.py 2020-09-26 21:27:40.000000000 +0200 @@ -12,13 +12,19 @@ from docutils import nodes from docutils.nodes import Element, Node, TextElement # noqa -from docutils.statemachine import StringList +from docutils.statemachine import StringList, UnexpectedIndentationError +from docutils.parsers.rst.states import Text try: from sphinxcontrib import phpdomain as php # type: ignore except ImportError: php = None +try: + from sphinx_csharp import csharp as cs # type: ignore +except ImportError: + cs = None + import re import six import textwrap @@ -142,6 +148,55 @@ # ---------------------------------------------------------------------------- +if cs is not None: + class CSharpCurrentNamespace(BaseObject, cs.CSharpCurrentNamespace): + pass + + class CSharpNamespacePlain(BaseObject, cs.CSharpNamespacePlain): + pass + + class CSharpClass(BaseObject, cs.CSharpClass): + pass + + class CSharpStruct(BaseObject, cs.CSharpStruct): + pass + + class CSharpInterface(BaseObject, cs.CSharpInterface): + pass + + class CSharpInherits(BaseObject, cs.CSharpInherits): + pass + + class CSharpMethod(BaseObject, cs.CSharpMethod): + pass + + class CSharpVariable(BaseObject, cs.CSharpVariable): + pass + + class CSharpProperty(BaseObject, cs.CSharpProperty): + pass + + class CSharpEvent(BaseObject, cs.CSharpEvent): + pass + + class CSharpEnum(BaseObject, cs.CSharpEnum): + pass + + class CSharpEnumValue(BaseObject, cs.CSharpEnumValue): + pass + + class CSharpAttribute(BaseObject, cs.CSharpAttribute): + pass + + class CSharpIndexer(BaseObject, cs.CSharpIndexer): + pass + + class CSharpXRefRole(BaseObject, cs.CSharpXRefRole): + pass + + +# ---------------------------------------------------------------------------- + class DomainDirectiveFactory: # A mapping from node kinds to domain directives and their names. cpp_classes = { @@ -191,6 +246,30 @@ 'global': (php.PhpGloballevel, 'global'), } + if cs is not None: + cs_classes = { + # 'doxygen-name': (CSharp class, key in CSharpDomain.object_types) + 'namespace': (CSharpNamespacePlain, 'namespace'), + + 'class': (CSharpClass, 'class'), + 'struct': (CSharpStruct, 'struct'), + 'interface': (CSharpInterface, 'interface'), + + 'function': (CSharpMethod, 'function'), + 'method': (CSharpMethod, 'method'), + + 'variable': (CSharpVariable, 'var'), + 'property': (CSharpProperty, 'property'), + 'event': (CSharpEvent, 'event'), + + 'enum': (CSharpEnum, 'enum'), + 'enumvalue': (CSharpEnumValue, 'enumerator'), + 'attribute': (CSharpAttribute, 'attr'), + + # Fallback to cpp domain + 'typedef': (CPPTypeObject, 'type'), + } + @staticmethod def create(domain: str, args) -> ObjectDescription: cls = cast(Type[ObjectDescription], None) @@ -214,6 +293,8 @@ arg_0 = 'global' cls, name = DomainDirectiveFactory.php_classes.get( arg_0, (php.PhpClasslike, 'class')) + elif cs is not None and domain == 'cs': + cls, name = DomainDirectiveFactory.cs_classes[args[0]] # type: ignore else: domain = 'cpp' cls, name = DomainDirectiveFactory.cpp_classes[args[0]] # type: ignore @@ -316,6 +397,49 @@ return definition +class InlineText(Text): + """ + Add a custom docutils class to allow parsing inline text. This is to be + used inside a @verbatim/@endverbatim block but only the first line is + consumed and a inline element is generated as the parent, instead of the + paragraph used by Text. + """ + patterns = {'inlinetext': r''} + initial_transitions = [('inlinetext', )] + + def indent(self, match, context, next_state): + """ + Avoid Text's indent from detecting space prefixed text and + doing "funny" stuff; always rely on inlinetext for parsing. + """ + return self.inlinetext(match, context, next_state) + + def eof(self, context): + """ + Text.eof() inserts a paragraph, so override it to skip adding elements. + """ + return [] + + def inlinetext(self, match, context, next_state): + """ + Called by the StateMachine when an inline element is found (which is + any text when this class is added as the single transition. + """ + startline = self.state_machine.abs_line_number() - 1 + msg = None + try: + block = self.state_machine.get_text_block() + except UnexpectedIndentationError as err: + block, src, srcline = err.args + msg = self.reporter.error('Unexpected indentation.', + source=src, line=srcline) + lines = context + list(block) + text, _ = self.inline_text(lines[0], startline) + self.parent += text + self.parent += msg + return [], next_state, [] + + class SphinxRenderer: """ Doxygen node visitor that converts input into Sphinx/RST representation. @@ -351,7 +475,44 @@ if self.context.domain == '': self.context.domain = self.get_domain() + # XXX: fix broken links in XML generated by Doxygen when Doxygen's + # SEPARATE_MEMBER_PAGES is set to YES; this function should be harmless + # when SEPARATE_MEMBER_PAGES is NO! + # + # The issue was discussed here: https://github.com/doxygen/doxygen/pull/7971 + # + # A Doxygen anchor consists of a 32-byte string version of the results of + # passing in the stringified identifier or prototype that is being "hashed". + # An "a" character is then prefixed to mark it as an anchor. Depending on how + # the identifier is linked, it can also get a "g" prefix to mean it is part + # of a Doxygen group. This results in an id having either 33 or 34 bytes + # (containing a "g" or not). Some identifiers, eg enumerators, get twice that + # length to have both a unique enum + unique enumerator, and sometimes they + # get two "g" characters as prefix instead of one. + def _fixup_separate_member_pages(self, refid: str) -> str: + if refid: + parts = refid.rsplit("_", 1) + if len(parts) == 2 and parts[1].startswith("1"): + anchorid = parts[1][1:] + if len(anchorid) in set([33, 34]) and parts[0].endswith(anchorid): + return parts[0][:-len(anchorid)] + parts[1] + elif len(anchorid) > 34: + index = 0 + if anchorid.startswith('gg'): + index = 1 + _len = 35 + elif anchorid.startswith('g'): + _len = 34 + else: + _len = 33 + if parts[0].endswith(anchorid[index:_len]): + return parts[0][:-(_len - index)] + parts[1] + + return refid + def get_refid(self, refid: str) -> str: + if self.app.config.breathe_separate_member_pages: # type: ignore + refid = self._fixup_separate_member_pages(refid) if self.app.config.breathe_use_project_refids: # type: ignore return "%s%s" % (self.project_info.name(), refid) else: @@ -446,11 +607,12 @@ declaration = declaration.replace('\n', ' ') nodes_ = self.run_directive(obj_type, declaration, content_callback, options) if self.app.env.config.breathe_debug_trace_doxygen_ids: - ts = self.create_doxygen_target(node) - if len(ts) == 0: + target = self.create_doxygen_target(node) + if len(target) == 0: print("{}Doxygen target: (none)".format(' ' * _debug_indent)) else: - print("{}Doxygen target: {}".format(' ' * _debug_indent, ts[0]['ids'])) + print("{}Doxygen target: {}".format(' ' * _debug_indent, + target[0]['ids'])) # <desc><desc_signature> and then one or more <desc_signature_line> # each <desc_signature_line> has a sphinx_line_type which hints what is present in that line @@ -477,7 +639,8 @@ assert n.astext()[-1] == " " txt = display_obj_type + ' ' declarator[0] = addnodes.desc_annotation(txt, txt) - target = self.create_doxygen_target(node) + if not self.app.env.config.breathe_debug_trace_doxygen_ids: + target = self.create_doxygen_target(node) declarator.insert(0, target) if declarator_callback: declarator_callback(declarator) @@ -644,11 +807,11 @@ obj_type = node.kind nodes = self.run_domain_directive(obj_type, [declaration.replace('\n', ' ')]) if self.app.env.config.breathe_debug_trace_doxygen_ids: - ts = self.create_doxygen_target(node) - if len(ts) == 0: + target = self.create_doxygen_target(node) + if len(target) == 0: print("{}Doxygen target (old): (none)".format(' ' * _debug_indent)) else: - print("{}Doxygen target (old): {}".format(' ' * _debug_indent, ts[0]['ids'])) + print("{}Doxygen target (old): {}".format(' ' * _debug_indent, target[0]['ids'])) rst_node = nodes[1] finder = NodeFinder(rst_node.document) @@ -662,7 +825,9 @@ update_signature(signode, obj_type) if description is None: description = self.description(node) - signode.insert(0, self.create_doxygen_target(node)) + if not self.app.env.config.breathe_debug_trace_doxygen_ids: + target = self.create_doxygen_target(node) + signode.insert(0, target) contentnode.extend(description) return nodes @@ -827,11 +992,11 @@ return self.visit_union(node) elif kind in ('struct', 'class', 'interface'): dom = self.get_domain() - if not dom or dom in ('c', 'cpp', 'py'): + if not dom or dom in ('c', 'cpp', 'py', 'cs'): return self.visit_class(node) elif kind == 'namespace': dom = self.get_domain() - if not dom or dom in ('c', 'cpp', 'py'): + if not dom or dom in ('c', 'cpp', 'py', 'cs'): return self.visit_namespace(node) self.context = cast(RenderContext, self.context) @@ -924,7 +1089,7 @@ # having two lists in case they fall out of sync # # If this list is edited, also change the sections option documentation for - # the doxygen(auto)file directive in documentation/source/autofile.rst. + # the doxygen(auto)file directive in documentation/source/file.rst. sections = [ ("user-defined", "User Defined"), ("public-type", "Public Types"), @@ -933,8 +1098,8 @@ ("public-slot", "Public Slots"), ("signal", "Signals"), ("dcop-func", "DCOP Function"), - ("property", "Property"), - ("event", "Event"), + ("property", "Properties"), + ("event", "Events"), ("public-static-func", "Public Static Functions"), ("public-static-attrib", "Public Static Attributes"), ("protected-type", "Protected Types"), @@ -1024,6 +1189,12 @@ 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_ @@ -1217,6 +1388,25 @@ def visit_highlight(self, node) -> List[Node]: return self.render_iterable(node.content_) + def _nested_inline_parse_with_titles(self, content, node) -> str: + """ + This code is basically a customized nested_parse_with_titles from + docutils, using the InlineText class on the statemachine. + """ + surrounding_title_styles = self.state.memo.title_styles + surrounding_section_level = self.state.memo.section_level + self.state.memo.title_styles = [] + self.state.memo.section_level = 0 + try: + return self.state.nested_parse(content, 0, node, match_titles=1, + state_machine_kwargs={ + 'state_classes': (InlineText,), + 'initial_state': 'InlineText' + }) + finally: + self.state.memo.title_styles = surrounding_title_styles + self.state.memo.section_level = surrounding_section_level + def visit_verbatim(self, node) -> List[Node]: if not node.text.strip().startswith("embed:rst"): # Remove trailing new lines. Purely subjective call from viewing results @@ -1225,6 +1415,8 @@ # Handle has a preformatted text return [nodes.literal_block(text, text)] + is_inline = False + # do we need to strip leading asterisks? # NOTE: We could choose to guess this based on every line starting with '*'. # However This would have a side-effect for any users who have an rst-block @@ -1243,11 +1435,19 @@ lines = map(lambda text: text.replace("///", " ", 1), lines) node.text = "\n".join(lines) - # Remove the first line which is "embed:rst[:leading-asterisk]" - text = "\n".join(node.text.split(u"\n")[1:]) + elif node.text.strip().startswith("embed:rst:inline"): + # Inline all text inside the verbatim + node.text = "".join(node.text.splitlines()) + is_inline = True + + if is_inline: + text = node.text.replace("embed:rst:inline", "", 1) + else: + # Remove the first line which is "embed:rst[:leading-asterisk]" + text = "\n".join(node.text.split(u"\n")[1:]) - # Remove starting whitespace - text = textwrap.dedent(text) + # Remove starting whitespace + text = textwrap.dedent(text) # Inspired by autodoc.py in Sphinx rst = StringList() @@ -1255,13 +1455,19 @@ rst.append(line, "<breathe>") # Parent node for the generated node subtree - rst_node = nodes.paragraph() + if is_inline: + rst_node = nodes.inline() + else: + rst_node = nodes.paragraph() rst_node.document = self.state.document # Generate node subtree - nested_parse_with_titles(self.state, rst, rst_node) - # TODO: hmm, what is supposed to be returned? something is strange with the types - return rst_node # type: ignore + if is_inline: + self._nested_inline_parse_with_titles(rst, rst_node) + else: + nested_parse_with_titles(self.state, rst, rst_node) + + return [rst_node] def visit_inc(self, node) -> List[Node]: if node.local == u"yes": @@ -1344,7 +1550,7 @@ def visit_function(self, node) -> List[Node]: dom = self.get_domain() - if not dom or dom in ('c', 'cpp', 'py'): + if not dom or dom in ('c', 'cpp', 'py', 'cs'): names = self.get_qualification() names.append(node.get_name()) name = self.join_nested_name(names) @@ -1396,11 +1602,12 @@ nodes = self.run_domain_directive(node.kind, self.context.directive_args[1]) if self.app.env.config.breathe_debug_trace_doxygen_ids: - ts = self.create_doxygen_target(node) - if len(ts) == 0: + target = self.create_doxygen_target(node) + if len(target) == 0: print("{}Doxygen target (old): (none)".format(' ' * _debug_indent)) else: - print("{}Doxygen target (old): {}".format(' ' * _debug_indent, ts[0]['ids'])) + print("{}Doxygen target (old): {}".format(' ' * _debug_indent, + target[0]['ids'])) rst_node = nodes[1] finder = NodeFinder(rst_node.document) @@ -1408,7 +1615,9 @@ # Templates have multiple signature nodes in recent versions of Sphinx. # Insert Doxygen target into the first signature node. - rst_node.children[0].insert(0, self.create_doxygen_target(node)) # type: ignore + if not self.app.env.config.breathe_debug_trace_doxygen_ids: + target = self.create_doxygen_target(node) + rst_node.children[0].insert(0, target) # type: ignore finder.content.extend(self.description(node)) return nodes @@ -1447,7 +1656,10 @@ return self.handle_declaration(node, declaration, content_callback=content) def visit_enumvalue(self, node) -> List[Node]: - declaration = node.name + self.make_initializer(node) + if self.app.config.breathe_show_enumvalue_initializer: # type: ignore + declaration = node.name + self.make_initializer(node) + else: + declaration = node.name return self.handle_declaration(node, declaration, obj_type='enumvalue') def visit_typedef(self, node) -> List[Node]: @@ -1495,14 +1707,17 @@ if len(initializer) != 0: options['value'] = initializer else: + typename = ''.join(n.astext() for n in self.render(node.get_type())) + if dom == 'c' and '::' in typename: + typename = typename.replace('::', '.') declaration = ' '.join([ self.create_template_prefix(node), - ''.join(n.astext() for n in self.render(node.get_type())), # type: ignore + typename, name, node.get_argsstring(), self.make_initializer(node) ]) - if not dom or dom in ('c', 'cpp', 'py'): + if not dom or dom in ('c', 'cpp', 'py', 'cs'): return self.handle_declaration(node, declaration, options=options) else: return self.render_declaration(node, declaration) @@ -1647,6 +1862,12 @@ return self.visit_typedef(node) if node.kind == "variable": return self.visit_variable(node) + if node.kind == "property": + # Note: visit like variable for now + return self.visit_variable(node) + if node.kind == "event": + # Note: visit like variable for now + return self.visit_variable(node) if node.kind == "define": return self.visit_define(node) if node.kind == "friend": diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/autofile.rst new/breathe-4.22.1/documentation/source/autofile.rst --- old/breathe-4.19.2/documentation/source/autofile.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/autofile.rst 2020-09-26 21:27:40.000000000 +0200 @@ -13,7 +13,7 @@ This should work:: .. autodoxygenfile:: auto_class.h - :source: auto + :project: auto With the following config value:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/class.rst new/breathe-4.22.1/documentation/source/class.rst --- old/breathe-4.19.2/documentation/source/class.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/class.rst 2020-09-26 21:27:40.000000000 +0200 @@ -89,6 +89,8 @@ .. doxygenclass:: TemplateClass :project: template_specialisation +Note the spacing inside the ``<>``, it's important: there must be a +space after the ``<`` and before the ``>``. Members Example --------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/directives.rst new/breathe-4.22.1/documentation/source/directives.rst --- old/breathe-4.19.2/documentation/source/directives.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/directives.rst 2020-09-26 21:27:40.000000000 +0200 @@ -211,6 +211,7 @@ :private-members: :undoc-members: :no-link: + :inner: Checkout the :ref:`doxygengroup documentation <group-example>` for more details and to see it in action. @@ -452,7 +453,7 @@ Then your ``autodoxygenfile`` usage can look like this:: .. autodoxygenfile:: file.c - :source: myprojectsource + :project: myprojectsource The directory entry in the tuple can be an empty string if the entries in the list are full paths. @@ -517,6 +518,13 @@ For example a define ``MAX_LENGTH 100`` would be shown with the value 100 if this is set to ``True``, and without if it is set to ``False``. +.. confval:: breathe_show_enumvalue_initializer + + A boolean flag which can be set to ``True`` to display the initializer of an enum value in the output. + + For example an enum value ``TWO = 2`` would be shown with the value 2 if this is set to ``True``, + and without if it is set to ``False``. + .. confval:: breathe_use_project_refids True or False setting to control if the refids generated by breathe for doxygen @@ -536,3 +544,11 @@ documentation should be placed immediately after the brief and detailed description or at the end, after the returns, remarks and warnings section. Default value and also the legacy behavior is False. + +.. confval:: breathe_separate_member_pages + + True or False setting to control if the input XML generated by Doxygen had the + Doxygen SEPARATE_MEMBER_PAGES option set to YES or NO. The Doxygen option defaults + to NO which generates XML that allows Breathe to resolve all references. When set + to YES the refid/id of elements get an extra element which Breathe tries to get rid + of when this setting is True. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/file.rst new/breathe-4.22.1/documentation/source/file.rst --- old/breathe-4.19.2/documentation/source/file.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/file.rst 2020-09-26 21:27:40.000000000 +0200 @@ -26,7 +26,7 @@ "derivedcompoundref", "Derived compound reference" "detaileddescription", "Detailed description" "enum", "Enumerator" - "event", "Event" + "event", "Events" "friend", "Friend" "func", "Function" "innerclass", "**Must be given to show sections inside a class**" @@ -42,7 +42,7 @@ "private-static-attrib", "Private static attribute" "private-static-func", "Private static function" "private-type", "Private type" - "property", "Property" + "property", "Properties" "protected-attrib", "Protected attribute" "protected-func", "Protected function" "protected-slot", "Protected slot" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/group.rst new/breathe-4.22.1/documentation/source/group.rst --- old/breathe-4.19.2/documentation/source/group.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/group.rst 2020-09-26 21:27:40.000000000 +0200 @@ -10,7 +10,7 @@ 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 @@ -42,6 +42,11 @@ 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:: @@ -190,6 +195,27 @@ 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 --------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/documentation/source/markups.rst new/breathe-4.22.1/documentation/source/markups.rst --- old/breathe-4.19.2/documentation/source/markups.rst 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/documentation/source/markups.rst 2020-09-26 21:27:40.000000000 +0200 @@ -127,6 +127,38 @@ ---- +Inline rST +~~~~~~~~~~ + +.. cpp:namespace:: @ex_markups_inline + +Normal verbatim elements result in block elements. But sometimes you'll want +to generate rST references where they need to be rendered inline with the text. +For example:: + + /// Some kind of method + /// + /// @param something a parameter + /// @returns the same value provided in something param + /// + /// @verbatim embed:rst:inline some inline text @endverbatim + +For these kinds of references, you can use an **embed:rst:inline** tag as +shown in the above example. + +This will appropriately handle the leading slashes and render as: + +---- + +.. doxygenfunction:: TestClass::rawInlineVerbatim + :project: rst + +.. doxygenfunction:: TestClass::rawVerbatim + :project: rst + :outline: + +---- + Aliases ~~~~~~~ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/examples/specific/group.h new/breathe-4.22.1/examples/specific/group.h --- old/breathe-4.19.2/examples/specific/group.h 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/examples/specific/group.h 2020-09-26 21:27:40.000000000 +0200 @@ -48,6 +48,28 @@ /** @} */ // 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 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/examples/specific/rst.cfg new/breathe-4.22.1/examples/specific/rst.cfg --- old/breathe-4.19.2/examples/specific/rst.cfg 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/examples/specific/rst.cfg 2020-09-26 21:27:40.000000000 +0200 @@ -12,3 +12,4 @@ ALIASES = "rst=\verbatim embed:rst" ALIASES += "endrst=\endverbatim" +ALIASES += "inlinerst=\verbatim embed:rst:inline" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/examples/specific/rst.h new/breathe-4.22.1/examples/specific/rst.h --- old/breathe-4.19.2/examples/specific/rst.h 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/examples/specific/rst.h 2020-09-26 21:27:40.000000000 +0200 @@ -12,7 +12,7 @@ This is some funky non-XML compliant text: <& !>< .. note:: - + This reStructuredText has been handled correctly. \endrst @@ -67,6 +67,12 @@ ////////////////////////////////////////////////////////////// virtual void rawLeadingSlashesVerbatim(int something) const = 0; + /*! + Inserting an inline reStructuredText snippet. + Linking to another function: \inlinerst :cpp:func:`TestClass::rawVerbatim` \endrst + */ + virtual void rawInlineVerbatim() const = 0; + //! Brief description virtual void testFunction() const {}; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/requirements/production.txt new/breathe-4.22.1/requirements/production.txt --- old/breathe-4.19.2/requirements/production.txt 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/requirements/production.txt 2020-09-26 21:27:40.000000000 +0200 @@ -2,5 +2,5 @@ Jinja2>=2.7.3 MarkupSafe>=0.23 Pygments>=1.6 -Sphinx>=3.0,<3.2 +Sphinx>=3.0,<3.4 six>=1.9.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/setup.py new/breathe-4.22.1/setup.py --- old/breathe-4.19.2/setup.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/setup.py 2020-09-26 21:27:40.000000000 +0200 @@ -7,15 +7,14 @@ from setuptools import setup, find_packages import sys - -import breathe +from breathe import __version__ long_desc = ''' Breathe is an extension to reStructuredText and Sphinx to be able to read and render `Doxygen <http://www.doxygen.org>`__ xml output. ''' -requires = ['Sphinx>=3.0,<3.2', 'docutils>=0.12', 'six>=1.9'] +requires = ['Sphinx>=3.0,<3.4', 'docutils>=0.12', 'six>=1.9'] if sys.version_info < (3, 5): print('ERROR: Sphinx requires at least Python 3.5 to run.') @@ -24,7 +23,7 @@ setup( name='breathe', - version=breathe.__version__, + version=__version__, url='https://github.com/michaeljones/breathe', download_url='https://github.com/michaeljones/breathe', license='BSD', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/breathe-4.19.2/tests/test_renderer.py new/breathe-4.22.1/tests/test_renderer.py --- old/breathe-4.19.2/tests/test_renderer.py 2020-06-17 22:03:59.000000000 +0200 +++ new/breathe-4.22.1/tests/test_renderer.py 2020-09-26 21:27:40.000000000 +0200 @@ -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 @@ -44,9 +47,9 @@ 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) @@ -78,6 +81,18 @@ 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) @@ -120,17 +135,17 @@ 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() @@ -152,6 +167,23 @@ 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): @@ -224,9 +256,11 @@ '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_separate_member_pages = False app.config.breathe_use_project_refids = False app.config.breathe_show_define_initializer = show_define_initializer app.config.breathe_debug_trace_directives = False @@ -238,9 +272,9 @@ 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) @@ -346,3 +380,24 @@ 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']))