pax_global_header00006660000000000000000000000064146767164420014533gustar00rootroot0000000000000052 comment=09e6272ac823de5ecd98ec2205ed547d5deca203 diagram-1.2.0/000077500000000000000000000000001467671644200131375ustar00rootroot00000000000000diagram-1.2.0/.editorconfig000066400000000000000000000007621467671644200156210ustar00rootroot00000000000000# EditorConfig helps developers define and maintain consistent # coding styles between different editors and IDEs # editorconfig.org root = true [*] end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [Makefile] indent_style = tab [*.lua] indent_style = space indent_size = 2 # Code should stay below 80 characters per line. max_line_length = 80 [*.md] # Text with 60 to 66 characters per line is said to be the easiest # to read. max_line_length = 66 diagram-1.2.0/.github/000077500000000000000000000000001467671644200144775ustar00rootroot00000000000000diagram-1.2.0/.github/FUNDING.yml000066400000000000000000000000211467671644200163050ustar00rootroot00000000000000github: [tarleb] diagram-1.2.0/.github/workflows/000077500000000000000000000000001467671644200165345ustar00rootroot00000000000000diagram-1.2.0/.github/workflows/ci.yaml000066400000000000000000000113741467671644200200210ustar00rootroot00000000000000name: CI on: # Run on all pull requests that change code. pull_request: paths-ignore: - 'README.md' - LICENSE - .editorconfig # Run every time a code change is pushed. push: paths-ignore: - 'README.md' - LICENSE - .editorconfig # Test if things still work each Tuesday morning. # This way we will catch incompatible pandoc changes in a timely # manner. schedule: # At 4:27am each Tuesday - cron: '27 4 * * 2' jobs: Asymptote: runs-on: ubuntu-latest strategy: fail-fast: true matrix: pandoc: - latest container: image: pandoc/latex:${{ matrix.pandoc }}-ubuntu steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ make inkscape asymptote - name: Test run: 'make test-asymptote' GraphViz: runs-on: ubuntu-latest strategy: fail-fast: true matrix: pandoc: - latest container: image: pandoc/core:${{ matrix.pandoc }}-ubuntu steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ make graphviz - name: Test run: 'make test-dot test-no-alt-or-caption' Mermaid: runs-on: ubuntu-latest strategy: fail-fast: true matrix: pandoc: - latest container: image: pandoc/core:${{ matrix.pandoc }} env: MERMAID_BIN: /usr/local/bin/mmdc-test PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium-browser steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies ## We need a little hack to get puppeteer working in the container. run: | apk update && apk add chromium chromium-chromedriver make npm npm install -g @mermaid-js/mermaid-cli printf '{"args":["--no-sandbox","--disable-setuid-sandbox", "--disable-gpu"]}' > \ /etc/puppeteer-conf.json printf '#!/bin/sh\nmmdc -p /etc/puppeteer-conf.json $@' > $MERMAID_BIN chmod +x $MERMAID_BIN - name: Test run: 'make test-mermaid' PlantUML: runs-on: ubuntu-latest strategy: fail-fast: true matrix: pandoc: - edge - latest # The oldest version that's guaranteed to be supported - '3.0' container: image: pandoc/core:${{ matrix.pandoc }}-ubuntu steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ make plantuml - name: Test run: make test-plantuml TikZ: runs-on: ubuntu-latest strategy: fail-fast: true matrix: pandoc: - latest container: image: pandoc/latex:${{ matrix.pandoc }}-ubuntu steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | tlmgr install pgf standalone apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ make inkscape - name: Test run: 'make test-tikz' CeTZ: runs-on: ubuntu-latest strategy: fail-fast: true container: image: ghcr.io/quarto-dev/quarto:latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ ca-certificates make - name: Render run: make PANDOC=/opt/quarto/bin/tools/x86_64/pandoc test-cetz Quarto: runs-on: ubuntu-latest strategy: fail-fast: true container: image: ghcr.io/quarto-dev/quarto:latest steps: - name: Checkout uses: actions/checkout@v4 - name: Install dependencies run: | apt-get -q --no-allow-insecure-repositories update && \ apt-get install --no-install-recommends --assume-yes \ make plantuml # Quarto rendering should complete without failure, and the # resulting HTML page should contain an image. - name: Render run: quarto render test/plantuml-quarto.qmd - name: Check for image run: grep -q ' [!IMPORTANT] > This filter makes the generated images available to pandoc, but > *does not* write image files by itself. Use pandoc's > `--extract-media` to write the generated images to disk. Or, > when producing HTML, use `--embed-resources` to incorporate the > images in the output file via `data` URIs. ### Plain pandoc Pass the filter to pandoc via the `--lua-filter` (or `-L`) command line option. pandoc --lua-filter diagram.lua ... ### Quarto Users of Quarto can install this filter as an extension with quarto install extension pandoc-ext/diagram and use it by adding `diagram` to the `filters` entry in their YAML header. ``` yaml --- filters: - diagram --- ``` #### Notes on usage with Quarto Quarto comes with its own system for diagram generation that can be used for a variety of diagrams. Especially Mermaid diagram generation is much faster with Quarto's built-in diagram handling. Due to the way in which Quarto handles code blocks, *do not* add `filename` attributes to code block attribute lists. `````` markdown ``` {.tikz filename="my-graph"} % DON'T use the filename attribute on code blocks ... `````` Instead, use the "comment-pipe" syntax to define the graphic's file name. `````` markdown ``` tikz %%| filename: my-graph % This should work ok. ... ``` `````` ### R Markdown Use `pandoc_args` to invoke the filter. See the [R Markdown Cookbook](https://bookdown.org/yihui/rmarkdown-cookbook/lua-filters.html) for details. ``` yaml --- output: word_document: pandoc_args: ['--lua-filter=diagram.lua'] --- ``` Diagram types ------------- The table below lists the supported diagram drawing systems, the class that must be used for the system, and the main executable that the filter calls to generate an image from the code. The *environment variables* column lists the names of env variables that can be used to specify a specific executable. | System | code block class | executable | env variable | |-------------|-------------------|------------|-----------------| | [Asymptote] | `asymptote` | `asy` | `ASYMPTOTE_BIN` | | [GraphViz] | `dot` | `dot` | `DOT_BIN` | | [Mermaid] | `mermaid` | `mmdc` | `MERMAID_BIN` | | [PlantUML] | `plantuml` | `plantuml` | `PLANTUML_BIN` | | [Ti*k*Z] | `tikz` | `pdflatex` | `PDFLATEX_BIN` | | [cetz] | `cetz` | `typst` | `TYPST_BIN` | ### Other diagram engines The filter can be extended with local packages; see [Configuration](#configuration) below. [Asymptote]: https://asymptote.sourceforge.io/ [GraphViz]: https://www.graphviz.org/ [Mermaid]: https://mermaid.js.org/ [PlantUML]: https://plantuml.com/ [Ti*k*Z]: https://github.com/pgf-tikz/pgf [Cetz]: https://github.com/cetz-package/cetz Figure options -------------- Options can be given using the syntax pioneered by [Quarto]: ```` ``` {.dot} //| label: fig-boring //| fig-cap: "A boring Graphviz graph." digraph boring { A -> B; } ``` ```` [Quarto]: https://quarto.org/ Configuration ------------- The filter can be configured with the `diagram` metadata entry. Currently supported options: - `cache`: controls whether the images are cached. If the cache is enabled, then the images are recreated only when their code changes. This option is *disabled* by default. - `cache-dir`: Sets the directory in which the images are cached. The default is to use the `pandoc-diagram-filter` subdir of the a common caching location. This will be, in the order of preference, the value of the `XDG_CACHE_HOME` environment variable if it is set, or alternatively `%USERPROFILE%\.cache` on Windows and `$HOME/.cache` on all other platforms. Caching is disabled if none of the environment variables mentioned above have been defined. - `engine`: options for specific engines, e.g. `plantuml` or `mermaid`. The options must be nested below the engine name. Allowed settings are either `true` or `false` to enable or disable the engine, respectively, or a map of options. The available settings are: + `mime-type`: the output MIME type that should be produced with this engine. This can be used to choose a specific type, or to disable certain output formats. For example, the following disables support for PDF output in PlantUML, which can be useful when the necessary libraries are unavailable on a system: ``` yaml diagram: engine: plantuml: mime-type: application/pdf: false ``` + `line_comment_start`: the character sequence that starts a line comment; unset or change this to disable or modify the syntax of user options in the diagram code. + `execpath`: the path to the engine's executable. Use this to override the default executable name listed in the table above. Use a list to pass additional arguments to the executable. E.g., `execpath: ['xelatex' '-halt-on-error']` will use `xelatex` as the executable and pass `-halt-on-error` as the first argument. + `package`: if this option is set then the filter will try to `require` a Lua package with the given name. If the operation is successful, then the result will be used as the compiler for that diagram type. + Any other option is passed through to the engine. See the engine-specific settings below. ### Engine-specific options Some engines accept additional options. These options can either be passed globally as part of the respective `engine` entry, or locally by adding `opt-NAME` as an attribute to the diagram code block. Global options always override local options for security reasons. #### Ti*k*Z The Ti*k*Z engine accepts the `header-includes` and `additional-packages` options. Both options are added to the intermediary TeX file that is used to produce the output file. The options differ only in how string values are handled, with bare strings in `header-includes` being escaped and those in `additional-packages` being treated as TeX code. While mentioned above, it should be highlighted that the `execpath` option can be used to select a specific LaTeX engine. The default is `pdflatex`. Example: ``` yaml --- diagram: engine: tikz: execpath: lualatex header-includes: - '\usepackage{adjustbox}' - '\usetikzlibrary{arrows, shapes}' --- ``` Security -------- This filter **should not** be used with **untrusted documents**, ***unless*** local configs prevent the setting of filter options in the metadata: An attacker that can set the execpath for an engine can execute any binary on the system with the user's permissions. It is hence recommended to review any document before using it with this filter to avoid malicious and misuse of the filter. The security is improved considerably if the `diagram` metadata field is unset or set to a predefined value before this filter is called, e.g., via another filter or a defaults file. Here is an example defaults file that configures the filter such that the configs cannot be overwritten by the document. ``` yaml # file: diagram-filter.yaml filters: ['diagram.lua'] metadata: engine: # enable dot/GraphViz and PlantUML with default options dot: true plantuml: true # disable processing of asymptote and Mermaid diagrams asymptote: false mermaid: false # Use LuaLaTeX to compile TikZ, define headers tikz: execpath: lualatex additional-packages: | \usepackage{adjustbox} \usetikzlibrary{arrows, shapes} ``` Usage: pandoc -d diagram-filter ... diagram-1.2.0/_extensions/000077500000000000000000000000001467671644200154755ustar00rootroot00000000000000diagram-1.2.0/_extensions/diagram/000077500000000000000000000000001467671644200171015ustar00rootroot00000000000000diagram-1.2.0/_extensions/diagram/_extension.yaml000066400000000000000000000001721467671644200221400ustar00rootroot00000000000000title: diagram author: Albert Krewinkel version: 1.2.0 quarto-required: ">=1.3" contributes: filters: - diagram.lua diagram-1.2.0/_extensions/diagram/diagram.lua000066400000000000000000000423131467671644200212130ustar00rootroot00000000000000--[[ diagram – create images and figures from code blocks. See copyright notice in file LICENSE. ]] -- The filter uses the Figure AST element, which was added in pandoc 3. PANDOC_VERSION:must_be_at_least '3.0' local version = pandoc.types.Version '1.2.0' -- Report Lua warnings to stderr if the `warn` function is not plugged into -- pandoc's logging system. if not warn then -- fallback warn = function(...) io.stderr:write(table.concat({ ... })) end elseif PANDOC_VERSION < '3.1.4' then -- starting with pandoc 3.1.4, warnings are reported to pandoc's logging -- system, so no need to print warnings to stderr. warn '@on' end local io = require 'io' local pandoc = require 'pandoc' local system = require 'pandoc.system' local utils = require 'pandoc.utils' local List = require 'pandoc.List' local stringify = utils.stringify local with_temporary_directory = system.with_temporary_directory local with_working_directory = system.with_working_directory --- Returns a filter-specific directory in which cache files can be --- stored, or nil if no such directory is available. local function cachedir () local cache_home = os.getenv 'XDG_CACHE_HOME' if not cache_home or cache_home == '' then local user_home = system.os == 'windows' and os.getenv 'USERPROFILE' or os.getenv 'HOME' if not user_home or user_home == '' then return nil end cache_home = pandoc.path.join{user_home, '.cache'} or nil end -- Create filter cache directory return pandoc.path.join{cache_home, 'pandoc-diagram-filter'} end --- Path holding the image cache, or `nil` if the cache is not used. local image_cache = nil local mimetype_for_extension = { jpeg = 'image/jpeg', jpg = 'image/jpeg', pdf = 'application/pdf', png = 'image/png', svg = 'image/svg+xml', } local extension_for_mimetype = { ['application/pdf'] = 'pdf', ['image/jpeg'] = 'jpg', ['image/png'] = 'png', ['image/svg+xml'] = 'svg', } --- Converts a list of format specifiers to a set of MIME types. local function mime_types_set (tbl) local set = {} local mime_type for _, image_format_spec in ipairs(tbl) do mime_type = mimetype_for_extension[image_format_spec] or image_format_spec set[mime_type] = true end return set end --- Reads the contents of a file. local function read_file (filepath) local fh = io.open(filepath, 'rb') local contents = fh:read('a') fh:close() return contents end --- Writes the contents into a file at the given path. local function write_file (filepath, content) local fh = io.open(filepath, 'wb') fh:write(content) fh:close() end --- Like `pandoc.pipe`, but allows "multi word" paths: -- Supplying a list as the first argument will use the first element as -- the executable path and prepend the remaining elements to the list of -- arguments. local function pipe (command, args, input) local cmd if pandoc.utils.type(command) == 'List' then command = command:map(stringify) cmd = command:remove(1) args = command .. args else cmd = stringify(command) end return pandoc.pipe(cmd, args, input) end -- -- Diagram Engines -- -- PlantUML engine; assumes that there's a `plantuml` binary. local plantuml = { line_comment_start = [[']], mime_types = mime_types_set{'pdf', 'png', 'svg'}, compile = function (self, puml) local mime_type = self.mime_type or 'image/svg+xml' -- PlantUML format identifiers correspond to common file extensions. local format = extension_for_mimetype[mime_type] if not format then format, mime_type = 'svg', 'image/svg+xml' end local args = {'-t' .. format, "-pipe", "-charset", "UTF8"} return pipe(self.execpath or 'plantuml', args, puml), mime_type end, } --- GraphViz engine for the dot language local graphviz = { line_comment_start = '//', mime_types = mime_types_set{'jpg', 'pdf', 'png', 'svg'}, mime_type = 'image/svg+xml', compile = function (self, code) local mime_type = self.mime_type -- GraphViz format identifiers correspond to common file extensions. local format = extension_for_mimetype[mime_type] if not format then format, mime_type = 'svg', 'image/svg+xml' end return pipe(self.execpath or 'dot', {"-T"..format}, code), mime_type end, } --- Mermaid engine local mermaid = { line_comment_start = '%%', mime_types = mime_types_set{'pdf', 'png', 'svg'}, compile = function (self, code) local mime_type = self.mime_type or 'image/svg+xml' local file_extension = extension_for_mimetype[mime_type] return with_temporary_directory("diagram", function (tmpdir) return with_working_directory(tmpdir, function () local infile = 'diagram.mmd' local outfile = 'diagram.' .. file_extension write_file(infile, code) pipe( self.execpath or 'mmdc', {"--pdfFit", "--input", infile, "--output", outfile}, '' ) return read_file(outfile), mime_type end) end) end, } --- TikZ -- --- LaTeX template used to compile TikZ images. local tikz_template = pandoc.template.compile [[ \documentclass{standalone} \usepackage{tikz} $for(header-includes)$ $it$ $endfor$ $additional-packages$ \begin{document} $body$ \end{document} ]] --- The TikZ engine uses pdflatex to compile TikZ code to an image local tikz = { line_comment_start = '%%', mime_types = { ['application/pdf'] = true, }, --- Compile LaTeX with TikZ code to an image compile = function (self, src, user_opts) return with_temporary_directory("tikz", function (tmpdir) return with_working_directory(tmpdir, function () -- Define file names: local file_template = "%s/tikz-image.%s" local tikz_file = file_template:format(tmpdir, "tex") local pdf_file = file_template:format(tmpdir, "pdf") -- Treat string values as raw LaTeX local meta = { ['header-includes'] = user_opts['header-includes'], ['additional-packages'] = {pandoc.RawInline( 'latex', stringify(user_opts['additional-packages'] or '') )}, } local tex_code = pandoc.write( pandoc.Pandoc({pandoc.RawBlock('latex', src)}, meta), 'latex', {template = tikz_template} ) write_file(tikz_file, tex_code) -- Execute the LaTeX compiler: local success, result = pcall( pipe, self.execpath or 'pdflatex', { '-interaction=nonstopmode', '-output-directory', tmpdir, tikz_file }, '' ) if not success then warn(string.format( "The call\n%s\nfailed with error code %s. Output:\n%s", result.command, result.error_code, result.output )) end return read_file(pdf_file), 'application/pdf' end) end) end } --- Asymptote diagram engine local asymptote = { line_comment_start = '%%', mime_types = { ['application/pdf'] = true, }, compile = function (self, code) return with_temporary_directory("asymptote", function(tmpdir) return with_working_directory(tmpdir, function () local pdf_file = "pandoc_diagram.pdf" local args = {'-tex', 'pdflatex', "-o", "pandoc_diagram", '-'} pipe(self.execpath or 'asy', args, code) return read_file(pdf_file), 'application/pdf' end) end) end, } --- Cetz diagram engine local cetz = { line_comment_start = '%%', mime_types = mime_types_set{'jpg', 'pdf', 'png', 'svg'}, mime_type = 'image/svg+xml', compile = function (self, code) local mime_type = self.mime_type local format = extension_for_mimetype[mime_type] if not format then format, mime_type = 'svg', 'image/svg+xml' end local preamble = [[ #import "@preview/cetz:0.2.2" #set page(width: auto, height: auto, margin: .5cm) ]] local typst_code = preamble .. code return with_temporary_directory("diagram", function (tmpdir) return with_working_directory(tmpdir, function () local outfile = 'diagram.' .. format local execpath = self.execpath if not execpath and quarto and quarto.version >= '1.4' then -- fall back to the Typst exec shipped with Quarto. execpath = List{'quarto', 'typst'} end pipe( execpath or 'typst', {"compile", "-f", format, "-", outfile}, typst_code ) return read_file(outfile), mime_type end) end) end, } local default_engines = { asymptote = asymptote, dot = graphviz, mermaid = mermaid, plantuml = plantuml, tikz = tikz, cetz = cetz, } -- -- Configuration -- --- Options for the output format of the given name. local function format_options (name) local pdf2svg = name ~= 'latex' and name ~= 'context' local is_office_format = name == 'docx' or name == 'odt' -- Office formats seem to work better with PNG than with SVG. local preferred_mime_types = is_office_format and pandoc.List{'image/png', 'application/pdf'} or pandoc.List{'application/pdf', 'image/png'} -- Prefer SVG for non-PDF output formats, except for Office formats if is_office_format then preferred_mime_types:insert('image/svg+xml') elseif pdf2svg then preferred_mime_types:insert(1, 'image/svg+xml') end return { name = name, pdf2svg = pdf2svg, preferred_mime_types = preferred_mime_types, best_mime_type = function (self, supported_mime_types, requested) return self.preferred_mime_types:find_if(function (preferred) return supported_mime_types[preferred] and (not requested or (pandoc.utils.type(requested) == 'List' and requested:includes(preferred)) or (pandoc.utils.type(requested) == 'table' and requested[preferred]) or -- Assume string, Inlines, and Blocks values specify the only -- acceptable MIME type. stringify(requested) == preferred) end) end } end --- Returns a configured diagram engine. local function get_engine (name, engopts, format) local engine = default_engines[name] or select(2, pcall(require, stringify(engopts.package))) -- Sanity check if not engine then warn(PANDOC_SCRIPT_FILE, ": No such engine '", name, "'.") return nil elseif engopts == false then -- engine is disabled return nil elseif engopts == true then -- use default options return engine end local execpath = engopts.execpath or os.getenv(name:upper() .. '_BIN') local mime_type = format:best_mime_type( engine.mime_types, engopts['mime-type'] or engopts['mime-types'] ) if not mime_type then warn(PANDOC_SCRIPT_FILE, ": Cannot use ", name, " with ", format.name) return nil end return { execpath = execpath, compile = engine.compile, line_comment_start = engine.line_comment_start, mime_type = mime_type, opt = engopts or {}, } end --- Returns the diagram engine configs. local function configure (meta, format_name) local conf = meta.diagram or {} local format = format_options(format_name) meta.diagram = nil -- cache for image files if conf.cache then image_cache = conf['cache-dir'] and stringify(conf['cache-dir']) or cachedir() pandoc.system.make_directory(image_cache, true) end -- engine configs local engine = {} for name, engopts in pairs(conf.engine or default_engines) do engine[name] = get_engine(name, engopts, format) end return { engine = engine, format = format, cache = image_cache and true, image_cache = image_cache, } end -- -- Format conversion -- --- Converts a PDF to SVG. local pdf2svg = function (imgdata) local pdf_file = os.tmpname() .. '.pdf' write_file(pdf_file, imgdata) local args = { '--export-type=svg', '--export-plain-svg', '--export-filename=-', pdf_file } return pandoc.pipe('inkscape', args, ''), os.remove(pdf_file) end local function properties_from_code (code, comment_start) local props = {} local pattern = comment_start:gsub('%p', '%%%1') .. '| ' .. '([-_%w]+): ([^\n]*)\n' for key, value in code:gmatch(pattern) do if key == 'fig-cap' then props['caption'] = value else props[key] = value end end return props end local function diagram_options (cb, comment_start) local attribs = comment_start and properties_from_code(cb.text, comment_start) or {} for key, value in pairs(cb.attributes) do attribs[key] = value end local alt local caption local fig_attr = {id = cb.identifier} local filename local image_attr = {} local user_opt = {} for attr_name, value in pairs(attribs) do if attr_name == 'alt' then alt = value elseif attr_name == 'caption' then -- Read caption attribute as Markdown caption = attribs.caption and pandoc.read(attribs.caption).blocks or nil elseif attr_name == 'filename' then filename = value elseif attr_name == 'label' then fig_attr.id = value elseif attr_name == 'name' then fig_attr.name = value else -- Check for prefixed attributes local prefix, key = attr_name:match '^(%a+)%-(%a[-%w]*)$' if prefix == 'fig' then fig_attr[key] = value elseif prefix == 'image' or prefix == 'img' then image_attr[key] = value elseif prefix == 'opt' then user_opt[key] = value else -- Use as image attribute image_attr[attr_name] = value end end end return { ['alt'] = alt or (caption and pandoc.utils.blocks_to_inlines(caption)) or {}, ['caption'] = caption, ['fig-attr'] = fig_attr, ['filename'] = filename, ['image-attr'] = image_attr, ['opt'] = user_opt, } end local function get_cached_image (hash, mime_type) if not image_cache then return nil end local filename = hash .. '.' .. extension_for_mimetype[mime_type] local imgpath = pandoc.path.join{image_cache, filename} local success, imgdata = pcall(read_file, imgpath) if success then return imgdata, mime_type end return nil end local function cache_image (codeblock, imgdata, mimetype) -- do nothing if caching is disabled or not possible. if not image_cache then return end local ext = extension_for_mimetype[mimetype] local filename = pandoc.sha1(codeblock.text) .. '.' .. ext local imgpath = pandoc.path.join{image_cache, filename} write_file(imgpath, imgdata) end -- Executes each document's code block to find matching code blocks: local function code_to_figure (conf) return function (block) -- Check if a converter exists for this block. If not, return the block -- unchanged. local diagram_type = block.classes[1] if not diagram_type then return nil end local engine = conf.engine[diagram_type] if not engine then return nil end -- Unified properties. local dgr_opt = diagram_options(block, engine.line_comment_start) for optname, value in pairs(engine.opt or {}) do dgr_opt.opt[optname] = dgr_opt.opt[optname] or value end local run_pdf2svg = engine.mime_type == 'application/pdf' and conf.format.pdf2svg -- Try to retrieve the image data from the cache. local imgdata, imgtype if conf.cache then imgdata, imgtype = get_cached_image( pandoc.sha1(block.text), run_pdf2svg and 'image/svg+xml' or engine.mime_type ) end if not imgdata or not imgtype then -- No cached image; call the converter local success success, imgdata, imgtype = pcall(engine.compile, engine, block.text, dgr_opt.opt) -- Bail if an error occurred; imgdata contains the error message -- when that happens. if not success then warn(PANDOC_SCRIPT_FILE, ': ', tostring(imgdata)) return nil elseif not imgdata then warn(PANDOC_SCRIPT_FILE, ': Diagram engine returned no image data.') return nil elseif not imgtype then warn(PANDOC_SCRIPT_FILE, ': Diagram engine did not return a MIME type.') return nil end -- Convert SVG if necessary. if imgtype == 'application/pdf' and conf.format.pdf2svg then imgdata, imgtype = pdf2svg(imgdata), 'image/svg+xml' end -- If we got here, then the transformation went ok and `img` contains -- the image data. cache_image(block, imgdata, imgtype) end -- Use the block's filename attribute or create a new name by hashing the -- image content. local basename, _extension = pandoc.path.split_extension( dgr_opt.filename or pandoc.sha1(imgdata) ) local fname = basename .. '.' .. extension_for_mimetype[imgtype] -- Store the data in the media bag: pandoc.mediabag.insert(fname, imgtype, imgdata) -- Create the image object. local image = pandoc.Image(dgr_opt.alt, fname, "", dgr_opt['image-attr']) -- Create a figure if the diagram has a caption; otherwise return -- just the image. return dgr_opt.caption and pandoc.Figure( pandoc.Plain{image}, dgr_opt.caption, dgr_opt['fig-attr'] ) or pandoc.Plain{image} end end return setmetatable( {{ Pandoc = function (doc) local conf = configure(doc.meta, FORMAT) return doc:walk { CodeBlock = code_to_figure(conf), } end }}, { version = version, } ) diagram-1.2.0/diagram.lua000077700000000000000000000000001467671644200233122_extensions/diagram/diagram.luaustar00rootroot00000000000000diagram-1.2.0/sample.md000066400000000000000000000272421467671644200147510ustar00rootroot00000000000000# Diagram Generator Lua Filter ## Introduction This Lua filter is used to create images with or without captions from code blocks. Currently PlantUML, Graphviz, Ti*k*Z, Asymptote, and Python can be processed. This document also serves as a test document, which is why the subsequent test diagrams are integrated in every supported language. ## Prerequisites To be able to use this Lua filter, the respective external tools must be installed. However, it is sufficient if the tools to be used are installed. If you only want to use PlantUML, you don't need LaTeX or Python, etc. ### PlantUML To use PlantUML, you must install PlantUML itself. See the [PlantUML website](http://plantuml.com/) for more details. It should be noted that PlantUML is a Java program and therefore Java must also be installed. By default, this filter expects the plantuml.jar file to be in the working directory. Alternatively, the environment variable `PLANTUML` can be set with a path. If, for example, a specific PlantUML version is to be used per pandoc document, the `plantuml_path` meta variable can be set. Furthermore, this filter assumes that Java is located in the system or user path. This means that from any place of the system the `java` command is understood. Alternatively, the `JAVA_HOME` environment variable gets used. To use a specific Java version per pandoc document, use the `java_path` meta variable. Please notice that `JAVA_HOME` must be set to the java's home directory e.g. `c:\Program Files\Java\jre1.8.0_201\` whereas `java_path` must be set to the absolute path of `java.exe` e.g. `c:\Program Files\Java\jre1.8.0_201\bin\java.exe`. Example usage: ```{.plantuml caption="This is an image, created by **PlantUML**." width=50%} @startuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another Response @enduml ``` ### Graphviz To use Graphviz you only need to install Graphviz, as you can read on its [website](http://www.graphviz.org/). There are no other dependencies. This filter assumes that the `dot` command is located in the path and therefore can be used from any location. Alternatively, you can set the environment variable `DOT` or use the pandoc's meta variable `dot_path`. Example usage from [the Graphviz gallery](https://graphviz.gitlab.io/_pages/Gallery/directed/fsm.html): ```{.graphviz caption="This is an image, created by **Graphviz**'s dot."} digraph finite_state_machine { rankdir=LR; node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; node [shape = circle]; LR_0 -> LR_2 [ label = "SS(B)" ]; LR_0 -> LR_1 [ label = "SS(S)" ]; LR_1 -> LR_3 [ label = "S($end)" ]; LR_2 -> LR_6 [ label = "SS(b)" ]; LR_2 -> LR_5 [ label = "SS(a)" ]; LR_2 -> LR_4 [ label = "S(A)" ]; LR_5 -> LR_7 [ label = "S(b)" ]; LR_5 -> LR_5 [ label = "S(a)" ]; LR_6 -> LR_6 [ label = "S(b)" ]; LR_6 -> LR_5 [ label = "S(a)" ]; LR_7 -> LR_8 [ label = "S(b)" ]; LR_7 -> LR_5 [ label = "S(a)" ]; LR_8 -> LR_6 [ label = "S(b)" ]; LR_8 -> LR_5 [ label = "S(a)" ]; } ``` ### Ti*k*Z Ti*k*Z (cf. [Wikipedia](https://en.wikipedia.org/wiki/PGF/TikZ)) is a description language for graphics of any kind that can be used within LaTeX (cf. [Wikipedia](https://en.wikipedia.org/wiki/LaTeX)). Therefore a LaTeX system must be installed on the system. The Ti*k*Z code is embedded into a dynamic LaTeX document. This temporary document gets translated into a PDF document using LaTeX (`pdflatex`). Finally, Inkscape is used to convert the PDF file to the desired format. Note: We are using Inkscape here to use a stable solution for the convertion. Formerly ImageMagick was used instead. ImageMagick is not able to convert PDF files. Hence, it uses Ghostscript to do so, cf. [1](https://stackoverflow.com/a/6599718/2258393). Unfortunately, Ghostscript behaves unpredictable during Windows and Linux tests cases, cf. [2](https://stackoverflow.com/questions/21774561/some-pdfs-are-converted-improperly-using-imagemagick), [3](https://stackoverflow.com/questions/9064706/imagemagic-convert-command-pdf-convertion-with-bad-size-orientation), [4](https://stackoverflow.com/questions/18837093/imagemagic-renders-image-with-black-background), [5](https://stackoverflow.com/questions/37392798/pdf-to-svg-is-not-perfect), [6](https://stackoverflow.com/q/10288065/2258393), etc. By using Inkscape, we need one dependency less and get rid of unexpected Ghostscript issues. Due to this more complicated process, the use of Ti*k*Z is also more complicated overall. The process is error-prone: An insufficiently configured LaTeX installation or an insufficiently configured Inkscape installation can lead to errors. Overall, this results in the following dependencies: - Any LaTeX installation. This should be configured so that missing packages are installed automatically. This filter uses the `pdflatex` command which is available by the system's path. Alternatively, you can set the `PDFLATEX` environment variable. In case you have to use a specific LaTeX version on a pandoc document basis, you might set the `pdflatex_path` meta variable. - An installation of [Inkscape](https://inkscape.org/). It is assumed that the `inkscape` command is in the path and can be executed from any location. Alternatively, the environment variable `INKSCAPE` can be set with a path. If a specific version per pandoc document is to be used, the `inkscape_path` meta-variable can be set. In order to use additional LaTeX packages, use the optional `additionalPackages` attribute in your document, as in the example below. Example usage from [TikZ examples](http://www.texample.net/tikz/examples/parallelepiped/) by [Kjell Magne Fauske](http://www.texample.net/tikz/examples/nav1d/): ```{.tikz caption="This is an image, created by **TikZ i.e. LaTeX**." additionalPackages="\usepackage{adjustbox}"} \usetikzlibrary{arrows} \tikzstyle{int}=[draw, fill=blue!20, minimum size=2em] \tikzstyle{init} = [pin edge={to-,thin,black}] \resizebox{16cm}{!}{% \trimbox{3.5cm 0cm 0cm 0cm}{ \begin{tikzpicture}[node distance=2.5cm,auto,>=latex'] \node [int, pin={[init]above:$v_0$}] (a) {$\frac{1}{s}$}; \node (b) [left of=a,node distance=2cm, coordinate] {a}; \node [int, pin={[init]above:$p_0$}] at (0,0) (c) [right of=a] {$\frac{1}{s}$}; \node [coordinate] (end) [right of=c, node distance=2cm]{}; \path[->] (b) edge node {$a$} (a); \path[->] (a) edge node {$v$} (c); \draw[->] (c) edge node {$p$} (end) ; \end{tikzpicture} } } ``` ### Python In order to use Python to generate an diagram, your Python code must store the final image data in a temporary file with the correct format. In case you use matplotlib for a diagram, add the following line to do so: ```python plt.savefig("$DESTINATION$", dpi=300, format="$FORMAT$") ``` The placeholder `$FORMAT$` gets replace by the necessary format. Most of the time, this will be `png` or `svg`. The second placeholder, `$DESTINATION$` gets replaced by the path and file name of the destination. Both placeholders can be used as many times as you want. Example usage from the [Matplotlib examples](https://matplotlib.org/gallery/lines_bars_and_markers/cohere.html#sphx-glr-gallery-lines-bars-and-markers-cohere-py): ```{.py2image caption="This is an image, created by **Python**."} import matplotlib matplotlib.use('Agg') import sys import numpy as np import matplotlib.pyplot as plt # Fixing random state for reproducibility np.random.seed(19680801) dt = 0.01 t = np.arange(0, 30, dt) nse1 = np.random.randn(len(t)) # white noise 1 nse2 = np.random.randn(len(t)) # white noise 2 # Two signals with a coherent part at 10Hz and a random part s1 = np.sin(2 * np.pi * 10 * t) + nse1 s2 = np.sin(2 * np.pi * 10 * t) + nse2 fig, axs = plt.subplots(2, 1) axs[0].plot(t, s1, t, s2) axs[0].set_xlim(0, 2) axs[0].set_xlabel('time') axs[0].set_ylabel('s1 and s2') axs[0].grid(True) cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt) axs[1].set_ylabel('coherence') fig.tight_layout() plt.savefig("$DESTINATION$", dpi=300, format="$FORMAT$") ``` Precondition to use Python is a Python environment which contains all necessary libraries you want to use. To use, for example, the standard [Anaconda Python](https://www.anaconda.com/distribution/) environment on a Microsoft Windows system ... - set the environment variable `PYTHON` or the meta key `pythonPath` to `c:\ProgramData\Anaconda3\python.exe` - set the environment variable `PYTHON_ACTIVATE` or the meta key `activate_python_path` to `c:\ProgramData\Anaconda3\Scripts\activate.bat`. Pandoc will activate this Python environment and starts Python with your code. ## Asymptote [Asymptote](https://asymptote.sourceforge.io/) is a graphics language inspired by Metapost. To use Asymptote, you will need to install the software itself, a TeX distribution such as [TeX Live](https://www.tug.org/texlive/), and [dvisvgm](https://dvisvgm.de/), which may be included in the TeX distribution. If png output is required (such as for the `docx`, `pptx` and `rtf` output formats) Inkscape must be installed. See the Ti*k*Z section for details. Ensure that the Asymptote `asy` binary is in the path, or point the environment variable `ASYMPTOTE` or the metadata variable `asymptotePath` to the full path name. Asymptote calls the various TeX utilities and dvipdfm, so you will need to configure Asymptote so that it finds them. ```{.asymptote caption="This is an image, created by **Asymptote**."} size(5cm); include graph; pair circumcenter(pair A, pair B, pair C) { pair P, Q, R, S; P = (A+B)/2; Q = (B+C)/2; R = rotate(90, P) * A; S = rotate(90, Q) * B; return extension(P, R, Q, S); } pair incenter(pair A, pair B, pair C) { real a = abs(angle(C-A)-angle(B-A)), b = abs(angle(C-B)-angle(A-B)), c = abs(angle(A-C)-angle(B-C)); return (sin(a)*A + sin(b)*B + sin(c)*C) / (sin(a)+sin(b)+sin(c)); } real dist_A_BC(pair A, pair B, pair C) { real det = cross(B-A, C-A); return abs(det/abs(B-C)); } pair A = (0, 0), B = (5, 0), C = (3.5, 4), O = circumcenter(A, B, C), I = incenter(A, B, C); dot(A); dot(B); dot(C); dot(O, blue); dot(I, magenta); draw(A--B--C--cycle, linewidth(2)); draw(Circle(O, abs(A-O)), blue+linewidth(1.5)); draw(Circle(I, dist_A_BC(I, A, B)), magenta+linewidth(1.5)); label("$A$", A, SW); label("$B$", B, SE); label("$C$", C, NE); label("$O$", O, W); label("$I$", I, E); ``` ## How to run pandoc This section will show, how to call Pandoc in order to use this filter with meta keys. The following command assume, that the filters are stored in the subdirectory `filters`. Further, this is a example for a Microsoft Windows system. Command to use PlantUML (a single line): ``` pandoc.exe README.md -f markdown -t docx --self-contained --standalone --lua-filter=filters\diagram-generator.lua --metadata=plantumlPath:"c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar" --metadata=javaPath:"c:\Program Files\Java\jre1.8.0_201\bin\java.exe" -o README.docx ``` All available environment variables: - `PLANTUML` e.g. `c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar`; Default: `plantuml.jar` - `INKSCAPE` e.g. `c:\Program Files\Inkscape\inkscape.exe`; Default: `inkscape` - `PYTHON` e.g. `c:\ProgramData\Anaconda3\python.exe`; Default: n/a - `PYTHON_ACTIVATE` e.g. `c:\ProgramData\Anaconda3\Scripts\activate.bat`; Default: n/a - `JAVA_HOME` e.g. `c:\Program Files\Java\jre1.8.0_201`; Default: n/a - `DOT` e.g. `c:\ProgramData\chocolatey\bin\dot.exe`; Default: `dot` - `PDFLATEX` e.g. `c:\Program Files\MiKTeX 2.9\miktex\bin\x64\pdflatex.exe`; Default: `pdflatex` - `ASYMPTOTE` e.g. `c:\Program Files\Asymptote\asy`; Default: `asy` All available meta keys: - `plantuml_path` - `inkscape_path` - `python_path` - `activate_python_path` - `java_path` - `dot_path` - `pdflatex_path` - `asymptote_path` diagram-1.2.0/test/000077500000000000000000000000001467671644200141165ustar00rootroot00000000000000diagram-1.2.0/test/expected-asymptote.html000066400000000000000000000003521467671644200206300ustar00rootroot00000000000000

Asymptote

This is an image, created by Asymptote.
diagram-1.2.0/test/expected-cetz.html000066400000000000000000000006761467671644200175610ustar00rootroot00000000000000

Cetz

The image code comes from the cetz docs licensed under LGPLv3.

This is an image, created with cetz
diagram-1.2.0/test/expected-dot.html000066400000000000000000000004461467671644200173750ustar00rootroot00000000000000

Graphviz

Example usage from the Graphviz gallery:

Finite State Machine
diagram-1.2.0/test/expected-mermaid.html000066400000000000000000000003621467671644200202220ustar00rootroot00000000000000

Mermaid

Mermaid is a JavaScript-based diagramming and charting tool.

A simple flowchart.
diagram-1.2.0/test/expected-no-alt-or-caption.html000066400000000000000000000002721467671644200220470ustar00rootroot00000000000000

This simple graph has neither alt text nor a caption. It should be converted to a simple image without any description.

diagram-1.2.0/test/expected-plantuml.html000066400000000000000000000004421467671644200204370ustar00rootroot00000000000000

Authentication

This is an image, created by PlantUML.
diagram-1.2.0/test/expected-tikz.html000066400000000000000000000012741467671644200175700ustar00rootroot00000000000000

TikZ

Example usage from TikZ examples by Kjell Magne Fauske:

Tetrahedron inscribed in a parallelepiped.

Diagram showing how the delta-graph relates to the other graphs. Note that this diagram does not have a caption, so it will be rendered as a plain image instead of a figure.

Diagram showing how the delta-graph relates to the other graphs. diagram-1.2.0/test/input-asymptote.md000066400000000000000000000020411467671644200176170ustar00rootroot00000000000000## Asymptote ```{.asymptote caption="This is an image, created by **Asymptote**." filename='triangle'} size(5cm); include graph; pair circumcenter(pair A, pair B, pair C) { pair P, Q, R, S; P = (A+B)/2; Q = (B+C)/2; R = rotate(90, P) * A; S = rotate(90, Q) * B; return extension(P, R, Q, S); } pair incenter(pair A, pair B, pair C) { real a = abs(angle(C-A)-angle(B-A)), b = abs(angle(C-B)-angle(A-B)), c = abs(angle(A-C)-angle(B-C)); return (sin(a)*A + sin(b)*B + sin(c)*C) / (sin(a)+sin(b)+sin(c)); } real dist_A_BC(pair A, pair B, pair C) { real det = cross(B-A, C-A); return abs(det/abs(B-C)); } pair A = (0, 0), B = (5, 0), C = (3.5, 4), O = circumcenter(A, B, C), I = incenter(A, B, C); dot(A); dot(B); dot(C); dot(O, blue); dot(I, magenta); draw(A--B--C--cycle, linewidth(2)); draw(Circle(O, abs(A-O)), blue+linewidth(1.5)); draw(Circle(I, dist_A_BC(I, A, B)), magenta+linewidth(1.5)); label("$A$", A, SW); label("$B$", B, SE); label("$C$", C, NE); label("$O$", O, W); label("$I$", I, E); ``` diagram-1.2.0/test/input-cetz.md000066400000000000000000000036371467671644200165530ustar00rootroot00000000000000# Cetz The image [code](https://github.com/cetz-package/cetz/blob/master/gallery/karls-picture.typ) comes from the cetz docs licensed under [LGPLv3](https://github.com/cetz-package/cetz/blob/master/LICENSE). ```{.cetz caption="This is an image, created with cetz" width=90% filename=karls} //| label: fig-auth //| class: important #show math.equation: block.with(fill: white, inset: 1pt) #cetz.canvas(length: 5cm, { import cetz.draw: * set-style( mark: (fill: black, scale: 2), stroke: (thickness: 0.4pt, cap: "round"), angle: ( radius: 0.3, label-radius: .22, fill: green.lighten(80%), stroke: (paint: green.darken(50%)) ), content: (padding: 1pt) ) grid((-1.5, -1.5), (1.4, 1.4), step: 0.5, stroke: gray + 0.2pt) circle((0,0), radius: 1) line((-1.5, 0), (1.5, 0), mark: (end: "stealth")) content((), $ x $, anchor: "west") line((0, -1.5), (0, 1.5), mark: (end: "stealth")) content((), $ y $, anchor: "south") for (x, ct) in ((-1, $ -1 $), (-0.5, $ -1/2 $), (1, $ 1 $)) { line((x, 3pt), (x, -3pt)) content((), anchor: "north", ct) } for (y, ct) in ((-1, $ -1 $), (-0.5, $ -1/2 $), (0.5, $ 1/2 $), (1, $ 1 $)) { line((3pt, y), (-3pt, y)) content((), anchor: "east", ct) } // Draw the green angle cetz.angle.angle((0,0), (1,0), (1, calc.tan(30deg)), label: text(green, [#sym.alpha])) line((0,0), (1, calc.tan(30deg))) set-style(stroke: (thickness: 1.2pt)) line((30deg, 1), ((), "|-", (0,0)), stroke: (paint: red), name: "sin") content(("sin.start", 50%, "sin.end"), text(red)[$ sin alpha $]) line("sin.end", (0,0), stroke: (paint: blue), name: "cos") content(("cos.start", 50%, "cos.end"), text(blue)[$ cos alpha $], anchor: "north") line((1, 0), (1, calc.tan(30deg)), name: "tan", stroke: (paint: orange)) content("tan.end", $ text(#orange, tan alpha) = text(#red, sin alpha) / text(#blue, cos alpha) $, anchor: "west") }) ``` diagram-1.2.0/test/input-dot.md000066400000000000000000000014171467671644200163660ustar00rootroot00000000000000### Graphviz Example usage from [the Graphviz gallery](https://graphviz.gitlab.io/_pages/Gallery/directed/fsm.html): ```{.dot caption="Finite State Machine" filename="fsm"} digraph finite_state_machine { rankdir=LR; node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8; node [shape = circle]; LR_0 -> LR_2 [ label = "SS(B)" ]; LR_0 -> LR_1 [ label = "SS(S)" ]; LR_1 -> LR_3 [ label = "S($end)" ]; LR_2 -> LR_6 [ label = "SS(b)" ]; LR_2 -> LR_5 [ label = "SS(a)" ]; LR_2 -> LR_4 [ label = "S(A)" ]; LR_5 -> LR_7 [ label = "S(b)" ]; LR_5 -> LR_5 [ label = "S(a)" ]; LR_6 -> LR_6 [ label = "S(b)" ]; LR_6 -> LR_5 [ label = "S(a)" ]; LR_7 -> LR_8 [ label = "S(b)" ]; LR_7 -> LR_5 [ label = "S(a)" ]; LR_8 -> LR_6 [ label = "S(b)" ]; LR_8 -> LR_5 [ label = "S(a)" ]; } ``` diagram-1.2.0/test/input-mermaid.md000066400000000000000000000003121467671644200172070ustar00rootroot00000000000000### Mermaid Mermaid is a JavaScript-based diagramming and charting tool. ``` mermaid %%| filename: flowchart %%| fig-cap: A simple flowchart. graph TD; A-->B; A-->C; B-->D; C-->D; ``` diagram-1.2.0/test/input-no-alt-or-caption.md000066400000000000000000000002611467671644200210370ustar00rootroot00000000000000This simple graph has neither alt text nor a caption. It should be converted to a simple image without any description. ```{.dot} digraph { A -> B; B -> C; C -> A; } ``` diagram-1.2.0/test/input-plantuml.md000066400000000000000000000005041467671644200174300ustar00rootroot00000000000000# Authentication ```{.plantuml caption="This is an image, created by **PlantUML**." width=50% filename=auth} '| label: fig-auth '| class: important @startuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another Response @enduml ``` diagram-1.2.0/test/input-tikz.md000066400000000000000000000037231467671644200165630ustar00rootroot00000000000000--- diagram: cache: false engine: tikz: execpath: ['xelatex', '-halt-on-error'] header-includes: - '\usetikzlibrary{arrows, shapes}' --- ### Ti*k*Z Example usage from [TikZ examples](http://www.texample.net/tikz/examples/parallelepiped/) by [Kjell Magne Fauske](http://www.texample.net/tikz/examples/nav1d/): ```{.tikz caption="Tetrahedron inscribed in a parallelepiped." filename="parallelepiped" opt-additional-packages="\usepackage{adjustbox}"} \tikzstyle{int}=[draw, fill=blue!20, minimum size=2em] \tikzstyle{init} = [pin edge={to-,thin,black}] \resizebox{16cm}{!}{% \trimbox{3.5cm 0cm 0cm 0cm}{ \begin{tikzpicture}[node distance=2.5cm,auto,>=latex'] \node [int, pin={[init]above:$v_0$}] (a) {$\frac{1}{s}$}; \node (b) [left of=a,node distance=2cm, coordinate] {a}; \node [int, pin={[init]above:$p_0$}] at (0,0) (c) [right of=a] {$\frac{1}{s}$}; \node [coordinate] (end) [right of=c, node distance=2cm]{}; \path[->] (b) edge node {$a$} (a); \path[->] (a) edge node {$v$} (c); \draw[->] (c) edge node {$p$} (end) ; \end{tikzpicture} } } ``` Diagram showing how the delta-graph relates to the other graphs. Note that this diagram does not have a caption, so it will be rendered as a plain image instead of a figure. ``` {.tikz} %%| label: delta-graph %%| filename: delta-graph.pdf %%| alt: Diagram showing how the delta-graph relates to the other graphs. \tikzset{cat object/.style= {node distance=4em}} \begin{tikzpicture}[] \node [cat object] (Del) {$D$}; \node [cat object] (L) [below of=Del] {$X$}; \node [cat object] (I) [right of=L] {$I$}; \node [cat object] (F) [left of=L] {$F$}; \draw [->] (Del) to node [left,near end]{$\scriptstyle{d_X}$} (L); \draw [->] (I) to node [below] {$\scriptstyle{x}$} (L); \draw [->] (Del) to node [above left] {$\scriptstyle{d_{F}}$} (F); \draw [->,dashed] (Del) to node {/}(I); \end{tikzpicture} ``` diagram-1.2.0/test/plantuml-quarto.qmd000066400000000000000000000006771467671644200200000ustar00rootroot00000000000000--- title: PlantUML diagram author: Tester McTestface format: html: filters: - '../diagram.lua' diagram: cache: false --- ```{.plantuml caption="This is an image, created by **PlantUML**." width=50%} '| label: fig-auth '| class: important '| filename: auth @startuml Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response Alice -> Bob: Another authentication Request Alice <-- Bob: another Response @enduml ``` diagram-1.2.0/test/test-asymptote.yaml000066400000000000000000000002251467671644200200030ustar00rootroot00000000000000input-files: ['test/input-asymptote.md'] filters: - diagram.lua to: html metadata: pagetitle: Asymptote diagram variables: document-css: false diagram-1.2.0/test/test-cetz.yaml000066400000000000000000000002301467671644200167170ustar00rootroot00000000000000input-files: ['test/input-cetz.md'] filters: - diagram.lua to: html metadata: diagram: engine: cetz: execpath: ['quarto', 'typst']diagram-1.2.0/test/test-dot.yaml000066400000000000000000000003011467671644200165370ustar00rootroot00000000000000input-files: ['test/input-dot.md'] filters: - diagram.lua to: html metadata: pagetitle: dot diagram diagram: cache: false engine: dot: true variables: document-css: false diagram-1.2.0/test/test-mermaid.yaml000066400000000000000000000002551467671644200173770ustar00rootroot00000000000000input-files: ['test/input-mermaid.md'] filters: - diagram.lua to: html metadata: pagetitle: Mermaid diagram diagram: cache: false variables: document-css: false diagram-1.2.0/test/test-no-alt-or-caption.yaml000066400000000000000000000001661467671644200212250ustar00rootroot00000000000000input-files: ['test/input-no-alt-or-caption.md'] filters: - diagram.lua to: html metadata: pagetitle: dot diagram diagram-1.2.0/test/test-plantuml.yaml000066400000000000000000000002571467671644200176170ustar00rootroot00000000000000input-files: ['test/input-plantuml.md'] filters: - diagram.lua to: html metadata: pagetitle: plantuml diagram diagram: cache: false variables: document-css: false diagram-1.2.0/test/test-tikz.yaml000066400000000000000000000001061467671644200167350ustar00rootroot00000000000000input-files: ['test/input-tikz.md'] filters: - diagram.lua to: html