75 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			75 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
from pathlib import Path
 | 
						|
 | 
						|
from docutils import nodes
 | 
						|
from sphinx.application import Sphinx
 | 
						|
from sphinx.util.docutils import SphinxDirective
 | 
						|
from sphinx.util.typing import ExtensionMetadata
 | 
						|
 | 
						|
 | 
						|
class DrawioDirective(SphinxDirective):
 | 
						|
    """A directive to show a drawio diagram!
 | 
						|
 | 
						|
    Usage:
 | 
						|
    .. drawio::
 | 
						|
       example-diagram.drawio.html
 | 
						|
       example-diagram.drawio.png
 | 
						|
       :alt: Example of a Draw.io diagram
 | 
						|
    """
 | 
						|
 | 
						|
    has_content = False
 | 
						|
    required_arguments = 2  # html and png
 | 
						|
    optional_arguments = 1
 | 
						|
    final_argument_whitespace = True  # indicating if the final argument may contain whitespace
 | 
						|
    option_spec = {
 | 
						|
        "alt": str,
 | 
						|
    }
 | 
						|
 | 
						|
    def run(self) -> list[nodes.Node]:
 | 
						|
        env = self.state.document.settings.env
 | 
						|
        builder = env.app.builder
 | 
						|
 | 
						|
        # Resolve paths relative to the document
 | 
						|
        docdir = Path(env.doc2path(env.docname)).parent
 | 
						|
        html_rel = Path(self.arguments[0])
 | 
						|
        png_rel = Path(self.arguments[1])
 | 
						|
        html_path = (docdir / html_rel).resolve()
 | 
						|
        png_path = (docdir / png_rel).resolve()
 | 
						|
 | 
						|
        alt_text = self.options.get("alt", "")
 | 
						|
 | 
						|
        container = nodes.container()
 | 
						|
 | 
						|
        # HTML output -> raw HTML node
 | 
						|
        if builder.format == "html":
 | 
						|
            # Embed the HTML file contents directly
 | 
						|
            try:
 | 
						|
                html_content = html_path.read_text(encoding="utf-8")
 | 
						|
            except OSError as e:
 | 
						|
                msg = self.state_machine.reporter.error(f"Cannot read HTML file: {e}")
 | 
						|
                return [msg]
 | 
						|
            aria_attribute = f' aria-label="{alt_text}"' if alt_text else ""
 | 
						|
            raw_html_node = nodes.raw(
 | 
						|
                "",
 | 
						|
                f'<div class="drawio-diagram"{aria_attribute}>{html_content}</div>',
 | 
						|
                format="html",
 | 
						|
            )
 | 
						|
            container += raw_html_node
 | 
						|
        else:
 | 
						|
            # Other outputs -> PNG image node
 | 
						|
            image_node = nodes.image(uri=png_path)
 | 
						|
            container += image_node
 | 
						|
 | 
						|
        return [container]
 | 
						|
 | 
						|
 | 
						|
def setup(app: Sphinx) -> ExtensionMetadata:
 | 
						|
    app.add_directive("drawio", DrawioDirective)
 | 
						|
 | 
						|
    return {
 | 
						|
        "version": "0.2",
 | 
						|
        "parallel_read_safe": True,
 | 
						|
        "parallel_write_safe": True,
 | 
						|
    }
 |