From 3e42e0603c0c3ee9298e8e5fe990d9e3b693b45c Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Mon, 8 Nov 2021 14:14:05 -0800 Subject: [PATCH 01/18] grab lang from \code cmd filename attr --- breathe/parser/compoundsuper.py | 14 ++++++++++---- breathe/renderer/sphinxrenderer.py | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index 58069f82..248c3712 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -3,6 +3,7 @@ # import sys +import os import getopt from xml.dom import minidom from xml.dom import Node @@ -2398,7 +2399,8 @@ def buildChildren(self, child_, nodeName_): class listingType(GeneratedsSuper): subclass = None superclass = None - def __init__(self, codeline=None): + def __init__(self, codeline=None, domain: str=None): + self.domain = domain if codeline is None: self.codeline = [] else: @@ -2436,14 +2438,18 @@ def hasContent_(self): return True else: return False - def build(self, node_): + def build(self, node_: minidom.Element): attrs = node_.attributes self.buildAttributes(attrs) for child_ in node_.childNodes: nodeName_ = child_.nodeName.split(':')[-1] self.buildChildren(child_, nodeName_) - def buildAttributes(self, attrs): - pass + def buildAttributes(self, attrs: minidom.NamedNodeMap): + if "filename" in attrs.keys(): + # extract the domain for this programlisting tag. + ext_tuple = os.path.splitext(attrs["filename"].value) + self.domain = ext_tuple[0 if not ext_tuple[1] else 1].lstrip(".") + # print("found domain as", self.domain) def buildChildren(self, child_, nodeName_): if child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'codeline': diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index a7223daa..108e34b7 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1599,10 +1599,13 @@ def visit_listing(self, node) -> List[Node]: if i: nodelist.append(nodes.Text("\n")) nodelist.extend(self.render(item)) - + code = "".join([x.astext() for x in nodelist]) # Add blank string at the start otherwise for some reason it renders # the pending_xref tags around the kind in plain text - block = nodes.literal_block("", "", *nodelist) + block = nodes.literal_block(code, code) + if node.domain: + print("indicated as", node.domain) + block["language"] = node.domain return [block] def visit_codeline(self, node) -> List[Node]: From f5dc7b9b2a22ebfb8f0f52df44847d6a23b0c178 Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 9 Nov 2021 03:26:52 -0800 Subject: [PATCH 02/18] pass known language names to code-blocks --- breathe/parser/compound.py | 8 ++++---- breathe/parser/compoundsuper.py | 7 +++++-- breathe/renderer/sphinxrenderer.py | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/breathe/parser/compound.py b/breathe/parser/compound.py index 9d56b7ff..a2908c5e 100644 --- a/breathe/parser/compound.py +++ b/breathe/parser/compound.py @@ -33,7 +33,7 @@ def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, - programlisting=None, location=None, listofallmembers=None): + programlisting=None, location=None, listofallmembers=None, language=None): supermod.compounddefType.__init__(self, kind, prot, id, compoundname, title, basecompoundref, derivedcompoundref, includes, includedby, @@ -41,7 +41,7 @@ def __init__(self, kind=None, prot=None, id=None, compoundname='', title='', innerclass, innernamespace, innerpage, innergroup, templateparamlist, sectiondef, briefdescription, detaileddescription, inheritancegraph, collaborationgraph, - programlisting, location, listofallmembers) + programlisting, location, listofallmembers, language) supermod.compounddefType.subclass = compounddefTypeSub @@ -378,8 +378,8 @@ class listingTypeSub(supermod.listingType): node_type = "listing" - def __init__(self, codeline=None): - supermod.listingType.__init__(self, codeline) + def __init__(self, codeline=None, domain=None): + supermod.listingType.__init__(self, codeline, domain) supermod.listingType.subclass = listingTypeSub diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index 248c3712..18abfb8c 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -194,10 +194,11 @@ def buildChildren(self, child_, nodeName_): class compounddefType(GeneratedsSuper): subclass = None superclass = None - def __init__(self, kind=None, prot=None, id=None, compoundname=None, title=None, basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None): + def __init__(self, kind=None, prot=None, id=None, compoundname=None, title=None, basecompoundref=None, derivedcompoundref=None, includes=None, includedby=None, incdepgraph=None, invincdepgraph=None, innerdir=None, innerfile=None, innerclass=None, innernamespace=None, innerpage=None, innergroup=None, templateparamlist=None, sectiondef=None, briefdescription=None, detaileddescription=None, inheritancegraph=None, collaborationgraph=None, programlisting=None, location=None, listofallmembers=None, language=None): self.kind = kind self.prot = prot self.id = id + self.language = language self.compoundname = compoundname self.title = title if basecompoundref is None: @@ -377,6 +378,8 @@ def buildAttributes(self, attrs): self.prot = attrs.get('prot').value if attrs.get('id'): self.id = attrs.get('id').value + if attrs.get('language'): + self.language = attrs.get('language').value.lower() def buildChildren(self, child_, nodeName_): if child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'compoundname': @@ -483,7 +486,7 @@ def buildChildren(self, child_, nodeName_): self.set_collaborationgraph(obj_) elif child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'programlisting': - obj_ = listingType.factory() + obj_ = listingType.factory(domain=self.language) obj_.build(child_) self.set_programlisting(obj_) elif child_.nodeType == Node.ELEMENT_NODE and \ diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 108e34b7..34aad730 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1604,7 +1604,6 @@ def visit_listing(self, node) -> List[Node]: # the pending_xref tags around the kind in plain text block = nodes.literal_block(code, code) if node.domain: - print("indicated as", node.domain) block["language"] = node.domain return [block] From a7ccb27d3a1a53856a3168efab9f9dd3ca8e3c4c Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 9 Nov 2021 03:44:41 -0800 Subject: [PATCH 03/18] remove debugging print() --- breathe/parser/compoundsuper.py | 1 - 1 file changed, 1 deletion(-) diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index 18abfb8c..45f509ac 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -2452,7 +2452,6 @@ def buildAttributes(self, attrs: minidom.NamedNodeMap): # extract the domain for this programlisting tag. ext_tuple = os.path.splitext(attrs["filename"].value) self.domain = ext_tuple[0 if not ext_tuple[1] else 1].lstrip(".") - # print("found domain as", self.domain) def buildChildren(self, child_, nodeName_): if child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'codeline': From 838eb8be577a79a86df193697ea1d8ece97f79ec Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 9 Nov 2021 03:52:46 -0800 Subject: [PATCH 04/18] remove outdated comments --- breathe/renderer/sphinxrenderer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 34aad730..e47006b1 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1595,13 +1595,12 @@ def visit_docformula(self, node) -> List[Node]: def visit_listing(self, node) -> List[Node]: nodelist = [] # type: List[Node] for i, item in enumerate(node.codeline): - # Put new lines between the lines. There must be a more pythonic way of doing this + # Put new lines between the lines if i: nodelist.append(nodes.Text("\n")) nodelist.extend(self.render(item)) + code = "".join([x.astext() for x in nodelist]) - # Add blank string at the start otherwise for some reason it renders - # the pending_xref tags around the kind in plain text block = nodes.literal_block(code, code) if node.domain: block["language"] = node.domain From cbc20588c57aa793eaccc879da2ba217f0db36eb Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 9 Nov 2021 05:04:21 -0800 Subject: [PATCH 05/18] revert stringifying code-block contents --- breathe/renderer/sphinxrenderer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index e47006b1..fb9d7af6 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -1600,8 +1600,9 @@ def visit_listing(self, node) -> List[Node]: nodelist.append(nodes.Text("\n")) nodelist.extend(self.render(item)) - code = "".join([x.astext() for x in nodelist]) - block = nodes.literal_block(code, code) + # Add blank string at the start otherwise for some reason it renders + # the pending_xref tags around the kind in plain text + block = nodes.literal_block("", "", *nodelist) if node.domain: block["language"] = node.domain return [block] From 14b17a5da0ddbf964bda6c35c51c434de9785e81 Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Thu, 11 Nov 2021 07:34:59 -0800 Subject: [PATCH 06/18] use pygments to guess lexer from full filename --- .github/workflows/unit_tests.yml | 2 +- breathe/parser/compoundsuper.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 386d34e3..978e0ed8 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -16,7 +16,7 @@ jobs: - 3.5.4 - 4.0.3 - 4.1.2 - - git+https://github.com/sphinx-doc/sphinx.git@4.2.x + - git+https://github.com/sphinx-doc/sphinx.git@4.3.x - git+https://github.com/sphinx-doc/sphinx.git@4.x - git+https://github.com/sphinx-doc/sphinx.git@master diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index 45f509ac..b5b3acdc 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -7,6 +7,7 @@ import getopt from xml.dom import minidom from xml.dom import Node +import pygments # # User methods @@ -2450,8 +2451,13 @@ def build(self, node_: minidom.Element): def buildAttributes(self, attrs: minidom.NamedNodeMap): if "filename" in attrs.keys(): # extract the domain for this programlisting tag. - ext_tuple = os.path.splitext(attrs["filename"].value) - self.domain = ext_tuple[0 if not ext_tuple[1] else 1].lstrip(".") + file_ext = list(os.path.splitext(attrs["filename"].value)) + try: + lexer_cls = pygments.lexers.get_lexer_for_filename(attrs["filename"].value) + file_ext[1] = lexer_cls.name.lower() + except pygments.util.ClassNotFound: + pass # use file's extension as a fallback (file_ext from above) + self.domain = file_ext[0 if not file_ext[1] else 1].lstrip(".") def buildChildren(self, child_, nodeName_): if child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'codeline': From 25c53c37794a616e5254090b666c27dbf67a42ca Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Sun, 14 Nov 2021 12:38:11 -0800 Subject: [PATCH 07/18] use lexer alias instead of name --- breathe/parser/compoundsuper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index b5b3acdc..fbc000a5 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -2454,7 +2454,7 @@ def buildAttributes(self, attrs: minidom.NamedNodeMap): file_ext = list(os.path.splitext(attrs["filename"].value)) try: lexer_cls = pygments.lexers.get_lexer_for_filename(attrs["filename"].value) - file_ext[1] = lexer_cls.name.lower() + file_ext[1] = lexer_cls.aliases[0] except pygments.util.ClassNotFound: pass # use file's extension as a fallback (file_ext from above) self.domain = file_ext[0 if not file_ext[1] else 1].lstrip(".") From 98a22953031a7f2899c5de0c1faba0f8f6e8a942 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 7 Feb 2022 20:15:10 +0000 Subject: [PATCH 08/18] Extract file extension code To a helper module so that we can more clearly see what is going on and document it a little. --- breathe/filetypes.py | 21 +++++++++++++++++++++ breathe/parser/compoundsuper.py | 11 +++-------- 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 breathe/filetypes.py diff --git a/breathe/filetypes.py b/breathe/filetypes.py new file mode 100644 index 00000000..b21d9267 --- /dev/null +++ b/breathe/filetypes.py @@ -0,0 +1,21 @@ +from typing import Optional +import os.path + +import pygments + + +def get_pygments_alias(filename: str) -> Optional[str]: + "Find first pygments alias from filename" + try: + lexer_cls = pygments.lexers.get_lexer_for_filename(filename) + return lexer_cls.aliases[0] + except pygments.util.ClassNotFound: + return None + + +def get_extension(filename: str) -> str: + "Get extension from filename" + # If the filename is just '.ext' then we get ('.ext', '') so we fall back to first part if + # the second isn't there + (first, second) = os.path.splitext(filename) + return (second or first).lstrip(".") diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index fbc000a5..0768058f 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -7,8 +7,8 @@ import getopt from xml.dom import minidom from xml.dom import Node -import pygments +from .. import filetypes # # User methods # @@ -2451,13 +2451,8 @@ def build(self, node_: minidom.Element): def buildAttributes(self, attrs: minidom.NamedNodeMap): if "filename" in attrs.keys(): # extract the domain for this programlisting tag. - file_ext = list(os.path.splitext(attrs["filename"].value)) - try: - lexer_cls = pygments.lexers.get_lexer_for_filename(attrs["filename"].value) - file_ext[1] = lexer_cls.aliases[0] - except pygments.util.ClassNotFound: - pass # use file's extension as a fallback (file_ext from above) - self.domain = file_ext[0 if not file_ext[1] else 1].lstrip(".") + filename = attrs["filename"].value + self.domain = filetypes.get_pygments_alias(filename) or filetypes.get_extension(filename) def buildChildren(self, child_, nodeName_): if child_.nodeType == Node.ELEMENT_NODE and \ nodeName_ == 'codeline': From 6531938b10a797f309a0798b4366d11fe03c1a6f Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 7 Feb 2022 20:21:12 +0000 Subject: [PATCH 09/18] Remove call to '.keys()' I suspect the underlying data structure supports 'in' without needing to call '.keys()' --- breathe/parser/compoundsuper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/breathe/parser/compoundsuper.py b/breathe/parser/compoundsuper.py index 0768058f..2e2b25f8 100644 --- a/breathe/parser/compoundsuper.py +++ b/breathe/parser/compoundsuper.py @@ -2449,7 +2449,7 @@ def build(self, node_: minidom.Element): nodeName_ = child_.nodeName.split(':')[-1] self.buildChildren(child_, nodeName_) def buildAttributes(self, attrs: minidom.NamedNodeMap): - if "filename" in attrs.keys(): + if "filename" in attrs: # extract the domain for this programlisting tag. filename = attrs["filename"].value self.domain = filetypes.get_pygments_alias(filename) or filetypes.get_extension(filename) From dc66aeb3e758045c3d9245c9b51c5eeb04d004d1 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 7 Feb 2022 20:24:18 +0000 Subject: [PATCH 10/18] Add types for pygments I think this is necessary for CI to be happy. --- requirements/development.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements/development.txt b/requirements/development.txt index c1b74992..7936f816 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -6,5 +6,6 @@ pytest mypy>=0.900 types-docutils>=0.17.0 +types-Pygments>=2.9.16 black==22.1.0 From 35911ef3f4324efe697612a550dc50085a13297b Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 7 Feb 2022 20:35:34 +0000 Subject: [PATCH 11/18] Remove types-Pygments I've failed to get it working with our current set up. We seem to need to import pygments.lexers but then it fails to find 'aliases' on the Lexer class. --- breathe/filetypes.py | 2 +- requirements/development.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/breathe/filetypes.py b/breathe/filetypes.py index b21d9267..52624903 100644 --- a/breathe/filetypes.py +++ b/breathe/filetypes.py @@ -1,7 +1,7 @@ from typing import Optional import os.path -import pygments +import pygments # type: ignore def get_pygments_alias(filename: str) -> Optional[str]: diff --git a/requirements/development.txt b/requirements/development.txt index 7936f816..c1b74992 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -6,6 +6,5 @@ pytest mypy>=0.900 types-docutils>=0.17.0 -types-Pygments>=2.9.16 black==22.1.0 From 81d6e6effd7bda45e4581bf95ffc28f111c6178a Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 7 Feb 2022 20:57:02 +0000 Subject: [PATCH 12/18] Fix linting failure --- breathe/filetypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/breathe/filetypes.py b/breathe/filetypes.py index 52624903..f64b0092 100644 --- a/breathe/filetypes.py +++ b/breathe/filetypes.py @@ -1,7 +1,7 @@ from typing import Optional import os.path -import pygments # type: ignore +import pygments # type: ignore def get_pygments_alias(filename: str) -> Optional[str]: From f49c53d2e9336486884a39d48781239a806c18c3 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 8 Feb 2022 20:22:56 +0000 Subject: [PATCH 13/18] Update copyright date --- documentation/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/source/conf.py b/documentation/source/conf.py index 9f81ce65..e4c0b926 100644 --- a/documentation/source/conf.py +++ b/documentation/source/conf.py @@ -144,7 +144,7 @@ # General information about the project. project = "Breathe" -copyright = "2009-2014, Michael Jones" +copyright = "2009-2022, Michael Jones" # The language for content autogenerated by Sphinx. Refer to documentation From fc8d2b6f8b20c1a4ba8456d3880b09d14b263e79 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 8 Feb 2022 20:26:31 +0000 Subject: [PATCH 14/18] Add test pages for code block highlighting With some basic examples based on @2bndy5 work and comments. --- documentation/source/examples/codeblocks.rst | 18 ++++++++++++ documentation/source/testpages.rst | 1 + examples/specific/Makefile | 2 +- examples/specific/code_blocks.cfg | 11 +++++++ examples/specific/code_blocks.h | 31 ++++++++++++++++++++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 documentation/source/examples/codeblocks.rst create mode 100644 examples/specific/code_blocks.cfg create mode 100644 examples/specific/code_blocks.h diff --git a/documentation/source/examples/codeblocks.rst b/documentation/source/examples/codeblocks.rst new file mode 100644 index 00000000..d1c3e5e4 --- /dev/null +++ b/documentation/source/examples/codeblocks.rst @@ -0,0 +1,18 @@ + +Examples: Code Blocks +===================== + +The following should render with standard C/C++ highlighting. + +.. doxygenfunction:: with_standard_code_block + :path: ../../examples/specific/code_blocks/xml + +The following should render with no detected highlighting. + +.. doxygenfunction:: with_unannotated_cmake_code_block + :path: ../../examples/specific/code_blocks/xml + +The following should render with specified cmake highlighting. + +.. doxygenfunction:: with_annotated_cmake_code_block + :path: ../../examples/specific/code_blocks/xml diff --git a/documentation/source/testpages.rst b/documentation/source/testpages.rst index 9ed56333..41576785 100644 --- a/documentation/source/testpages.rst +++ b/documentation/source/testpages.rst @@ -11,4 +11,5 @@ Test Pages embeddedrst inline members + examples/codeblocks diff --git a/examples/specific/Makefile b/examples/specific/Makefile index fb8639fd..d2a76539 100644 --- a/examples/specific/Makefile +++ b/examples/specific/Makefile @@ -28,7 +28,7 @@ projects = nutshell alias rst inline namespacefile array inheritance \ cpp_inherited_members cpp_trailing_return_type cpp_constexpr_hax \ cpp_function_lookup \ c_file c_struct c_enum c_typedef c_macro c_union membergroups \ - simplesect + simplesect code_blocks special = programlisting decl_impl multifilexml auto class typedef diff --git a/examples/specific/code_blocks.cfg b/examples/specific/code_blocks.cfg new file mode 100644 index 00000000..7a2346f3 --- /dev/null +++ b/examples/specific/code_blocks.cfg @@ -0,0 +1,11 @@ +PROJECT_NAME = "Code Blocks" +OUTPUT_DIRECTORY = code_blocks +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = code_blocks.h +QUIET = YES +JAVADOC_AUTOBRIEF = YES +GENERATE_HTML = NO +GENERATE_XML = YES diff --git a/examples/specific/code_blocks.h b/examples/specific/code_blocks.h new file mode 100644 index 00000000..4dd696f0 --- /dev/null +++ b/examples/specific/code_blocks.h @@ -0,0 +1,31 @@ + +/** with_standard_code_block + * + * @code + * int result = with_standard_code_block() + * @endcode + * + */ +void with_standard_code_block(); + +/** with_unannotated_cmake_code_block + * + * @code + * set(user_list A B C) + * for(element in ${user_list}) + * message(STATUS "Element is ${element}") + * endfor() + * @endcode + */ +void with_unannotated_cmake_code_block(); + +/** with_annotated_cmake_code_block + * + * @code{.cmake} + * set(user_list A B C) + * for(element in ${user_list}) + * message(STATUS "Element is ${element}") + * endfor() + * @endcode + */ +void with_annotated_cmake_code_block(); From 5b27b752944f3f4d99b3dfa321b24049c3e582da Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 8 Feb 2022 20:46:50 +0000 Subject: [PATCH 15/18] Add a documentation page for code blocks I haven't done this in a while. But it seems reasonable. --- documentation/source/codeblocks.rst | 96 ++++++++++++++++++++ documentation/source/examples/codeblocks.rst | 3 + documentation/source/index.rst | 1 + examples/specific/code_blocks.h | 7 +- 4 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 documentation/source/codeblocks.rst diff --git a/documentation/source/codeblocks.rst b/documentation/source/codeblocks.rst new file mode 100644 index 00000000..734c7c8a --- /dev/null +++ b/documentation/source/codeblocks.rst @@ -0,0 +1,96 @@ + +Code Blocks +=========== + +Breathe suppports rendering code blocks with syntax highlighting provided by the +`Pygments `_ library. + +The Doxygen syntax for code blocks supports specifying the language as follows: + +.. code-block:: + + \code{.py} + class Python: + pass + \endcode + + @code{.cpp} + class Cpp {}; + @endcode + +Breathe will pass the language specified to Pygments to get accurate +highlighting. + +Examples +-------- + +The following should render with standard C/C++ highlighting. + +---- + +.. code-block:: cpp + + /** A function with an unannotated code block with C/C++ code. + * + * @code + * int result = with_standard_code_block() + * @endcode + */ + void with_standard_code_block(); + +---- + +.. doxygenfunction:: with_standard_code_block + :path: ../../examples/specific/code_blocks/xml + :no-link: + +---- + +The following should render with no detected highlighting. + +---- + +.. code-block:: cpp + + /** A function with an unannotated code block with non-C/C++ code. + * + * @code + * set(user_list A B C) + * for(element in ${user_list}) + * message(STATUS "Element is ${element}") + * endfor() + * @endcode + */ + void with_unannotated_cmake_code_block(); + +---- + +.. doxygenfunction:: with_unannotated_cmake_code_block + :path: ../../examples/specific/code_blocks/xml + :no-link: + +---- + +The following should render with specified cmake highlighting. + +---- + +.. code-block:: cpp + + /** A function with an annotated cmake code block. + * + * @code{.cmake} + * set(user_list A B C) + * for(element in ${user_list}) + * message(STATUS "Element is ${element}") + * endfor() + * @endcode + */ + void with_annotated_cmake_code_block(); + +---- + +.. doxygenfunction:: with_annotated_cmake_code_block + :path: ../../examples/specific/code_blocks/xml + :no-link: + diff --git a/documentation/source/examples/codeblocks.rst b/documentation/source/examples/codeblocks.rst index d1c3e5e4..f09d7874 100644 --- a/documentation/source/examples/codeblocks.rst +++ b/documentation/source/examples/codeblocks.rst @@ -6,13 +6,16 @@ The following should render with standard C/C++ highlighting. .. doxygenfunction:: with_standard_code_block :path: ../../examples/specific/code_blocks/xml + :no-link: The following should render with no detected highlighting. .. doxygenfunction:: with_unannotated_cmake_code_block :path: ../../examples/specific/code_blocks/xml + :no-link: The following should render with specified cmake highlighting. .. doxygenfunction:: with_annotated_cmake_code_block :path: ../../examples/specific/code_blocks/xml + :no-link: diff --git a/documentation/source/index.rst b/documentation/source/index.rst index a066cde1..655edefa 100644 --- a/documentation/source/index.rst +++ b/documentation/source/index.rst @@ -65,6 +65,7 @@ Features markups latexmath + codeblocks domains customcss groups diff --git a/examples/specific/code_blocks.h b/examples/specific/code_blocks.h index 4dd696f0..3af108f5 100644 --- a/examples/specific/code_blocks.h +++ b/examples/specific/code_blocks.h @@ -1,14 +1,13 @@ -/** with_standard_code_block +/** A function with an unannotated code block with C/C++ code. * * @code * int result = with_standard_code_block() * @endcode - * */ void with_standard_code_block(); -/** with_unannotated_cmake_code_block +/** A function with an unannotated code block with non-C/C++ code. * * @code * set(user_list A B C) @@ -19,7 +18,7 @@ void with_standard_code_block(); */ void with_unannotated_cmake_code_block(); -/** with_annotated_cmake_code_block +/** A function with an annotated cmake code block. * * @code{.cmake} * set(user_list A B C) From 72880fc3aafe41f1845f7d6b7f2544366a3789bf Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 8 Feb 2022 21:18:37 +0000 Subject: [PATCH 16/18] Clarify behaviour & fix cmake code @2bndy5 has clarified that the cmake should be a little different. --- documentation/source/codeblocks.rst | 12 +++++++----- examples/specific/code_blocks.h | 8 ++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/documentation/source/codeblocks.rst b/documentation/source/codeblocks.rst index 734c7c8a..630bb538 100644 --- a/documentation/source/codeblocks.rst +++ b/documentation/source/codeblocks.rst @@ -3,7 +3,9 @@ Code Blocks =========== Breathe suppports rendering code blocks with syntax highlighting provided by the -`Pygments `_ library. +`Pygments `_ library. By default, Breathe will assume +that code blocks match the language of the source file but you can also specify +the language of the code blocks using Doxygen syntax. The Doxygen syntax for code blocks supports specifying the language as follows: @@ -56,9 +58,9 @@ The following should render with no detected highlighting. * * @code * set(user_list A B C) - * for(element in ${user_list}) + * foreach(element ${user_list}) * message(STATUS "Element is ${element}") - * endfor() + * endforeach() * @endcode */ void with_unannotated_cmake_code_block(); @@ -81,9 +83,9 @@ The following should render with specified cmake highlighting. * * @code{.cmake} * set(user_list A B C) - * for(element in ${user_list}) + * foreach(element ${user_list}) * message(STATUS "Element is ${element}") - * endfor() + * endforeach() * @endcode */ void with_annotated_cmake_code_block(); diff --git a/examples/specific/code_blocks.h b/examples/specific/code_blocks.h index 3af108f5..2451b56f 100644 --- a/examples/specific/code_blocks.h +++ b/examples/specific/code_blocks.h @@ -11,9 +11,9 @@ void with_standard_code_block(); * * @code * set(user_list A B C) - * for(element in ${user_list}) + * foreach(element ${user_list}) * message(STATUS "Element is ${element}") - * endfor() + * endforeach() * @endcode */ void with_unannotated_cmake_code_block(); @@ -22,9 +22,9 @@ void with_unannotated_cmake_code_block(); * * @code{.cmake} * set(user_list A B C) - * for(element in ${user_list}) + * foreach(element ${user_list}) * message(STATUS "Element is ${element}") - * endfor() + * endforeach() * @endcode */ void with_annotated_cmake_code_block(); From 345960a331db365fc2c5fa89db9bc1e7f4126231 Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 8 Feb 2022 14:35:13 -0800 Subject: [PATCH 17/18] more details for new doc --- documentation/source/codeblocks.rst | 62 ++++++++++++++++++++++------- examples/specific/code_blocks.h | 3 +- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/documentation/source/codeblocks.rst b/documentation/source/codeblocks.rst index 630bb538..9ad5d756 100644 --- a/documentation/source/codeblocks.rst +++ b/documentation/source/codeblocks.rst @@ -2,31 +2,57 @@ Code Blocks =========== -Breathe suppports rendering code blocks with syntax highlighting provided by the +Breathe supports rendering code blocks with syntax highlighting provided by the `Pygments `_ library. By default, Breathe will assume -that code blocks match the language of the source file but you can also specify -the language of the code blocks using Doxygen syntax. +that code blocks match the language of the source file, but you can also specify +the language of the code blocks using +`Doxygen's code command `_ +or `MarkDown's fenced code blocks `_. + +.. note:: + Any hyperlinked text found within the code blocks rendered with Doxygen's HTML output + will not be hyperlinked in any Sphinx output due to the use of the Pygments library. + As a benefit, a code-block's syntax highlighting can be any syntax supported by + Pygments (which is much more than only the languages supported by Doxygen's parsers). The Doxygen syntax for code blocks supports specifying the language as follows: .. code-block:: - \code{.py} - class Python: - pass - \endcode + \code{.py} + class Python: + pass + \endcode + + @code{.cpp} + class Cpp {}; + @endcode + +This technique can also be utilized from MarkDown syntax/files + +.. code-block:: markdown + + ```py + class Python: + pass + ``` - @code{.cpp} - class Cpp {}; - @endcode + ```cpp + class Cpp {}; + ``` Breathe will pass the language specified to Pygments to get accurate -highlighting. +highlighting. If no language is explicitly provided (either from ``\code`` +command or via Doxygen's XML output about the language documented), then +Pygments will try to guess what syntax the code block is using (based on +the code block's contents). Examples -------- -The following should render with standard C/C++ highlighting. +The following should render with standard C/C++ highlighting. Notice, the +syntax is automatically highlighted as C++ because the documented function +exists in a C++ source file. ---- @@ -35,7 +61,8 @@ The following should render with standard C/C++ highlighting. /** A function with an unannotated code block with C/C++ code. * * @code - * int result = with_standard_code_block() + * char *buffer = new char[42]; + * int charsAdded = sprintf(buffer, "Tabs are normally %d spaces\n", 8); * @endcode */ void with_standard_code_block(); @@ -49,6 +76,8 @@ The following should render with standard C/C++ highlighting. ---- The following should render with no detected highlighting. +Notice there is no syntax highlighting because Pygments does not +recognize the code block's contained syntax as a C++ snippet. ---- @@ -73,7 +102,9 @@ The following should render with no detected highlighting. ---- -The following should render with specified cmake highlighting. +The following should render with specified CMake highlighting. Here, the syntax +highlighting is explicitly recognized as a CMake script snippet which overrides +the inherent C++ context. ---- @@ -96,3 +127,6 @@ The following should render with specified cmake highlighting. :path: ../../examples/specific/code_blocks/xml :no-link: +.. warning:: + Pygments will raise a warning in the Sphinx build logs if + the specified syntax does conform the specified syntax's convention(s). diff --git a/examples/specific/code_blocks.h b/examples/specific/code_blocks.h index 2451b56f..390616ba 100644 --- a/examples/specific/code_blocks.h +++ b/examples/specific/code_blocks.h @@ -2,7 +2,8 @@ /** A function with an unannotated code block with C/C++ code. * * @code - * int result = with_standard_code_block() + * char* buffer = new char[42]; + * int charsAdded = sprintf(buffer, "Tabs are normally %d spaces\n", 8); * @endcode */ void with_standard_code_block(); From 9f20a1c909bd70c19d309f5647cf6e94678deaa0 Mon Sep 17 00:00:00 2001 From: 2bndy5 <2bndy5@gmail.com> Date: Tue, 8 Feb 2022 17:47:57 -0800 Subject: [PATCH 18/18] add missing comma --- documentation/source/codeblocks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/source/codeblocks.rst b/documentation/source/codeblocks.rst index 9ad5d756..ca3ed92e 100644 --- a/documentation/source/codeblocks.rst +++ b/documentation/source/codeblocks.rst @@ -76,7 +76,7 @@ exists in a C++ source file. ---- The following should render with no detected highlighting. -Notice there is no syntax highlighting because Pygments does not +Notice, there is no syntax highlighting because Pygments does not recognize the code block's contained syntax as a C++ snippet. ----