diff --git a/docs/source/_extensions/kpm_plugin.py b/docs/source/_extensions/kpm_plugin.py new file mode 100644 index 00000000..dacb019d --- /dev/null +++ b/docs/source/_extensions/kpm_plugin.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +from typing import Optional +from urllib.parse import urlencode + +from docutils import nodes +from docutils.parsers.rst.directives import path +from sphinx.addnodes import download_reference +from sphinx.application import Sphinx +from sphinx.util.docutils import SphinxDirective +from sphinx.util.typing import ExtensionMetadata +from sphinx.writers.html5 import HTML5Translator +from sphinx.writers.latex import LaTeXTranslator + +KPM_PATH = "_static/kpm/index.html" + + +class KPMNode(nodes.container): + def __init__( + self, + depth: int, + preview: bool, + spec_ref: Optional[str], + graph_ref: Optional[str], + height: Optional[str], + ) -> None: + # we're leveraging the builtin download_reference node + # to automatically move necessary files from sources + # into the build directory and have a path to them + spec_node = graph_node = None + if spec_ref: + spec_node = download_reference("", "", reftarget=spec_ref, disabled=True) + if graph_ref: + graph_node = download_reference("", "", reftarget=graph_ref, disabled=True) + + super().__init__("", *(node for node in (spec_node, graph_node) if node)) + self.spec_node = spec_node + self.graph_node = graph_node + self.rel_pfx = "../" * depth + self.preview = preview + self.height = height + + def _node_to_target(self, node: download_reference) -> str: + if "filename" in node: + return "relative://../../_downloads/" + node["filename"] + elif "refuri" in node: + return node["refuri"] + + raise ValueError("The KPM file path is neither a valid file nor a URL") + + @staticmethod + def visit_html(trans: HTML5Translator, node: KPMNode): + params = {} + if node.spec_node: + params["spec"] = node._node_to_target(node.spec_node) + if node.graph_node: + params["graph"] = node._node_to_target(node.graph_node) + if node.preview: + params["preview"] = str(node.preview).lower() + + trans.body.append( + f""" +""" + ) + + @staticmethod + def visit_latex(trans: LaTeXTranslator, _: KPMNode): + trans.body.append( + r""" +\begin{sphinxadmonition}{warning}{Note:} +\sphinxAtStartPar +An interactive KPM frame, where you can explore the block design for this section, +is available here in the HTML version of this documentation. +\end{sphinxadmonition}""" + ) + + @staticmethod + def depart_node(*_): + pass + + +class KPMDirective(SphinxDirective): + option_spec = {"spec": path, "dataflow": path, "preview": bool, "height": str} + + def run(self) -> list[nodes.Node]: + return [ + KPMNode( + self.env.docname.count("/"), + self.options.get("preview", False), + self.options.get("spec"), + self.options.get("dataflow"), + self.options.get("height"), + ) + ] + + +def setup(app: Sphinx) -> ExtensionMetadata: + app.add_node( + KPMNode, + html=(KPMNode.visit_html, KPMNode.depart_node), + latex=(KPMNode.visit_latex, KPMNode.depart_node), + ) + app.add_directive("kpm_iframe", KPMDirective) + + return { + "version": "0.1", + "parallel_read_safe": True, + "parallel_write_safe": True, + } diff --git a/docs/source/conf.py b/docs/source/conf.py index 6cb04c68..054b61d8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,6 +15,8 @@ from datetime import datetime from os import environ +import os +import sys from antmicro_sphinx_utils.defaults import antmicro_html, antmicro_latex from antmicro_sphinx_utils.defaults import extensions as default_extensions @@ -29,7 +31,7 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath('./_extensions')) # -- General configuration ----------------------------------------------------- @@ -51,7 +53,7 @@ # If you need to add extensions just add to those lists extensions = list(set(default_extensions + [ - 'sphinx.ext.autodoc', + 'sphinx.ext.autodoc', 'kpm_plugin' ])) myst_enable_extensions = default_myst_enable_extensions myst_fence_as_directive = default_myst_fence_as_directive diff --git a/docs/source/developers_guide/inline_kpm_howto.md b/docs/source/developers_guide/inline_kpm_howto.md new file mode 100644 index 00000000..f088600a --- /dev/null +++ b/docs/source/developers_guide/inline_kpm_howto.md @@ -0,0 +1,43 @@ +# Using KPM iframes inside docs + +It is possible to use the `kpm_iframe` Sphinx directive to embed KPM directly inside a doc. + +## Usage + +```` +```{kpm_iframe} +:spec: +:dataflow: +:preview: +:height: +``` +```` + +`URI` can represent either a local file from sources that gets copied into the build directory, or a remote resource. + +All parameters of this directive are optional. + + +## Tests + +### Use remote specification + +```{kpm_iframe} +:spec: https://raw.githubusercontent.com/antmicro/topwrap/main/tests/data/data_kpm/examples/hdmi/specification_hdmi.json +``` + +### Use local files + +```{kpm_iframe} +:spec: ../../../tests/data/data_kpm/examples/hierarchy/specification_hierarchy.json +:dataflow: ../../../tests/data/data_kpm/examples/hierarchy/dataflow_hierarchy.json +:height: 80vh +``` + +### Open in preview mode + +```{kpm_iframe} +:spec: ../../../tests/data/data_kpm/examples/hierarchy/specification_hierarchy.json +:dataflow: ../../../tests/data/data_kpm/examples/hierarchy/dataflow_hierarchy.json +:preview: true +``` diff --git a/docs/source/index.md b/docs/source/index.md index 34144f88..cc608cd2 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -31,4 +31,5 @@ developers_guide/config developers_guide/parsing developers_guide/examples developers_guide/future_enhancements +developers_guide/inline_kpm_howto ``` diff --git a/noxfile.py b/noxfile.py index 077746aa..0a9d9e62 100644 --- a/noxfile.py +++ b/noxfile.py @@ -137,6 +137,15 @@ def doc_gen(session: nox.Session) -> None: session.install(".[docs]") session.run("make", "-C", "docs", "html", external=True) session.run("make", "-C", "docs", "latexpdf", external=True) + session.run( + "pipeline_manager", + "build", + "static-html", + "--output-directory", + "docs/build/html/_static/kpm", + "--workspace-directory", + "docs/build/kpm", + ) session.run("cp", "docs/build/latex/topwrap.pdf", "docs/build/html", external=True)