summaryrefslogtreecommitdiff
path: root/paper/lua-filters/minted
diff options
context:
space:
mode:
Diffstat (limited to 'paper/lua-filters/minted')
-rw-r--r--paper/lua-filters/minted/Makefile65
-rw-r--r--paper/lua-filters/minted/README.md316
-rwxr-xr-xpaper/lua-filters/minted/background_color.py76
-rw-r--r--paper/lua-filters/minted/minted.lua456
-rwxr-xr-xpaper/lua-filters/minted/run_minted_tests.py522
-rw-r--r--paper/lua-filters/minted/sample.md135
6 files changed, 1570 insertions, 0 deletions
diff --git a/paper/lua-filters/minted/Makefile b/paper/lua-filters/minted/Makefile
new file mode 100644
index 0000000..5d509f9
--- /dev/null
+++ b/paper/lua-filters/minted/Makefile
@@ -0,0 +1,65 @@
+.PHONY: all
+all: sample_beamer.pdf sample_latex.pdf sample.html
+
+# NOTE: `pandoc_inputs` can have multiple filenames if you want to send `pandoc`
+# more than one input file at once. In the commands for the targets that depend
+# on `pandoc_inputs` you will see a pattern `$^ > $@`. It's less magic than it
+# seems, but useful to point out if you have not seen these before. They are
+# called "Automatic Variables", and more documentation can be found here:
+#
+# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
+#
+# So by depending on $(pandoc_inputs) and using $^ as the input files to
+# `pandoc`, $^ will expand to all filenames in `pandoc_inputs` and the target
+# will re-run when the timestamp of _any_ file listed in `pandoc_inputs` is
+# updated. By redirecting the output to $@, it will send the `pandoc` output to
+# the target name. In the examples below, $@ expands to either
+# `sample_beamer.tex`, `sample_latex.tex`, or `sample.html` (depending on the
+# target name).
+#
+# TL;DR: You should be able to copy-paste the commands below and just rename the
+# target names to match whatever output filenames you want.
+pandoc_inputs := sample.md
+
+# Sample beamer presentation.
+sample_beamer.tex: $(pandoc_inputs)
+ pandoc -s -t beamer --no-highlight --lua-filter=minted.lua $^ > $@
+
+sample_beamer.pdf: sample_beamer.tex
+ latexmk -pdf -shell-escape -jobname=sample_beamer sample_beamer
+
+# Sample latex document.
+sample_latex.tex: $(pandoc_inputs)
+ pandoc -s -t latex --no-highlight --lua-filter=minted.lua $^ > $@
+
+sample_latex.pdf: sample_latex.tex
+ latexmk -pdf -shell-escape -jobname=sample_latex sample_latex
+
+# Sample html5 document.
+sample.html: $(pandoc_inputs)
+ pandoc -s -t html5 --lua-filter=minted.lua $^ > $@
+
+# ---
+
+.PHONY: clean realclean
+clean:
+ @# latexmk errors if no auxiliary files exist to cleanup. Using `|| true`
+ @# just makes it so that the subsequent commands will also execute.
+ latexmk -c sample_beamer >/dev/null 2>&1 || true
+ @# latexmk does not clean all beamer files
+ rm -f sample_beamer.{nav,snm,vrb}
+ rm -rf _minted-sample_beamer/
+ latexmk -c sample_latex >/dev/null 2>&1 || true
+ rm -rf _minted-sample_latex/
+
+realclean: clean
+ rm -f sample_beamer.{tex,pdf}
+ rm -f sample_latex.{tex,pdf}
+ rm -f sample.html
+
+.PHONY: test lint
+lint:
+ flake8 --max-line-length=80 run_minted_tests.py background_color.py
+
+test:
+ @./run_minted_tests.py
diff --git a/paper/lua-filters/minted/README.md b/paper/lua-filters/minted/README.md
new file mode 100644
index 0000000..b26491d
--- /dev/null
+++ b/paper/lua-filters/minted/README.md
@@ -0,0 +1,316 @@
+# minted
+
+This filter enables users to use the [`minted`][minted] package with the
+`beamer` and `latex` writers. Users may attach any desired `minted` specific
+styling / attributes to their code-blocks (or via document metadata). These
+`minted` specific attributes will be _removed_ for any writers that are not
+`beamer` or `latex`, since many of the `minted` options require using `latex`
+specific syntax that can cause problems in other output formats. For example,
+if the `fontsize=\footnotesize` attribute were applied to a code block, an
+`html` export would include `data-fontsize="\footnotesize"`, which may produce
+errors or more commonly be entirely meaningless for non-latex writers.
+
+The `minted` package will be used as a _replacement_ for the existing `pandoc`
+inline code and code block elements. Behind the scenes, `minted` builds on top
+of the `fancyvrb` latex package, using [pygments][pygments] to perform the
+highlighting. The `minted` package contains _many_ options for customizing
+output, users are encouraged to read / review section 5.3 of the
+[minted documentation][minted_docs]. **This filter does not make any attempts
+to validate arguments supplied to the `minted` package**. Invalid / conflicting
+arguments are a usage error.
+
+**Contents**
+
+- [Setup](#setup)
+ - [LaTeX Preamble Configuration](#latex-preamble-configuration)
+ - [PDF Compilation](#pdf-compilation)
+- [Minted Filter Settings](#minted-filter-settings)
+ - [Default Settings](#default-settings)
+ - [All Metadata Settings](#all-metadata-settings)
+ - [`no_default_autogobble`](#no_default_autogobble-boolean)
+ - [`no_mintinline`](#no_mintinline-boolean)
+ - [`default_block_language`](#default_block_language-string)
+ - [`default_inline_language`](#default_inline_language-string)
+ - [`block_attributes`](#block_attributes-list-of-strings)
+ - [`inline_attributes`](#inline_attributes-list-of-strings)
+- [Important Usage Notes](#important-usage-notes)
+- [Bonus](#bonus)
+
+# Setup
+
+## LaTeX Preamble Configuration
+
+Since this filter will emit `\mintline` commands for inline code, and
+`\begin{minted} ... \end{minted}` environments for code blocks, you must ensure
+that your document includes the `minted` package in the preamble of your
+`beamer` or `latex` document. The filter cannot accomplish this for you.
+
+**Option 1**
+
+Use the `header-includes` feature of `pandoc` (`-H` / `--include-in-header`).
+This will be injected into the preamble section of your `beamer` or `latex`
+document. The bare minimum you need in this file is
+
+```latex
+\usepackage{minted}
+```
+
+However, there are many other things you can set here (related or unrelated to
+this filter), and this is a good opportunity to perform some global setup on the
+`minted` package. Some examples:
+
+```latex
+\usepackage{minted}
+
+% Set the `style=tango` attribute for all minted blocks. Can still be overriden
+% per block (e.g., you want to change just one). Run `pygmentize -L` to see
+% all available options.
+\usemintedstyle{tango}
+
+% Depending on which pygments style you choose, comments and preprocessor
+% directives may be italic. The `tango` style is one of these. This disables
+% all italics in the `minted` environment.
+\AtBeginEnvironment{minted}{\let\itshape\relax}
+
+% This disables italics for the `\mintinline` commands.
+% Credit: https://tex.stackexchange.com/a/469702/113687
+\usepackage{xpatch}
+\xpatchcmd{\mintinline}{\begingroup}{\begingroup\let\itshape\relax}{}{}
+```
+
+The `minted` package has many options, see the
+[minted documentation][minted_docs] for more information. For example, see the
+`bgcolor` option for the `minted` package. In this "header-include" file would
+be an excellent location to `\definecolor`s that you want to use with `bgcolor`.
+
+**Option 1.5**
+
+You can also set `header-includes` in the metadata of your document. The above
+example could be set as (noting the escaped backslashes):
+
+```yaml
+colorlinks: true
+header-includes:
+ # Include the minted package, set global style, define colors, etc.
+ - "\\usepackage{minted}"
+ - "\\usemintedstyle{tango}"
+ # Prevent italics in the `minted` environment.
+ - "\\AtBeginEnvironment{minted}{\\let\\itshape\\relax}"
+ # Prevent italics in the `\mintinline` command.
+ - "\\usepackage{xpatch}"
+ - "`\\xpatchcmd{\\mintinline}{\\begingroup}{\\begingroup\\let\\itshape\\relax}{}{}`{=latex}"
+```
+
+Note on the last line calling `\xpatchcmd`, we escape the backslashes and
+additionally force `pandoc` to treat this as `latex` code by making it an inline
+`latex` code element. See [pandoc issue 2139 (comment)][pandoc_issue_2139] for
+more information.
+
+Formally, you may want to apply the ``-"`\\raw_tex`{=latex}"`` trick to all
+metadata to indicate it is `latex` specific code. However, since `pandoc`
+strips out any raw `latex` when converting to other writers, it isn't necessary.
+
+**Option 2**
+
+You can also create your own custom `beamer` or `latex` template to have much
+finer control over what is / is not included in your document. You may obtain
+a copy of the template that `pandoc` uses by default by running
+`pandoc -D beamer` or `pandoc -D latex` depending on your document type.
+
+After you have modified the template to suit your needs (including at the very
+least a `\usepackage{minted}`), specify your template file to `pandoc` using
+the `--template <path/to/template/file>` command line argument.
+
+## PDF Compilation
+
+To compile a PDF, there are two things that the `minted` package requires be
+available: an escaped shell to be able to run external commands (the
+`-shell-escape` command line flag), and the ability to create and later read
+auxiliary files (`minted` runs `pygmentize` for the highlighting).
+
+At the time of writing this, only one of these is accessible using `pandoc`
+directly. One may pass `--pdf-engine-opt=-shell-escape` to forward the
+`-shell-escape` flag to the latex engine being used. Unfortunately, though,
+the second component (related to temporary files being created) is not supported
+by `pandoc`. See [pandoc issue 4271][pandoc_issue_4271].
+
+**However**, in reality this is an minor issue that can easily be worked around.
+Instead of generating `md => pdf`, you just use `pandoc` to generate `md => tex`
+and then compile `tex => pdf` yourself. See the [sample Makefile](Makefile) for
+examples of how to execute both stages. **Furthermore**, you will notice a
+significant advantage of managing the `pdf` compilation yourself: the generated
+`minted` files are cached and unless you `make clean` (or remove them manually),
+unchanged code listings will be reused. That is, you will have faster
+compilation times :slightly_smiling_face:
+
+# Minted Filter Settings
+
+Direct control over the settings of this filter are performed by setting
+sub-keys of a `minted` metadata key for your document.
+
+## Default Settings
+
+By default, this filter
+
+1. Transforms all inline `Code` elements to `\mintinline`. This can be disabled
+ globally by setting `no_mintinline: true`.
+
+2. Transforms all `CodeBlock` elements to `\begin{minted} ... \end{minted}` raw
+ latex code. This cannot be disabled.
+
+3. Both (1) and (2) default to the `"text"` pygments lexer, meaning that inline
+ code or code blocks without a specific code class applied will receive no
+ syntax highlighting. This can be changed globally by setting
+ `default_block_language: "lexer"` or `default_inline_language: "lexer"`.
+
+4. All `CodeBlock` elements have the `autogobble` attribute applied to them,
+ which informs `minted` to trim all common preceding whitespace. This can be
+ disabled globally by setting `no_default_autogobble: true`. However, doing
+ this is **strongly discouraged**. Consider a code block nested underneath
+ a list item. Pandoc will (correctly) generate indented code, meaning you
+ will need to manually inform `minted` to `gobble=indent` where `indent` is
+ the number of spaces to trim. Note that `pandoc` may not reproduce the same
+ indentation level of the original document.
+
+## All Metadata Settings
+
+Each of the following are nested under the `minted` metadata key.
+
+### `no_default_autogobble` (boolean)
+
+By default this filter will always use `autogobble` with minted, which will
+automatically trim common preceding whitespace. This is important because
+code blocks nested under a list or other block elements _will_ have common
+preceding whitespace that you _will_ want trimmed.
+
+### `no_mintinline` (boolean)
+
+Globally prevent this filter from emitting `\mintinline` calls for inline
+Code elements, emitting `\texttt` instead. Possibly useful in saving
+compile time for large documents that do not seek to have syntax
+highlighting on inline code elements.
+
+### `default_block_language` (string)
+
+The default pygments lexer class to use for code blocks. By default this
+is `"text"`, meaning no syntax highlighting. This is a fallback value, code
+blocks that explicitly specify a lexer will not use it.
+
+### `default_inline_language` (string)
+
+Same as `default_block_language`, only for inline code (typed in single
+backticks). The default is also `"text"`, and changing is discouraged.
+
+### `block_attributes` (list of strings)
+
+Any default attributes to apply to _all_ code blocks. These may be
+overriden on a per-code-block basis. See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+### `inline_attributes` (list of strings)
+
+Any default attributes to apply to _all_ inline code. These may be
+overriden on a per-code basis. See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+[minted_docs]: http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+[minted]: https://ctan.org/pkg/minted?lang=en
+[pygments]: http://pygments.org/
+[pandoc_issue_2139]: https://github.com/jgm/pandoc/issues/2139#issuecomment-310522113
+[pandoc_issue_4271]: https://github.com/jgm/pandoc/issues/4721
+
+# Important Usage Notes
+
+Refer to the [`sample.md`](sample.md) file for some live examples of how to use
+this filter. If you execute `make` in this directory, `sample_beamer.pdf`,
+`sample_latex.pdf`, and `sample.html` will all be generated to demonstrate the
+filter in action.
+
+`pandoc` allows you to specify additional attributes on either the closing
+backtick of an inline code element, or after the third backtick of a fenced
+code block. This is done using `{curly braces}`, an example:
+
+```md
+`#include <type_traits>`{.cpp .showspaces style=bw}
+```
+
+or
+
+ ```{.cpp .showspaces style=bw}
+ #include <type_traits>
+ ```
+
+In order, these are
+
+- `.cpp`: specify the language lexer class.
+- `.showspaces`: a `minted` boolean attribute.
+- `style=bw`: a `minted` attribute that takes an argument (`bw` is a pygments
+ style, black-white, just an example).
+
+There are two rules that must not be violated:
+
+1. Any time you want to supply extra arguments to `minted` to a specific inline
+ code or code block element, **the lexer class must always be first, and
+ always be present**.
+
+ This is a limitation of the implementation of this filter.
+
+2. Observe the difference between specifying boolean attributes vs attributes
+ that take an argument. Boolean `minted` attributes **must** have a leading
+ `.`, and `minted` attributes that take an argument **may not** have a leading
+ `.`.
+
+ - **Yes**: `{.cpp .showspaces}`, **No**: `{.cpp showspaces}`
+ - **Yes**: `{.cpp style=bw}`, **No**: `{.cpp .style=bw}`
+
+ If you violate this, then `pandoc` will likely not produce an actual inline
+ `Code` or `CodeBlock` element, but instead something else (undefined).
+
+Last, but not least, you will see that the `--no-highlight` flag is used in the
+`Makefile` for the latex targets. This is added in the spirit of the filter
+being a "full replacement" for `pandoc` highlighting with `minted`. This only
+affects inline code elements that meet the following criteria:
+
+1. The inline code element has a lexer, e.g., `{.cpp}`.
+2. The inline code element can actually be parsed for that language by `pandoc`.
+
+If these two conditions are met, and you do **not** specify `--no-highlight`,
+the `pandoc` highlighting engine will take over. Users are encouraged to build
+the samples (`make` in this directory) and look at the end of the
+`Special Characters are Supported` section. If you remove `--no-highlight`,
+`make realclean`, and then `make` again, you will see that the pandoc
+highlighting engine will colorize the `auto foo = [](){};`.
+
+Simply put: if you do not want any pandoc highlighting in your LaTeX, **make
+sure you add `--no-highlight`** and it will not happen.
+
+It is advantageous for this filter to rely on this behavior, because it means
+that the filter does not need to worry about escaping special characters for
+LaTeX -- `pandoc` will do that for us. Inspect the generated `sample_*.tex`
+files (near the end) to see the difference. `--no-highlight` will produce
+`\texttt` commands, but omitting this flag will result in some `\VERB` commands
+from `pandoc`.
+
+# Bonus
+
+Included here is a simple python script to help you get the right color
+definitions for `bgcolor` with minted. Just run
+[`background_color.py`](background_color.py) with a single argument that is the
+name of the pygments style you want the `latex` background color definition for:
+
+```console
+$ ./background_color.py monokai
+Options for monokai (choose *one*):
+
+ (*) \definecolor{monokai_bg}{HTML}{272822}
+ (*) \definecolor{monokai_bg}{RGB}{39,40,34}
+ (*) \definecolor{monokai_bg}{rgb}{0.1529,0.1569,0.1333}
+ |--------/
+ |
+ +--> You can rename this too :)
+```
+
+See the contents of [`sample.md`](sample.md) (click on "View Raw" to see the
+comments in the metadata section). Notably, in order to use `\definecolor` you
+should make sure that the `xcolor` package is actually included. Comments in
+the file explain the options.
diff --git a/paper/lua-filters/minted/background_color.py b/paper/lua-filters/minted/background_color.py
new file mode 100755
index 0000000..e830db4
--- /dev/null
+++ b/paper/lua-filters/minted/background_color.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+
+r"""
+A simple script to print out the RGB ``\definecolor`` command for the background
+color of a specified pygments style name.
+"""
+
+import sys
+try:
+ from pygments.styles import get_style_by_name
+except ImportError as ie:
+ sys.stderr.write("Please install the Pygments package:\n{0}\n".format(ie))
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ # Make sure we have a style name provided.
+ if len(sys.argv) != 2:
+ sys.stderr.write("Usage: {0} <style_name>\n\n".format(sys.argv[0]))
+ sys.stderr.write(" Tip: run `pygmentize -L` to see style names.\n")
+ sys.exit(1)
+
+ # Grab the style object, error out if invalid name.
+ style_name = sys.argv[1]
+ try:
+ style = get_style_by_name(style_name)
+ except Exception as e:
+ sys.stderr.write("Unable to find {0}:\n{1}\n".format(style_name, e))
+ sys.exit(1)
+
+ # Convert the hexadecimal string into rgb.
+ background_hex = style.background_color.replace("#", "")
+ if len(background_hex) != 6:
+ sys.stderr.write("Unknown hex color: {0}\n".format(background_hex))
+ sys.exit(1)
+
+ try:
+ r = int(background_hex[0:2], 16)
+ g = int(background_hex[2:4], 16)
+ b = int(background_hex[4:6], 16)
+ except Exception as e:
+ sys.stderr.write("Unable to convert to integers:\n{0}\n".format(e))
+ sys.exit(1)
+
+ # Build out the various options for \definecolor
+ # All should be equivalent, but users may have a preference of one format
+ # over another :p
+ tex_color_name = "{0}_bg".format(style_name)
+ def_HTML = r"\definecolor{{{0}}}{{HTML}}{{{1}}}".format(
+ tex_color_name, background_hex.upper()
+ )
+ def_RGB = r"\definecolor{{{0}}}{{RGB}}{{{1}}}".format(
+ tex_color_name, "{0},{1},{2}".format(r, g, b)
+ )
+ def_rgb = r"\definecolor{{{0}}}{{rgb}}{{{1}}}".format(
+ tex_color_name,
+ ",".join(["{0:.4}".format(float(c) / 255.0) for c in [r, g, b]])
+ )
+
+ # Enumerate the options
+ print("Options for {0} (choose *one*):\n".format(style_name))
+ print(" (*) {0}".format(def_HTML))
+ print(" (*) {0}".format(def_RGB))
+ print(" (*) {0}".format(def_rgb))
+
+ # Make sure they know that `{style_name}_bg` can be changed to whatever
+ # they want to be using in their document.
+ notice = "{0}|{1}/".format(
+ len(r" (*) \definecolor{") * " ",
+ (len(tex_color_name) - 2) * "-"
+ )
+ vline = notice[0:notice.find("|")+1]
+ can_change = vline.replace("|", "+--> You can rename this too :)")
+ print(notice)
+ print(vline)
+ print(can_change)
diff --git a/paper/lua-filters/minted/minted.lua b/paper/lua-filters/minted/minted.lua
new file mode 100644
index 0000000..19f608e
--- /dev/null
+++ b/paper/lua-filters/minted/minted.lua
@@ -0,0 +1,456 @@
+--[[
+minted -- enable the minted environment for code listings in beamer and latex.
+
+MIT License
+
+Copyright (c) 2019 Stephen McDowell
+
+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.
+]]
+
+--------------------------------------------------------------------------------
+-- Quick documentation. See full documentation here: --
+-- https://github.com/pandoc/lua-filters/blob/master/minted --
+--------------------------------------------------------------------------------
+--[[
+Brief overview of metadata keys that you can use in your document:
+
+minted:
+ no_default_autogobble: <boolean>, *DISCOURAGED*
+ no_mintinline: <boolean>
+ default_block_language: <string>
+ default_inline_language: <string>
+ block_attributes: <list of strings>
+ - attr_1
+ - attr_2
+ - ...
+ inline_attributes: <list of strings>
+ - attr_1
+ - attr_2
+ - ...
+
+In words, underneath the `minted` metadata key, you have the following options:
+
+### `no_default_autogobble` (boolean)
+
+By default this filter will always use `autogobble` with minted, which will
+automatically trim common preceding whitespace. This is important because
+code blocks nested under a list or other block elements _will_ have common
+preceding whitespace that you _will_ want trimmed.
+
+### `no_mintinline` (boolean)
+
+Globally prevent this filter from emitting `\mintinline` calls for inline
+Code elements, emitting `\texttt` instead. Possibly useful in saving
+compile time for large documents that do not seek to have syntax
+highlighting on inline code elements.
+
+### `default_block_language` (string)
+
+The default pygments lexer class to use for code blocks. By default this
+is `"text"`, meaning no syntax highlighting. This is a fallback value, code
+blocks that explicitly specify a lexer will not use it.
+
+### `default_inline_language` (string)
+
+Same as `default_block_language`, only for inline code (typed in single
+backticks). The default is also `"text"`, and changing is discouraged.
+
+### `block_attributes` (list of strings)
+
+Any default attributes to apply to _all_ code blocks. These may be
+overriden on a per-code-block basis. See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+### `inline_attributes` (list of strings)
+
+Any default attributes to apply to _all_ inline code. These may be
+overriden on a per-code basis. See section 5.3 of the
+[minted documentation][minted_docs] for available options.
+
+[minted_docs]: http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+]]
+
+local List = require('pandoc.List')
+
+--------------------------------------------------------------------------------
+-- Potential metadata elements to override. --
+--------------------------------------------------------------------------------
+local minted_no_mintinline = false
+local minted_default_block_language = "text"
+local minted_default_inline_language = "text"
+local minted_block_attributes = {}
+local minted_inline_attributes = {}
+
+--------------------------------------------------------------------------------
+-- Constants used to differentiate Code and CodeBlock elements. --
+--------------------------------------------------------------------------------
+local MintedInline = 0
+local MintedBlock = 1
+
+--------------------------------------------------------------------------------
+-- Utility functions. --
+--------------------------------------------------------------------------------
+-- Return the string lexer class to be used with minted. `elem` should be
+-- either a Code or CodeBlock element (whose `classes` list will be inspected
+-- first). `kind` is assumed to be either `MintedInline` or `MintedBlock` in
+-- order to choose the appropriate fallback lexer when unspecified.
+local function minted_language(elem, kind)
+ -- If the code [block] attached classes, we assume the first one is the
+ -- lexer class to use.
+ if #elem.classes > 0 then
+ return elem.classes[1]
+ end
+ -- Allow user-level metadata to override the inline language.
+ if kind == MintedInline then
+ return minted_default_inline_language
+ end
+ -- Allow user-level metadata to override the block language.
+ if kind == MintedBlock then
+ return minted_default_block_language
+ end
+
+ -- Failsafe, should not hit here unless function called incorrectly.
+ return "text"
+end
+
+-- Returns a boolean specifying whether or not the specified string `cls` is an
+-- option that is supported by the minted package.
+local function is_minted_class(cls)
+ -- Section 5.3 Available Options of Minted documentation. Note that many of
+ -- these do not apply to \mintinline (inline Code). Users are responsible
+ -- for supplying valid arguments to minted. For example, specifying
+ -- `autogobble` and `gobble` at the same time is a usage error.
+ --
+ -- http://mirrors.ctan.org/macros/latex/contrib/minted/minted.pdf
+ local all_minted_options = List:new{
+ "autogobble", "baselinestretch", "beameroverlays", "breakafter",
+ "breakaftergroup", "breakaftersymbolpre", "breakaftersymbolpost",
+ "breakanywhere", "breakanywheresymbolpre", "breakanywheresymbolpost",
+ "breakautoindent", "breakbefore", "breakbeforegroup",
+ "breakbeforesymbolpre", "breakbeforesymbolpost", "breakbytoken",
+ "breakbytokenanywhere", "breakindent", "breakindentnchars", "breaklines",
+ "breaksymbol", "breaksymbolleft", "breaksymbolright", "breaksymbolindent",
+ "breaksymbolindentnchars", "breaksymbolindentleft",
+ "breaksymbolindentleftnchars", "breaksymbolindentright",
+ "breaksymbolindentrightnchars", "breaksymbolsep", "breaksymbolsepnchars",
+ "breaksymbolsepleft", "breaksymbolsepleftnchars", "breaksymbolsepright",
+ "breaksymbolseprightnchars", "bgcolor", "codetagify", "curlyquotes",
+ "encoding", "escapeinside", "firstline", "firstnumber", "fontfamily",
+ "fontseries", "fontsize", "fontshape", "formatcom", "frame", "framerule",
+ "framesep", "funcnamehighlighting", "gobble", "highlightcolor",
+ "highlightlines", "keywordcase", "label", "labelposition", "lastline",
+ "linenos", "numberfirstline", "numbers", "mathescape", "numberblanklines",
+ "numbersep", "obeytabs", "outencoding", "python3", "resetmargins",
+ "rulecolor", "samepage", "showspaces", "showtabs", "space", "spacecolor",
+ "startinline", "style", "stepnumber", "stepnumberfromfirst",
+ "stepnumberoffsetvalues", "stripall", "stripnl", "tab", "tabcolor",
+ "tabsize", "texcl", "texcomments", "xleftmargin", "xrightmargin"
+ }
+ return all_minted_options:includes(cls, 0)
+end
+
+-- Return a string for the minted attributes `\begin{minted}[attributes]` or
+-- `\mintinline[attributes]`. Attributes are acquired by inspecting the
+-- specified element's `classes` and `attr` fields. Any global attributes
+-- provided in the document metadata will be included _only_ if they do not
+-- override the element-level attributes.
+--
+-- `elem` should either be a Code or CodeBlock element, and `kind` is assumed to
+-- be either `MintedInline` or `MintedBlock`. The `kind` determines which
+-- global default attribute list to use.
+local function minted_attributes(elem, kind)
+ -- The full listing of attributes that will be joined and returned.
+ local minted_attributes = {}
+
+ -- Book-keeping, track xxx=yyy keys `xxx` that have been added to
+ -- `minted_attributes` to make checking optional global defaults via the
+ -- `block_attributes` or `inline_attributes` easier.
+ local minted_keys = {}
+
+ -- Boolean style options for minted (e.g., ```{.bash .autogobble}) will appear
+ -- in the list of classes.
+ for _, cls in ipairs(elem.classes) do
+ if is_minted_class(cls) then
+ table.insert(minted_attributes, cls)
+ table.insert(minted_keys, cls)
+ end
+ end
+
+ -- Value options using key=value (e.g., ```{.bash fontsize=\scriptsize}) show
+ -- up in the list of attributes.
+ for _, attr in ipairs(elem.attributes) do
+ cls, value = attr[1], attr[2]
+ if is_minted_class(cls) then
+ table.insert(minted_attributes, cls .. "=" .. value)
+ table.insert(minted_keys, cls)
+ end
+ end
+
+ -- Add any global defaults _only_ if they do not conflict. Note that conflict
+ -- is only in the literal sense. If a user has `autogobble` and `gobble=2`
+ -- specified, these do conflict in the minted sense, but this filter makes no
+ -- checks on validity ;)
+ local global_defaults = nil
+ if kind == MintedInline then
+ global_defaults = minted_inline_attributes
+ elseif kind == MintedBlock then
+ global_defaults = minted_block_attributes
+ end
+ for _, global_attr in ipairs(global_defaults) do
+ -- Either use the index of `=` minus one, or -1 if no `=` present. Fallback
+ -- on -1 means that the substring is the original string.
+ local end_idx = (string.find(global_attr, "=") or 0) - 1
+ local global_key = string.sub(global_attr, 1, end_idx)
+ local can_insert_global = true
+ for _, existing_key in ipairs(minted_keys) do
+ if existing_key == global_key then
+ can_insert_global = false
+ break
+ end
+ end
+
+ if can_insert_global then
+ table.insert(minted_attributes, global_attr)
+ end
+ end
+
+ -- Return a comma delimited string for specifying the attributes to minted.
+ return table.concat(minted_attributes, ",")
+end
+
+-- Return the specified `elem` with any minted data removed from the `classes`
+-- and `attr`. Otherwise writers such as the HTML writer might produce invalid
+-- code since latex makes heavy use of the \backslash.
+local function remove_minted_attibutes(elem)
+ -- Remove any minted items from the classes.
+ classes = {}
+ for _, cls in ipairs(elem.classes) do
+ if not is_minted_class(cls) and cls ~= "no_minted" then
+ table.insert(classes, cls)
+ end
+ end
+ elem.classes = classes
+
+ -- Remove any minted items from the attributes.
+ extra_attrs = {}
+ for _, attr in ipairs(elem.attributes) do
+ cls, value = attr[1], attr[2]
+ if not is_minted_class(cls) then
+ table.insert(extra_attrs, {cls, value})
+ end
+ end
+ elem.attributes = extra_attrs
+
+ -- Return the (potentially modified) element for pandoc to take over.
+ return elem
+end
+
+-- Return a `start_delim` and `end_delim` that can safely wrap around the
+-- specified `text` when used inline. If no special characters occur in `text`,
+-- then a pair of braces are returned. Otherwise, if any character of
+-- `possible_delims` are not in `text`, then it is returned. If no delimiter
+-- could be found, an error is raised.
+local function minted_inline_delims(text)
+ local start_delim, end_delim
+ if text:find('[{}]') then
+ -- Try some other delimiter (the alphanumeric digits are in Python's
+ -- string.digits + string.ascii_letters order)
+ possible_delims = ('|!@#^&*-=+' .. '0123456789' ..
+ 'abcdefghijklmnopqrstuvwxyz' ..
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')
+ for char in possible_delims:gmatch('.') do
+ if not text:find(char, 1, true) then
+ start_delim = char
+ end_delim = char
+ break
+ end
+ end
+ if not start_delim then
+ local msg = 'Unable to determine delimiter to use around inline code %q'
+ error(msg:format(text))
+ end
+ else
+ start_delim = '{'
+ end_delim = '}'
+ end
+
+ return start_delim, end_delim
+end
+
+--------------------------------------------------------------------------------
+-- Pandoc overrides. --
+--------------------------------------------------------------------------------
+-- Override the pandoc Meta function so that we can parse the metadata for the
+-- document and store the necessary variables locally to use in other functions
+-- such as Code and CodeBlock (helper methods).
+function Meta(m)
+ -- Grab the `minted` metadata, quit early if not present.
+ local minted = m["minted"]
+ local found_autogobble = false
+ local always_autogobble = true
+ if minted ~= nil then
+ -- Parse and set the global bypass to turn off all \mintinline calls.
+ local no_mintinline = minted["no_mintinline"]
+ if no_mintinline ~= nil then
+ minted_no_mintinline = no_mintinline
+ end
+
+ -- Parse and set the default block language.
+ local default_block_language = minted.default_block_language
+ and pandoc.utils.stringify(minted.default_block_language)
+ if default_block_language ~= nil then
+ minted_default_block_language = default_block_language
+ end
+
+ -- Parse and set the default inline language.
+ local default_inline_language = minted.default_inline_language
+ and pandoc.utils.stringify(minted.default_inline_language)
+ if default_inline_language ~= nil then
+ minted_default_inline_language = default_inline_language
+ end
+
+ -- Parse the global default minted attributes to use on every block.
+ local block_attributes = minted["block_attributes"]
+ if block_attributes ~= nil then
+ for _, attr in ipairs(block_attributes) do
+ if attr == "autogobble" then
+ found_autogobble = true
+ end
+ table.insert(minted_block_attributes, attr[1].text)
+ end
+ end
+
+ -- Allow users to turn off autogobble for blocks, but really they should not
+ -- ever seek to do this (indented code blocks under list for example).
+ local no_default_autogobble = minted["no_default_autogobble"]
+ if no_default_autogobble ~= nil then
+ always_autogobble = not no_default_autogobble
+ end
+
+ -- Parse the global default minted attributes to use on ever inline.
+ local inline_attributes = minted["inline_attributes"]
+ if inline_attributes ~= nil then
+ for _, attr in ipairs(inline_attributes) do
+ table.insert(minted_inline_attributes, attr[1].text)
+ end
+ end
+ end
+
+ -- Make sure autogobble is turned on by default if no `minted` meta key is
+ -- provided for the document.
+ if always_autogobble and not found_autogobble then
+ table.insert(minted_block_attributes, "autogobble")
+ end
+
+ -- Return the metadata to pandoc (unchanged).
+ return m
+end
+
+-- Override inline code elements to use \mintinline for beamer / latex writers.
+-- Other writers have all minted attributes removed.
+function Code(elem)
+ if FORMAT == "beamer" or FORMAT == "latex" then
+ -- Allow a bypass to turn off \mintinline via adding .no_minted class.
+ local found_no_minted_class = false
+ for _, cls in ipairs(elem.classes) do
+ if cls == "no_minted" then
+ found_no_minted_class = true
+ break
+ end
+ end
+
+ -- Check for local or global bypass to turn off \mintinline
+ if minted_no_mintinline or found_no_minted_class then
+ return nil -- Return `nil` signals to `pandoc` that elem is not changed.
+ end
+
+ local start_delim, end_delim = minted_inline_delims(elem.text)
+ local language = minted_language(elem, MintedInline)
+ local attributes = minted_attributes(elem, MintedInline)
+ local raw_minted = string.format(
+ "\\mintinline[%s]{%s}%s%s%s",
+ attributes,
+ language,
+ start_delim,
+ elem.text,
+ end_delim
+ )
+ -- NOTE: prior to pandoc commit 24a0d61, `beamer` cannot be used as the
+ -- RawBlock format. Using `latex` should not cause any problems.
+ return pandoc.RawInline("latex", raw_minted)
+ else
+ return remove_minted_attibutes(elem)
+ end
+end
+
+-- Override code blocks to use \begin{minted}...\end{minted} for beamer / latex
+-- writers. Other writers have all minted attributes removed.
+function CodeBlock(block)
+ if FORMAT == "beamer" or FORMAT == "latex" then
+ local language = minted_language(block, MintedBlock)
+ local attributes = minted_attributes(block, MintedBlock)
+ local raw_minted = string.format(
+ "\\begin{minted}[%s]{%s}\n%s\n\\end{minted}",
+ attributes,
+ language,
+ block.text
+ )
+ -- NOTE: prior to pandoc commit 24a0d61, `beamer` cannot be used as the
+ -- RawBlock format. Using `latex` should not cause any problems.
+ return pandoc.RawBlock("latex", raw_minted)
+ else
+ return remove_minted_attibutes(block)
+ end
+end
+
+-- Override headers to make all beamer frames fragile, since any minted
+-- environments or \mintinline invocations will halt compilation if the frame
+-- is not marked as fragile.
+function Header(elem)
+ if FORMAT == 'beamer' then
+ -- Check first that 'fragile' is not already present.
+ local has_fragile = false
+ for _, val in ipairs(elem.classes) do
+ if val == 'fragile' then
+ has_fragile = true
+ break
+ end
+ end
+
+ -- If not found, add fragile to the list of classes.
+ if not has_fragile then
+ table.insert(elem.classes, 'fragile')
+ end
+
+ -- NOTE: pass the remaining work to pandoc, noting that 2.5 and below
+ -- may duplicate the 'fragile' specifier. Duplicated fragile does *not*
+ -- cause compile errors.
+ return elem
+ end
+end
+
+-- NOTE: order of return matters, Meta needs to be first otherwise the metadata
+-- from the document will not be loaded _first_.
+return {
+ {Meta = Meta},
+ {Code = Code},
+ {CodeBlock = CodeBlock},
+ {Header = Header}
+}
diff --git a/paper/lua-filters/minted/run_minted_tests.py b/paper/lua-filters/minted/run_minted_tests.py
new file mode 100755
index 0000000..15803da
--- /dev/null
+++ b/paper/lua-filters/minted/run_minted_tests.py
@@ -0,0 +1,522 @@
+#!/usr/bin/env python
+
+"""
+Unit tests for the pandoc minted.lua filter.
+"""
+
+# Lint this file with: flake8 --max-line-length=80
+import os
+import string
+import subprocess
+import sys
+import textwrap
+
+code_block = textwrap.dedent('''
+ ## A Code Block
+
+ ```{.cpp}
+ auto mult = []<typename T, typename U>(T const & x, U const & y) {
+ return x * y;
+ };
+ ```
+''')
+"""
+The base CodeBlock code. {.cpp} is used as a replacement marker in most tests!
+"""
+
+inline_delims = '|!@#^&*-=+' + string.digits + string.ascii_letters
+inline_code = textwrap.dedent('''
+ ## Inline Code
+
+ `#include <type_traits>`{.cpp}
+ C and C++ use `{` and `}` to delimit scopes.
+ Some other special characters:
+ These check bypass: `~!@#$%^&*()-=_+[]\\{}|;\':",./<>?`
+ These check regular inline: ''' + ' '.join(
+ '`{' + inline_delims[:i] + '`' for i in range(len(inline_delims))
+))
+"""
+The base Code code. {.cpp} is used as a replacement marker in most tests!
+"""
+
+
+def run_pandoc(pandoc_args, stdin):
+ """Run pandoc with the specified arguments, returning the output."""
+ # The input / output should be small enough for these tests that buffer
+ # overflows should not happen.
+ pandoc_proc = subprocess.Popen(
+ ["pandoc"] + pandoc_args,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE
+ )
+
+ # Python 3.x and later require communicating with bytes.
+ if sys.version_info[0] >= 3:
+ stdin = bytes(stdin, "utf-8")
+
+ stdout, stderr = pandoc_proc.communicate(input=stdin)
+ if pandoc_proc.returncode != 0:
+ sys.stderr.write("Non-zero exit code of {ret} from pandoc!\n".format(
+ ret=pandoc_proc.returncode
+ ))
+ sys.stderr.write("pandoc stderr: {stderr}".format(
+ stderr=stderr.decode("utf-8")
+ ))
+ sys.exit(1)
+
+ return stdout.decode("utf-8")
+
+
+def fail_test(test_name, messages, ansi_color_code="31"):
+ """
+ Print failure message and ``sys.exit(1)``.
+
+ ``test_name`` (str)
+ The name of the test (to make finding in code easier).
+
+ ``messages`` (list of str -- or -- str)
+ A single string, or list of strings, to print out to ``stderr`` that
+ explain the reason for the test failure.
+
+ ``ansi_color_code`` (str)
+ A an ANSI color code to use to colorize the failure message :) Default
+ is ``"31"``, which is red.
+ """
+ sys.stderr.write(
+ "\033[0;{ansi_color_code}mTest {test_name} FAILED\033[0m\n".format(
+ ansi_color_code=ansi_color_code, test_name=test_name
+ )
+ )
+ if isinstance(messages, list):
+ for m in messages:
+ sys.stderr.write("--> {m}\n".format(m=m))
+ else:
+ sys.stderr.write("--> {messages}\n".format(messages=messages))
+ sys.exit(1)
+
+
+def ensure_fragile(test_name, pandoc_output):
+ r"""
+ Ensure that every \begin{frame} has (at least one) fragile.
+
+ ``test_name`` (str)
+ The name of the test (forwards to ``fail_test``).
+
+ ``pandoc_output`` (str)
+ The pandoc output for the test case.
+ """
+ for line in pandoc_output.splitlines():
+ if r"\begin{frame}" in line:
+ if "fragile" not in line:
+ fail_test(
+ test_name,
+ r"\begin{frame} without 'fragile': {line}".format(line=line)
+ )
+
+
+def ensure_present(test_name, string, pandoc_output):
+ """
+ Assert that ``string`` is found in ``pandoc_output``.
+
+ ``test_name`` (str)
+ The name of the test (forwards to ``fail_test``).
+
+ ``string`` (str)
+ The string to check verbatim ``string in pandoc_output``.
+
+ ``pandoc_output`` (str)
+ The pandoc output for the test case.
+ """
+ if string not in pandoc_output:
+ fail_test(
+ test_name,
+ "The requested string '{string}' was not found in:\n{pout}".format(
+ string=string, pout=pandoc_output
+ )
+ )
+
+
+def ensure_not_present(test_name, string, pandoc_output):
+ """
+ Assert that ``string`` is **not** found in ``pandoc_output``.
+
+ ``test_name`` (str)
+ The name of the test (forwards to ``fail_test``).
+
+ ``string`` (str)
+ The string to check verbatim ``string not in pandoc_output``.
+
+ ``pandoc_output`` (str)
+ The pandoc output for the test case.
+ """
+ if string in pandoc_output:
+ fail_test(
+ test_name,
+ "The forbidden string '{string}' was found in:\n{pout}".format(
+ string=string, pout=pandoc_output
+ )
+ )
+
+
+def run_tex_tests(pandoc_args, fmt):
+ """
+ Run same tests for latex writers.
+
+ ``pandoc_args`` (list of str)
+ The base list of arguments to forward to pandoc. Some tests may remove
+ the ``--no-highlight`` flag to validate whether or not pandoc
+ highlighting macros appear as expected (or not at all).
+
+ ``fmt`` (str)
+ The format is assumed to be either 'latex' or 'beamer'.
+ """
+ def verify(test_name, args, md, *strings):
+ """Run pandoc, ensure fragile, and string in output."""
+ output = run_pandoc(args + ["-t", fmt], md)
+ if fmt == "beamer":
+ ensure_fragile(test_name, output)
+ else: # latex writer
+ ensure_not_present(test_name, "fragile", output)
+ for s in strings:
+ ensure_present(test_name, s, output)
+ # Make sure the pandoc highlighting is not being used
+ if "--no-highlight" in args:
+ ensure_not_present(test_name, r"\VERB", output)
+ # if `nil` is present, that likely means a problem parsing the metadata
+ ensure_not_present(test_name, "nil", output)
+
+ ############################################################################
+ # CodeBlock tests. #
+ ############################################################################
+ begin_minted = r"\begin{{minted}}[{attrs}]{{{lang}}}"
+ verify(
+ "[code-block] default",
+ pandoc_args,
+ code_block,
+ begin_minted.format(attrs="autogobble", lang="cpp")
+ )
+ verify(
+ "[code-block] no_default_autogobble",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ no_default_autogobble: true
+ ---
+ {code_block}
+ ''').format(code_block=code_block),
+ begin_minted.format(attrs="", lang="cpp")
+ )
+ verify(
+ "[code-block] default block language is 'text'",
+ pandoc_args,
+ code_block.replace("{.cpp}", ""),
+ begin_minted.format(attrs="autogobble", lang="text")
+ )
+ verify(
+ "[code-block] user provided default_block_language",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ default_block_language: "haskell"
+ ---
+ {code_block}
+ ''').format(code_block=code_block.replace("{.cpp}", "")),
+ begin_minted.format(attrs="autogobble", lang="haskell")
+ )
+ verify(
+ "[code-block] user provided block_attributes",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ block_attributes:
+ - "showspaces"
+ - "space=."
+ ---
+ {code_block}
+ ''').format(code_block=code_block),
+ begin_minted.format(
+ attrs=",".join(["showspaces", "space=.", "autogobble"]),
+ lang="cpp"
+ )
+ )
+ verify(
+ "[code-block] user provided block_attributes and no_default_autogobble",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ no_default_autogobble: true
+ block_attributes:
+ - "style=monokai"
+ - "bgcolor=monokai_bg"
+ ---
+ {code_block}
+ ''').format(code_block=code_block),
+ begin_minted.format(
+ attrs=",".join(["style=monokai", "bgcolor=monokai_bg"]), lang="cpp"
+ )
+ )
+ verify(
+ "[code-block] attributes on code block",
+ pandoc_args,
+ code_block.replace(
+ "{.cpp}", "{.cpp .showspaces bgcolor=tango_bg style=tango}"
+ ),
+ begin_minted.format(
+ attrs=",".join([
+ "showspaces", "bgcolor=tango_bg", "style=tango", "autogobble"
+ ]),
+ lang="cpp"
+ )
+ )
+ verify(
+ "[code-block] attributes on code block + user block_attributes",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ block_attributes:
+ - "showspaces"
+ - "space=."
+ ---
+ {code_block}
+ ''').format(
+ code_block=code_block.replace(
+ "{.cpp}", "{.cpp bgcolor=tango_bg style=tango}"
+ )
+ ),
+ begin_minted.format(
+ attrs=",".join([
+ "bgcolor=tango_bg",
+ "style=tango",
+ "showspaces",
+ "space=.",
+ "autogobble"
+ ]),
+ lang="cpp"
+ )
+ )
+ verify(
+ "[code-block] traditional fenced code block",
+ pandoc_args,
+ code_block.replace("{.cpp}", "cpp"),
+ begin_minted.format(attrs="autogobble", lang="cpp")
+ )
+ verify(
+ "[code-block] non-minted attributes not forwarded",
+ pandoc_args,
+ code_block.replace("{.cpp}", "{.cpp .showspaces .hello}"),
+ begin_minted.format(
+ attrs=",".join(["showspaces", "autogobble"]), lang="cpp"
+ )
+ )
+
+ ############################################################################
+ # Inline Code tests. #
+ ############################################################################
+ mintinline = r"\mintinline[{attrs}]{{{lang}}}"
+ verify(
+ "[inline-code] default",
+ pandoc_args,
+ inline_code,
+ mintinline.format(attrs="", lang="cpp"),
+ "|{|",
+ "|}|",
+ *[
+ delim + '{' + inline_delims[:i] + delim
+ for i, delim in enumerate(inline_delims)
+ ]
+ )
+ verify(
+ "[inline-code] default language is text",
+ pandoc_args,
+ inline_code,
+ mintinline.format(attrs="", lang="text"),
+ "|{|",
+ "|}|"
+ )
+ # begin: global no_mintinline shared testing with / without --no-highlight
+ inline_no_mintinline_globally_md = textwrap.dedent('''
+ ---
+ minted:
+ no_mintinline: true
+ ---
+ {inline_code}
+ ''').format(inline_code=inline_code)
+ inline_no_mintinline_globally_strings = [
+ r"\texttt{\{}",
+ r"\texttt{\}}",
+ (r"\texttt{" +
+ r"\textasciitilde{}!@\#\$\%\^{}\&*()-=\_+{[}{]}\textbackslash{}\{\}" +
+ r"""\textbar{};\textquotesingle{}:",./\textless{}\textgreater{}?}""")
+ ]
+ verify(
+ "[inline-code] no_mintinline off globally",
+ pandoc_args,
+ inline_no_mintinline_globally_md,
+ r"\texttt{\#include\ \textless{}type\_traits\textgreater{}}",
+ *inline_no_mintinline_globally_strings
+ )
+ verify(
+ "[inline-code] no_mintinline off globally, remove --no-highlight",
+ [arg for arg in pandoc_args if arg != "--no-highlight"],
+ inline_no_mintinline_globally_md,
+ r"\VERB|\PreprocessorTok{#include }\ImportTok{<type_traits>}|",
+ *inline_no_mintinline_globally_strings
+ )
+ # end: global no_mintinline shared testing with / without --no-highlight
+ # begin: no_minted shared testing with / without --no-highlight
+ inline_no_minted_md = inline_code.replace("{.cpp}", "{.cpp .no_minted}")
+ inline_no_minted_strings = ["|{|", "|}|"]
+ verify(
+ "[inline-code] .no_minted on single inline Code",
+ pandoc_args,
+ inline_no_minted_md,
+ r"texttt{\#include\ \textless{}type\_traits\textgreater{}}",
+ *inline_no_minted_strings
+ )
+ verify(
+ "[inline-code] .no_minted on single inline Code, remove --no-highlight",
+ [arg for arg in pandoc_args if arg != "--no-highlight"],
+ inline_no_minted_md,
+ r"\VERB|\PreprocessorTok{#include }\ImportTok{<type_traits>}|",
+ *inline_no_minted_strings
+ )
+ # end: no_minted shared testing with / without --no-highlight
+ verify(
+ "[inline-code] user provided default_inline_language",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ default_inline_language: "haskell"
+ ---
+ {inline_code}
+ ''').format(inline_code=inline_code),
+ mintinline.format(attrs="", lang="haskell")
+ )
+ verify(
+ "[inline-code] user provided inline_attributes",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ inline_attributes:
+ - "showspaces"
+ - "space=."
+ ---
+ {inline_code}
+ ''').format(inline_code=inline_code),
+ mintinline.format(
+ attrs=",".join(["showspaces", "space=."]), lang="cpp"
+ ),
+ mintinline.format(
+ attrs=",".join(["showspaces", "space=."]), lang="text"
+ )
+ )
+ verify(
+ "[inline-code] attributes on inline code",
+ pandoc_args,
+ inline_code.replace(
+ "{.cpp}", "{.cpp .showspaces bgcolor=tango_bg style=tango}"
+ ),
+ mintinline.format(
+ attrs=",".join(["showspaces", "bgcolor=tango_bg", "style=tango"]),
+ lang="cpp"
+ )
+ )
+ verify(
+ "[inline-code] attributes on inline code + user inline_attributes",
+ pandoc_args,
+ textwrap.dedent('''
+ ---
+ minted:
+ inline_attributes:
+ - "showspaces"
+ - "space=."
+ ---
+ {inline_code}
+ ''').format(
+ inline_code=inline_code.replace(
+ "{.cpp}", "{.cpp bgcolor=tango_bg style=tango}"
+ )
+ ),
+ mintinline.format(
+ attrs=",".join([
+ "bgcolor=tango_bg",
+ "style=tango",
+ "showspaces",
+ "space=."
+ ]),
+ lang="cpp"
+ )
+ )
+ verify(
+ "[inline-code] non-minted attributes not forwarded",
+ pandoc_args,
+ inline_code.replace("{.cpp}", "{.cpp .showspaces .hello}"),
+ mintinline.format(attrs="showspaces", lang="cpp")
+ )
+
+
+def run_html_tests(args):
+ """
+ Run tests with an html5 writer to make sure minted commands are not used.
+ Also make sure minted specific attributes are indeed stripped.
+
+ ``args`` (list of str)
+ The base list of arguments to forward to pandoc.
+ """
+ def verify(test_name, md, attrs=[]):
+ """Verify minted and any strings in attrs not produced"""
+ output = run_pandoc(args + ["-t", "html5"], md)
+ ensure_not_present(test_name, "mint", output)
+ ensure_not_present(test_name, "fragile", output)
+ if attrs:
+ for a in attrs:
+ ensure_not_present(test_name, a, output)
+ # if `nil` is present, that likely means a problem parsing the metadata
+ ensure_not_present(test_name, "nil", output)
+
+ verify(r"[html] no \begin{minted}", code_block)
+ verify(r"[html] no \mintinline", inline_code)
+ verify(
+ r"[html] no \begin{minted} or \mintinline",
+ "{code_block}\n\n{inline_code}".format(
+ code_block=code_block, inline_code=inline_code
+ )
+ )
+ verify(
+ "[html] code block minted specific attributes stripped",
+ code_block.replace(
+ "{.cpp}",
+ "{.cpp .showspaces space=. bgcolor=minted_bg style=minted}"
+ ),
+ ["showspaces", "space", "bgcolor", "style"]
+ )
+ verify(
+ "[html] inline code minted specific attributes stripped",
+ inline_code.replace(
+ "{.cpp}",
+ "{.cpp .showspaces space=. bgcolor=minted_bg style=minted}"
+ ),
+ ["showspaces", "space", "bgcolor", "style"]
+ )
+
+
+if __name__ == "__main__":
+ # Initial path setup for input tests and lua filter
+ this_file_dir = os.path.abspath(os.path.dirname(__file__))
+ minted_lua = os.path.join(this_file_dir, "minted.lua")
+ if not os.path.isfile(minted_lua):
+ sys.stderr.write("Cannot find '{minted_lua}'...".format(
+ minted_lua=minted_lua
+ ))
+ sys.exit(1)
+
+ args = ["--fail-if-warnings", "--no-highlight", "--lua-filter", minted_lua]
+ run_tex_tests(args, "beamer")
+ run_tex_tests(args, "latex")
+ run_html_tests(args)
diff --git a/paper/lua-filters/minted/sample.md b/paper/lua-filters/minted/sample.md
new file mode 100644
index 0000000..7197047
--- /dev/null
+++ b/paper/lua-filters/minted/sample.md
@@ -0,0 +1,135 @@
+---
+title: Pandoc Minted Sample
+# NOTE: If you want to use `\definecolor` commands in your `header-includes`
+# section, setting `colorlinks: true` will `\usepackage{xcolor}` which is needed
+# for `\definecolor`. You can alternatively `\usepackage{xcolor}` explicitly in
+# in the `header-includes` section if you do not want everything else that
+# `colorlinks: true` will bring in. See `pandoc -D latex` output to see
+# everything that `colorlinks: true` will do _in addition_ to including xcolor.
+colorlinks: true
+header-includes:
+ # Include the minted package, set global style, define colors, etc.
+ - "\\usepackage{minted}"
+ - "\\usemintedstyle{tango}"
+ - "\\definecolor{tango_bg}{rgb}{0.9725,0.9725,0.9725}"
+ - "\\definecolor{monokai_bg}{rgb}{0.1529,0.1569,0.1333}"
+ # NOTE: comment out these last three and recompile to see the italics used
+ # by default for the `tango` style.
+ # Prevent italics in the `minted` environment.
+ - "\\AtBeginEnvironment{minted}{\\let\\itshape\\relax}"
+ # Prevent italics in the `\mintinline` command.
+ - "\\usepackage{xpatch}"
+ - "`\\xpatchcmd{\\mintinline}{\\begingroup}{\\begingroup\\let\\itshape\\relax}{}{}`{=latex}"
+minted:
+ block_attributes:
+ - "bgcolor=tango_bg"
+---
+
+## Inline Code in Pandoc
+
+- Raw inline code:
+
+ ```md
+ `#include <type_traits>`
+ ```
+
+ \vspace*{-3ex} produces: `#include <type_traits>`
+
+- Apply just a lexer:
+
+ ```md
+ `#include <type_traits>`{.cpp}
+ ```
+
+ \vspace*{-3ex} produces: `#include <type_traits>`{.cpp}
+
+- Change the background color and highlighting style:
+
+ ```{.md fontsize=\scriptsize}
+ <!-- Note: we defined monokai_bg in the metadata! -->
+ `#include <type_traits>`{.cpp bgcolor=monokai_bg style=monokai}
+ ```
+
+ \vspace*{-3ex} produces:
+ `#include <type_traits>`{.cpp bgcolor=monokai_bg style=monokai}
+
+ - Must **always** include language (`.cpp` here) **first**, always!
+
+## Inline Code Bypasses
+
+- Want the regular teletype text? Specify **both** the lexer class name and one
+ additional class `.no_minted`.
+
+ ```{.md}
+ <!-- The "text lexer" -->
+ `no minted`{.text .no_minted}
+ ```
+
+ \vspace*{-3ex} produces: `no mintinline`{.text .no_minted} vs `with mintinline`
+
+ - Inspect generated code, the PDF output is indistinguishable.
+
+- Alternatively, you can set `no_mintinline: true`{.yaml style=paraiso-light} to prevent the filter
+ from emitting _any_ `\mintinline`{.latex} calls.
+ - If you don't need syntax highlighting on your inline code elements, this may
+ greatly improve compile times for large documents.
+
+
+## Code Blocks
+
+- Use the defaults, but still supply the lexer:
+
+ ```bash
+ echo "Hi there" # How are you?
+ ```
+
+ \vspace*{-3ex} produces
+
+ ```bash
+ echo "Hi there" # How are you?
+ ```
+
+ \vspace*{-3ex}
+
+- As with inline code, you can change whatever you want:
+
+ ```{.bash bgcolor=monokai_bg style=monokai}
+ echo "Hi there" # How are you?
+ ```
+
+ \vspace*{-3ex} produces
+
+ ```{.bash bgcolor=monokai_bg style=monokai}
+ echo "Hi there" # How are you?
+ ```
+
+ \vspace*{-3ex}
+
+ - Must **always** include language (`.bash` here) **first**, always!
+
+
+## Special Characters are Supported
+
+- Code blocks:
+
+ ```md
+ `~!@#$%^&*()-=_+[]}{|;':",.\/<>?
+ ```
+
+ \vspace*{-3ex}
+
+- Inline code
+
+ ``with mintinline `~!@#$%^&*()-=_+[]}{|;':",.\/<>?``
+
+ Note: If you use almost all special characters *and* all alphanumeric
+ characters in a single inline code fragment, minted may not be able to find a
+ suitable delimiter to place around the \LaTeX\ inline command.
+
+- Inline code with bypass
+
+ ``no mintinline `~!@#$%^&*()-=_+[]}{|;':",.\/<>?``{.text .no_minted}
+
+- Specific lexer with mintinline: `auto foo = [](){};`{.cpp}
+- Without mintinline: `auto foo = [](){};`{.cpp .no_minted}
+ - Output color depends on `--no-highlight` flag for `pandoc`.