diff --git a/.wiki/Makefile b/.wiki/Makefile index 829c3ae..4fd1139 100644 --- a/.wiki/Makefile +++ b/.wiki/Makefile @@ -19,9 +19,8 @@ all: $(exports) --citeproc \ --resource-path=$(VIMWIKI_DIR)/img/ \ --lua-filter=$(VIMWIKI_DIR)/filters/html-links.lua \ - --lua-filter=$(VIMWIKI_DIR)/filters/diagram-generator.lua \ - --lua-filter=$(VIMWIKI_DIR)/filters/tikz.lua \ - --lua-filter=$(VIMWIKI_DIR)/filters/lilypond.lua \ + --lua-filter=$(VIMWIKI_DIR)/lua-filters/diagram-generator/diagram-generator.lua \ + --lua-filter=$(VIMWIKI_DIR)/lua-filters/lilypond/lilypond.lua \ --mathjax \ --extract-media=img \ --strip-comments \ diff --git a/.wiki/filters/LICENSE b/.wiki/filters/LICENSE deleted file mode 100644 index 5fe62a3..0000000 --- a/.wiki/filters/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-2021 pandoc Lua filters contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/.wiki/filters/diagram-generator.lua b/.wiki/filters/diagram-generator.lua deleted file mode 100644 index 7345de0..0000000 --- a/.wiki/filters/diagram-generator.lua +++ /dev/null @@ -1,396 +0,0 @@ ---[[ -diagram-generator – create images and figures from code blocks. - -This Lua filter is used to create images with or without captions -from code blocks. Currently PlantUML, GraphViz, Tikz, and Python -can be processed. For further details, see README.md. - -Copyright: © 2018-2020 John MacFarlane , - 2018 Florian Schätzig , - 2019 Thorsten Sommer , - 2019-2020 Albert Krewinkel -License: MIT – see LICENSE file for details -]] --- Module pandoc.system is required and was added in version 2.7.3 -PANDOC_VERSION:must_be_at_least '2.7.3' - -local system = require 'pandoc.system' -local utils = require 'pandoc.utils' -local stringify = utils.stringify -local with_temporary_directory = system.with_temporary_directory -local with_working_directory = system.with_working_directory - --- The PlantUML path. If set, uses the environment variable PLANTUML or the --- value "plantuml.jar" (local PlantUML version). In order to define a --- PlantUML version per pandoc document, use the meta data to define the key --- "plantuml_path". -local plantuml_path = os.getenv("PLANTUML") or "plantuml.jar" - --- The Inkscape path. In order to define an Inkscape version per pandoc --- document, use the meta data to define the key "inkscape_path". -local inkscape_path = os.getenv("INKSCAPE") or "inkscape" - --- The Python path. In order to define a Python version per pandoc document, --- use the meta data to define the key "python_path". -local python_path = os.getenv("PYTHON") or "python" - --- The Python environment's activate script. Can be set on a per document --- basis by using the meta data key "activatePythonPath". -local python_activate_path = os.getenv("PYTHON_ACTIVATE") - --- The Java path. In order to define a Java version per pandoc document, --- use the meta data to define the key "java_path". -local java_path = os.getenv("JAVA_HOME") -if java_path then - java_path = java_path .. package.config:sub(1,1) .. "bin" - .. package.config:sub(1,1) .. "java" -else - java_path = "java" -end - --- The dot (Graphviz) path. In order to define a dot version per pandoc --- document, use the meta data to define the key "dot_path". -local dot_path = os.getenv("DOT") or "dot" - --- The pdflatex path. In order to define a pdflatex version per pandoc --- document, use the meta data to define the key "pdflatex_path". -local pdflatex_path = os.getenv("PDFLATEX") or "pdflatex" - --- The asymptote path. There is also the metadata variable --- "asymptote_path". -local asymptote_path = os.getenv ("ASYMPTOTE") or "asy" - --- The default format is SVG i.e. vector graphics: -local filetype = "svg" -local mimetype = "image/svg+xml" - --- Check for output formats that potentially cannot use SVG --- vector graphics. In these cases, we use a different format --- such as PNG: -if FORMAT == "docx" then - filetype = "png" - mimetype = "image/png" -elseif FORMAT == "pptx" then - filetype = "png" - mimetype = "image/png" -elseif FORMAT == "rtf" then - filetype = "png" - mimetype = "image/png" -end - --- Execute the meta data table to determine the paths. This function --- must be called first to get the desired path. If one of these --- meta options was set, it gets used instead of the corresponding --- environment variable: -function Meta(meta) - plantuml_path = stringify( - meta.plantuml_path or meta.plantumlPath or plantuml_path - ) - inkscape_path = stringify( - meta.inkscape_path or meta.inkscapePath or inkscape_path - ) - python_path = stringify( - meta.python_path or meta.pythonPath or python_path - ) - python_activate_path = - meta.activate_python_path or meta.activatePythonPath or python_activate_path - python_activate_path = python_activate_path and stringify(python_activate_path) - java_path = stringify( - meta.java_path or meta.javaPath or java_path - ) - dot_path = stringify( - meta.path_dot or meta.dotPath or dot_path - ) - pdflatex_path = stringify( - meta.pdflatex_path or meta.pdflatexPath or pdflatex_path - ) - asymptote_path = stringify( - meta.asymptote_path or meta.asymptotePath or asymptote_path - ) -end - --- Call plantuml.jar with some parameters (cf. PlantUML help): -local function plantuml(puml, filetype) - return pandoc.pipe( - java_path, - {"-jar", plantuml_path, "-t" .. filetype, "-pipe", "-charset", "UTF8"}, - puml - ) -end - --- Call dot (GraphViz) in order to generate the image --- (thanks @muxueqz for this code): -local function graphviz(code, filetype) - return pandoc.pipe(dot_path, {"-T" .. filetype}, code) -end - --- --- TikZ --- - ---- LaTeX template used to compile TikZ images. Takes additional ---- packages as the first, and the actual TikZ code as the second ---- argument. -local tikz_template = [[ -\documentclass{standalone} -\usepackage{tikz} -%% begin: additional packages -%s -%% end: additional packages -\begin{document} -%s -\end{document} -]] - --- Returns a function which takes the filename of a PDF or SVG file --- and a target filename, and writes the input as the given format. --- Returns `nil` if conversion into the target format is not possible. -local function convert_with_inkscape(filetype) - -- Build the basic Inkscape command for the conversion - local inkscape_output_args - if filetype == 'png' then - inkscape_output_args = '--export-png="%s" --export-dpi=300' - elseif filetype == 'svg' then - inkscape_output_args = '--export-plain-svg="%s"' - else - return nil - end - return function (pdf_file, outfile) - local inkscape_command = string.format( - '"%s" --without-gui --file="%s" ' .. inkscape_output_args, - inkscape_path, - pdf_file, - outfile - ) - io.stderr:write(inkscape_command .. '\n') - local command_output = io.popen(inkscape_command) - -- TODO: print output when debugging. - command_output:close() - end -end - ---- Compile LaTeX with Tikz code to an image -local function tikz2image(src, filetype, additional_packages) - local convert = convert_with_inkscape(filetype) - -- Bail if there is now known way from PDF to the target format. - if not convert then - error(string.format("Don't know how to convert pdf to %s.", filetype)) - end - return with_temporary_directory("tikz2image", 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") - local outfile = file_template:format(tmpdir, filetype) - - -- Build and write the LaTeX document: - local f = io.open(tikz_file, 'w') - f:write(tikz_template:format(additional_packages or '', src)) - f:close() - - -- Execute the LaTeX compiler: - pandoc.pipe(pdflatex_path, {'-output-directory', tmpdir, tikz_file}, '') - - convert(pdf_file, outfile) - - -- Try to open and read the image: - local img_data - local r = io.open(outfile, 'rb') - if r then - img_data = r:read("*all") - r:close() - else - -- TODO: print warning - end - - return img_data - end) - end) -end - --- Run Python to generate an image: -local function py2image(code, filetype) - - -- Define the temp files: - local outfile = string.format('%s.%s', os.tmpname(), filetype) - local pyfile = os.tmpname() - - -- Replace the desired destination's file type in the Python code: - local extendedCode = string.gsub(code, "%$FORMAT%$", filetype) - - -- Replace the desired destination's path in the Python code: - extendedCode = string.gsub(extendedCode, "%$DESTINATION%$", outfile) - - -- Write the Python code: - local f = io.open(pyfile, 'w') - f:write(extendedCode) - f:close() - - -- Execute Python in the desired environment: - local pycmd = python_path .. ' ' .. pyfile - local command = python_activate_path - and python_activate_path .. ' && ' .. pycmd - or pycmd - os.execute(command) - - -- Try to open the written image: - local r = io.open(outfile, 'rb') - local imgData = nil - - -- When the image exist, read it: - if r then - imgData = r:read("*all") - r:close() - else - io.stderr:write(string.format("File '%s' could not be opened", outfile)) - error 'Could not create image from python code.' - end - - -- Delete the tmp files: - os.remove(pyfile) - os.remove(outfile) - - return imgData -end - --- --- Asymptote --- - -local function asymptote(code, filetype) - local convert - if filetype ~= 'svg' and filetype ~= 'png' then - error(string.format("Conversion to %s not implemented", filetype)) - end - return with_temporary_directory( - "asymptote", - function(tmpdir) - return with_working_directory( - tmpdir, - function () - local asy_file = "pandoc_diagram.asy" - local svg_file = "pandoc_diagram.svg" - local f = io.open(asy_file, 'w') - f:write(code) - f:close() - - pandoc.pipe(asymptote_path, {"-f", "svg", "-o", "pandoc_diagram", asy_file}, "") - - local r - if filetype == 'svg' then - r = io.open(svg_file, 'rb') - else - local png_file = "pandoc_diagram.png" - convert_with_inkscape("png")(svg_file, png_file) - r = io.open(png_file, 'rb') - end - - local img_data - if r then - img_data = r:read("*all") - r:close() - else - error("could not read asymptote result file") - end - return img_data - end) - end) -end - --- Executes each document's code block to find matching code blocks: -function CodeBlock(block) - - -- Predefine a potential image: - local fname = nil - - -- Using a table with all known generators i.e. converters: - local converters = { - plantuml = plantuml, - graphviz = graphviz, - tikz = tikz2image, - py2image = py2image, - asymptote = asymptote, - } - - -- Check if a converter exists for this block. If not, return the block - -- unchanged. - local img_converter = converters[block.classes[1]] - if not img_converter then - return nil - end - - -- Call the correct converter which belongs to the used class: - local success, img = pcall(img_converter, block.text, - filetype, block.attributes["additionalPackages"] or nil) - - -- Was ok? - if success and img then - -- Hash the figure name and content: - fname = pandoc.sha1(img) .. "." .. filetype - - -- Store the data in the media bag: - pandoc.mediabag.insert(fname, mimetype, img) - - else - - -- an error occured; img contains the error message - io.stderr:write(tostring(img)) - io.stderr:write('\n') - error 'Image conversion failed. Aborting.' - - end - - -- Case: This code block was an image e.g. PlantUML or dot/Graphviz, etc.: - if fname then - - -- Define the default caption: - local caption = {} - local enableCaption = nil - - -- If the user defines a caption, use it: - if block.attributes["caption"] then - caption = pandoc.read(block.attributes.caption).blocks[1].content - - -- This is pandoc's current hack to enforce a caption: - enableCaption = "fig:" - end - - -- Create a new image for the document's structure. Attach the user's - -- caption. Also use a hack (fig:) to enforce pandoc to create a - -- figure i.e. attach a caption to the image. - local imgObj = pandoc.Image(caption, fname, enableCaption) - - -- Now, transfer the attribute "name" from the code block to the new - -- image block. It might gets used by the figure numbering lua filter. - -- If the figure numbering gets not used, this additional attribute - -- gets ignored as well. - if block.attributes["name"] then - imgObj.attributes["name"] = block.attributes["name"] - end - - -- Transfer the identifier from the code block to the new image block - -- to enable downstream filters like pandoc-crossref. This allows a figure - -- block starting with: - -- - -- ```{#fig:pumlExample .plantuml caption="This is an image, created by **PlantUML**."} - -- - -- to be referenced as @fig:pumlExample outside of the figure. - if block.identifier then - imgObj.identifier = block.identifier - end - - -- Finally, put the image inside an empty paragraph. By returning the - -- resulting paragraph object, the source code block gets replaced by - -- the image: - return pandoc.Para{ imgObj } - end -end - --- Normally, pandoc will run the function in the built-in order Inlines -> --- Blocks -> Meta -> Pandoc. We instead want Meta -> Blocks. Thus, we must --- define our custom order: -return { - {Meta = Meta}, - {CodeBlock = CodeBlock}, -} diff --git a/.wiki/filters/lilypond.lua b/.wiki/filters/lilypond.lua deleted file mode 100644 index 0cf3eca..0000000 --- a/.wiki/filters/lilypond.lua +++ /dev/null @@ -1,154 +0,0 @@ -if PANDOC_VERSION and PANDOC_VERSION.must_be_at_least then - -- Actually, this check is redundant since `Version' objects were - -- introduced in pandoc v2.7.3, but I've left it in for clarity. - PANDOC_VERSION:must_be_at_least("2.7.3") -else - error("pandoc version >=2.7.3 is required") -end - -local OPTIONS = { - image_directory = ".", -} - -local SPECIAL_CLASSES = { - ["lilypond"] = true, - ["ly-fragment"] = true, - ["ly-norender"] = true - } - -local SPECIAL_ATTRIBUTES = { - ["ly-caption"] = true, - ["ly-name"] = true, - ["ly-resolution"] = true, - ["ly-title"] = true - } - --- pandoc.system.with_temporary_directory had a different (undocumented) --- name in the 2.7.3 release. -local with_temporary_directory = tostring(PANDOC_VERSION) == "2.7.3" - and pandoc.system.with_temp_directory - or pandoc.system.with_temporary_directory - --- This is the extra boilerplate that's added to code snippets when the --- `ly-fragment' class is present. It's adapted from what `lilypond-book' --- does. (The file `lilypond-book-preamble.ly' is placed on the include --- path as part of the default LilyPond installation.) -local function wrap_fragment(src) - return table.concat( - { - [[\include "lilypond-book-preamble.ly"]], - [[\paper { indent = 0\mm }]], - src, - }, - "\n" - ) -end - -local function generate_image(name, input, dpi) - local fullname = name .. ".png" - return fullname, with_temporary_directory( - "lilypond-lua-XXXXX", - function (tmp_dir) - return pandoc.system.with_working_directory( - tmp_dir, - function () - pandoc.pipe( - "lilypond", - { - "--silent", - "--png", dpi and "-dresolution=" .. dpi or "", - "--output=" .. name, "-" - }, - input - ) - local fh = io.open(fullname, 'rb') - local data = fh:read('*all') - fh:close() - return data - end - ) - end - ) -end - -local function process_lilypond(elem, inline) - local code = elem.text - local fragment = elem.classes:includes("ly-fragment") or inline - local input = fragment - and wrap_fragment(code) - or code - local dpi = elem.attributes["ly-resolution"] - local name = elem.attributes["ly-name"] or pandoc.sha1(code) - - local image_filename, image_data = generate_image(name, input, dpi) - local src = OPTIONS.image_directory .. '/' .. image_filename - pandoc.mediabag.insert(src, "image/png", image_data) - - local caption = elem.attributes["ly-caption"] or "Musical notation" - -- The "fig:" prefix causes this image to be rendered as a proper figure - -- in HTML ouput (this is a rather ugly pandoc feature and may be replaced - -- by something more elegant in the future). - local fudge = inline and "" or "fig:" - -- Strip newlines, indendation, etc. from the code for a more readable title. - local title = fudge .. (elem.attributes["ly-title"] - or code:gsub("%s+", " ")) - - -- Strip most of the LilyPond-related attributes from this code element, for - -- tidiness. - local classes = elem.classes:filter( - function (cls) - return not SPECIAL_CLASSES[cls] - end - ) - table.insert( - classes, - -- Add one special class for styling/manipulation purposes. - inline and "lilypond-image-inline" - or "lilypond-image-standalone" - ) - local attributes = elem.attributes - for a, t in pairs(SPECIAL_ATTRIBUTES) do - attributes[a] = nil - end - local attrs = pandoc.Attr(elem.identifier, classes, attributes) - - return pandoc.Image(caption, src, title, attrs) -end - --- Update `OPTIONS' based on the document metadata. -local function meta_transformer(md) - local ly_block = md.lilypond or {} - local dir_conf = ly_block.image_directory - OPTIONS.image_directory = dir_conf - and pandoc.utils.stringify(dir_conf) - or OPTIONS.image_directory - md.lilypond = nil - return md -end - -local function code_transformer(elem) - if elem.classes:includes("lilypond") - and not elem.classes:includes("ly-norender") then - return process_lilypond(elem, true) - else - return elem - end -end - -local function code_block_transformer(elem) - if elem.classes:includes("lilypond") - and not elem.classes:includes("ly-norender") then - -- When replacing a block element we must wrap the generated image - -- in a `Para' since `Image' is an inline element. - return pandoc.Para({process_lilypond(elem, false)}) - else - return elem - end -end - --- Make sure the metadata transformation runs first so that the code --- transformations operate with the correct options. -return { - {Meta = meta_transformer}, - {Code = code_transformer, CodeBlock = code_block_transformer}, - } diff --git a/.wiki/filters/linebreak.lua b/.wiki/filters/linebreak.lua deleted file mode 100644 index 99d82d6..0000000 --- a/.wiki/filters/linebreak.lua +++ /dev/null @@ -1,5 +0,0 @@ -function RawInline (el) - if el.format:match '^html' and el.text:match '%
' then - return pandoc.LineBreak() - end -end diff --git a/.wiki/filters/tikz.lua b/.wiki/filters/tikz.lua deleted file mode 100644 index 4c13baf..0000000 --- a/.wiki/filters/tikz.lua +++ /dev/null @@ -1,63 +0,0 @@ -local system = require 'pandoc.system' - -local tikz_doc_template = [[ -\documentclass{standalone} -\usepackage{xcolor} -\usepackage{tikz} -\begin{document} -\nopagecolor -%s -\end{document} -]] - -local function tikz2image(src, filetype, outfile) - system.with_temporary_directory('tikz2image', function (tmpdir) - system.with_working_directory(tmpdir, function() - local f = io.open('tikz.tex', 'w') - f:write(tikz_doc_template:format(src)) - f:close() - os.execute('pdflatex tikz.tex') - if filetype == 'pdf' then - os.rename('tikz.pdf', outfile) - else - os.execute('pdf2svg tikz.pdf ' .. outfile) - end - end) - end) -end - -extension_for = { - html = 'svg', - html4 = 'svg', - html5 = 'svg', - latex = 'pdf', - beamer = 'pdf' } - - local function file_exists(name) - local f = io.open(name, 'r') - if f ~= nil then - io.close(f) - return true - else - return false - end - end - - local function starts_with(start, str) - return str:sub(1, #start) == start - end - - - function RawBlock(el) - if starts_with('\\begin{tikzpicture}', el.text) then - local filetype = extension_for[FORMAT] or 'svg' - local fname = system.get_working_directory() .. '/' .. - pandoc.sha1(el.text) .. '.' .. filetype - if not file_exists(fname) then - tikz2image(el.text, filetype, fname) - end - return pandoc.Para({pandoc.Image({}, fname)}) - else - return el - end - end diff --git a/.wiki/lua-filters b/.wiki/lua-filters new file mode 160000 index 0000000..9b6f9b4 --- /dev/null +++ b/.wiki/lua-filters @@ -0,0 +1 @@ +Subproject commit 9b6f9b4bec7979d22b5cb33f366068026cfcfc78