From 9f7f677afb79c653e9c800a2e5c5d9248e11f873 Mon Sep 17 00:00:00 2001 From: Jakub Andrysek Date: Thu, 28 Dec 2023 14:42:28 +0100 Subject: [PATCH] Add basic support for diagrams and dot files generation --- .idea/misc.xml | 3 + .idea/workspace.xml | 143 ++++++++++++++++++++++----------- mkdocs.yml | 20 ++++- mkdoxy/doxygen.py | 3 +- mkdoxy/generatorAuto.py | 19 +++++ mkdoxy/generatorBase.py | 23 +++++- mkdoxy/node.py | 27 +++++++ mkdoxy/property.py | 49 +++++++++++ mkdoxy/templates/member.jinja2 | 28 +++++++ 9 files changed, 266 insertions(+), 49 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index f88c0a0d..a0641c7e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,7 @@ + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index c29d74d2..f6a4f4ba 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -5,9 +5,8 @@ - - + + + + + { + "associatedIndex": 2 +} @@ -50,22 +55,26 @@ - { - "keyToString": { - "RunOnceActivity.ShowReadmeOnStart": "true", - "SHARE_PROJECT_CONFIGURATION_FILES": "true", - "WebServerToolWindowFactoryState": "false", - "git-widget-placeholder": "main", - "last_opened_file_path": "/Users/kuba/Documents/git/kuba/mkdoxy/mkdoxy-base/mkdoxy-new-templates/docs", - "node.js.detected.package.eslint": "true", - "node.js.detected.package.tslint": "true", - "node.js.selected.package.eslint": "(autodetect)", - "node.js.selected.package.tslint": "(autodetect)", - "nodejs_package_manager_path": "npm", - "settings.editor.selected.configurable": "reference.settings.ide.settings.new.ui", - "vue.rearranger.settings.migration": "true" + +}]]> @@ -80,7 +89,7 @@ - + @@ -93,8 +102,32 @@ + + + + + + + + - + + + + + + + + @@ -276,6 +322,11 @@ + + + + + 1674630349699 @@ -497,19 +548,14 @@ - - file://$PROJECT_DIR$/mkdoxy/generatorAuto.py - 235 - file://$PROJECT_DIR$/mkdoxy/node.py - 224 + 227 file://$PROJECT_DIR$/mkdoxy/node.py - 227 + 230 @@ -519,14 +565,9 @@ file://$PROJECT_DIR$/mkdoxy/node.py - 842 + 869 - - file://$PROJECT_DIR$/mkdoxy/generatorBase.py - 82 - file://$PROJECT_DIR$/mkdoxy/DoxyTagParser.py 41 @@ -547,6 +588,16 @@ 22 + + file://$PROJECT_DIR$/mkdoxy/generatorAuto.py + 266 + + + file://$PROJECT_DIR$/mkdoxy/generatorAuto.py + 265 + file://$PROJECT_DIR$/mkdoxy/templates/relatedPages.jinja2 5 @@ -556,22 +607,22 @@ - - + - - + + + + - - - - - + + + + diff --git a/mkdocs.yml b/mkdocs.yml index f6760a7b..1e995d3d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,10 +24,16 @@ theme: icon: repo: fontawesome/brands/github + palette: - - scheme: slate + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate primary: orange accent: orange + toggle: + icon: material/brightness-4 + name: Switch to light mode extra: social: @@ -74,6 +80,12 @@ plugins: OPTIMIZE_OUTPUT_JAVA: True JAVADOC_AUTOBRIEF: True EXTRACT_ALL: True + + GENERATE_HTML: YES + HAVE_DOT: YES + DOT_IMAGE_FORMAT: jpg + # HAVE_DOT: YES + UML_LOOK: YES animal: src-dirs: demo-projects/animal full-doc: True @@ -81,6 +93,12 @@ plugins: FILE_PATTERNS: "*.cpp *.h*" EXAMPLE_PATH: examples RECURSIVE: True + GENERATE_HTML: YES + HAVE_DOT: YES + # DOT_IMAGE_FORMAT: jpg + DOT_IMAGE_FORMAT: svg + # INTERACTIVE_SVG: YES + # UML_LOOK: YES save-api: .mkdoxy full-doc: True debug: False diff --git a/mkdoxy/doxygen.py b/mkdoxy/doxygen.py index a56f4be8..0e18177a 100644 --- a/mkdoxy/doxygen.py +++ b/mkdoxy/doxygen.py @@ -1,5 +1,6 @@ import logging import os +from pathlib import PurePath from xml.etree import ElementTree from mkdoxy.cache import Cache @@ -11,7 +12,7 @@ class Doxygen: - def __init__(self, index_path: str, parser: XmlParser, cache: Cache): + def __init__(self, index_path: PurePath, parser: XmlParser, cache: Cache): self.debug = parser.debug path_xml = os.path.join(index_path, "index.xml") if self.debug: diff --git a/mkdoxy/generatorAuto.py b/mkdoxy/generatorAuto.py index 8f5d77d6..72c9fd7a 100644 --- a/mkdoxy/generatorAuto.py +++ b/mkdoxy/generatorAuto.py @@ -64,6 +64,17 @@ def save(self, path: str, output: str): with open(os.path.join(self.tempDoxyDir, pathRel), "w", encoding="utf-8") as file: file.write(output) + def save_image(self, path: str, image_source_link: str): + # copy image from image_source_link to mkdocs + source = os.path.join(self.tempDoxyDir, "html", image_source_link) + if not os.path.exists(source): + return + destination = os.path.join(self.siteDir, self.apiPath, path, image_source_link) + os.makedirs(os.path.dirname(destination), exist_ok=True) + with open(source, "rb") as fsrc: + with open(destination, "wb") as fdst: + fdst.write(fsrc.read()) + def fullDoc(self, defaultTemplateConfig: dict): self.annotated(self.doxygen.root.children, defaultTemplateConfig) self.fileindex(self.doxygen.files.children, defaultTemplateConfig) @@ -246,6 +257,14 @@ def hierarchy(self, nodes: [Node], config: dict = None): def member(self, node: Node, config: dict = None): path = node.filename + refid = node.refid + + if node.has_inheritance_graph: + self.save_image(refid, node.inheritance_graph) + if node.has_collaboration_graph: + self.save_image(refid, node.collaboration_graph) + # if node.has_directory_dependency: + # self.save_image(refid, node.directory_dependency) output = self.generatorBase.member(node, config) self.save(path, output) diff --git a/mkdoxy/generatorBase.py b/mkdoxy/generatorBase.py index 3b0cd193..5422a802 100644 --- a/mkdoxy/generatorBase.py +++ b/mkdoxy/generatorBase.py @@ -6,6 +6,7 @@ from jinja2 import Template from jinja2.exceptions import TemplateError from mkdocs import exceptions +from pprint import pformat import mkdoxy from mkdoxy.constants import Kind @@ -94,10 +95,30 @@ def render(self, tmpl: Template, data: dict) -> str: @param data (dict): Data to render the template. @return (str): Rendered template. """ + + def print_node_content(node: Node, level=0, max_depth=1): + if level > max_depth: + return "" # Stop recursion when max depth is exceeded + + indent = "\n" + " " * (level * 4) + "- " # Indentation for better readability + # node_representation = f"{indent}Node at Level {level}: {pformat(vars(node))}\n" + node_representation = f"{indent}Node at Level {level}: {node.name}\n" + # print all attributes of the node + for key, value in vars(node).items(): + if key == "children": + continue + node_representation += f"{indent} {key}: {pformat(value)}\n" + + # Assuming each node has a list or iterable of child nodes in an attribute like `children` + for child in getattr(node, "children", []): + node_representation += print_node_content(child, level + 1, max_depth) + + return node_representation + try: # if self.debug: # print('Generating', path) # TODO: add path to data - rendered: str = tmpl.render(data) + rendered: str = tmpl.render(data, pformat=pformat, vars=vars, print_node_content=print_node_content) return rendered except TemplateError as e: raise Exception(str(e)) from e diff --git a/mkdoxy/node.py b/mkdoxy/node.py index d79a3f5e..209fe31d 100644 --- a/mkdoxy/node.py +++ b/mkdoxy/node.py @@ -87,6 +87,9 @@ def __init__( self._initializer = Property.Initializer(self._xml, parser, self._kind) self._definition = Property.Definition(self._xml, parser, self._kind) self._programlisting = Property.Programlisting(self._xml, parser, self._kind) + self._inheritancegraph = Property.InheritanceGraph(self._xml, parser, self._kind) + self._collaborationgraph = Property.CollaborationGraph(self._xml, parser, self._kind) + # self._directorydependency = Property.DirectoryDependency(self._xml, parser, self._kind) def __repr__(self): return f"Node: {self.name} refid: {self._refid}" @@ -828,6 +831,30 @@ def has_programlisting(self) -> bool: def programlisting(self) -> str: return self._programlisting.md() + @property + def has_inheritance_graph(self) -> bool: + return self._inheritancegraph.has() + + @property + def inheritance_graph(self) -> str: + return self._inheritancegraph.md() + + @property + def has_collaboration_graph(self) -> bool: + return self._collaborationgraph.has() + + @property + def collaboration_graph(self) -> str: + return self._collaborationgraph.md() + + # @property + # def has_directory_dependency(self) -> bool: + # return self._directorydependency.has() + # + # @property + # def directory_dependency(self) -> str: + # return self._directorydependency.md() + @property def is_resolved(self) -> bool: return True diff --git a/mkdoxy/property.py b/mkdoxy/property.py index b7c840f8..d2143667 100644 --- a/mkdoxy/property.py +++ b/mkdoxy/property.py @@ -344,3 +344,52 @@ def md(self, plain: bool = False) -> str: def has(self) -> bool: return self.xml.find("programlisting") is not None + + class InheritanceGraph: + def __init__(self, xml: Element, parser: XmlParser, kind: Kind): + self.xml = xml + self.parser = parser + self.kind = kind + self.refid = self.xml.attrib.get("id") if self.xml is not None else None + + def md(self, plain: bool = False) -> str: + return f"{self.refid}__inherit__graph.svg" + + def plain(self) -> str: + return self.md(plain=True) + + def has(self) -> bool: + return self.kind.is_class() and self.refid is not None and self.xml.find("inheritancegraph") is not None + + class CollaborationGraph: + def __init__(self, xml: Element, parser: XmlParser, kind: Kind): + self.xml = xml + self.parser = parser + self.kind = kind + self.refid = self.xml.attrib.get("id") if self.xml is not None else None + + def md(self, plain: bool = False) -> str: + return f"{self.refid}__coll__graph.svg" + + def plain(self) -> str: + return self.md(plain=True) + + def has(self) -> bool: + return self.kind.is_class() and self.refid is not None and self.xml.find("collaborationgraph") is not None + + # class DirectoryDependency: + # def __init__(self, xml: Element, parser: XmlParser, kind: Kind): + # self.xml = xml + # self.parser = parser + # self.kind = kind + # self.refid = self.xml.attrib.get("id") if self.xml is not None else None + # + # def md(self, plain: bool = False) -> str: + # return f"{self.refid}_dep.svg" + # + # def plain(self) -> str: + # return self.md(plain=True) + # + # def has(self) -> bool: + # return (self.refid is not None and + # (self.kind.is_dir())) diff --git a/mkdoxy/templates/member.jinja2 b/mkdoxy/templates/member.jinja2 index 1e939b4c..52970770 100644 --- a/mkdoxy/templates/member.jinja2 +++ b/mkdoxy/templates/member.jinja2 @@ -5,6 +5,9 @@ implements: True --- {% filter indent(config.get('indent_level', 0), True) %} + +{#{{ print_node_content(node) }}#} + # {{node.kind.value|title}} {{node.name_long}} {% if node.has_templateparams %} **template <{{node.templateparams}}>** @@ -31,6 +34,31 @@ implements: True {% endfor -%} {%- endif %} + +{% if node.has_inheritance_graph %} +### Inheritance diagram: +{#{{ node.inheritance_graph }}#} +

+ ![alt]({{ node.inheritance_graph }}) +

+{% endif %} + +{% if node.has_collaboration_graph %} +### Collaboration diagram: +{#{{ node.collaboration_graph }}#} +

+ ![alt]({{ node.collaboration_graph }}) +

+{% endif %} + +{#{% if node.has_directory_dependency %}#} +{#### Directory dependency graph:#} +{#{{ node.directory_dependency }}#} +{#

#} +{# ![alt]({{ node.directory_dependency }})#} +{#

#} +{#{% endif %}#} + {% if node.has_base_classes %} Inherits the following classes: {%- for base in node.base_classes -%}