Add wiki pandoc files (Makefile+filters)
							parent
							
								
									ea671c0be9
								
							
						
					
					
						commit
						9e8d5422e7
					
				| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
entries := $(wildcard *.md)
 | 
			
		||||
 | 
			
		||||
target=wiki
 | 
			
		||||
exports= \
 | 
			
		||||
  $(entries:.md=.html) \
 | 
			
		||||
	# $(target).pdf  \
 | 
			
		||||
 | 
			
		||||
VIMWIKI_DIR=/home/h/.wiki
 | 
			
		||||
 | 
			
		||||
all: $(exports)
 | 
			
		||||
 | 
			
		||||
%.html:%.md
 | 
			
		||||
	pandoc																										 \
 | 
			
		||||
	 -f markdown																							 \
 | 
			
		||||
	 -t html5																									 \
 | 
			
		||||
	 -c pandoc.css																						 \
 | 
			
		||||
	 --pdf-engine=xelatex																			 \
 | 
			
		||||
	 --bibliography $(VIMWIKI_DIR)/references.bib							 \
 | 
			
		||||
	 --citeproc																								 \
 | 
			
		||||
	 --lua-filter=$(VIMWIKI_DIR)/filters/html-links.lua        \
 | 
			
		||||
	 --lua-filter=$(VIMWIKI_DIR)/filters/diagram-generator.lua \
 | 
			
		||||
	 --lua-filter=$(VIMWIKI_DIR)/filters/lilypond.lua          \
 | 
			
		||||
	 --mathjax																								 \
 | 
			
		||||
	 --extract-media=diagrams																	 \
 | 
			
		||||
	 -s -o $@ $<
 | 
			
		||||
 | 
			
		||||
$(target).pdf:$(entries)
 | 
			
		||||
	pandoc \
 | 
			
		||||
		-f markdown $(entries)                       \
 | 
			
		||||
		--pdf-engine=xelatex                         \
 | 
			
		||||
		--bibliography $(VIMWIKI_DIR)/references.bib \
 | 
			
		||||
		--citeproc                                   \
 | 
			
		||||
		--table-of-contents                          \
 | 
			
		||||
		-o $@
 | 
			
		||||
 | 
			
		||||
# clean:
 | 
			
		||||
# 	rm -f *.html
 | 
			
		||||
# 	rm wiki.pdf
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,396 @@
 | 
			
		|||
--[[
 | 
			
		||||
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 <jgm@berkeley.edu>,
 | 
			
		||||
             2018 Florian Schätzig <florian@schaetzig.de>,
 | 
			
		||||
             2019 Thorsten Sommer <contact@sommer-engineering.com>,
 | 
			
		||||
             2019-2020 Albert Krewinkel <albert+pandoc@zeitkraut.de>
 | 
			
		||||
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},
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
-- https://stackoverflow.com/questions/40993488/convert-markdown-links-to-html-with-pandoc
 | 
			
		||||
function Link(el)
 | 
			
		||||
  el.target = string.gsub(el.target, "%.md", ".html")
 | 
			
		||||
  return el
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="utf-8" />
 | 
			
		||||
  <meta name="generator" content="pandoc" />
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
 | 
			
		||||
  <title>lilypond</title>
 | 
			
		||||
  <style>
 | 
			
		||||
    code{white-space: pre-wrap;}
 | 
			
		||||
    span.smallcaps{font-variant: small-caps;}
 | 
			
		||||
    span.underline{text-decoration: underline;}
 | 
			
		||||
    div.column{display: inline-block; vertical-align: top; width: 50%;}
 | 
			
		||||
    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
 | 
			
		||||
    ul.task-list{list-style: none;}
 | 
			
		||||
  </style>
 | 
			
		||||
  <link rel="stylesheet" href="pandoc.css" />
 | 
			
		||||
  <!--[if lt IE 9]>
 | 
			
		||||
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
 | 
			
		||||
  <![endif]-->
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
<p>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</p>
 | 
			
		||||
<p>local OPTIONS = { image_directory = “.” }</p>
 | 
			
		||||
<p>local SPECIAL_CLASSES = { [“lilypond”] = true, [“ly-fragment”] = true, [“ly-norender”] = true }</p>
 | 
			
		||||
<p>local SPECIAL_ATTRIBUTES = { [“ly-caption”] = true, [“ly-name”] = true, [“ly-resolution”] = true, [“ly-title”] = true }</p>
 | 
			
		||||
<p>– 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</p>
 | 
			
		||||
– This is the extra boilerplate that’s added to code snippets when the – <code>ly-fragment' class is present. It's adapted from what</code>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( { [[
 | 
			
		||||
<p>“lilypond-book-preamble.ly”]], [[]], src, }, “” ) end</p>
 | 
			
		||||
<p>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</p>
 | 
			
		||||
<p>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)</p>
 | 
			
		||||
<p>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)</p>
 | 
			
		||||
<p>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+,” " "))</p>
 | 
			
		||||
<p>– 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)</p>
 | 
			
		||||
<p>return pandoc.Image(caption, src, title, attrs) end</p>
 | 
			
		||||
<p>– 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</p>
 | 
			
		||||
<p>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</p>
 | 
			
		||||
<p>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 <code>Para' since</code>Image’ is an inline element. return pandoc.Para({process_lilypond(elem, false)}) else return elem end end</p>
 | 
			
		||||
<p>– 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}, }</p>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,154 @@
 | 
			
		|||
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},
 | 
			
		||||
       }
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
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
 | 
			
		||||
		Loading…
	
		Reference in New Issue