% \iffalse
%<*driver>
\documentclass{ltxdockit}
\usepackage{btxdockit}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[american]{babel}
\usepackage{microtype}
\usepackage{amsmath}
\usepackage{fancyvrb}
\usepackage{hologo}
\usepackage{xcolor}
\usepackage{doc}

% Set up the style.
\emergencystretch=1em
\RecustomVerbatimEnvironment
  {Verbatim}{Verbatim}
  {gobble=2,frame=single}
\setcounter{secnumdepth}{4}
\addtokomafont{title}{\sffamily}
\addtokomafont{paragraph}{\spotcolor}
\addtokomafont{section}{\spotcolor}
\addtokomafont{subsection}{\spotcolor}
\addtokomafont{subsubsection}{\spotcolor}
\addtokomafont{descriptionlabel}{\spotcolor}
\setkomafont{caption}{\bfseries\sffamily\spotcolor}
\setkomafont{captionlabel}{\bfseries\sffamily\spotcolor}
\hypersetup{citecolor=spot}
\let\oldCodelineNo\theCodelineNo
\def\theCodelineNo{\textcolor{gray}{\oldCodelineNo}}

% Define some markup.
\let\pkg\relax % A package name
\newcommand\mdef[1]{% A TeX macro definition
  \phantomsection\label{macro:#1}\textcolor{spot}{\cs{#1}}}
\newcommand\m[1]{% A TeX macro reference
  \hyperref[macro:#1]{\textcolor{spot}{\cs{#1}}}}
\newcommand\envmdef[1]{% A TeX macro definition
  \phantomsection\label{environment:#1}\textcolor{spot}{\t`#1`}}
\newcommand\envm[1]{% A LaTeX environment reference
  \hyperref[environment:#1]{\textcolor{spot}{\t`#1`}}}
\newcommand\luamdef[1]{% A Lua object / method definition
  \phantomsection\label{lua:#1}\textcolor{spot}{\t`#1`}}
\newcommand\luam[1]{% A Lua object / method reference
  \hyperref[lua:#1]{\t`#1`}}
\def\t`#1`{% Inline code
  \textcolor{spot}{\text{\texttt{#1}}}}
\newcommand\Optitem[2][]{\penalty -1000\relax % An option item definition
  \phantomsection\label{opt:#2}\optitem[#1]{#2}}
\newcommand\Valitem[2][]{\penalty -1000\relax % A value item definition
  \phantomsection\label{opt:#2}\valitem[#1]{#2}}
\newcommand\Opt[1]{% An option / value item reference
  \hyperref[opt:#1]{\t`#1`}}
\newcommand\acro[1]{% An acronym
  \textsc{#1}}

% Set up the catcodes.
\catcode`\_=12 % We won't be typesetting math and Lua contains lots of `_`.

% Set up the title page.
\titlepage{%
  title={A Markdown Interpreter for \TeX{}},
  subtitle={},
  url={https://github.com/witiko/markdown},
  author={Vít Novotný},
  email={witiko@mail.muni.cz},
  revision={\input VERSION},
  date={\today}}
\hypersetup{%
  pdftitle={A Markdown Interpreter for \TeX{}},
  pdfauthor={Vít Novotný}}
\CodelineIndex

% Set up the bibliography.
\usepackage{filecontents}
\begin{filecontents}{markdown.bib}
  @online{sotkov17,
    author    = {Sotkov, Anton},
    title     = {File transclusion syntax for Markdown},
    date      = {2017-01-19},
    url       = {https://github.com/iainc/Markdown-Content-Blocks},
    urldate   = {2018-01-08}}
  @book{luatex17,
    author    = {{Lua\TeX{} development team}},
    title     = {Lua\TeX{} reference manual},
    year      = {2017},
    month     = {2},
    url       = {http://www.luatex.org/svn/trunk/manual/luatex.pdf},
    urldate   = {2018-01-08}}
  @book{latex17,
    author    = {Braams, Johannes and Carlisle, David and Jeffrey, Alan and
                 Lamport, Leslie and Mittelbach, Frank and Rowley, Chris and
                 Schöpf, Rainer},
    title     = {The \Hologo{LaTeX2e} Sources},
    date      = {2017-04-15},
    url       = {http://mirrors.ctan.org/macros/latex/base/source2e.pdf},
    urldate   = {2018-01-08}}
  @book{ierusalimschy13,
    author    = {Ierusalimschy, Roberto},
    year      = {2013},
    title     = {Programming in Lua},
    edition   = {3},
    isbn      = {978-85-903798-5-0},
    pagetotal = {xviii, 347},
    location  = {Rio de Janeiro},
    publisher = {PUC-Rio}}
  @book{knuth86,
    author    = {Knuth, Donald Ervin},
    year      = {1986},
    title     = {The \TeX{}book},
    edition   = {3},
    isbn      = {0-201-13447-0},
    pagetotal = {ix, 479},
    publisher = {Addison-Wesley}}
\end{filecontents}
\usepackage[
  backend=biber,
  style=iso-numeric,
  sorting=none,
  autolang=other,
  sortlocale=auto]{biblatex}
\addbibresource{markdown.bib}

\begin{document}
  \printtitlepage
  \tableofcontents
  \DocInput{markdown.dtx}
  \printbibliography
\end{document}
%</driver>
% \fi
%
% \section{Introduction}
% This document is a reference manual for the \pkg{Markdown} package. It is
% split into three sections. This section explains the purpose and the
% background of the package and outlines its prerequisites. Section
% \ref{sec:interfaces} describes the interfaces exposed by the package along
% with usage notes and examples. It is aimed at the user of the package.
% Section \ref{sec:implementation} describes the implementation of the package.
% It is aimed at the developer of the package and the curious user.
%
% \subsection{About \pkg{Markdown}}
% The \pkg{Markdown} package provides facilities for the conversion of markdown
% markup to plain \TeX{}. These are provided both in the form of a Lua module
% and in the form of plain \TeX{}, \LaTeX{}, and \Hologo{ConTeXt} macro
% packages that enable the direct inclusion of markdown documents inside \TeX{}
% documents.
%
% Architecturally, the package consists of the \pkg{Lunamark} v0.5.0 Lua module
% by John MacFarlane, which was slimmed down and rewritten for the needs of the
% package. On top of \pkg{Lunamark} sits code for the plain \TeX{}, \LaTeX{},
% and \Hologo{ConTeXt} formats by Vít Novotný.
%
% \iffalse
%<*lua>
% \fi
%  \begin{macrocode}
local metadata = {
    version   = "2.5.5",
    comment   = "A module for the conversion from markdown to plain TeX",
    author    = "John MacFarlane, Hans Hagen, Vít Novotný",
    copyright = "2009-2016 John MacFarlane, Hans Hagen; " ..
                "2016-2018 Vít Novotný",
    license   = "LPPL 1.3"
}
if not modules then modules = { } end
modules['markdown'] = metadata
%    \end{macrocode}
%
% \subsection{Feedback}
% Please use the \pkg{markdown} project page on
% GitHub\footnote{\url{https://github.com/witiko/markdown/issues}} to report
% bugs and submit feature requests. Before making a feature request, please
% ensure that you have thoroughly studied this manual. If you do not want to
% report a bug or request a feature but are simply in need of assistance, you
% might want to consider posting your question on the \TeX-\LaTeX{} Stack
% Exchange\footnote{\url{https://tex.stackexchange.com}}.
%
% \subsection{Acknowledgements}
% I would like to thank the Faculty of Informatics at the Masaryk University in
% Brno for providing me with the opportunity to work on this package alongside
% my studies. I would also like to thank the creator of the Lunamark Lua
% module, John Macfarlane, for releasing Lunamark under a permissive license
% that enabled its inclusion into the package.
%
% The \TeX{} part of the package draws inspiration from several sources
% including the source code of \Hologo{LaTeX2e}, the \pkg{minted} package by
% Geoffrey M. Poore -- which likewise tackles the issue of interfacing with an
% external interpreter from \TeX, the \pkg{filecontents} package by Scott
% Pakin, and others.
%
% \subsection{Prerequisites}
% This section gives an overview of all resources required by the package.
%
% \subsubsection{Lua Prerequisites}\label{sec:luaprerequisites}
% The Lua part of the package requires that the following Lua modules are
% available from within the Lua\TeX{} engine:
% \begin{description}
%   \item[\pkg{LPeg${}\geq{}$0.10}] A pattern-matching library for the writing
%     of recursive descent parsers via the Parsing Expression Grammars
%     (\acro{peg}s). It is used by the \pkg{Lunamark} library to parse the
%     markdown input. \pkg{LPeg${}\geq{}$0.10} is included in
%     Lua\TeX${}\geq{}$0.72.0 (\TeX Live${}\geq{}2013$).
%  \begin{macrocode}
local lpeg = require("lpeg")
%    \end{macrocode}
%   \item[\pkg{Selene Unicode}] A library that provides support for the
%     processing of wide strings. It is used by the \pkg{Lunamark} library to
%     cast image, link, and footnote tags to the lower case. \pkg{Selene
%     Unicode} is included in all releases of Lua\TeX{} (\TeX
%     Live${}\geq{}2008$).
%  \begin{macrocode}
local unicode = require("unicode")
%    \end{macrocode}
%   \item[\pkg{MD5}] A library that provides \acro{md5} crypto functions. It is
%     used by the \pkg{Lunamark} library to compute the digest of the input for
%     caching purposes. \pkg{MD5} is included in all releases of Lua\TeX{}
%     (\TeX Live${}\geq{}2008$).
%  \begin{macrocode}
local md5 = require("md5")
%    \end{macrocode}
% \end{description}
% All the abovelisted modules are statically linked into the current version of
% the Lua\TeX{} engine (see \cite[Section~3.3]{luatex17}).
%
% \iffalse
%</lua>
%<*tex>
% \fi
% \subsubsection{Plain \TeX{} Prerequisites}\label{sec:texprerequisites}
% The plain \TeX{} part of the package requires that the plain \TeX{}
% format (or its superset) is loaded, all the Lua prerequisites (see
% Section \ref{sec:luaprerequisites}), and the following Lua module:
% \begin{description}
%   \item[\pkg{Lua File System}] A library that provides access to the
%     filesystem via \acro{os}-specific syscalls. It is used by the plain
%     \TeX{} code to create the cache directory specified by the
%     \m{markdownOptionCacheDir} macro before interfacing with the
%     \pkg{Lunamark} library. \pkg{Lua File System} is included in all releases
%     of Lua\TeX{} (\TeX Live${}\geq{}2008$).
%
%     The plain \TeX{} code makes use of the \luam{isdir} method that was added
%     to the \pkg{Lua File System} library by the Lua\TeX{} engine developers
%     (see \cite[Section~3.2]{luatex17}).
% \end{description}
% The \pkg{Lua File System} module is statically linked into the Lua\TeX{}
% engine (see \cite[Section~3.3]{luatex17}).
%
% The plain \TeX{} part of the package also requires that either the Lua\TeX{}
% \m{directlua} primitive or the shell access file stream 18 is available in
% your \TeX{} engine. If only the shell access file stream is available in your
% \TeX{} engine (as is the case with \hologo{pdfTeX} and \Hologo{XeTeX}) or if
% you enforce the use of shell using the \m{markdownMode} macro, then note that
% unless your \TeX{} engine is globally configured to enable shell access, you
% will need to provide the \t`-shell-escape` parameter to your engine when
% typesetting a document.
%
% \iffalse
%</tex>
%<*latex>
% \fi
% \subsubsection{\LaTeX{} Prerequisites}\label{sec:latexprerequisites}
% The \LaTeX{} part of the package requires that the \Hologo{LaTeX2e} format is
% loaded,
%  \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}%
%    \end{macrocode}
% all the plain \TeX{} prerequisites (see Section \ref{sec:texprerequisites}),
% and the following \Hologo{LaTeX2e} packages:
% \begin{description}
%   \item[\pkg{keyval}] A package that enables the creation of parameter sets.
%     This package is used to provide the \m{markdownSetup} macro, the package
%     options processing, as well as the parameters of the \envm{markdown*}
%     \LaTeX{} environment.
%  \begin{macrocode}
\RequirePackage{keyval}
%    \end{macrocode}
%   \item[\pkg{url}] A package that provides the \m{url} macro for the
%     typesetting of \acro{url}s. It is used to provide the default token renderer
%     prototype (see Section \ref{sec:texrendererprototypes}) for links.
%  \begin{macrocode}
\RequirePackage{url}
%    \end{macrocode}
%   \item[\pkg{graphicx}] A package that provides the \m{includegraphics} macro for
%     the typesetting of images. It is used to provide the corresponding
%     default token renderer prototype (see Section
%     \ref{sec:texrendererprototypes}).
%  \begin{macrocode}
\RequirePackage{graphicx}
%    \end{macrocode}
%   \item[\pkg{paralist}] A package that provides the \envm{compactitem},
%     \envm{compactenum}, and \envm{compactdesc} macros for the
%     typesetting of tight bulleted lists, ordered lists, and definition lists.
%     It is used to provide the corresponding default token renderer prototypes
%     (see Section \ref{sec:texrendererprototypes}).
%   \item[\pkg{ifthen}] A package that provides a concise syntax for the
%     inspection of macro values. It is used to determine whether or not the
%     \pkg{paralist} package should be loaded based on the user options.
%  \begin{macrocode}
\RequirePackage{ifthen}
%    \end{macrocode}
%   \item[\pkg{fancyvrb}] A package that provides the \m{VerbatimInput} macros
%     for the verbatim inclusion of files containing code.  It is used to
%     provide the corresponding default token renderer prototype (see Section
%     \ref{sec:texrendererprototypes}).
%  \begin{macrocode}
\RequirePackage{fancyvrb}
%    \end{macrocode}
%   \item[\pkg{csvsimple}] A package that provides the default token renderer
%     prototype for iA\,Writer content blocks with the \acro{csv} filename
%     extension (see Section \ref{sec:texrendererprototypes}).
%  \begin{macrocode}
\RequirePackage{csvsimple}
%    \end{macrocode}
% \end{description}
%
% \iffalse
%</latex>
%<*context>
% \fi
% \subsubsection{\Hologo{ConTeXt} prerequisites}
% The \Hologo{ConTeXt} part of the package requires that either the Mark II or
% the Mark IV format is loaded, all the plain \TeX{} prerequisites (see
% Section \ref{sec:texprerequisites}), and the following \Hologo{ConTeXt}
% modules:
% \begin{description}
%   \item[\pkg{m-database}] A module that provides the default token renderer
%     prototype for iA\,Writer content blocks with the \acro{csv} filename
%     extension (see Section \ref{sec:texrendererprototypes}).
% \end{description}
%
% \section{User Guide}\label{sec:interfaces}
% This part of the manual describes the interfaces exposed by the package
% along with usage notes and examples. It is aimed at the user of the package.
%
% Since neither \TeX{} nor Lua provide interfaces as a language construct, the
% separation to interfaces and implementations is purely abstract. It serves as
% a means of structuring this manual and as a promise to the user that if they
% only access the package through the interfaces, the future versions of the
% package should remain backwards compatible.
%
% \iffalse
%</context>
%<*lua>
% \fi
% \subsection{Lua Interface}\label{sec:luainterface}
% The Lua interface provides the conversion from \acro{utf}-\oldstylenums8
% encoded markdown to plain \TeX{}. This interface is used by the plain \TeX{}
% implementation (see Section \ref{sec:teximplementation}) and will be of
% interest to the developers of other packages and Lua modules.
%
% The Lua interface is implemented by the \t`markdown` Lua module.
%
%  \begin{macrocode}
local M = {}
%    \end{macrocode}
%
% \subsubsection{Conversion from Markdown to Plain \TeX{}}
% \label{sec:luaconversion}
% The Lua interface exposes the \luamdef{new}\t`(options)` method.  This
% method creates converter functions that perform the conversion from markdown
% to plain \TeX{} according to the table \t`options` that contains options
% recognized by the Lua interface.  (see Section \ref{sec:luaoptions}). The
% \t`options` parameter is optional; when unspecified, the behaviour will be
% the same as if \t`options` were an empty table.
%
% The following example Lua code converts the markdown string \t`_Hello
% world!_` to a \TeX{} output using the default options and prints the \TeX{}
% output:
% \begin{Verbatim}
% local md = require("markdown")
% local convert = md.new()
% print(convert("_Hello world!_"))
% \end{Verbatim}
%
% \subsubsection{Options}\label{sec:luaoptions}
% The Lua interface recognizes the following options. When unspecified, the
% value of a key is taken from the \luamdef{defaultOptions} table.
%  \begin{macrocode}
local defaultOptions = {}
%    \end{macrocode}
% \pagebreak
% \paragraph{File and Directory Names}
% \begin{optionlist}
%   \Valitem[.]{cacheDir}{path}
%     A path to the directory containing auxiliary cache files. It is
%     considered sane to set the path to a subdirectory of \t`outputDir`.
%     If the last segment of the path does not exist, it will be created by the
%     plain \TeX, \LaTeX, and \Hologo{ConTeXt} implementations. The Lua
%     implementation expects that the entire path already exists.
% 
%     When iteratively writing and typesetting a markdown document, the cache
%     files are going to accumulate over time. You are advised to clean the
%     cache directory every now and then, or to set it to a temporary filesystem
%     (such as \t`/tmp` on \acro{un*x} systems), which gets periodically
%     emptied.
%  \begin{macrocode}
defaultOptions.cacheDir = "."
%    \end{macrocode}
%
%   \Valitem[.]{outputDir}{path}
%     A path to the directory containing output files. The path must be set
%     to the same value as the \t`-output-directory` option of your \TeX\
%     engine for the package to function correctly.
%  \begin{macrocode}
defaultOptions.outputDir = "."
%    \end{macrocode}
% \end{optionlist}
% \paragraph{Parser Options}
% \begin{optionlist}
%   \Optitem[false]{blankBeforeBlockquote}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Require a blank line between a paragraph and the following
%         blockquote.
%       \item[false] Do not require a blank line between a paragraph and the
%         following blockquote.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.blankBeforeBlockquote = false
%    \end{macrocode}
%
%   \Optitem[false]{blankBeforeCodeFence}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Require a blank line between a paragraph and the following
%         fenced code block.
%       \item[false] Do not require a blank line between a paragraph and the
%         following fenced code block.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.blankBeforeCodeFence = false
%    \end{macrocode}
%
%   \Optitem[false]{blankBeforeHeading}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Require a blank line between a paragraph and the following
%         header.
%       \item[false] Do not require a blank line between a paragraph and the
%         following header.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.blankBeforeHeading = false
%    \end{macrocode}
%
%   \Optitem[false]{breakableBlockquotes}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] A blank line separates block quotes.
%       \item[false] Blank lines in the middle of a block quote are ignored.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.breakableBlockquotes = false
%    \end{macrocode}
%
%   \Optitem[false]{citationNbsps}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Replace regular spaces with non-breakable spaces inside the
%         prenotes and postnotes of citations produced via the pandoc citation
%         syntax extension.
%       \item[false] Do not replace regular spaces with non-breakable spaces
%         inside the prenotes and postnotes of citations produced via the pandoc
%         citation syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.citationNbsps = true
%    \end{macrocode}
%
%   \Optitem[false]{citations}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the pandoc citation syntax extension:
%         \begin{Verbatim}
% Here is a simple parenthetical citation [@doe99] and here
% is a string of several [see @doe99, pp. 33-35; also
% @smith04, chap. 1].
% 
% A parenthetical citation can have a [prenote @doe99] and
% a [@smith04 postnote]. The name of the author can be
% suppressed by inserting a dash before the name of an
% author as follows [-@smith04].
%
% Here is a simple text citation @doe99 and here is
% a string of several @doe99 [pp. 33-35; also @smith04,
% chap. 1]. Here is one with the name of the author
% suppressed -@doe99.
%         \end{Verbatim}
%       \item[false] Disable the pandoc citation syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.citations = false
%    \end{macrocode}
%
%   \Optitem[true]{codeSpans}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the code span syntax:
%         \begin{Verbatim}
% Use the `printf()` function.
% ``There is a literal backtick (`) here.``
%         \end{Verbatim}
%       \item[false] Disable the code span syntax. This allows you to easily
%         use the quotation mark ligatures in texts that do not contain code
%         spans:
%         \begin{Verbatim}
% ``This is a quote.''
%         \end{Verbatim}
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.codeSpans = true
%    \end{macrocode}
%
%   \Optitem[false]{contentBlocks}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the iA\,Writer content blocks syntax
%         extension~\cite{sotkov17}:
%         \begin{Verbatim}
% http://example.com/minard.jpg (Napoleon’s disastrous
% Russian campaign of 1812)
% /Flowchart.png "Engineering Flowchart"
% /Savings Account.csv 'Recent Transactions'
% /Example.swift
% /Lorem Ipsum.txt
%         \end{Verbatim}
%       \item[false] Disable the iA\,Writer content blocks syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.contentBlocks = false
%    \end{macrocode}
%
%   \Valitem[markdown-languages.json]{contentBlocksLanguageMap}{filename}
%     The filename of the \acro{json} file that maps filename extensions to
%     programming language names in the iA\,Writer content blocks. See
%     Section~\ref{sec:texcontentblockrenderers} for more information.
%  \begin{macrocode}
defaultOptions.contentBlocksLanguageMap = "markdown-languages.json"
%    \end{macrocode}
%
%   \Optitem[false]{definitionLists}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the pandoc definition list syntax extension:
%         \begin{Verbatim}
% Term 1
% 
% :   Definition 1
% 
% Term 2 with *inline markup*
% 
% :   Definition 2
% 
%         { some code, part of Definition 2 }
% 
%     Third paragraph of definition 2.
%         \end{Verbatim}
%       \item[false] Disable the pandoc definition list syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.definitionLists = false
%    \end{macrocode}
%
%   \Optitem[false]{fencedCode}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the commonmark fenced code block extension:
%         \begin{Verbatim}
% ~~~ js
% if (a > 3) {
%     moveShip(5 * gravity, DOWN);
% }
% ~~~~~~
%
%   ``` html
%   <pre>
%     <code>
%       // Some comments
%       line 1 of code
%       line 2 of code
%       line 3 of code
%     </code>
%   </pre>
%   ```
%         \end{Verbatim}
%       \item[false] Disable the commonmark fenced code block extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.fencedCode = false
%    \end{macrocode}
%
%   \Optitem[false]{footnotes}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the pandoc footnote syntax extension:
%         \begin{Verbatim}
% Here is a footnote reference,[^1] and another.[^longnote]
% 
% [^1]: Here is the footnote.
% 
% [^longnote]: Here's one with multiple blocks.
% 
%     Subsequent paragraphs are indented to show that they
% belong to the previous footnote.
% 
%         { some.code }
% 
%     The whole paragraph can be indented, or just the
%     first line.  In this way, multi-paragraph footnotes
%     work like multi-paragraph list items.
% 
% This paragraph won't be part of the note, because it
% isn't indented.
%         \end{Verbatim}
%       \item[false] Disable the pandoc footnote syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.footnotes = false
%    \end{macrocode}
% 
%   \Optitem[false]{hashEnumerators}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the use of hash symbols (\t`\#`) as ordered item
%         list markers:
%         \begin{Verbatim}
% #.  Bird
% #.  McHale
% #.  Parish
%         \end{Verbatim}
%       \item[false] Disable the use of hash symbols (\t`\#`) as ordered item
%         list markers.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.hashEnumerators = false
%    \end{macrocode}
% 
%   \Optitem[false]{html}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true]  Enable the recognition of \textsc{html} tags, block
%                    elements, comments, \textsc{html} instructions, and
%                    entities in the input. Tags, block elements (along with
%                    contents), \textsc{html} instructions, and comments will
%                    be ignored and \textsc{html} entities will be replaced
%                    with the corresponding Unicode codepoints.
%
%       \item[false] Disable the recognition of \textsc{html} markup. Any
%                    \textsc{html} markup in the input will be rendered as
%                    plain text.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.html = false
%    \end{macrocode}
%
%   \Optitem[false]{hybrid}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Disable the escaping of special plain \TeX{} characters,
%         which makes it possible to intersperse your markdown markup with
%         \TeX{} code. The intended usage is in documents prepared manually by
%         a human author.  In such documents, it can often be desirable to mix
%         \TeX{} and markdown markup freely.
%
%       \item[false] Enable the escaping of special plain \TeX{} characters
%         outside verbatim environments, so that they are not interpretted by
%         \TeX{}. This is encouraged when typesetting automatically generated
%         content or markdown documents that were not prepared with this
%         package in mind.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.hybrid = false
%    \end{macrocode}
%
%   \Optitem[false]{inlineFootnotes}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Enable the pandoc inline footnote syntax extension:
%         \begin{Verbatim}
% Here is an inline note.^[Inlines notes are easier to
% write, since you don't have to pick an identifier and
% move down to type the note.]
%         \end{Verbatim}
%       \item[false] Disable the pandoc inline footnote syntax extension.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.inlineFootnotes = false
%    \end{macrocode}
%
%   \Optitem[false]{preserveTabs}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Preserve all tabs in the input.
%       \item[false] Convert any tabs in the input to spaces.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.preserveTabs = false
%    \end{macrocode}
%
%   \Optitem[false]{smartEllipses}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Convert any ellipses in the input to the
%         \m{markdownRendererEllipsis} \TeX{} macro.
%       \item[false] Preserve all ellipses in the input.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.smartEllipses = false
%    \end{macrocode}
%
%   \Optitem[true]{startNumber}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Make the number in the first item in ordered lists
%         significant. The item numbers will be passed to the
%         \m{markdownRendererOlItemWithNumber} \TeX{} macro.
%       \item[false] Ignore the number in the items of ordered lists. Each
%         item will only produce a \m{markdownRendererOlItem} \TeX{} macro.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.startNumber = true
%    \end{macrocode}
%
%   \Optitem[true]{tightLists}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true] Lists whose bullets do not consist of multiple paragraphs
%         will be detected and passed to the 
%         \m{markdownRendererOlBeginTight}, \m{markdownRendererOlEndTight},
%         \m{markdownRendererUlBeginTight}, \m{markdownRendererUlEndTight},
%         \m{markdownRendererDlBeginTight}, and \m{markdownRendererDlEndTight}
%         macros.
%       \item[false] Lists whose bullets do not consist of multiple paragraphs
%         will be treated the same way as lists that do.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.tightLists = true
%    \end{macrocode}
%
%   \Optitem[true]{underscores}{\opt{true}, \opt{false}}
%     \begin{valuelist}
%       \item[true]  Both underscores and asterisks can be used to denote
%         emphasis and strong emphasis:
%         \begin{Verbatim}
% *single asterisks*
% _single underscores_
% **double asterisks**
% __double underscores__
%         \end{Verbatim}
%       \item[false] Only asterisks can be used to denote emphasis and strong
%         emphasis. This makes it easy to write math with the \t`hybrid` option
%         without the need to constantly escape subscripts.
%     \end{valuelist}
%  \begin{macrocode}
defaultOptions.underscores = true
%    \end{macrocode}
% \end{optionlist}
% 
% \iffalse
%</lua>
%<*tex>
% \fi\subsection{Plain \TeX{} Interface}\label{sec:texinterface}
% The plain \TeX{} interface provides macros for the typesetting of markdown input
% from within plain \TeX{}, for setting the Lua interface options (see Section
% \ref{sec:luaoptions}) used during the conversion from markdown to plain
% \TeX{}, and for changing the way markdown the tokens are rendered.
%  \begin{macrocode}
\def\markdownLastModified{2018/01/08}%
\def\markdownVersion{2.5.5}%
%    \end{macrocode}
%
% The plain \TeX{} interface is implemented by the \t`markdown.tex` file that
% can be loaded as follows:
% \begin{Verbatim}
% \input markdown
% \end{Verbatim}
% It is expected that the special plain \TeX{} characters have the expected
% category codes, when \m{input}ting the file.
%
% \subsubsection{Typesetting Markdown}\label{sec:textypesetting}
% The interface exposes the \mdef{markdownBegin}, \mdef{markdownEnd}, and
% \mdef{markdownInput} macros.
%
% The \m{markdownBegin} macro marks the beginning of a markdown document
% fragment and the \m{markdownEnd} macro marks its end.
%  \begin{macrocode}
\let\markdownBegin\relax
\let\markdownEnd\relax
%    \end{macrocode}
% You may prepend your own code to the \m{markdownBegin} macro and redefine the
% \m{markdownEnd} macro to produce special effects before and after the
% markdown block.
%
% There are several limitations to the macros you need to be aware of.
% The first limitation concerns the \m{markdownEnd} macro, which must be
% visible directly from the input line buffer (it may not be produced as a
% result of input expansion). Otherwise, it will not be recognized as the end
% of the markdown string. As a corrolary, the \m{markdownEnd} string
% may not appear anywhere inside the markdown input.
%
% Another limitation concerns spaces at the right end of an input line. In
% markdown, these are used to produce a forced line break. However, any such
% spaces are removed before the lines enter the input buffer of \TeX{} (see
% \cite[p.~46]{knuth86}). As a corrolary, the \m{markdownBegin} macro also
% ignores them.
%
% The \m{markdownBegin} and \m{markdownEnd} macros will also consume the rest
% of the lines at which they appear.  In the following example plain \TeX{}
% code, the characters \t`c`, \t`e`, and \t`f` will not appear in the output.
% \begin{Verbatim}
% \input markdown
% a
% b \markdownBegin c 
% d 
% e \markdownEnd   f
% g 
% \bye
% \end{Verbatim}
%
% Note that you may also not nest the \m{markdownBegin} and \m{markdownEnd}
% macros.
%
% The following example plain \TeX{} code showcases the usage of the
% \m{markdownBegin} and \m{markdownEnd} macros:
% \begin{Verbatim}
% \input markdown
% \markdownBegin
% _Hello_ **world** ...
% \markdownEnd
% \bye
% \end{Verbatim}
%
% The \m{markdownInput} macro accepts a single parameter containing the
% filename of a markdown document and expands to the result of the conversion
% of the input markdown document to plain \TeX{}.
%  \begin{macrocode}
\let\markdownInput\relax
%    \end{macrocode}
% This macro is not subject to the abovelisted limitations of the
% \m{markdownBegin} and \m{markdownEnd} macros.
%
% The following example plain \TeX{} code showcases the usage of the
% \m{markdownInput} macro:
% \begin{Verbatim}
% \input markdown
% \markdownInput{hello.md}
% \bye
% \end{Verbatim}
%
% \subsubsection{Options}\label{sec:texoptions}
% The plain \TeX{} options are represented by \TeX{} macros. Some of them map
% directly to the options recognized by the Lua interface (see Section
% \ref{sec:luaoptions}), while some of them are specific to the plain \TeX{}
% interface.
%
% \paragraph{File and Directory names}
% The \mdef{markdownOptionHelperScriptFileName} macro sets the filename of the
% helper Lua script file that is created during the conversion from markdown to
% plain \TeX{} in \TeX{} engines without the \m{directlua} primitive. It
% defaults to \m{jobname}\t`.markdown.lua`, where \m{jobname} is the base name
% of the document being typeset.
%
% The expansion of this macro must not contain quotation marks (\t`"`) or
% backslash symbols (\t`\textbackslash`). Mind that \TeX{} engines tend to
% put quotation marks around \m{jobname}, when it contains spaces.
%  \begin{macrocode}
\def\markdownOptionHelperScriptFileName{\jobname.markdown.lua}%
%    \end{macrocode}
%
% The \mdef{markdownOptionInputTempFileName} macro sets the filename of the
% temporary input file that is created during the conversion from markdown to
% plain \TeX{} in \m{markdownMode} other than \t`2`. It defaults to
% \m{jobname}\t`.markdown.out`. The same limitations as in the case of the
% \m{markdownOptionHelperScriptFileName} macro apply here.
%  \begin{macrocode}
\def\markdownOptionInputTempFileName{\jobname.markdown.in}%
%    \end{macrocode}
%
% The \mdef{markdownOptionOutputTempFileName} macro sets the filename of the
% temporary output file that is created during the conversion from markdown to
% plain \TeX{} in \m{markdownMode} other than \t`2`. It defaults to
% \m{jobname}\t`.markdown.out`. The same limitations apply here as in the case
% of the \m{markdownOptionHelperScriptFileName} macro.
%  \begin{macrocode}
\def\markdownOptionOutputTempFileName{\jobname.markdown.out}%
%    \end{macrocode}
%
% The \mdef{markdownOptionErrorTempFileName} macro sets the filename of the
% temporary output file that is created when a Lua error is encountered during
% the conversion from markdown to plain \TeX{} in \m{markdownMode} other than
% \t`2`. It defaults to \m{jobname}\t`.markdown.err`. The same limitations
% apply here as in the case of the \m{markdownOptionHelperScriptFileName}
% macro.
%  \begin{macrocode}
\def\markdownOptionErrorTempFileName{\jobname.markdown.err}%
%    \end{macrocode}
%
% The \mdef{markdownOptionCacheDir} macro corresponds to the Lua interface
% \Opt{cacheDir} option that sets the name of the directory that will contain
% the produced cache files. The option defaults to \t`_markdown_`\m{jobname},
% which is a similar naming scheme to the one used by the \pkg{minted} \LaTeX{}
% package. The same limitations apply here as in the case of the
% \m{markdownOptionHelperScriptFileName} macro.
%  \begin{macrocode}
\def\markdownOptionCacheDir{\markdownOptionOutputDir/_markdown_\jobname}%
%    \end{macrocode}
%
% The \mdef{markdownOptionOutputDir} macro corresponds to the Lua interface
% \Opt{outputDir} option that sets the name of the directory that will contain
% the produced cache files. The option defaults to \t`.`. The same limitations
% apply here as in the case of the \m{markdownOptionHelperScriptFileName}
% macro.
%  \begin{macrocode}
\def\markdownOptionOutputDir{.}%
%    \end{macrocode}
%
% \paragraph{Lua Interface Options}
% The following macros map directly to the options recognized by the Lua
% interface (see Section \ref{sec:luaoptions}) and are not processed by the
% plain \TeX{} implementation, only passed along to Lua. They are undefined, which
% makes them fall back to the default values provided by the Lua interface.
% 
% For the macros that correspond to the non-boolean options recognized by the
% Lua interface, the same limitations apply here in the case of the
% \m{markdownOptionHelperScriptFileName} macro.
%  \begin{macrocode}
\let\markdownOptionBlankBeforeBlockquote\undefined
\let\markdownOptionBlankBeforeCodeFence\undefined
\let\markdownOptionBlankBeforeHeading\undefined
\let\markdownOptionBreakableBlockquotes\undefined
\let\markdownOptionCitations\undefined
\let\markdownOptionCitationNbsps\undefined
\let\markdownOptionContentBlocks\undefined
\let\markdownOptionContentBlocksLanguageMap\undefined
\let\markdownOptionDefinitionLists\undefined
\let\markdownOptionFootnotes\undefined
\let\markdownOptionFencedCode\undefined
\let\markdownOptionHashEnumerators\undefined
\let\markdownOptionHtml\undefined
\let\markdownOptionHybrid\undefined
\let\markdownOptionInlineFootnotes\undefined
\let\markdownOptionPreserveTabs\undefined
\let\markdownOptionSmartEllipses\undefined
\let\markdownOptionStartNumber\undefined
\let\markdownOptionTightLists\undefined
%    \end{macrocode}
%
% \subsubsection{Token Renderers}\label{sec:texrenderersuser}
% The following \TeX{} macros may occur inside the output of the
% converter functions exposed by the Lua interface (see Section
% \ref{sec:luaconversion}) and represent the parsed markdown tokens. These
% macros are intended to be redefined by the user who is typesetting a
% document. By default, they point to the corresponding prototypes (see Section
% \ref{sec:texrendererprototypes}).
%
% \paragraph{Interblock Separator Renderer}
% The \mdef{markdownRendererInterblockSeparator} macro represents a separator
% between two markdown block elements. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererInterblockSeparator{%
  \markdownRendererInterblockSeparatorPrototype}%
%    \end{macrocode}
%
% \paragraph{Line Break Renderer}
% The \mdef{markdownRendererLineBreak} macro represents a forced line break.
% The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererLineBreak{%
  \markdownRendererLineBreakPrototype}%
%    \end{macrocode}
%
% \paragraph{Ellipsis Renderer}
% The \mdef{markdownRendererEllipsis} macro replaces any occurance of ASCII
% ellipses in the input text. This macro will only be produced, when the
% \Opt{smartEllipses} option is \t`true`.  The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererEllipsis{%
  \markdownRendererEllipsisPrototype}%
%    \end{macrocode}
%
% \paragraph{Non-breaking Space Renderer}
% The \mdef{markdownRendererNbsp} macro represents a non-breaking space.
%  \begin{macrocode}
\def\markdownRendererNbsp{%
  \markdownRendererNbspPrototype}%
%    \end{macrocode}
%
% \paragraph{Special Character Renderers}
% The following macros replace any special plain \TeX{} characters (including
% the active pipe character (\t`|`) of \Hologo{ConTeXt}) in the input text.
% These macros will only be produced, when the \Opt{hybrid} option is
% \t`false`.
%  \begin{macrocode}
\def\markdownRendererLeftBrace{%
  \markdownRendererLeftBracePrototype}%
\def\markdownRendererRightBrace{%
  \markdownRendererRightBracePrototype}%
\def\markdownRendererDollarSign{%
  \markdownRendererDollarSignPrototype}%
\def\markdownRendererPercentSign{%
  \markdownRendererPercentSignPrototype}%
\def\markdownRendererAmpersand{%
  \markdownRendererAmpersandPrototype}%
\def\markdownRendererUnderscore{%
  \markdownRendererUnderscorePrototype}%
\def\markdownRendererHash{%
  \markdownRendererHashPrototype}%
\def\markdownRendererCircumflex{%
  \markdownRendererCircumflexPrototype}%
\def\markdownRendererBackslash{%
  \markdownRendererBackslashPrototype}%
\def\markdownRendererTilde{%
  \markdownRendererTildePrototype}%
\def\markdownRendererPipe{%
  \markdownRendererPipePrototype}%
%    \end{macrocode}
%
% \paragraph{Code Span Renderer}
% The \mdef{markdownRendererCodeSpan} macro represents inlined code span in the
% input text. It receives a single argument that corresponds to the inlined
% code span.
%  \begin{macrocode}
\def\markdownRendererCodeSpan{%
  \markdownRendererCodeSpanPrototype}%
%    \end{macrocode}
%
% \paragraph{Link Renderer}
% The \mdef{markdownRendererLink} macro represents a hyperlink. It receives
% four arguments: the label, the fully escaped \acro{uri} that can be directly
% typeset, the raw \acro{uri} that can be used outside typesetting, and the
% title of the link.
%  \begin{macrocode}
\def\markdownRendererLink{%
  \markdownRendererLinkPrototype}%
%    \end{macrocode}
%
% \paragraph{Image Renderer}
% The \mdef{markdownRendererImage} macro represents an image. It receives
% four arguments: the label, the fully escaped \acro{uri} that can be directly
% typeset, the raw \acro{uri} that can be used outside typesetting, and the
% title of the link.
%  \begin{macrocode}
\def\markdownRendererImage{%
  \markdownRendererImagePrototype}%
%    \end{macrocode}
%
% \paragraph{Content Block Renderers}\label{sec:texcontentblockrenderers}
% The \mdef{markdownRendererContentBlock} macro represents an iA\,Writer content
% block. It receives four arguments: the local file or online image filename
% extension cast to the lower case, the fully escaped \acro{uri} that can be
% directly typeset, the raw \acro{uri} that can be used outside typesetting,
% and the title of the content block.
%  \begin{macrocode}
\def\markdownRendererContentBlock{%
  \markdownRendererContentBlockPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererContentBlockOnlineImage} macro represents an
% iA\,Writer online image content block. The macro receives the same arguments
% as \m{markdownRendererContentBlock}.
%  \begin{macrocode}
\def\markdownRendererContentBlockOnlineImage{%
  \markdownRendererContentBlockOnlineImagePrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererContentBlockCode} macro represents an iA\,Writer
% content block that was recognized as a file in a known programming language
% by its filename extension $s$. If any \t`markdown-languages.json` file found
% by \pkg{kpathsea}\footnote{Local files take precedence. Filenames other
% than \t`markdown-languages.json` may be specified using the
% \t`contentBlocksLanguageMap` Lua option.} contains a record $(k, v)$, then a
% non-online-image content block with the filename extension $s,
% s$\t`:lower()`${}=k$ is considered to be in a known programming language $v$.
% The macro receives five arguments: the local file name extension $s$ cast to
% the lower case, the language $v$, the fully escaped \acro{uri} that can be
% directly typeset, the raw \acro{uri} that can be used outside typesetting,
% and the title of the content block.
%
% Note that you will need to place place a \t`markdown-languages.json` file
% inside your working directory or inside your local TeX directory structure.
% In this file, you will define a mapping between filename extensions and the
% language names recognized by your favorite syntax highlighter; there may
% exist other creative uses beside syntax highlighting. The \t`Languages.json`
% file provided by \cite{sotkov17} is a good starting point.
%  \begin{macrocode}
\def\markdownRendererContentBlockCode{%
  \markdownRendererContentBlockCodePrototype}%
%    \end{macrocode}
%
% \paragraph{Bullet List Renderers}
% The \mdef{markdownRendererUlBegin} macro represents the beginning of a
% bulleted list that contains an item with several paragraphs of text (the
% list is not tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlBegin{%
  \markdownRendererUlBeginPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererUlBeginTight} macro represents the beginning of a
% bulleted list that contains no item with several paragraphs of text (the list
% is tight). This macro will only be produced, when the \Opt{tightLists} option
% is \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlBeginTight{%
  \markdownRendererUlBeginTightPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererUlItem} macro represents an item in a bulleted
% list. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlItem{%
  \markdownRendererUlItemPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererUlItemEnd} macro represents the end of an item in a
% bulleted list. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlItemEnd{%
  \markdownRendererUlItemEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererUlEnd} macro represents the end of a bulleted list
% that contains an item with several paragraphs of text (the list is not
% tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlEnd{%
  \markdownRendererUlEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererUlEndTight} macro represents the end of a bulleted
% list that contains no item with several paragraphs of text (the list is
% tight). This macro will only be produced, when the \Opt{tightLists} option is
% \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererUlEndTight{%
  \markdownRendererUlEndTightPrototype}%
%    \end{macrocode}
%
% \paragraph{Ordered List Renderers}
% The \mdef{markdownRendererOlBegin} macro represents the beginning of an
% ordered list that contains an item with several paragraphs of text (the
% list is not tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlBegin{%
  \markdownRendererOlBeginPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlBeginTight} macro represents the beginning of an
% ordered list that contains no item with several paragraphs of text (the
% list is tight). This macro will only be produced, when the \Opt{tightLists}
% option is \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlBeginTight{%
  \markdownRendererOlBeginTightPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlItem} macro represents an item in an ordered list.
% This macro will only be produced, when the \Opt{startNumber} option is
% \t`false`.  The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlItem{%
  \markdownRendererOlItemPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlItemEnd} macro represents the end of an item in
% an ordered list. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlItemEnd{%
  \markdownRendererOlItemEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlItemWithNumber} macro represents an item in an
% ordered list.  This macro will only be produced, when the \Opt{startNumber}
% option is \t`true`.  The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlItemWithNumber{%
  \markdownRendererOlItemWithNumberPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlEnd} macro represents the end of an ordered list
% that contains an item with several paragraphs of text (the list is not
% tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlEnd{%
  \markdownRendererOlEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererOlEndTight} macro represents the end of an ordered
% list that contains no item with several paragraphs of text (the list is
% tight). This macro will only be produced, when the \Opt{tightLists} option is
% \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererOlEndTight{%
  \markdownRendererOlEndTightPrototype}%
%    \end{macrocode}
%
% \paragraph{Definition List Renderers}
% The following macros are only produces, when the \Opt{definitionLists} option
% is \t`true`.
%
% The \mdef{markdownRendererDlBegin} macro represents the beginning of a
% definition list that contains an item with several paragraphs of text (the
% list is not tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererDlBegin{%
  \markdownRendererDlBeginPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlBeginTight} macro represents the beginning of a
% definition list that contains an item with several paragraphs of text (the
% list is not tight). This macro will only be produced, when the
% \Opt{tightLists} option is \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererDlBeginTight{%
  \markdownRendererDlBeginTightPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlItem} macro represents a term in a definition
% list. The macro receives a single argument that corresponds to the term
% being defined.
%  \begin{macrocode}
\def\markdownRendererDlItem{%
  \markdownRendererDlItemPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlItemEnd} macro represents the end of a list of
% definitions for a single term.
%  \begin{macrocode}
\def\markdownRendererDlItemEnd{%
  \markdownRendererDlItemEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlDefinitionBegin} macro represents the beginning
% of a definition in a definition list. There can be several definitions for
% a single term.
%  \begin{macrocode}
\def\markdownRendererDlDefinitionBegin{%
  \markdownRendererDlDefinitionBeginPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlDefinitionEnd} macro represents the end of a
% definition in a definition list. There can be several definitions for a
% single term.
%  \begin{macrocode}
\def\markdownRendererDlDefinitionEnd{%
  \markdownRendererDlDefinitionEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlEnd} macro represents the end of a definition
% list that contains an item with several paragraphs of text (the list is not
% tight). The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererDlEnd{%
  \markdownRendererDlEndPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererDlEndTight} macro represents the end of a
% definition list that contains no item with several paragraphs of text (the
% list is tight). This macro will only be produced, when the \Opt{tightLists}
% option is \t`false`. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererDlEndTight{%
  \markdownRendererDlEndTightPrototype}%
%    \end{macrocode}
%
% \paragraph{Emphasis Renderers}
% The \mdef{markdownRendererEmphasis} macro represents an emphasized span of
% text. The macro receives a single argument that corresponds to the emphasized
% span of text.
%  \begin{macrocode}
\def\markdownRendererEmphasis{%
  \markdownRendererEmphasisPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererStrongEmphasis} macro represents a strongly
% emphasized span of text. The macro receives a single argument that
% corresponds to the emphasized span of text.
%  \begin{macrocode}
\def\markdownRendererStrongEmphasis{%
  \markdownRendererStrongEmphasisPrototype}%
%    \end{macrocode}
%
% \paragraph{Block Quote Renderers}
% The \mdef{markdownRendererBlockQuoteBegin} macro represents the beginning of
% a block quote. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererBlockQuoteBegin{%
  \markdownRendererBlockQuoteBeginPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererBlockQuoteEnd} macro represents the end of a block
% quote. The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererBlockQuoteEnd{%
  \markdownRendererBlockQuoteEndPrototype}%
%    \end{macrocode}
%
% \paragraph{Code Block Renderers}
% The \mdef{markdownRendererInputVerbatim} macro represents a code
% block. The macro receives a single argument that corresponds to the
% filename of a file contaning the code block contents.
%  \begin{macrocode}
\def\markdownRendererInputVerbatim{%
  \markdownRendererInputVerbatimPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererInputFencedCode} macro represents a fenced code
% block. This macro will only be produced, when the \Opt{fencedCode} option is
% \t`true`. The macro receives two arguments that correspond to the filename of
% a file contaning the code block contents and to the code fence infostring.
%  \begin{macrocode}
\def\markdownRendererInputFencedCode{%
  \markdownRendererInputFencedCodePrototype}%
%    \end{macrocode}
%
% \paragraph{Heading Renderers}
% The \mdef{markdownRendererHeadingOne} macro represents a first level heading.
% The macro receives a single argument that corresponds to the heading text.
%  \begin{macrocode}
\def\markdownRendererHeadingOne{%
  \markdownRendererHeadingOnePrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererHeadingTwo} macro represents a second level
% heading. The macro receives a single argument that corresponds to the heading
% text.
%  \begin{macrocode}
\def\markdownRendererHeadingTwo{%
  \markdownRendererHeadingTwoPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererHeadingThree} macro represents a third level
% heading. The macro receives a single argument that corresponds to the heading
% text.
%  \begin{macrocode}
\def\markdownRendererHeadingThree{%
  \markdownRendererHeadingThreePrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererHeadingFour} macro represents a fourth level
% heading. The macro receives a single argument that corresponds to the heading
% text.
%  \begin{macrocode}
\def\markdownRendererHeadingFour{%
  \markdownRendererHeadingFourPrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererHeadingFive} macro represents a fifth level
% heading. The macro receives a single argument that corresponds to the heading
% text.
%  \begin{macrocode}
\def\markdownRendererHeadingFive{%
  \markdownRendererHeadingFivePrototype}%
%    \end{macrocode}
%
% The \mdef{markdownRendererHeadingSix} macro represents a sixth level
% heading. The macro receives a single argument that corresponds to the heading
% text.
%  \begin{macrocode}
\def\markdownRendererHeadingSix{%
  \markdownRendererHeadingSixPrototype}%
%    \end{macrocode}
%
% \paragraph{Horizontal Rule Renderer}
% The \mdef{markdownRendererHorizontalRule} macro represents a horizontal rule.
% The macro receives no arguments.
%  \begin{macrocode}
\def\markdownRendererHorizontalRule{%
  \markdownRendererHorizontalRulePrototype}%
%    \end{macrocode}
%
% \paragraph{Footnote Renderer}
% The \mdef{markdownRendererFootnote} macro represents a footnote. This macro
% will only be produced, when the \Opt{footnotes} option is \t`true`.  The
% macro receives a single argument that corresponds to the footnote text.
%  \begin{macrocode}
\def\markdownRendererFootnote{%
  \markdownRendererFootnotePrototype}%
%    \end{macrocode}
%
% \paragraph{Parenthesized Citations Renderer}
% The \mdef{markdownRendererCite} macro represents a string of one or more
% parenthetical citations. This macro will only be produced, when the
% \Opt{citations} option is \t`true`. The macro receives the parameter
% \t`\textbraceleft`\meta{number of citations}\t`\textbraceright` followed by
% \meta{suppress author}\t`\textbraceleft`\meta{prenote}\t`\textbraceright^^A
% \textbraceleft`\meta{postnote}\t`\textbraceright\textbraceleft`\meta{name}^^A
% \t`\textbraceright` repeated \meta{number of citations} times. The
% \meta{suppress author} parameter is either the token \t`-`, when the author's
% name is to be suppressed, or \t`+` otherwise.
%  \begin{macrocode}
\def\markdownRendererCite{%
  \markdownRendererCitePrototype}%
%    \end{macrocode}
%
% \paragraph{Text Citations Renderer}
% The \mdef{markdownRendererTextCite} macro represents a string of one or more
% text citations. This macro will only be produced, when the
% \Opt{citations} option is \t`true`. The macro receives parameters in the same 
% format as the \m{markdownRendererCite} macro.
%  \begin{macrocode}
\def\markdownRendererTextCite{%
  \markdownRendererTextCitePrototype}%
%    \end{macrocode}
%
% \subsubsection{Token Renderer Prototypes}\label{sec:texrendererprototypes}
% The following \TeX{} macros provide definitions for the token renderers (see
% Section \ref{sec:texrenderersuser}) that have not been redefined by the
% user. These macros are intended to be redefined by macro package authors
% who wish to provide sensible default token renderers. They are also redefined
% by the \LaTeX{} and \Hologo{ConTeXt} implementations (see sections
% \ref{sec:lateximplementation} and \ref{sec:contextimplementation}).
%  \begin{macrocode}
\def\markdownRendererInterblockSeparatorPrototype{}%
\def\markdownRendererLineBreakPrototype{}%
\def\markdownRendererEllipsisPrototype{}%
\def\markdownRendererNbspPrototype{}%
\def\markdownRendererLeftBracePrototype{}%
\def\markdownRendererRightBracePrototype{}%
\def\markdownRendererDollarSignPrototype{}%
\def\markdownRendererPercentSignPrototype{}%
\def\markdownRendererAmpersandPrototype{}%
\def\markdownRendererUnderscorePrototype{}%
\def\markdownRendererHashPrototype{}%
\def\markdownRendererCircumflexPrototype{}%
\def\markdownRendererBackslashPrototype{}%
\def\markdownRendererTildePrototype{}%
\def\markdownRendererPipePrototype{}%
\def\markdownRendererCodeSpanPrototype#1{}%
\def\markdownRendererLinkPrototype#1#2#3#4{}%
\def\markdownRendererImagePrototype#1#2#3#4{}%
\def\markdownRendererContentBlockPrototype#1#2#3#4{}%
\def\markdownRendererContentBlockOnlineImagePrototype#1#2#3#4{}%
\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{}%
\def\markdownRendererUlBeginPrototype{}%
\def\markdownRendererUlBeginTightPrototype{}%
\def\markdownRendererUlItemPrototype{}%
\def\markdownRendererUlItemEndPrototype{}%
\def\markdownRendererUlEndPrototype{}%
\def\markdownRendererUlEndTightPrototype{}%
\def\markdownRendererOlBeginPrototype{}%
\def\markdownRendererOlBeginTightPrototype{}%
\def\markdownRendererOlItemPrototype{}%
\def\markdownRendererOlItemWithNumberPrototype#1{}%
\def\markdownRendererOlItemEndPrototype{}%
\def\markdownRendererOlEndPrototype{}%
\def\markdownRendererOlEndTightPrototype{}%
\def\markdownRendererDlBeginPrototype{}%
\def\markdownRendererDlBeginTightPrototype{}%
\def\markdownRendererDlItemPrototype#1{}%
\def\markdownRendererDlItemEndPrototype{}%
\def\markdownRendererDlDefinitionBeginPrototype{}%
\def\markdownRendererDlDefinitionEndPrototype{}%
\def\markdownRendererDlEndPrototype{}%
\def\markdownRendererDlEndTightPrototype{}%
\def\markdownRendererEmphasisPrototype#1{}%
\def\markdownRendererStrongEmphasisPrototype#1{}%
\def\markdownRendererBlockQuoteBeginPrototype{}%
\def\markdownRendererBlockQuoteEndPrototype{}%
\def\markdownRendererInputVerbatimPrototype#1{}%
\def\markdownRendererInputFencedCodePrototype#1#2{}%
\def\markdownRendererHeadingOnePrototype#1{}%
\def\markdownRendererHeadingTwoPrototype#1{}%
\def\markdownRendererHeadingThreePrototype#1{}%
\def\markdownRendererHeadingFourPrototype#1{}%
\def\markdownRendererHeadingFivePrototype#1{}%
\def\markdownRendererHeadingSixPrototype#1{}%
\def\markdownRendererHorizontalRulePrototype{}%
\def\markdownRendererFootnotePrototype#1{}%
\def\markdownRendererCitePrototype#1{}%
\def\markdownRendererTextCitePrototype#1{}%
%    \end{macrocode}
%
% \subsubsection{Logging Facilities}
% The \mdef{markdownInfo}, \mdef{markdownWarning}, and
% \mdef{markdownError} macros provide access to logging to the rest of
% the macros. Their first argument specifies the text of the info, warning, or
% error message.
%  \begin{macrocode}
\def\markdownInfo#1{}%
\def\markdownWarning#1{}%
%    \end{macrocode}
% The \m{markdownError} macro receives a second argument that provides a help
% text suggesting a remedy to the error.
%  \begin{macrocode}
\def\markdownError#1#2{}%
%    \end{macrocode}
% You may redefine these macros to redirect and process the info, warning, and
% error messages.
%
% \subsubsection{Miscellanea}
% The \mdef{markdownMakeOther} macro is used by the package, when a \TeX{}
% engine that does not support direct Lua access is starting to buffer a text.
% The plain \TeX{} implementation changes the category code of plain \TeX{}
% special characters to other, but there may be other active characters that
% may break the output. This macro should temporarily change the category of
% these to \emph{other}.
%  \begin{macrocode}
\let\markdownMakeOther\relax
%    \end{macrocode}
%
% The \mdef{markdownReadAndConvert} macro implements the \m{markdownBegin}
% macro. The first argument specifies the token sequence that will terminate
% the markdown input (\m{markdownEnd} in the instance of the \m{markdownBegin}
% macro) when the plain \TeX{} special characters have had their category
% changed to \emph{other}. The second argument specifies the token sequence
% that will actually be inserted into the document, when the ending token
% sequence has been found.
%  \begin{macrocode}
\let\markdownReadAndConvert\relax
\begingroup
%    \end{macrocode}
% Locally swap the category code of the backslash symbol (\t`\textbackslash`)
% with the pipe symbol (\t`|`). This is required in order that all the special
% symbols in the first argument of the \t`markdownReadAndConvert` macro have
% the category code \emph{other}.
%  \begin{macrocode}
  \catcode`\|=0\catcode`\\=12%
  |gdef|markdownBegin{%
    |markdownReadAndConvert{\markdownEnd}%
                           {|markdownEnd}}%
|endgroup
%    \end{macrocode}
% The macro is exposed in the interface, so that the user can create their own
% markdown environments. Due to the way the arguments are passed to Lua (see
% Section \ref{sec:directlua}), the first argument may not contain the
% string \t`]]` (regardless of the category code of the bracket symbol (\t`]`)).
%
% The \mdef{markdownMode} macro specifies how the plain \TeX{} implementation
% interfaces with the Lua interface. The valid values and their meaning are
% as follows:
% \begin{itemize}
%   \item\t`0` -- Shell escape via the 18 output file stream
%   \item\t`1` -- Shell escape via the Lua \luam{os.execute} method
%   \item\t`2` -- Direct Lua access
% \end{itemize}
% By defining the macro, the user can coerce the package to use a specific mode.
% If the user does not define the macro prior to loading the plain \TeX{}
% implementation, the correct value will be automatically detected. The outcome
% of changing the value of \m{markdownMode} after the implementation has been
% loaded is undefined.
%  \begin{macrocode}
\ifx\markdownMode\undefined
  \ifx\directlua\undefined
    \def\markdownMode{0}%
  \else
    \def\markdownMode{2}%
  \fi
\fi
%    \end{macrocode}
% 
% The following macros are no longer a part of the plain \TeX{} interface and
% are only defined for backwards compatibility:
%  \begin{macrocode}
\def\markdownLuaRegisterIBCallback#1{\relax}%
\def\markdownLuaUnregisterIBCallback#1{\relax}%
%    \end{macrocode}
% \iffalse
%</tex>
%<*latex>
% \fi\subsection{\LaTeX{} Interface}\label{sec:latexinterface}
% The \LaTeX{} interface provides \LaTeX{} environments for the typesetting of
% markdown input from within \LaTeX{}, facilities for setting Lua interface
% options (see Section \ref{sec:luaoptions}) used during the conversion from
% markdown to plain \TeX{}, and facilities for changing the way markdown tokens
% are rendered. The rest of the interface is inherited from the plain \TeX{}
% interface (see Section \ref{sec:texinterface}).
%
% The \LaTeX{} interface is implemented by the \t`markdown.sty` file, which
% can be loaded from the \LaTeX{} document preamble as follows:
% \begin{Verbatim}[commandchars=\\\{\}]
% \textbackslash{}usepackage[\textrm{\meta{options}}]\{markdown\}
% \end{Verbatim}
% where \meta{options} are the \LaTeX{} interface options (see Section
% \ref{sec:latexoptions}). Note that \meta{options} inside the \m{usepackage}
% macro may not set the \t`markdownRenderers` (see Section
% \ref{sec:latexrenderers}) and \t`markdownRendererPrototypes` (see Section
% \ref{sec:latexrendererprototypes}) keys. This limitation is due to the way
% \Hologo{LaTeX2e} parses package options.
%
% \subsubsection{Typesetting Markdown}
% The interface exposes the \envmdef{markdown} and \envmdef{markdown*}
% \LaTeX{} environments, and redefines the \m{markdownInput} command.
%
% The \envm{markdown} and \envm{markdown*} \LaTeX{} environments are used to
% typeset markdown document fragments. The starred version of the
% \envm{markdown} environment accepts \LaTeX{} interface options (see
% Section \ref{sec:latexoptions}) as its only argument. These options will
% only influnce this markdown document fragment.
%  \begin{macrocode}
\newenvironment{markdown}\relax\relax
\newenvironment{markdown*}[1]\relax\relax
%    \end{macrocode}
% You may prepend your own code to the \m{markdown} macro and append your own
% code to the \m{endmarkdown} macro to produce special effects before and after
% the \envm{markdown} \LaTeX{} environment (and likewise for the starred
% version).
%
% Note that the \envm{markdown} and \envm{markdown*} \LaTeX{} environments are
% subject to the same limitations as the \m{markdownBegin} and \m{markdownEnd}
% macros exposed by the plain \TeX{} interface.
%
% The following example \LaTeX{} code showcases the usage of the
% \envm{markdown} and \envm{markdown*} environments:
% \begin{Verbatim}
% \documentclass{article}            \documentclass{article}
% \usepackage{markdown}              \usepackage{markdown}
% \begin{document}                   \begin{document}
% % ...                              % ...
% \begin{markdown}                   \begin{markdown*}{smartEllipses}
% _Hello_ **world** ...              _Hello_ **world** ...
% \end{markdown}                     \end{markdown*}
% % ...                              % ...
% \end{document}                     \end{document}
% \end{Verbatim}
%
% The \m{markdownInput} macro accepts a single mandatory parameter containing
% the filename of a markdown document and expands to the result of the
% conversion of the input markdown document to plain \TeX{}.  Unlike the
% \m{markdownInput} macro provided by the plain \TeX{} interface, this macro
% also accepts \LaTeX{} interface options (see Section \ref{sec:latexoptions})
% as its optional argument. These options will only influnce this markdown
% document.
%
% The following example \LaTeX{} code showcases the usage of the
% \m{markdownInput} macro:
% \begin{Verbatim}
% \documentclass{article}
% \usepackage{markdown}
% \begin{document}
% % ...
% \markdownInput[smartEllipses]{hello.md}
% % ...
% \end{document}
% \end{Verbatim}
%
% \subsubsection{Options}\label{sec:latexoptions}
% The \LaTeX{} options are represented by a comma-delimited list of
% \meta{\meta{key}=\meta{value}} pairs. For boolean options, the
% \meta{=\meta{value}} part is optional, and \meta{\meta{key}} will be
% interpreted as \meta{\meta{key}=true}.
%
% The \LaTeX{} options map directly to the options recognized by the plain
% \TeX{} interface (see Section \ref{sec:texoptions}) and to the markdown token
% renderers and their prototypes recognized by the plain \TeX{} interface (see
% Sections \ref{sec:texrenderersuser} and \ref{sec:texrendererprototypes}).
%
% The \LaTeX{} options may be specified when loading the \LaTeX{} package (see
% Section \ref{sec:latexinterface}), when using the \envm{markdown*} \LaTeX{}
% environment, or via the \mdef{markdownSetup} macro.  The \m{markdownSetup}
% macro receives the options to set up as its only argument.
%  \begin{macrocode}
\newcommand\markdownSetup[1]{%
  \setkeys{markdownOptions}{#1}}%
%    \end{macrocode}
%
% \paragraph{Plain \TeX{} Interface Options}
% The following options map directly to the option macros exposed by the plain
% \TeX{} interface (see Section \ref{sec:texoptions}).
%  \begin{macrocode}
\define@key{markdownOptions}{helperScriptFileName}{%
  \def\markdownOptionHelperScriptFileName{#1}}%
\define@key{markdownOptions}{inputTempFileName}{%
  \def\markdownOptionInputTempFileName{#1}}%
\define@key{markdownOptions}{outputTempFileName}{%
  \def\markdownOptionOutputTempFileName{#1}}%
\define@key{markdownOptions}{errorTempFileName}{%
  \def\markdownOptionErrorTempFileName{#1}}%
\define@key{markdownOptions}{cacheDir}{%
  \def\markdownOptionCacheDir{#1}}%
\define@key{markdownOptions}{outputDir}{%
  \def\markdownOptionOutputDir{#1}}%
\define@key{markdownOptions}{blankBeforeBlockquote}[true]{%
  \def\markdownOptionBlankBeforeBlockquote{#1}}%
\define@key{markdownOptions}{blankBeforeCodeFence}[true]{%
  \def\markdownOptionBlankBeforeCodeFence{#1}}%
\define@key{markdownOptions}{blankBeforeHeading}[true]{%
  \def\markdownOptionBlankBeforeHeading{#1}}%
\define@key{markdownOptions}{breakableBlockquotes}[true]{%
  \def\markdownOptionBreakableBlockquotes{#1}}%
\define@key{markdownOptions}{citations}[true]{%
  \def\markdownOptionCitations{#1}}%
\define@key{markdownOptions}{citationNbsps}[true]{%
  \def\markdownOptionCitationNbsps{#1}}%
\define@key{markdownOptions}{contentBlocks}[true]{%
  \def\markdownOptionContentBlocks{#1}}%
\define@key{markdownOptions}{codeSpans}[true]{%
  \def\markdownOptionCodeSpans{#1}}%
\define@key{markdownOptions}{contentBlocksLanguageMap}{%
  \def\markdownOptionContentBlocksLanguageMap{#1}}%
\define@key{markdownOptions}{definitionLists}[true]{%
  \def\markdownOptionDefinitionLists{#1}}%
\define@key{markdownOptions}{footnotes}[true]{%
  \def\markdownOptionFootnotes{#1}}%
\define@key{markdownOptions}{fencedCode}[true]{%
  \def\markdownOptionFencedCode{#1}}%
\define@key{markdownOptions}{hashEnumerators}[true]{%
  \def\markdownOptionHashEnumerators{#1}}%
\define@key{markdownOptions}{html}[true]{%
  \def\markdownOptionHtml{#1}}%
\define@key{markdownOptions}{hybrid}[true]{%
  \def\markdownOptionHybrid{#1}}%
\define@key{markdownOptions}{inlineFootnotes}[true]{%
  \def\markdownOptionInlineFootnotes{#1}}%
\define@key{markdownOptions}{preserveTabs}[true]{%
  \def\markdownOptionPreserveTabs{#1}}%
\define@key{markdownOptions}{smartEllipses}[true]{%
  \def\markdownOptionSmartEllipses{#1}}%
\define@key{markdownOptions}{startNumber}[true]{%
  \def\markdownOptionStartNumber{#1}}%
\define@key{markdownOptions}{tightLists}[true]{%
  \def\markdownOptionTightLists{#1}}%
\define@key{markdownOptions}{underscores}[true]{%
  \def\markdownOptionUnderscores{#1}}%
%    \end{macrocode}
%
% The following example \LaTeX{} code showcases a possible configuration of
% plain \TeX{} interface options \m{markdownOptionHybrid},
% \m{markdownOptionSmartEllipses}, and \m{markdownOptionCacheDir}.
% \begin{Verbatim}
% \markdownSetup{
%   hybrid,
%   smartEllipses,
%   cacheDir = /tmp,
% }
% \end{Verbatim}
%
% \paragraph{Plain \TeX{} Markdown Token Renderers}\label{sec:latexrenderers}
% The \LaTeX{} interface recognizes an option with the \t`renderers` key,
% whose value must be a list of options that map directly to the markdown token
% renderer macros exposed by the plain \TeX{} interface (see Section
% \ref{sec:texrenderersuser}).
%  \begin{macrocode}
\define@key{markdownRenderers}{interblockSeparator}{%
  \renewcommand\markdownRendererInterblockSeparator{#1}}%
\define@key{markdownRenderers}{lineBreak}{%
  \renewcommand\markdownRendererLineBreak{#1}}%
\define@key{markdownRenderers}{ellipsis}{%
  \renewcommand\markdownRendererEllipsis{#1}}%
\define@key{markdownRenderers}{nbsp}{%
  \renewcommand\markdownRendererNbsp{#1}}%
\define@key{markdownRenderers}{leftBrace}{%
  \renewcommand\markdownRendererLeftBrace{#1}}%
\define@key{markdownRenderers}{rightBrace}{%
  \renewcommand\markdownRendererRightBrace{#1}}%
\define@key{markdownRenderers}{dollarSign}{%
  \renewcommand\markdownRendererDollarSign{#1}}%
\define@key{markdownRenderers}{percentSign}{%
  \renewcommand\markdownRendererPercentSign{#1}}%
\define@key{markdownRenderers}{ampersand}{%
  \renewcommand\markdownRendererAmpersand{#1}}%
\define@key{markdownRenderers}{underscore}{%
  \renewcommand\markdownRendererUnderscore{#1}}%
\define@key{markdownRenderers}{hash}{%
  \renewcommand\markdownRendererHash{#1}}%
\define@key{markdownRenderers}{circumflex}{%
  \renewcommand\markdownRendererCircumflex{#1}}%
\define@key{markdownRenderers}{backslash}{%
  \renewcommand\markdownRendererBackslash{#1}}%
\define@key{markdownRenderers}{tilde}{%
  \renewcommand\markdownRendererTilde{#1}}%
\define@key{markdownRenderers}{pipe}{%
  \renewcommand\markdownRendererPipe{#1}}%
\define@key{markdownRenderers}{codeSpan}{%
  \renewcommand\markdownRendererCodeSpan[1]{#1}}%
\define@key{markdownRenderers}{link}{%
  \renewcommand\markdownRendererLink[4]{#1}}%
\define@key{markdownRenderers}{contentBlock}{%
  \renewcommand\markdownRendererContentBlock[4]{#1}}%
\define@key{markdownRenderers}{contentBlockOnlineImage}{%
  \renewcommand\markdownRendererContentBlockOnlineImage[4]{#1}}%
\define@key{markdownRenderers}{contentBlockCode}{%
  \renewcommand\markdownRendererContentBlockCode[5]{#1}}%
\define@key{markdownRenderers}{image}{%
  \renewcommand\markdownRendererImage[4]{#1}}%
\define@key{markdownRenderers}{ulBegin}{%
  \renewcommand\markdownRendererUlBegin{#1}}%
\define@key{markdownRenderers}{ulBeginTight}{%
  \renewcommand\markdownRendererUlBeginTight{#1}}%
\define@key{markdownRenderers}{ulItem}{%
  \renewcommand\markdownRendererUlItem{#1}}%
\define@key{markdownRenderers}{ulItemEnd}{%
  \renewcommand\markdownRendererUlItemEnd{#1}}%
\define@key{markdownRenderers}{ulEnd}{%
  \renewcommand\markdownRendererUlEnd{#1}}%
\define@key{markdownRenderers}{ulEndTight}{%
  \renewcommand\markdownRendererUlEndTight{#1}}%
\define@key{markdownRenderers}{olBegin}{%
  \renewcommand\markdownRendererOlBegin{#1}}%
\define@key{markdownRenderers}{olBeginTight}{%
  \renewcommand\markdownRendererOlBeginTight{#1}}%
\define@key{markdownRenderers}{olItem}{%
  \renewcommand\markdownRendererOlItem{#1}}%
\define@key{markdownRenderers}{olItemWithNumber}{%
  \renewcommand\markdownRendererOlItemWithNumber[1]{#1}}%
\define@key{markdownRenderers}{olItemEnd}{%
  \renewcommand\markdownRendererOlItemEnd{#1}}%
\define@key{markdownRenderers}{olEnd}{%
  \renewcommand\markdownRendererOlEnd{#1}}%
\define@key{markdownRenderers}{olEndTight}{%
  \renewcommand\markdownRendererOlEndTight{#1}}%
\define@key{markdownRenderers}{dlBegin}{%
  \renewcommand\markdownRendererDlBegin{#1}}%
\define@key{markdownRenderers}{dlBeginTight}{%
  \renewcommand\markdownRendererDlBeginTight{#1}}%
\define@key{markdownRenderers}{dlItem}{%
  \renewcommand\markdownRendererDlItem[1]{#1}}%
\define@key{markdownRenderers}{dlItemEnd}{%
  \renewcommand\markdownRendererDlItemEnd{#1}}%
\define@key{markdownRenderers}{dlDefinitionBegin}{%
  \renewcommand\markdownRendererDlDefinitionBegin{#1}}%
\define@key{markdownRenderers}{dlDefinitionEnd}{%
  \renewcommand\markdownRendererDlDefinitionEnd{#1}}%
\define@key{markdownRenderers}{dlEnd}{%
  \renewcommand\markdownRendererDlEnd{#1}}%
\define@key{markdownRenderers}{dlEndTight}{%
  \renewcommand\markdownRendererDlEndTight{#1}}%
\define@key{markdownRenderers}{emphasis}{%
  \renewcommand\markdownRendererEmphasis[1]{#1}}%
\define@key{markdownRenderers}{strongEmphasis}{%
  \renewcommand\markdownRendererStrongEmphasis[1]{#1}}%
\define@key{markdownRenderers}{blockQuoteBegin}{%
  \renewcommand\markdownRendererBlockQuoteBegin{#1}}%
\define@key{markdownRenderers}{blockQuoteEnd}{%
  \renewcommand\markdownRendererBlockQuoteEnd{#1}}%
\define@key{markdownRenderers}{inputVerbatim}{%
  \renewcommand\markdownRendererInputVerbatim[1]{#1}}%
\define@key{markdownRenderers}{inputFencedCode}{%
  \renewcommand\markdownRendererInputFencedCode[2]{#1}}%
\define@key{markdownRenderers}{headingOne}{%
  \renewcommand\markdownRendererHeadingOne[1]{#1}}%
\define@key{markdownRenderers}{headingTwo}{%
  \renewcommand\markdownRendererHeadingTwo[1]{#1}}%
\define@key{markdownRenderers}{headingThree}{%
  \renewcommand\markdownRendererHeadingThree[1]{#1}}%
\define@key{markdownRenderers}{headingFour}{%
  \renewcommand\markdownRendererHeadingFour[1]{#1}}%
\define@key{markdownRenderers}{headingFive}{%
  \renewcommand\markdownRendererHeadingFive[1]{#1}}%
\define@key{markdownRenderers}{headingSix}{%
  \renewcommand\markdownRendererHeadingSix[1]{#1}}%
\define@key{markdownRenderers}{horizontalRule}{%
  \renewcommand\markdownRendererHorizontalRule{#1}}%
\define@key{markdownRenderers}{footnote}{%
  \renewcommand\markdownRendererFootnote[1]{#1}}%
\define@key{markdownRenderers}{cite}{%
  \renewcommand\markdownRendererCite[1]{#1}}%
\define@key{markdownRenderers}{textCite}{%
  \renewcommand\markdownRendererTextCite[1]{#1}}%
%    \end{macrocode}
%
% The following example \LaTeX{} code showcases a possible configuration of the
% \m{markdownRendererLink} and \m{markdownRendererEmphasis} markdown token
% renderers.
% \begin{Verbatim}
% \markdownSetup{
%   renderers = {
%     link = {#4},                   % Render links as the link title.
%     emphasis = {\emph{#1}},    % Render emphasized text via `\emph`.
%   }
% }
% \end{Verbatim}
%
% \paragraph{Plain \TeX{} Markdown Token Renderer Prototypes}
% \label{sec:latexrendererprototypes}
% The \LaTeX{} interface recognizes an option with the \t`rendererPrototypes`
% key, whose value must be a list of options that map directly to the markdown
% token renderer prototype macros exposed by the plain \TeX{} interface (see
% Section \ref{sec:texrendererprototypes}).
%  \begin{macrocode}
\define@key{markdownRendererPrototypes}{interblockSeparator}{%
  \renewcommand\markdownRendererInterblockSeparatorPrototype{#1}}%
\define@key{markdownRendererPrototypes}{lineBreak}{%
  \renewcommand\markdownRendererLineBreakPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ellipsis}{%
  \renewcommand\markdownRendererEllipsisPrototype{#1}}%
\define@key{markdownRendererPrototypes}{nbsp}{%
  \renewcommand\markdownRendererNbspPrototype{#1}}%
\define@key{markdownRendererPrototypes}{leftBrace}{%
  \renewcommand\markdownRendererLeftBracePrototype{#1}}%
\define@key{markdownRendererPrototypes}{rightBrace}{%
  \renewcommand\markdownRendererRightBracePrototype{#1}}%
\define@key{markdownRendererPrototypes}{dollarSign}{%
  \renewcommand\markdownRendererDollarSignPrototype{#1}}%
\define@key{markdownRendererPrototypes}{percentSign}{%
  \renewcommand\markdownRendererPercentSignPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ampersand}{%
  \renewcommand\markdownRendererAmpersandPrototype{#1}}%
\define@key{markdownRendererPrototypes}{underscore}{%
  \renewcommand\markdownRendererUnderscorePrototype{#1}}%
\define@key{markdownRendererPrototypes}{hash}{%
  \renewcommand\markdownRendererHashPrototype{#1}}%
\define@key{markdownRendererPrototypes}{circumflex}{%
  \renewcommand\markdownRendererCircumflexPrototype{#1}}%
\define@key{markdownRendererPrototypes}{backslash}{%
  \renewcommand\markdownRendererBackslashPrototype{#1}}%
\define@key{markdownRendererPrototypes}{tilde}{%
  \renewcommand\markdownRendererTildePrototype{#1}}%
\define@key{markdownRendererPrototypes}{pipe}{%
  \renewcommand\markdownRendererPipePrototype{#1}}%
\define@key{markdownRendererPrototypes}{codeSpan}{%
  \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{link}{%
  \renewcommand\markdownRendererLinkPrototype[4]{#1}}%
\define@key{markdownRendererPrototypes}{contentBlock}{%
  \renewcommand\markdownRendererContentBlockPrototype[4]{#1}}%
\define@key{markdownRendererPrototypes}{contentBlockOnlineImage}{%
  \renewcommand\markdownRendererContentBlockOnlineImagePrototype[4]{#1}}%
\define@key{markdownRendererPrototypes}{contentBlockCode}{%
  \renewcommand\markdownRendererContentBlockCodePrototype[5]{#1}}%
\define@key{markdownRendererPrototypes}{image}{%
  \renewcommand\markdownRendererImagePrototype[4]{#1}}%
\define@key{markdownRendererPrototypes}{ulBegin}{%
  \renewcommand\markdownRendererUlBeginPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ulBeginTight}{%
  \renewcommand\markdownRendererUlBeginTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ulItem}{%
  \renewcommand\markdownRendererUlItemPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ulItemEnd}{%
  \renewcommand\markdownRendererUlItemEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ulEnd}{%
  \renewcommand\markdownRendererUlEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{ulEndTight}{%
  \renewcommand\markdownRendererUlEndTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olBegin}{%
  \renewcommand\markdownRendererOlBeginPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olBeginTight}{%
  \renewcommand\markdownRendererOlBeginTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olItem}{%
  \renewcommand\markdownRendererOlItemPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olItemWithNumber}{%
  \renewcommand\markdownRendererOlItemWithNumberPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{olItemEnd}{%
  \renewcommand\markdownRendererOlItemEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olEnd}{%
  \renewcommand\markdownRendererOlEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{olEndTight}{%
  \renewcommand\markdownRendererOlEndTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlBegin}{%
  \renewcommand\markdownRendererDlBeginPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlBeginTight}{%
  \renewcommand\markdownRendererDlBeginTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlItem}{%
  \renewcommand\markdownRendererDlItemPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{dlItemEnd}{%
  \renewcommand\markdownRendererDlItemEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlDefinitionBegin}{%
  \renewcommand\markdownRendererDlDefinitionBeginPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlDefinitionEnd}{%
  \renewcommand\markdownRendererDlDefinitionEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlEnd}{%
  \renewcommand\markdownRendererDlEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{dlEndTight}{%
  \renewcommand\markdownRendererDlEndTightPrototype{#1}}%
\define@key{markdownRendererPrototypes}{emphasis}{%
  \renewcommand\markdownRendererEmphasisPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{strongEmphasis}{%
  \renewcommand\markdownRendererStrongEmphasisPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{blockQuoteBegin}{%
  \renewcommand\markdownRendererBlockQuoteBeginPrototype{#1}}%
\define@key{markdownRendererPrototypes}{blockQuoteEnd}{%
  \renewcommand\markdownRendererBlockQuoteEndPrototype{#1}}%
\define@key{markdownRendererPrototypes}{inputVerbatim}{%
  \renewcommand\markdownRendererInputVerbatimPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{inputFencedCode}{%
  \renewcommand\markdownRendererInputFencedCodePrototype[2]{#1}}%
\define@key{markdownRendererPrototypes}{headingOne}{%
  \renewcommand\markdownRendererHeadingOnePrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{headingTwo}{%
  \renewcommand\markdownRendererHeadingTwoPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{headingThree}{%
  \renewcommand\markdownRendererHeadingThreePrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{headingFour}{%
  \renewcommand\markdownRendererHeadingFourPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{headingFive}{%
  \renewcommand\markdownRendererHeadingFivePrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{headingSix}{%
  \renewcommand\markdownRendererHeadingSixPrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{horizontalRule}{%
  \renewcommand\markdownRendererHorizontalRulePrototype{#1}}%
\define@key{markdownRendererPrototypes}{footnote}{%
  \renewcommand\markdownRendererFootnotePrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{cite}{%
  \renewcommand\markdownRendererCitePrototype[1]{#1}}%
\define@key{markdownRendererPrototypes}{textCite}{%
  \renewcommand\markdownRendererTextCitePrototype[1]{#1}}%
%    \end{macrocode}
%
% The following example \LaTeX{} code showcases a possible configuration of the
% \m{markdownRendererImagePrototype} and \m{markdownRendererCodeSpanPrototype}
% markdown token renderer prototypes.
% \begin{Verbatim}
% \markdownSetup{
%   rendererPrototypes = {
%     image = {\includegraphics{#2}},
%     codeSpan = {\texttt{#1}},    % Render inline code via `\texttt`.
%   }
% }
% \end{Verbatim}
%
% \iffalse
%</latex>
%<*context>
% \fi\subsection{\Hologo{ConTeXt} Interface}\label{sec:contextinterface}
% The \Hologo{ConTeXt} interface provides a start-stop macro pair for the
% typesetting of markdown input from within \Hologo{ConTeXt}. The rest of the
% interface is inherited from the plain \TeX{} interface (see Section
% \ref{sec:texinterface}).
%  \begin{macrocode}
\writestatus{loading}{ConTeXt User Module / markdown}%
\unprotect
%    \end{macrocode}
%
% The \Hologo{ConTeXt} interface is implemented by the
% \t`t-markdown.tex` \Hologo{ConTeXt} module file that can be loaded as follows:
% \begin{Verbatim}
% \usemodule[t][markdown]
% \end{Verbatim}
% It is expected that the special plain \TeX{} characters have the expected
% category codes, when \m{input}ting the file.
%
% \subsubsection{Typesetting Markdown}
% The interface exposes the \mdef{startmarkdown} and \mdef{stopmarkdown} macro
% pair for the typesetting of a markdown document fragment.
%  \begin{macrocode}
\let\startmarkdown\relax
\let\stopmarkdown\relax
%    \end{macrocode}
% You may prepend your own code to the \m{startmarkdown} macro and redefine the
% \m{stopmarkdown} macro to produce special effects before and after the
% markdown block.
%
% Note that the \m{startmarkdown} and \m{stopmarkdown} macros
% are subject to the same limitations as the \m{markdownBegin} and
% \m{markdownEnd} macros exposed by the plain \TeX{} interface.
%
% The following example \Hologo{ConTeXt} code showcases the usage of the
% \m{startmarkdown} and \m{stopmarkdown} macros:
% \begin{Verbatim}
% \usemodule[t][markdown]
% \starttext
% \startmarkdown
% _Hello_ **world** ...
% \stopmarkdown
% \stoptext
% \end{Verbatim}
% 
% \section{Technical Documentation}\label{sec:implementation}
% This part of the manual describes the implementation of the interfaces
% exposed by the package (see Section \ref{sec:interfaces}) and is aimed at the
% developers of the package, as well as the curious users.
%
% \iffalse
%</context>
%<*lua>
% \fi\subsection{Lua Implementation}\label{sec:luaimplementation}
% The Lua implementation implements \luamdef{writer} and \luamdef{reader}
% objects that provide the conversion from markdown to plain \TeX{}.
%
% The Lunamark Lua module implements writers for the conversion to various
% other formats, such as DocBook, Groff, or \acro{HTML}. These were stripped
% from the module and the remaining markdown reader and plain \TeX{} writer
% were hidden behind the converter functions exposed by the Lua interface (see
% Section \ref{sec:luainterface}).
%
%  \begin{macrocode}
local upper, gsub, format, length =
  string.upper, string.gsub, string.format, string.len
local concat = table.concat
local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, any =
  lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cg, lpeg.Cb,
  lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.P(1)
%    \end{macrocode}
% 
% \subsubsection{Utility Functions}
% This section documents the utility functions used by the plain \TeX{}
% writer and the markdown reader. These functions are encapsulated in the
% \t`util` object. The functions were originally located in the
% \t`lunamark/util.lua` file in the Lunamark Lua module.
%  \begin{macrocode}
local util = {}
%    \end{macrocode}
% 
% The \luamdef{util.err} method prints an error message \t`msg` and exits.
% If \t`exit_code` is provided, it specifies the exit code.  Otherwise, the
% exit code will be 1.
%  \begin{macrocode}
function util.err(msg, exit_code)
  io.stderr:write("markdown.lua: " .. msg .. "\n")
  os.exit(exit_code or 1)
end
%    \end{macrocode}
%
% The \luamdef{util.cache} method computes the digest of \t`string` and
% \t`salt`, adds the \t`suffix` and looks into the directory \t`dir`, whether a
% file with such a name exists. If it does not, it gets created with
% \t`transform(string)` as its content. The filename is then returned.
%  \begin{macrocode}
function util.cache(dir, string, salt, transform, suffix)
  local digest = md5.sumhexa(string .. (salt or ""))
  local name = util.pathname(dir, digest .. suffix)
  local file = io.open(name, "r")
  if file == nil then -- If no cache entry exists, then create a new one.
    local file = assert(io.open(name, "w"))
    local result = string
    if transform ~= nil then
      result = transform(result)
    end
    assert(file:write(result))
    assert(file:close())
  end
  return name
end
%    \end{macrocode}
%
% The \luamdef{util.table_copy} method creates a shallow copy of a table \t`t`
% and its metatable.
%  \begin{macrocode}
function util.table_copy(t)
  local u = { }
  for k, v in pairs(t) do u[k] = v end
  return setmetatable(u, getmetatable(t))
end
%    \end{macrocode}
%
% The \luamdef{util.expand_tabs_in_line} expands tabs in string \t`s`. If
% \t`tabstop` is specified, it is used as the tab stop width. Otherwise,
% the tab stop width of 4 characters is used. The method is a copy of the tab
% expansion algorithm from \cite[Chapter~21]{ierusalimschy13}.
%  \begin{macrocode}
function util.expand_tabs_in_line(s, tabstop)
  local tab = tabstop or 4
  local corr = 0
  return (s:gsub("()\t", function(p)
            local sp = tab - (p - 1 + corr) % tab
            corr = corr - 1 + sp
            return string.rep(" ", sp)
          end))
end
%    \end{macrocode}
%
% The \luamdef{util.walk} method walks a rope \t`t`, applying a function \t`f`
% to each leaf element in order. A rope is an array whose elements may be
% ropes, strings, numbers, or functions.  If a leaf element is a function, call
% it and get the return value before proceeding.
%  \begin{macrocode}
function util.walk(t, f)
  local typ = type(t)
  if typ == "string" then
    f(t)
  elseif typ == "table" then
    local i = 1
    local n
    n = t[i]
    while n do
      util.walk(n, f)
      i = i + 1
      n = t[i]
    end
  elseif typ == "function" then
    local ok, val = pcall(t)
    if ok then
      util.walk(val,f)
    end
  else
    f(tostring(t))
  end
end
%    \end{macrocode}
%
% The \luamdef{util.flatten} method flattens an array \t`ary` that does not
% contain cycles and returns the result.
%  \begin{macrocode}
function util.flatten(ary)
  local new = {}
  for _,v in ipairs(ary) do
    if type(v) == "table" then
      for _,w in ipairs(util.flatten(v)) do
        new[#new + 1] = w
      end
    else
      new[#new + 1] = v
    end
  end
  return new
end
%    \end{macrocode}
%
% The \luamdef{util.rope_to_string} method converts a rope \t`rope` to a
% string and returns it. For the definition of a rope, see the definition of
% the \luam{util.walk} method.
%  \begin{macrocode}
function util.rope_to_string(rope)
  local buffer = {}
  util.walk(rope, function(x) buffer[#buffer + 1] = x end)
  return table.concat(buffer)
end
%    \end{macrocode}
%
% The \luamdef{util.rope_last} method retrieves the last item in a rope. For
% the definition of a rope, see the definition of the \luam{util.walk} method.
%  \begin{macrocode}
function util.rope_last(rope)
  if #rope == 0 then
    return nil
  else
    local l = rope[#rope]
    if type(l) == "table" then
      return util.rope_last(l)
    else
      return l
    end
  end
end
%    \end{macrocode}
%
% Given an array \t`ary` and a string \t`x`, the \luamdef{util.intersperse}
% method returns an array \t`new`, such that \t`ary[i] == new[2*(i-1)+1]` and
% \t`new[2*i] == x` for all $1\leq\t`i`\leq\t`\#ary`$.
%  \begin{macrocode}
function util.intersperse(ary, x)
  local new = {}
  local l = #ary
  for i,v in ipairs(ary) do
    local n = #new
    new[n + 1] = v
    if i ~= l then
      new[n + 2] = x
    end
  end
  return new
end
%    \end{macrocode}
% 
% Given an array \t`ary` and a function \t`f`, the \luamdef{util.map} method
% returns an array \t`new`, such that \t`new[i] == f(ary[i])` for all
% $1\leq\t`i`\leq\t`\#ary`$.
%  \begin{macrocode}
function util.map(ary, f)
  local new = {}
  for i,v in ipairs(ary) do
    new[i] = f(v)
  end
  return new
end
%    \end{macrocode}
%
% Given a table \t`char_escapes` mapping escapable characters to escaped
% strings and optionally a table \t`string_escapes` mapping escapable strings
% to escaped strings, the \luamdef{util.escaper} method returns an escaper
% function that escapes all occurances of escapable strings and characters (in
% this order).
% 
% The method uses \pkg{LPeg}, which is faster than the Lua \t`string.gsub`
% built-in method.
%  \begin{macrocode}
function util.escaper(char_escapes, string_escapes)
%    \end{macrocode}
% Build a string of escapable characters.
%  \begin{macrocode}
  local char_escapes_list = ""
  for i,_ in pairs(char_escapes) do
    char_escapes_list = char_escapes_list .. i
  end
%    \end{macrocode}
% Create an \pkg{LPeg} capture \t`escapable` that produces the escaped string
% corresponding to the matched escapable character.
%  \begin{macrocode}
  local escapable = S(char_escapes_list) / char_escapes
%    \end{macrocode}
% If \t`string_escapes` is provided, turn \t`escapable` into the
% {\catcode`\_=8\[
%   \sum_{(\t`k`,\t`v`)\in\t`string\_escapes`}\t`P(k) / v` + \t`escapable`
% \]}^^A
% capture that replaces any occurance of the string \t`k` with the string
% \t`v` for each $(\t`k`, \t`v`)\in\t`string\_escapes`$. Note that the pattern
% summation is not commutative and its operands are inspected in the
% summation order during the matching. As a corrolary, the strings always
% take precedence over the characters.
%  \begin{macrocode}
  if string_escapes then
    for k,v in pairs(string_escapes) do
      escapable = P(k) / v + escapable
    end
  end
%    \end{macrocode}
% Create an \pkg{LPeg} capture \t`escape_string` that captures anything
% \t`escapable` does and matches any other unmatched characters.
%  \begin{macrocode}
  local escape_string = Cs((escapable + any)^0)
%    \end{macrocode}
% Return a function that matches the input string \t`s` against the
% \t`escape_string` capture.
%  \begin{macrocode}
  return function(s)
    return lpeg.match(escape_string, s)
  end
end
%    \end{macrocode}
%
% The \luamdef{util.pathname} method produces a pathname out of a directory
% name \t`dir` and a filename \t`file` and returns it.
%  \begin{macrocode}
function util.pathname(dir, file)
  if #dir == 0 then
    return file
  else
    return dir .. "/" .. file
  end
end
%    \end{macrocode}
% \subsubsection{\textsc{html} Entities}
% This section documents the \textsc{html} entities recognized by the
% markdown reader.  These functions are encapsulated in the \t`entities`
% object. The functions were originally located in the
% \t`lunamark/entities.lua` file in the Lunamark Lua module.
%  \begin{macrocode}
local entities = {}

local character_entities = {
  ["quot"] = 0x0022,
  ["amp"] = 0x0026,
  ["apos"] = 0x0027,
  ["lt"] = 0x003C,
  ["gt"] = 0x003E,
  ["nbsp"] = 160,
  ["iexcl"] = 0x00A1,
  ["cent"] = 0x00A2,
  ["pound"] = 0x00A3,
  ["curren"] = 0x00A4,
  ["yen"] = 0x00A5,
  ["brvbar"] = 0x00A6,
  ["sect"] = 0x00A7,
  ["uml"] = 0x00A8,
  ["copy"] = 0x00A9,
  ["ordf"] = 0x00AA,
  ["laquo"] = 0x00AB,
  ["not"] = 0x00AC,
  ["shy"] = 173,
  ["reg"] = 0x00AE,
  ["macr"] = 0x00AF,
  ["deg"] = 0x00B0,
  ["plusmn"] = 0x00B1,
  ["sup2"] = 0x00B2,
  ["sup3"] = 0x00B3,
  ["acute"] = 0x00B4,
  ["micro"] = 0x00B5,
  ["para"] = 0x00B6,
  ["middot"] = 0x00B7,
  ["cedil"] = 0x00B8,
  ["sup1"] = 0x00B9,
  ["ordm"] = 0x00BA,
  ["raquo"] = 0x00BB,
  ["frac14"] = 0x00BC,
  ["frac12"] = 0x00BD,
  ["frac34"] = 0x00BE,
  ["iquest"] = 0x00BF,
  ["Agrave"] = 0x00C0,
  ["Aacute"] = 0x00C1,
  ["Acirc"] = 0x00C2,
  ["Atilde"] = 0x00C3,
  ["Auml"] = 0x00C4,
  ["Aring"] = 0x00C5,
  ["AElig"] = 0x00C6,
  ["Ccedil"] = 0x00C7,
  ["Egrave"] = 0x00C8,
  ["Eacute"] = 0x00C9,
  ["Ecirc"] = 0x00CA,
  ["Euml"] = 0x00CB,
  ["Igrave"] = 0x00CC,
  ["Iacute"] = 0x00CD,
  ["Icirc"] = 0x00CE,
  ["Iuml"] = 0x00CF,
  ["ETH"] = 0x00D0,
  ["Ntilde"] = 0x00D1,
  ["Ograve"] = 0x00D2,
  ["Oacute"] = 0x00D3,
  ["Ocirc"] = 0x00D4,
  ["Otilde"] = 0x00D5,
  ["Ouml"] = 0x00D6,
  ["times"] = 0x00D7,
  ["Oslash"] = 0x00D8,
  ["Ugrave"] = 0x00D9,
  ["Uacute"] = 0x00DA,
  ["Ucirc"] = 0x00DB,
  ["Uuml"] = 0x00DC,
  ["Yacute"] = 0x00DD,
  ["THORN"] = 0x00DE,
  ["szlig"] = 0x00DF,
  ["agrave"] = 0x00E0,
  ["aacute"] = 0x00E1,
  ["acirc"] = 0x00E2,
  ["atilde"] = 0x00E3,
  ["auml"] = 0x00E4,
  ["aring"] = 0x00E5,
  ["aelig"] = 0x00E6,
  ["ccedil"] = 0x00E7,
  ["egrave"] = 0x00E8,
  ["eacute"] = 0x00E9,
  ["ecirc"] = 0x00EA,
  ["euml"] = 0x00EB,
  ["igrave"] = 0x00EC,
  ["iacute"] = 0x00ED,
  ["icirc"] = 0x00EE,
  ["iuml"] = 0x00EF,
  ["eth"] = 0x00F0,
  ["ntilde"] = 0x00F1,
  ["ograve"] = 0x00F2,
  ["oacute"] = 0x00F3,
  ["ocirc"] = 0x00F4,
  ["otilde"] = 0x00F5,
  ["ouml"] = 0x00F6,
  ["divide"] = 0x00F7,
  ["oslash"] = 0x00F8,
  ["ugrave"] = 0x00F9,
  ["uacute"] = 0x00FA,
  ["ucirc"] = 0x00FB,
  ["uuml"] = 0x00FC,
  ["yacute"] = 0x00FD,
  ["thorn"] = 0x00FE,
  ["yuml"] = 0x00FF,
  ["OElig"] = 0x0152,
  ["oelig"] = 0x0153,
  ["Scaron"] = 0x0160,
  ["scaron"] = 0x0161,
  ["Yuml"] = 0x0178,
  ["fnof"] = 0x0192,
  ["circ"] = 0x02C6,
  ["tilde"] = 0x02DC,
  ["Alpha"] = 0x0391,
  ["Beta"] = 0x0392,
  ["Gamma"] = 0x0393,
  ["Delta"] = 0x0394,
  ["Epsilon"] = 0x0395,
  ["Zeta"] = 0x0396,
  ["Eta"] = 0x0397,
  ["Theta"] = 0x0398,
  ["Iota"] = 0x0399,
  ["Kappa"] = 0x039A,
  ["Lambda"] = 0x039B,
  ["Mu"] = 0x039C,
  ["Nu"] = 0x039D,
  ["Xi"] = 0x039E,
  ["Omicron"] = 0x039F,
  ["Pi"] = 0x03A0,
  ["Rho"] = 0x03A1,
  ["Sigma"] = 0x03A3,
  ["Tau"] = 0x03A4,
  ["Upsilon"] = 0x03A5,
  ["Phi"] = 0x03A6,
  ["Chi"] = 0x03A7,
  ["Psi"] = 0x03A8,
  ["Omega"] = 0x03A9,
  ["alpha"] = 0x03B1,
  ["beta"] = 0x03B2,
  ["gamma"] = 0x03B3,
  ["delta"] = 0x03B4,
  ["epsilon"] = 0x03B5,
  ["zeta"] = 0x03B6,
  ["eta"] = 0x03B7,
  ["theta"] = 0x03B8,
  ["iota"] = 0x03B9,
  ["kappa"] = 0x03BA,
  ["lambda"] = 0x03BB,
  ["mu"] = 0x03BC,
  ["nu"] = 0x03BD,
  ["xi"] = 0x03BE,
  ["omicron"] = 0x03BF,
  ["pi"] = 0x03C0,
  ["rho"] = 0x03C1,
  ["sigmaf"] = 0x03C2,
  ["sigma"] = 0x03C3,
  ["tau"] = 0x03C4,
  ["upsilon"] = 0x03C5,
  ["phi"] = 0x03C6,
  ["chi"] = 0x03C7,
  ["psi"] = 0x03C8,
  ["omega"] = 0x03C9,
  ["thetasym"] = 0x03D1,
  ["upsih"] = 0x03D2,
  ["piv"] = 0x03D6,
  ["ensp"] = 0x2002,
  ["emsp"] = 0x2003,
  ["thinsp"] = 0x2009,
  ["ndash"] = 0x2013,
  ["mdash"] = 0x2014,
  ["lsquo"] = 0x2018,
  ["rsquo"] = 0x2019,
  ["sbquo"] = 0x201A,
  ["ldquo"] = 0x201C,
  ["rdquo"] = 0x201D,
  ["bdquo"] = 0x201E,
  ["dagger"] = 0x2020,
  ["Dagger"] = 0x2021,
  ["bull"] = 0x2022,
  ["hellip"] = 0x2026,
  ["permil"] = 0x2030,
  ["prime"] = 0x2032,
  ["Prime"] = 0x2033,
  ["lsaquo"] = 0x2039,
  ["rsaquo"] = 0x203A,
  ["oline"] = 0x203E,
  ["frasl"] = 0x2044,
  ["euro"] = 0x20AC,
  ["image"] = 0x2111,
  ["weierp"] = 0x2118,
  ["real"] = 0x211C,
  ["trade"] = 0x2122,
  ["alefsym"] = 0x2135,
  ["larr"] = 0x2190,
  ["uarr"] = 0x2191,
  ["rarr"] = 0x2192,
  ["darr"] = 0x2193,
  ["harr"] = 0x2194,
  ["crarr"] = 0x21B5,
  ["lArr"] = 0x21D0,
  ["uArr"] = 0x21D1,
  ["rArr"] = 0x21D2,
  ["dArr"] = 0x21D3,
  ["hArr"] = 0x21D4,
  ["forall"] = 0x2200,
  ["part"] = 0x2202,
  ["exist"] = 0x2203,
  ["empty"] = 0x2205,
  ["nabla"] = 0x2207,
  ["isin"] = 0x2208,
  ["notin"] = 0x2209,
  ["ni"] = 0x220B,
  ["prod"] = 0x220F,
  ["sum"] = 0x2211,
  ["minus"] = 0x2212,
  ["lowast"] = 0x2217,
  ["radic"] = 0x221A,
  ["prop"] = 0x221D,
  ["infin"] = 0x221E,
  ["ang"] = 0x2220,
  ["and"] = 0x2227,
  ["or"] = 0x2228,
  ["cap"] = 0x2229,
  ["cup"] = 0x222A,
  ["int"] = 0x222B,
  ["there4"] = 0x2234,
  ["sim"] = 0x223C,
  ["cong"] = 0x2245,
  ["asymp"] = 0x2248,
  ["ne"] = 0x2260,
  ["equiv"] = 0x2261,
  ["le"] = 0x2264,
  ["ge"] = 0x2265,
  ["sub"] = 0x2282,
  ["sup"] = 0x2283,
  ["nsub"] = 0x2284,
  ["sube"] = 0x2286,
  ["supe"] = 0x2287,
  ["oplus"] = 0x2295,
  ["otimes"] = 0x2297,
  ["perp"] = 0x22A5,
  ["sdot"] = 0x22C5,
  ["lceil"] = 0x2308,
  ["rceil"] = 0x2309,
  ["lfloor"] = 0x230A,
  ["rfloor"] = 0x230B,
  ["lang"] = 0x27E8,
  ["rang"] = 0x27E9,
  ["loz"] = 0x25CA,
  ["spades"] = 0x2660,
  ["clubs"] = 0x2663,
  ["hearts"] = 0x2665,
  ["diams"] = 0x2666,
}
%    \end{macrocode}
%
% Given a string \t`s` of decimal digits, the \luamdef{entities.dec_entity}
% returns the corresponding \textsc{utf}8-encoded Unicode codepoint.
%  \begin{macrocode}
function entities.dec_entity(s)
  return unicode.utf8.char(tonumber(s))
end
%    \end{macrocode}
%
% Given a string \t`s` of hexadecimal digits, the
% \luamdef{entities.hex_entity} returns the corresponding
% \textsc{utf}8-encoded Unicode codepoint.
%  \begin{macrocode}
function entities.hex_entity(s)
  return unicode.utf8.char(tonumber("0x"..s))
end
%    \end{macrocode}
%
% Given a character entity name \t`s` (like \t`ouml`), the
% \luamdef{entities.char_entity} returns the corresponding
% \textsc{utf}8-encoded Unicode codepoint.
%  \begin{macrocode}
function entities.char_entity(s)
  local n = character_entities[s]
  return unicode.utf8.char(n)
end
%    \end{macrocode}
%
% \subsubsection{Plain \TeX{} Writer}\label{sec:texwriter}
% This section documents the \luam{writer} object, which implements the
% routines for producing the \TeX{} output. The object is an amalgamate of the
% generic, \TeX{}, \LaTeX{} writer objects that were located in the
% \t`lunamark/writer/generic.lua`, \t`lunamark/writer/tex.lua`, and
% \t`lunamark/writer/latex.lua` files in the Lunamark Lua module.
%
% Although not specified in the Lua interface (see Section
% \ref{sec:luainterface}), the \luam{writer} object is exported, so that the
% curious user could easily tinker with the methods of the objects produced by
% the \luam{writer.new} method described below. The user should be aware,
% however, that the implementation may change in a future revision.
%  \begin{macrocode}
M.writer = {}
%    \end{macrocode}
%
% The \luamdef{writer.new} method creates and returns a new \TeX{} writer
% object associated with the Lua interface options (see Section
% \ref{sec:luaoptions}) \t`options`. When \t`options` are unspecified, it is
% assumed that an empty table was passed to the method.
%
% The objects produced by the \luam{writer.new} method expose instance methods
% and variables of their own. As a convention, I will refer to these
% \meta{member}s as \t`writer->`\meta{member}.
%  \begin{macrocode}
function M.writer.new(options)
  local self = {}
  options = options or {}
%    \end{macrocode}
%
% Make the \t`options` table inherit from the \luam{defaultOptions} table.
%  \begin{macrocode}
  setmetatable(options, { __index = function (_, key)
    return defaultOptions[key] end })
%    \end{macrocode}
%
% Define \luamdef{writer->suffix} as the suffix of the produced cache files.
%  \begin{macrocode}
  self.suffix = ".tex"
%    \end{macrocode}
%
% Define \luamdef{writer->space} as the output format of a space character.
%  \begin{macrocode}
  self.space = " "
%    \end{macrocode}
%
% Define \luamdef{writer->nbsp} as the output format of a non-breaking space
% character.
%  \begin{macrocode}
  self.nbsp = "\\markdownRendererNbsp{}"
%    \end{macrocode}
%
% Define \luamdef{writer->plain} as a function that will transform an input
% plain text block \t`s` to the output format.
%  \begin{macrocode}
  function self.plain(s)
    return s
  end
%    \end{macrocode}
%
% Define \luamdef{writer->paragraph} as a function that will transform an
% input paragraph \t`s` to the output format.
%  \begin{macrocode}
  function self.paragraph(s)
    return s
  end
%    \end{macrocode}
%
% Define \luamdef{writer->pack} as a function that will take the filename
% \t`name` of the output file prepared by the reader and transform it to the
% output format.
%  \begin{macrocode}
  function self.pack(name)
    return [[\input"]] .. name .. [["\relax]]
  end
%    \end{macrocode}
%
% Define \luamdef{writer->interblocksep} as the output format of a block
% element separator.
%  \begin{macrocode}
  self.interblocksep = "\\markdownRendererInterblockSeparator\n{}"
%    \end{macrocode}
%
% Define \luamdef{writer->eof} as the end of file marker in the output format.
%  \begin{macrocode}
  self.eof = [[\relax]]
%    \end{macrocode}
%
% Define \luamdef{writer->linebreak} as the output format of a forced line break.
%  \begin{macrocode}
  self.linebreak = "\\markdownRendererLineBreak\n{}"
%    \end{macrocode}
%
% Define \luamdef{writer->ellipsis} as the output format of an ellipsis.
%  \begin{macrocode}
  self.ellipsis = "\\markdownRendererEllipsis{}"
%    \end{macrocode}
%
% Define \luamdef{writer->hrule} as the output format of a horizontal rule.
%  \begin{macrocode}
  self.hrule = "\\markdownRendererHorizontalRule{}"
%    \end{macrocode}
%
% Define a table \luamdef{escaped_chars} containing the mapping from special
% plain \TeX{} characters (including the active pipe character (\t`|`) of
% \Hologo{ConTeXt}) to their escaped variants. Define tables
% \luamdef{escaped_minimal_chars} and \luamdef{escaped_minimal_strings}
% containing the mapping from special plain characters and character strings
% that need to be escaped even in content that will not be typeset.
%  \begin{macrocode}
  local escaped_chars = {
     ["{"] = "\\markdownRendererLeftBrace{}",
     ["}"] = "\\markdownRendererRightBrace{}",
     ["$"] = "\\markdownRendererDollarSign{}",
     ["%"] = "\\markdownRendererPercentSign{}",
     ["&"] = "\\markdownRendererAmpersand{}",
     ["_"] = "\\markdownRendererUnderscore{}",
     ["#"] = "\\markdownRendererHash{}",
     ["^"] = "\\markdownRendererCircumflex{}",
     ["\\"] = "\\markdownRendererBackslash{}",
     ["~"] = "\\markdownRendererTilde{}",
     ["|"] = "\\markdownRendererPipe{}",
   }
   local escaped_uri_chars = {
     ["{"] = "\\markdownRendererLeftBrace{}",
     ["}"] = "\\markdownRendererRightBrace{}",
     ["%"] = "\\markdownRendererPercentSign{}",
     ["\\"] = "\\markdownRendererBackslash{}",
   }
   local escaped_citation_chars = {
     ["{"] = "\\markdownRendererLeftBrace{}",
     ["}"] = "\\markdownRendererRightBrace{}",
     ["%"] = "\\markdownRendererPercentSign{}",
     ["#"] = "\\markdownRendererHash{}",
     ["\\"] = "\\markdownRendererBackslash{}",
   }
   local escaped_minimal_strings = {
     ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ",
   }
%    \end{macrocode}
% Use the \luam{escaped_chars} table to create an escaper function
% \luamdef{escape} and the \luam{escaped_minimal_chars} and
% \luam{escaped_minimal_strings} tables to create an escaper function
% \luamdef{escape_minimal}.
%  \begin{macrocode}
  local escape = util.escaper(escaped_chars)
  local escape_citation = util.escaper(escaped_citation_chars,
    escaped_minimal_strings)
  local escape_uri = util.escaper(escaped_uri_chars, escaped_minimal_strings)
%    \end{macrocode}
%
% Define \luamdef{writer->string} as a function that will transform an input
% plain text span \t`s` to the output format and \luamdef{writer->uri} as a
% function that will transform an input \acro{uri} \t`u` to the output format.
% If the \Opt{hybrid} option is \t`true`, use identity functions. Otherwise,
% use the \luam{escape} and \luam{escape_minimal} functions.
%  \begin{macrocode}
  if options.hybrid then
    self.string = function(s) return s end
    self.citation = function(c) return c end
    self.uri = function(u) return u end
  else
    self.string = escape
    self.citation = escape_citation
    self.uri = escape_uri
  end
%    \end{macrocode}
%
% Define \luamdef{writer->code} as a function that will transform an input
% inlined code span \t`s` to the output format.
%  \begin{macrocode}
  function self.code(s)
    return {"\\markdownRendererCodeSpan{",escape(s),"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->link} as a function that will transform an input
% hyperlink to the output format, where \t`lab` corresponds to the label,
% \t`src` to \acro{uri}, and \t`tit` to the title of the link.
%  \begin{macrocode}
  function self.link(lab,src,tit)
    return {"\\markdownRendererLink{",lab,"}",
                          "{",self.string(src),"}",
                          "{",self.uri(src),"}",
                          "{",self.string(tit or ""),"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->image} as a function that will transform an input
% image to the output format, where \t`lab` corresponds to the label, \t`src`
% to the \acro{url}, and \t`tit` to the title of the image.
%  \begin{macrocode}
  function self.image(lab,src,tit)
    return {"\\markdownRendererImage{",lab,"}",
                           "{",self.string(src),"}",
                           "{",self.uri(src),"}",
                           "{",self.string(tit or ""),"}"}
  end
%    \end{macrocode}
%
% The \luamdef{languages_json} table maps programming language filename
% extensions to fence infostrings. All \luam{options.contentBlocksLanguageMap}
% files located by \pkg{kpathsea} are loaded into a chain of tables.
% \luam{languages_json} corresponds to the first table and is chained with
% the rest via Lua metatables.
%  \begin{macrocode}
local languages_json = (function()
  local kpse = require('kpse')
  kpse.set_program_name('luatex')
  local base, prev, curr
  for _, file in ipairs{kpse.lookup(options.contentBlocksLanguageMap,
                                    { all=true })} do
    json = assert(io.open(file, "r")):read("*all")
                                     :gsub('("[^\n]-"):','[%1]=')
    curr = (function()
      local _ENV={ json=json, load=load } -- run in sandbox
      return load("return "..json)()
    end)()
    if type(curr) == "table" then
      if base == nil then
        base = curr
      else
        setmetatable(prev, { __index = curr })
      end
      prev = curr
    end
  end
  return base or {}
end)()
%    \end{macrocode}
%
% Define \luamdef{writer->contentblock} as a function that will transform an
% input iA\,Writer content block to the output format, where \t`src`
% corresponds to the \acro{uri} prefix, \t`suf` to the \acro{uri} extension,
% \t`type` to the type of the content block (\t`localfile` or \t`onlineimage`),
% and \t`tit` to the title of the content block.
%  \begin{macrocode}
  function self.contentblock(src,suf,type,tit)
    src = src.."."..suf
    suf = suf:lower()
    if type == "onlineimage" then
      return {"\\markdownRendererContentBlockOnlineImage{",suf,"}",
                             "{",self.string(src),"}",
                             "{",self.uri(src),"}",
                             "{",self.string(tit or ""),"}"}
    elseif languages_json[suf] then
      return {"\\markdownRendererContentBlockCode{",suf,"}",
                             "{",self.string(languages_json[suf]),"}",
                             "{",self.string(src),"}",
                             "{",self.uri(src),"}",
                             "{",self.string(tit or ""),"}"}
    else
      return {"\\markdownRendererContentBlock{",suf,"}",
                             "{",self.string(src),"}",
                             "{",self.uri(src),"}",
                             "{",self.string(tit or ""),"}"}
    end
  end
%    \end{macrocode}
%
% Define \luamdef{writer->bulletlist} as a function that will transform an input
% bulleted list to the output format, where \t`items` is an array of the list
% items and \t`tight` specifies, whether the list is tight or not.
%  \begin{macrocode}
  local function ulitem(s)
    return {"\\markdownRendererUlItem ",s,
            "\\markdownRendererUlItemEnd "}
  end

  function self.bulletlist(items,tight)
    local buffer = {}
    for _,item in ipairs(items) do
      buffer[#buffer + 1] = ulitem(item)
    end
    local contents = util.intersperse(buffer,"\n")
    if tight and options.tightLists then
      return {"\\markdownRendererUlBeginTight\n",contents,
        "\n\\markdownRendererUlEndTight "}
    else
      return {"\\markdownRendererUlBegin\n",contents,
        "\n\\markdownRendererUlEnd "}
    end
  end
%    \end{macrocode}
%
% Define \luamdef{writer->ollist} as a function that will transform an input
% ordered list to the output format, where \t`items` is an array of the list
% items and \t`tight` specifies, whether the list is tight or not. If the
% optional parameter \t`startnum` is present, it should be used as the number
% of the first list item.
%  \begin{macrocode}
  local function olitem(s,num)
    if num ~= nil then
      return {"\\markdownRendererOlItemWithNumber{",num,"}",s,
              "\\markdownRendererOlItemEnd "}
    else
      return {"\\markdownRendererOlItem ",s,
              "\\markdownRendererOlItemEnd "}
    end
  end

  function self.orderedlist(items,tight,startnum)
    local buffer = {}
    local num = startnum
    for _,item in ipairs(items) do
      buffer[#buffer + 1] = olitem(item,num)
      if num ~= nil then
        num = num + 1
      end
    end
    local contents = util.intersperse(buffer,"\n")
    if tight and options.tightLists then
      return {"\\markdownRendererOlBeginTight\n",contents,
        "\n\\markdownRendererOlEndTight "}
    else
      return {"\\markdownRendererOlBegin\n",contents,
        "\n\\markdownRendererOlEnd "}
    end
  end
%    \end{macrocode}
%
% Define \luamdef{writer->inline_html} and \luamdef{writer->display_html}
% as functions that will transform an inline or block \textsc{html} element
% respectively to the output format, where \t`html` is the \textsc{html}
% input.
%  \begin{macrocode}
  function self.inline_html(html)  return "" end
  function self.display_html(html) return "" end
%    \end{macrocode}
%
% Define \luamdef{writer->definitionlist} as a function that will transform an
% input definition list to the output format, where \t`items` is an array of
% tables, each of the form \t`\{ term = t, definitions = defs \}`, where \t`t`
% is a term and \t`defs` is an array of definitions. \t`tight` specifies,
% whether the list is tight or not.
%  \begin{macrocode}
  local function dlitem(term, defs)
    local retVal = {"\\markdownRendererDlItem{",term,"}"}
    for _, def in ipairs(defs) do
      retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def,
                           "\\markdownRendererDlDefinitionEnd "}
    end
    retVal[#retVal+1] = "\\markdownRendererDlItemEnd "
    return retVal
  end

  function self.definitionlist(items,tight)
    local buffer = {}
    for _,item in ipairs(items) do
      buffer[#buffer + 1] = dlitem(item.term, item.definitions)
    end
    if tight and options.tightLists then
      return {"\\markdownRendererDlBeginTight\n", buffer,
        "\n\\markdownRendererDlEndTight"}
    else
      return {"\\markdownRendererDlBegin\n", buffer,
        "\n\\markdownRendererDlEnd"}
    end
  end
%    \end{macrocode}
%
% Define \luamdef{writer->emphasis} as a function that will transform an
% emphasized span \t`s` of input text to the output format.
%  \begin{macrocode}
  function self.emphasis(s)
    return {"\\markdownRendererEmphasis{",s,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->strong} as a function that will transform a strongly
% emphasized span \t`s` of input text to the output format.
%  \begin{macrocode}
  function self.strong(s)
    return {"\\markdownRendererStrongEmphasis{",s,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->blockquote} as a function that will transform an
% input block quote \t`s` to the output format.
%  \begin{macrocode}
  function self.blockquote(s)
    return {"\\markdownRendererBlockQuoteBegin\n",s,
      "\n\\markdownRendererBlockQuoteEnd "}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->verbatim} as a function that will transform an
% input code block \t`s` to the output format.
%  \begin{macrocode}
  function self.verbatim(s)
    local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
    return {"\\markdownRendererInputVerbatim{",name,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->codeFence} as a function that will transform an
% input fenced code block \t`s` with the infostring \t`i` to the output
% format.
%  \begin{macrocode}
  function self.fencedCode(i, s)
    local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
    return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->heading} as a function that will transform an
% input heading \t`s` at level \t`level` to the output format.
%  \begin{macrocode}
  function self.heading(s,level)
    local cmd
    if level == 1 then
      cmd = "\\markdownRendererHeadingOne"
    elseif level == 2 then
      cmd = "\\markdownRendererHeadingTwo"
    elseif level == 3 then
      cmd = "\\markdownRendererHeadingThree"
    elseif level == 4 then
      cmd = "\\markdownRendererHeadingFour"
    elseif level == 5 then
      cmd = "\\markdownRendererHeadingFive"
    elseif level == 6 then
      cmd = "\\markdownRendererHeadingSix"
    else
      cmd = ""
    end
    return {cmd,"{",s,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->note} as a function that will transform an
% input footnote \t`s` to the output format.
%  \begin{macrocode}
  function self.note(s)
    return {"\\markdownRendererFootnote{",s,"}"}
  end
%    \end{macrocode}
%
% Define \luamdef{writer->citations} as a function that will transform an
% input array of citations \t`cites` to the output format. If \t`text_cites`
% is \t`true`, the citations should be rendered in-text, when applicable.
% The \t`cites` array contains tables with the following keys and values:
% \begin{itemize}
%   \item\t`suppress_author` -- If the value of the key is true, then the
%     author of the work should be omitted in the citation, when applicable.
%   \item\t`prenote` -- The value of the key is either \t`nil` or a rope
%     that should be inserted before the citation.
%   \item\t`postnote` -- The value of the key is either \t`nil` or a rope
%     that should be inserted after the citation.
%   \item\t`name` -- The value of this key is the citation name.
% \end{itemize}
%  \begin{macrocode}
  function self.citations(text_cites, cites)
    local buffer = {"\\markdownRenderer", text_cites and "TextCite" or "Cite",
      "{", #cites, "}"}
    for _,cite in ipairs(cites) do
      buffer[#buffer+1] = {cite.suppress_author and "-" or "+", "{",
        cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"}
    end
    return buffer
  end

  return self
end
%    \end{macrocode}
% \subsubsection{Parsers}
% The \luamdef{parsers} hash table stores \acro{peg} patterns that are
% static and can be reused between different \luam{reader} objects.
%  \begin{macrocode}
local parsers                  = {}
%    \end{macrocode}
% \paragraph{Basic Parsers}
%  \begin{macrocode}
parsers.percent                = P("%")
parsers.at                     = P("@")
parsers.comma                  = P(",")
parsers.asterisk               = P("*")
parsers.dash                   = P("-")
parsers.plus                   = P("+")
parsers.underscore             = P("_")
parsers.period                 = P(".")
parsers.hash                   = P("#")
parsers.ampersand              = P("&")
parsers.backtick               = P("`")
parsers.less                   = P("<")
parsers.more                   = P(">")
parsers.space                  = P(" ")
parsers.squote                 = P("'")
parsers.dquote                 = P('"')
parsers.lparent                = P("(")
parsers.rparent                = P(")")
parsers.lbracket               = P("[")
parsers.rbracket               = P("]")
parsers.circumflex             = P("^")
parsers.slash                  = P("/")
parsers.equal                  = P("=")
parsers.colon                  = P(":")
parsers.semicolon              = P(";")
parsers.exclamation            = P("!")
parsers.tilde                  = P("~")
parsers.tab                    = P("\t")
parsers.newline                = P("\n")
parsers.tightblocksep          = P("\001")

parsers.digit                  = R("09")
parsers.hexdigit               = R("09","af","AF")
parsers.letter                 = R("AZ","az")
parsers.alphanumeric           = R("AZ","az","09")
parsers.keyword                = parsers.letter
                               * parsers.alphanumeric^0
parsers.citation_chars         = parsers.alphanumeric
                               + S("#$%&-+<>~/_")
parsers.internal_punctuation   = S(":;,.?")

parsers.doubleasterisks        = P("**")
parsers.doubleunderscores      = P("__")
parsers.fourspaces             = P("    ")

parsers.any                    = P(1)
parsers.fail                   = parsers.any - 1

parsers.escapable              = S("\\`*_{}[]()+_.!<>#-~:^@;")
parsers.anyescaped             = P("\\") / "" * parsers.escapable
                               + parsers.any

parsers.spacechar              = S("\t ")
parsers.spacing                = S(" \n\r\t")
parsers.nonspacechar           = parsers.any - parsers.spacing
parsers.optionalspace          = parsers.spacechar^0

parsers.specialchar            = S("*_`&[]<!\\.@-^")

parsers.normalchar             = parsers.any - (parsers.specialchar
                                                + parsers.spacing
                                                + parsers.tightblocksep)
parsers.eof                    = -parsers.any
parsers.nonindentspace         = parsers.space^-3 * - parsers.spacechar
parsers.indent                 = parsers.space^-3 * parsers.tab
                               + parsers.fourspaces / ""
parsers.linechar               = P(1 - parsers.newline)

parsers.blankline              = parsers.optionalspace
                               * parsers.newline / "\n"
parsers.blanklines             = parsers.blankline^0
parsers.skipblanklines         = (parsers.optionalspace * parsers.newline)^0
parsers.indentedline           = parsers.indent    /""
                               * C(parsers.linechar^1 * parsers.newline^-1)
parsers.optionallyindentedline = parsers.indent^-1 /""
                               * C(parsers.linechar^1 * parsers.newline^-1)
parsers.sp                     = parsers.spacing^0
parsers.spnl                   = parsers.optionalspace
                               * (parsers.newline * parsers.optionalspace)^-1
parsers.line                   = parsers.linechar^0 * parsers.newline
                               + parsers.linechar^1 * parsers.eof
parsers.nonemptyline           = parsers.line - parsers.blankline

parsers.chunk                  = parsers.line * (parsers.optionallyindentedline
                                                - parsers.blankline)^0

-- block followed by 0 or more optionally
-- indented blocks with first line indented.
parsers.indented_blocks = function(bl)
  return Cs( bl
         * (parsers.blankline^1 * parsers.indent * -parsers.blankline * bl)^0
         * (parsers.blankline^1 + parsers.eof) )
end
%    \end{macrocode}
% \paragraph{Parsers Used for Markdown Lists}
%  \begin{macrocode}
parsers.bulletchar = C(parsers.plus + parsers.asterisk + parsers.dash)

parsers.bullet = ( parsers.bulletchar * #parsers.spacing
                                      * (parsers.tab + parsers.space^-3)
                 + parsers.space * parsers.bulletchar * #parsers.spacing
                                 * (parsers.tab + parsers.space^-2)
                 + parsers.space * parsers.space * parsers.bulletchar
                                 * #parsers.spacing
                                 * (parsers.tab + parsers.space^-1)
                 + parsers.space * parsers.space * parsers.space
                                 * parsers.bulletchar * #parsers.spacing
                 )
%    \end{macrocode}
% \paragraph{Parsers Used for Markdown Code Spans}
%  \begin{macrocode}
parsers.openticks   = Cg(parsers.backtick^1, "ticks")

local function captures_equal_length(s,i,a,b)
  return #a == #b and i
end

parsers.closeticks  = parsers.space^-1
                    * Cmt(C(parsers.backtick^1)
                         * Cb("ticks"), captures_equal_length)

parsers.intickschar = (parsers.any - S(" \n\r`"))
                    + (parsers.newline * -parsers.blankline)
                    + (parsers.space - parsers.closeticks)
                    + (parsers.backtick^1 - parsers.closeticks)

parsers.inticks     = parsers.openticks * parsers.space^-1
                    * C(parsers.intickschar^0) * parsers.closeticks
%    \end{macrocode}
% \paragraph{Parsers Used for Fenced Code Blocks}
%  \begin{macrocode}
local function captures_geq_length(s,i,a,b)
  return #a >= #b and i
end

parsers.infostring     = (parsers.linechar - (parsers.backtick
                       + parsers.space^1 * (parsers.newline + parsers.eof)))^0

local fenceindent
parsers.fencehead    = function(char)
  return               C(parsers.nonindentspace) / function(s) fenceindent = #s end
                     * Cg(char^3, "fencelength")
                     * parsers.optionalspace * C(parsers.infostring)
                     * parsers.optionalspace * (parsers.newline + parsers.eof)
end

parsers.fencetail    = function(char)
  return               parsers.nonindentspace
                     * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length)
                     * parsers.optionalspace * (parsers.newline + parsers.eof)
                     + parsers.eof
end

parsers.fencedline   = function(char)
  return               C(parsers.line - parsers.fencetail(char))
                     / function(s)
                         i = 1
                         remaining = fenceindent
                         while true do
                           c = s:sub(i, i)
                           if c == " " and remaining > 0 then
                             remaining = remaining - 1
                             i = i + 1
                           elseif c == "\t" and remaining > 3 then
                             remaining = remaining - 4
                             i = i + 1
                           else
                             break
                           end
                         end
                         return s:sub(i)
                       end
end
%    \end{macrocode}
% \paragraph{Parsers Used for Markdown Tags and Links}
%  \begin{macrocode}
parsers.leader      = parsers.space^-3

-- content in balanced brackets, parentheses, or quotes:
parsers.bracketed   = P{ parsers.lbracket
                       * ((parsers.anyescaped - (parsers.lbracket
                                                + parsers.rbracket
                                                + parsers.blankline^2)
                          ) + V(1))^0
                       * parsers.rbracket }

parsers.inparens    = P{ parsers.lparent
                       * ((parsers.anyescaped - (parsers.lparent
                                                + parsers.rparent
                                                + parsers.blankline^2)
                          ) + V(1))^0
                       * parsers.rparent }

parsers.squoted     = P{ parsers.squote * parsers.alphanumeric
                       * ((parsers.anyescaped - (parsers.squote
                                                + parsers.blankline^2)
                          ) + V(1))^0
                       * parsers.squote }

parsers.dquoted     = P{ parsers.dquote * parsers.alphanumeric
                       * ((parsers.anyescaped - (parsers.dquote
                                                + parsers.blankline^2)
                          ) + V(1))^0
                       * parsers.dquote }

-- bracketed tag for markdown links, allowing nested brackets:
parsers.tag         = parsers.lbracket
                    * Cs((parsers.alphanumeric^1
                         + parsers.bracketed
                         + parsers.inticks
                         + (parsers.anyescaped
                           - (parsers.rbracket + parsers.blankline^2)))^0)
                    * parsers.rbracket

-- url for markdown links, allowing nested brackets:
parsers.url         = parsers.less * Cs((parsers.anyescaped
                                        - parsers.more)^0)
                                   * parsers.more
                    + Cs((parsers.inparens + (parsers.anyescaped
                                             - parsers.spacing
                                             - parsers.rparent))^1)

-- quoted text, possibly with nested quotes:
parsers.title_s     = parsers.squote * Cs(((parsers.anyescaped-parsers.squote)
                                           + parsers.squoted)^0)
                                     * parsers.squote

parsers.title_d     = parsers.dquote * Cs(((parsers.anyescaped-parsers.dquote)
                                           + parsers.dquoted)^0)
                                     * parsers.dquote

parsers.title_p     = parsers.lparent
                    * Cs((parsers.inparens + (parsers.anyescaped-parsers.rparent))^0)
                    * parsers.rparent

parsers.title       = parsers.title_d + parsers.title_s + parsers.title_p

parsers.optionaltitle
                    = parsers.spnl * parsers.title * parsers.spacechar^0
                    + Cc("")
%    \end{macrocode}
% \paragraph{Parsers Used for iA\,Writer Content Blocks}
%  \begin{macrocode}
parsers.contentblock_tail
                    = parsers.optionaltitle
                    * (parsers.newline + parsers.eof)

-- case insensitive online image suffix:
parsers.onlineimagesuffix
                    = (function(...)
                        local parser = nil
                        for _,suffix in ipairs({...}) do
                          local pattern=nil
                          for i=1,#suffix do
                            local char=suffix:sub(i,i)
                            char = S(char:lower()..char:upper())
                            if pattern == nil then
                              pattern = char
                            else
                              pattern = pattern * char
                            end
                          end
                          if parser == nil then
                            parser = pattern
                          else
                            parser = parser + pattern
                          end
                        end
                        return parser
                      end)("png", "jpg", "jpeg", "gif", "tif", "tiff")

-- online image url for iA Writer content blocks with mandatory suffix,
-- allowing nested brackets:
parsers.onlineimageurl
                    = (parsers.less
                      * Cs((parsers.anyescaped
                           - parsers.more
                           - #(parsers.period
                              * parsers.onlineimagesuffix
                              * parsers.more
                              * parsers.contentblock_tail))^0)
                      * parsers.period
                      * Cs(parsers.onlineimagesuffix)
                      * parsers.more
                      + (Cs((parsers.inparens
                            + (parsers.anyescaped
                              - parsers.spacing
                              - parsers.rparent
                              - #(parsers.period
                                 * parsers.onlineimagesuffix
                                 * parsers.contentblock_tail)))^0)
                        * parsers.period
                        * Cs(parsers.onlineimagesuffix))
                      ) * Cc("onlineimage")

-- filename for iA Writer content blocks with mandatory suffix:
parsers.localfilepath
                    = parsers.slash
                    * Cs((parsers.anyescaped
                         - parsers.tab
                         - parsers.newline
                         - #(parsers.period
                            * parsers.alphanumeric^1
                            * parsers.contentblock_tail))^1)
                    * parsers.period
                    * Cs(parsers.alphanumeric^1)
                    * Cc("localfile")
%    \end{macrocode}
% \paragraph{Parsers Used for Citations}
%  \begin{macrocode}
parsers.citation_name = Cs(parsers.dash^-1) * parsers.at
                      * Cs(parsers.citation_chars
                          * (((parsers.citation_chars + parsers.internal_punctuation
                              - parsers.comma - parsers.semicolon)
                             * -#((parsers.internal_punctuation - parsers.comma
                                  - parsers.semicolon)^0
                                 * -(parsers.citation_chars + parsers.internal_punctuation
                                    - parsers.comma - parsers.semicolon)))^0
                            * parsers.citation_chars)^-1)

parsers.citation_body_prenote
                    = Cs((parsers.alphanumeric^1
                         + parsers.bracketed
                         + parsers.inticks
                         + (parsers.anyescaped
                           - (parsers.rbracket + parsers.blankline^2))
                         - (parsers.spnl * parsers.dash^-1 * parsers.at))^0)

parsers.citation_body_postnote
                    = Cs((parsers.alphanumeric^1
                         + parsers.bracketed
                         + parsers.inticks
                         + (parsers.anyescaped
                           - (parsers.rbracket + parsers.semicolon 
                             + parsers.blankline^2))
                         - (parsers.spnl * parsers.rbracket))^0)

parsers.citation_body_chunk
                    = parsers.citation_body_prenote
                    * parsers.spnl * parsers.citation_name
                    * ((parsers.internal_punctuation - parsers.semicolon)
                      * parsers.spnl)^-1
                    * parsers.citation_body_postnote

parsers.citation_body
                    = parsers.citation_body_chunk
                    * (parsers.semicolon * parsers.spnl
                      * parsers.citation_body_chunk)^0

parsers.citation_headless_body_postnote
                    = Cs((parsers.alphanumeric^1
                         + parsers.bracketed
                         + parsers.inticks
                         + (parsers.anyescaped
                           - (parsers.rbracket + parsers.at
                             + parsers.semicolon + parsers.blankline^2))
                         - (parsers.spnl * parsers.rbracket))^0)

parsers.citation_headless_body
                    = parsers.citation_headless_body_postnote
                    * (parsers.sp * parsers.semicolon * parsers.spnl
                      * parsers.citation_body_chunk)^0
%    \end{macrocode}
% \paragraph{Parsers Used for Footnotes}
%  \begin{macrocode}
local function strip_first_char(s)
  return s:sub(2)
end

parsers.RawNoteRef = #(parsers.lbracket * parsers.circumflex)
                   * parsers.tag / strip_first_char
%    \end{macrocode}
% \paragraph{Parsers Used for \textsc{html}}
%  \begin{macrocode}
-- case-insensitive match (we assume s is lowercase). must be single byte encoding
parsers.keyword_exact = function(s)
  local parser = P(0)
  for i=1,#s do
    local c = s:sub(i,i)
    local m = c .. upper(c)
    parser = parser * S(m)
  end
  return parser
end

parsers.block_keyword =
    parsers.keyword_exact("address") + parsers.keyword_exact("blockquote") +
    parsers.keyword_exact("center") + parsers.keyword_exact("del") +
    parsers.keyword_exact("dir") + parsers.keyword_exact("div") +
    parsers.keyword_exact("p") + parsers.keyword_exact("pre") +
    parsers.keyword_exact("li") + parsers.keyword_exact("ol") +
    parsers.keyword_exact("ul") + parsers.keyword_exact("dl") +
    parsers.keyword_exact("dd") + parsers.keyword_exact("form") +
    parsers.keyword_exact("fieldset") + parsers.keyword_exact("isindex") +
    parsers.keyword_exact("ins") + parsers.keyword_exact("menu") +
    parsers.keyword_exact("noframes") + parsers.keyword_exact("frameset") +
    parsers.keyword_exact("h1") + parsers.keyword_exact("h2") +
    parsers.keyword_exact("h3") + parsers.keyword_exact("h4") +
    parsers.keyword_exact("h5") + parsers.keyword_exact("h6") +
    parsers.keyword_exact("hr") + parsers.keyword_exact("script") +
    parsers.keyword_exact("noscript") + parsers.keyword_exact("table") +
    parsers.keyword_exact("tbody") + parsers.keyword_exact("tfoot") +
    parsers.keyword_exact("thead") + parsers.keyword_exact("th") +
    parsers.keyword_exact("td") + parsers.keyword_exact("tr")

-- There is no reason to support bad html, so we expect quoted attributes
parsers.htmlattributevalue
                          = parsers.squote * (parsers.any - (parsers.blankline
                                                            + parsers.squote))^0
                                           * parsers.squote
                          + parsers.dquote * (parsers.any - (parsers.blankline
                                                            + parsers.dquote))^0
                                           * parsers.dquote

parsers.htmlattribute     = parsers.spacing^1
                          * (parsers.alphanumeric + S("_-"))^1
                          * parsers.sp * parsers.equal * parsers.sp
                          * parsers.htmlattributevalue

parsers.htmlcomment       = P("<!--") * (parsers.any - P("-->"))^0 * P("-->")

parsers.htmlinstruction   = P("<?")   * (parsers.any - P("?>" ))^0 * P("?>" )

parsers.openelt_any = parsers.less * parsers.keyword * parsers.htmlattribute^0
                    * parsers.sp * parsers.more

parsers.openelt_exact = function(s)
  return parsers.less * parsers.sp * parsers.keyword_exact(s)
       * parsers.htmlattribute^0 * parsers.sp * parsers.more
end

parsers.openelt_block = parsers.sp * parsers.block_keyword
                      * parsers.htmlattribute^0 * parsers.sp * parsers.more

parsers.closeelt_any = parsers.less * parsers.sp * parsers.slash
                     * parsers.keyword * parsers.sp * parsers.more

parsers.closeelt_exact = function(s)
  return parsers.less * parsers.sp * parsers.slash * parsers.keyword_exact(s)
       * parsers.sp * parsers.more
end

parsers.emptyelt_any = parsers.less * parsers.sp * parsers.keyword
                     * parsers.htmlattribute^0 * parsers.sp * parsers.slash
                     * parsers.more

parsers.emptyelt_block = parsers.less * parsers.sp * parsers.block_keyword
                       * parsers.htmlattribute^0 * parsers.sp * parsers.slash
                       * parsers.more

parsers.displaytext = (parsers.any - parsers.less)^1

-- return content between two matched HTML tags
parsers.in_matched = function(s)
  return { parsers.openelt_exact(s)
         * (V(1) + parsers.displaytext
           + (parsers.less - parsers.closeelt_exact(s)))^0
         * parsers.closeelt_exact(s) }
end

local function parse_matched_tags(s,pos)
  local t = string.lower(lpeg.match(C(parsers.keyword),s,pos))
  return lpeg.match(parsers.in_matched(t),s,pos-1)
end

parsers.in_matched_block_tags = parsers.less
                              * Cmt(#parsers.openelt_block, parse_matched_tags)

parsers.displayhtml = parsers.htmlcomment
                    + parsers.emptyelt_block
                    + parsers.openelt_exact("hr")
                    + parsers.in_matched_block_tags
                    + parsers.htmlinstruction

parsers.inlinehtml  = parsers.emptyelt_any
                    + parsers.htmlcomment
                    + parsers.htmlinstruction
                    + parsers.openelt_any
                    + parsers.closeelt_any
%    \end{macrocode}
% \paragraph{Parsers Used for \textsc{html} entities}
%  \begin{macrocode}
parsers.hexentity = parsers.ampersand * parsers.hash * S("Xx")
                  * C(parsers.hexdigit^1) * parsers.semicolon
parsers.decentity = parsers.ampersand * parsers.hash
                  * C(parsers.digit^1) * parsers.semicolon
parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1)
                  * parsers.semicolon
%    \end{macrocode}
% \paragraph{Helpers for References}
%  \begin{macrocode}
-- parse a reference definition:  [foo]: /bar "title"
parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon
                                * parsers.spacechar^0 * parsers.url
                                * parsers.optionaltitle * parsers.blankline^1
%    \end{macrocode}
% \paragraph{Inline Elements}
%  \begin{macrocode}
parsers.Inline       = V("Inline")

-- parse many p between starter and ender
parsers.between = function(p, starter, ender)
  local ender2 = B(parsers.nonspacechar) * ender
  return (starter * #parsers.nonspacechar * Ct(p * (p - ender2)^0) * ender2)
end

parsers.urlchar      = parsers.anyescaped - parsers.newline - parsers.more
%    \end{macrocode}
% \paragraph{Block Elements}
%  \begin{macrocode}
parsers.Block        = V("Block")

parsers.OnlineImageURL
                     = parsers.leader
                     * parsers.onlineimageurl
                     * parsers.optionaltitle

parsers.LocalFilePath
                     = parsers.leader
                     * parsers.localfilepath
                     * parsers.optionaltitle

parsers.TildeFencedCode
                     = parsers.fencehead(parsers.tilde)
                     * Cs(parsers.fencedline(parsers.tilde)^0)
                     * parsers.fencetail(parsers.tilde)

parsers.BacktickFencedCode
                     = parsers.fencehead(parsers.backtick)
                     * Cs(parsers.fencedline(parsers.backtick)^0)
                     * parsers.fencetail(parsers.backtick)

parsers.lineof = function(c)
    return (parsers.leader * (P(c) * parsers.optionalspace)^3
           * (parsers.newline * parsers.blankline^1
             + parsers.newline^-1 * parsers.eof))
end
%    \end{macrocode}
% \paragraph{Lists}
%  \begin{macrocode}
parsers.defstartchar = S("~:")
parsers.defstart     = ( parsers.defstartchar * #parsers.spacing
                                              * (parsers.tab + parsers.space^-3)
                     + parsers.space * parsers.defstartchar * #parsers.spacing
                                     * (parsers.tab + parsers.space^-2)
                     + parsers.space * parsers.space * parsers.defstartchar
                                     * #parsers.spacing
                                     * (parsers.tab + parsers.space^-1)
                     + parsers.space * parsers.space * parsers.space
                                     * parsers.defstartchar * #parsers.spacing
                     )

parsers.dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0)
%    \end{macrocode}
% \paragraph{Headings}
%  \begin{macrocode}
-- parse Atx heading start and return level
parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6)
                     * -parsers.hash / length

-- parse setext header ending and return level
parsers.HeadingLevel = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2)

local function strip_atx_end(s)
  return s:gsub("[#%s]*\n$","")
end
%    \end{macrocode}
% 
% \subsubsection{Markdown Reader}\label{sec:markdownreader}
% This section documents the \luam{reader} object, which implements the
% routines for parsing the markdown input. The object corresponds to the
% markdown reader object that was located in the
% \t`lunamark/reader/markdown.lua` file in the Lunamark Lua module.
%
% Although not specified in the Lua interface (see Section
% \ref{sec:luainterface}), the \luam{reader} object is exported, so that the
% curious user could easily tinker with the methods of the objects produced by
% the \luam{reader.new} method described below. The user should be aware,
% however, that the implementation may change in a future revision.
%
% The \luamdef{reader.new} method creates and returns a new \TeX{} reader
% object associated with the Lua interface options (see Section
% \ref{sec:luaoptions}) \t`options` and with a writer object \t`writer`. When
% \t`options` are unspecified, it is assumed that an empty table was passed to
% the method.
%
% The objects produced by the \luam{reader.new} method expose instance methods
% and variables of their own. As a convention, I will refer to these
% \meta{member}s as \t`reader->`\meta{member}.
%  \begin{macrocode}
M.reader = {}
function M.reader.new(writer, options)
  local self = {}
  options = options or {}
%    \end{macrocode}
%
% Make the \t`options` table inherit from the \luam{defaultOptions} table.
%  \begin{macrocode}
  setmetatable(options, { __index = function (_, key)
    return defaultOptions[key] end })
%    \end{macrocode}
%
% \paragraph{Top-Level Helper Functions}
% Define \luamdef{normalize_tag} as a function that normalizes a markdown
% reference tag by lowercasing it, and by collapsing any adjacent whitespace
% characters.
%  \begin{macrocode}
  local function normalize_tag(tag)
    return unicode.utf8.lower(
      gsub(util.rope_to_string(tag), "[ \n\r\t]+", " "))
  end
%    \end{macrocode}
% 
% Define \luamdef{expandtabs} either as an identity function, when the
% \Opt{preserveTabs} Lua inrerface option is \t`true`, or to a function that
% expands tabs into spaces otherwise.
%  \begin{macrocode}
  local expandtabs
  if options.preserveTabs then
    expandtabs = function(s) return s end
  else
    expandtabs = function(s)
                   if s:find("\t") then
                     return s:gsub("[^\n]*", util.expand_tabs_in_line)
                   else
                     return s
                   end
                 end
  end
%    \end{macrocode}
% 
% The \luamdef{larsers} (as in ``local \luam{parsers}'') hash table stores
% \acro{peg} patterns that depend on the received \t`options`, which impedes
% their reuse between different \luam{reader} objects.
%  \begin{macrocode}
  local larsers    = {}
%    \end{macrocode}
% \paragraph{Top-Level Parser Functions}
%  \begin{macrocode}
  local function create_parser(name, grammar)
    return function(str)
      local res = lpeg.match(grammar(), str)
      if res == nil then
        error(format("%s failed on:\n%s", name, str:sub(1,20)))
      else
        return res
      end
    end
  end
    
  local parse_blocks
    = create_parser("parse_blocks",
                    function()
                      return larsers.blocks
                    end)

  local parse_blocks_toplevel
    = create_parser("parse_blocks_toplevel",
                    function()
                      return larsers.blocks_toplevel
                    end)

  local parse_inlines
    = create_parser("parse_inlines",
                    function()
                      return larsers.inlines
                    end)

  local parse_inlines_no_link
    = create_parser("parse_inlines_no_link",
                    function()
                      return larsers.inlines_no_link
                    end)

  local parse_inlines_no_inline_note
    = create_parser("parse_inlines_no_inline_note",
                    function()
                      return larsers.inlines_no_inline_note
                    end)

  local parse_inlines_nbsp
    = create_parser("parse_inlines_nbsp",
                    function()
                      return larsers.inlines_nbsp
                    end)
%    \end{macrocode}
% \paragraph{Parsers Used for Markdown Lists (local)}
%  \begin{macrocode}
  if options.hashEnumerators then
    larsers.dig = parsers.digit + parsers.hash
  else
    larsers.dig = parsers.digit
  end

  larsers.enumerator = C(larsers.dig^3 * parsers.period) * #parsers.spacing
                     + C(larsers.dig^2 * parsers.period) * #parsers.spacing
                                       * (parsers.tab + parsers.space^1)
                     + C(larsers.dig * parsers.period) * #parsers.spacing
                                     * (parsers.tab + parsers.space^-2)
                     + parsers.space * C(larsers.dig^2 * parsers.period)
                                     * #parsers.spacing
                     + parsers.space * C(larsers.dig * parsers.period)
                                     * #parsers.spacing
                                     * (parsers.tab + parsers.space^-1)
                     + parsers.space * parsers.space * C(larsers.dig^1
                                     * parsers.period) * #parsers.spacing
%    \end{macrocode}
% \paragraph{Parsers Used for Blockquotes (local)}
%  \begin{macrocode}
  -- strip off leading > and indents, and run through blocks
  larsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/""
                             * parsers.linechar^0 * parsers.newline)^1
                            * (-(parsers.leader * parsers.more
                                + parsers.blankline) * parsers.linechar^1
                              * parsers.newline)^0
                            
  if not options.breakableBlockquotes then
    larsers.blockquote_body = larsers.blockquote_body
                            * (parsers.blankline^0 / "")
  end
%    \end{macrocode}
% \paragraph{Parsers Used for Citations (local)}
%  \begin{macrocode}
  larsers.citations = function(text_cites, raw_cites)
      local function normalize(str)
          if str == "" then
              str = nil
          else
              str = (options.citationNbsps and parse_inlines_nbsp or
                parse_inlines)(str)
          end
          return str
      end

      local cites = {}
      for i = 1,#raw_cites,4 do
          cites[#cites+1] = {
              prenote = normalize(raw_cites[i]),
              suppress_author = raw_cites[i+1] == "-",
              name = writer.citation(raw_cites[i+2]),
              postnote = normalize(raw_cites[i+3]),
          }
      end
      return writer.citations(text_cites, cites)
  end
%    \end{macrocode}
% \paragraph{Parsers Used for Footnotes (local)}
%  \begin{macrocode}
  local rawnotes = {}

  -- like indirect_link
  local function lookup_note(ref)
    return function()
      local found = rawnotes[normalize_tag(ref)]
      if found then
        return writer.note(parse_blocks_toplevel(found))
      else
        return {"[", parse_inlines("^" .. ref), "]"}
      end
    end
  end

  local function register_note(ref,rawnote)
    rawnotes[normalize_tag(ref)] = rawnote
    return ""
  end

  larsers.NoteRef    = parsers.RawNoteRef / lookup_note


  larsers.NoteBlock  = parsers.leader * parsers.RawNoteRef * parsers.colon
                     * parsers.spnl * parsers.indented_blocks(parsers.chunk)
                     / register_note

  larsers.InlineNote = parsers.circumflex
                     * (parsers.tag / parse_inlines_no_inline_note) -- no notes inside notes
                     / writer.note
%    \end{macrocode}
% \paragraph{Helpers for Links and References (local)}
%  \begin{macrocode}
  -- List of references defined in the document
  local references

  -- add a reference to the list
  local function register_link(tag,url,title)
      references[normalize_tag(tag)] = { url = url, title = title }
      return ""
  end

  -- lookup link reference and return either
  -- the link or nil and fallback text.
  local function lookup_reference(label,sps,tag)
      local tagpart
      if not tag then
          tag = label
          tagpart = ""
      elseif tag == "" then
          tag = label
          tagpart = "[]"
      else
          tagpart = {"[", parse_inlines(tag), "]"}
      end
      if sps then
        tagpart = {sps, tagpart}
      end
      local r = references[normalize_tag(tag)]
      if r then
        return r
      else
        return nil, {"[", parse_inlines(label), "]", tagpart}
      end
  end

  -- lookup link reference and return a link, if the reference is found,
  -- or a bracketed label otherwise.
  local function indirect_link(label,sps,tag)
    return function()
      local r,fallback = lookup_reference(label,sps,tag)
      if r then
        return writer.link(parse_inlines_no_link(label), r.url, r.title)
      else
        return fallback
      end
    end
  end

  -- lookup image reference and return an image, if the reference is found,
  -- or a bracketed label otherwise.
  local function indirect_image(label,sps,tag)
    return function()
      local r,fallback = lookup_reference(label,sps,tag)
      if r then
        return writer.image(writer.string(label), r.url, r.title)
      else
        return {"!", fallback}
      end
    end
  end
%    \end{macrocode}
% \paragraph{Inline Elements (local)}
%  \begin{macrocode}
  larsers.Str      = parsers.normalchar^1 / writer.string

  larsers.Symbol   = (parsers.specialchar - parsers.tightblocksep)
                   / writer.string

  larsers.Ellipsis = P("...") / writer.ellipsis

  larsers.Smart    = larsers.Ellipsis

  larsers.Code     = parsers.inticks / writer.code

  if options.blankBeforeBlockquote then
    larsers.bqstart = parsers.fail
  else
    larsers.bqstart = parsers.more
  end

  if options.blankBeforeHeading then
    larsers.headerstart = parsers.fail
  else
    larsers.headerstart = parsers.hash
                        + (parsers.line * (parsers.equal^1 + parsers.dash^1)
                        * parsers.optionalspace * parsers.newline)
  end

  if not options.fencedCode or options.blankBeforeCodeFence then
    larsers.fencestart = parsers.fail
  else
    larsers.fencestart = parsers.fencehead(parsers.backtick)
                       + parsers.fencehead(parsers.tilde)
  end

  larsers.Endline   = parsers.newline * -( -- newline, but not before...
                        parsers.blankline -- paragraph break
                      + parsers.tightblocksep  -- nested list
                      + parsers.eof       -- end of document
                      + larsers.bqstart
                      + larsers.headerstart
                      + larsers.fencestart
                    ) * parsers.spacechar^0 / writer.space

  larsers.Space      = parsers.spacechar^2 * larsers.Endline / writer.linebreak
                     + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / ""
                     + parsers.spacechar^1 * larsers.Endline^-1
                                           * parsers.optionalspace / writer.space

  larsers.NonbreakingEndline
                    = parsers.newline * -( -- newline, but not before...
                        parsers.blankline -- paragraph break
                      + parsers.tightblocksep  -- nested list
                      + parsers.eof       -- end of document
                      + larsers.bqstart
                      + larsers.headerstart
                      + larsers.fencestart
                    ) * parsers.spacechar^0 / writer.nbsp

  larsers.NonbreakingSpace
                  = parsers.spacechar^2 * larsers.Endline / writer.linebreak
                  + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / ""
                  + parsers.spacechar^1 * larsers.Endline^-1
                                        * parsers.optionalspace / writer.nbsp

  if options.underscores then
    larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks,
                                       parsers.doubleasterisks)
                     + parsers.between(parsers.Inline, parsers.doubleunderscores,
                                       parsers.doubleunderscores)
                     ) / writer.strong

    larsers.Emph   = ( parsers.between(parsers.Inline, parsers.asterisk,
                                       parsers.asterisk)
                     + parsers.between(parsers.Inline, parsers.underscore,
                                       parsers.underscore)
                     ) / writer.emphasis
  else
    larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks,
                                       parsers.doubleasterisks)
                     ) / writer.strong

    larsers.Emph   = ( parsers.between(parsers.Inline, parsers.asterisk,
                                       parsers.asterisk)
                     ) / writer.emphasis
  end

  larsers.AutoLinkUrl    = parsers.less
                         * C(parsers.alphanumeric^1 * P("://") * parsers.urlchar^1)
                         * parsers.more
                         / function(url)
                             return writer.link(writer.string(url), url)
                           end

  larsers.AutoLinkEmail = parsers.less
                        * C((parsers.alphanumeric + S("-._+"))^1
                        * P("@") * parsers.urlchar^1)
                        * parsers.more
                        / function(email)
                            return writer.link(writer.string(email),
                                               "mailto:"..email)
                          end

  larsers.DirectLink    = (parsers.tag / parse_inlines_no_link)  -- no links inside links
                        * parsers.spnl
                        * parsers.lparent
                        * (parsers.url + Cc(""))  -- link can be empty [foo]()
                        * parsers.optionaltitle
                        * parsers.rparent
                        / writer.link

  larsers.IndirectLink  = parsers.tag * (C(parsers.spnl) * parsers.tag)^-1
                        / indirect_link

  -- parse a link or image (direct or indirect)
  larsers.Link          = larsers.DirectLink + larsers.IndirectLink

  larsers.DirectImage   = parsers.exclamation
                        * (parsers.tag / parse_inlines)
                        * parsers.spnl
                        * parsers.lparent
                        * (parsers.url + Cc(""))  -- link can be empty [foo]()
                        * parsers.optionaltitle
                        * parsers.rparent
                        / writer.image

  larsers.IndirectImage = parsers.exclamation * parsers.tag
                        * (C(parsers.spnl) * parsers.tag)^-1 / indirect_image

  larsers.Image         = larsers.DirectImage + larsers.IndirectImage

  larsers.TextCitations = Ct(Cc("")
                        * parsers.citation_name
                        * ((parsers.spnl
                            * parsers.lbracket
                            * parsers.citation_headless_body
                            * parsers.rbracket) + Cc("")))
                        / function(raw_cites)
                            return larsers.citations(true, raw_cites)
                          end
  
  larsers.ParenthesizedCitations
                        = Ct(parsers.lbracket
                        * parsers.citation_body
                        * parsers.rbracket)
                        / function(raw_cites)
                            return larsers.citations(false, raw_cites)
                          end

  larsers.Citations     = larsers.TextCitations + larsers.ParenthesizedCitations

  -- avoid parsing long strings of * or _ as emph/strong
  larsers.UlOrStarLine  = parsers.asterisk^4 + parsers.underscore^4
                        / writer.string

  larsers.EscapedChar   = S("\\") * C(parsers.escapable) / writer.string
  
  larsers.InlineHtml    = C(parsers.inlinehtml) / writer.inline_html
  
  larsers.HtmlEntity    = parsers.hexentity / entities.hex_entity  / writer.string
                        + parsers.decentity / entities.dec_entity  / writer.string
                        + parsers.tagentity / entities.char_entity / writer.string
%    \end{macrocode}
% \paragraph{Block Elements (local)}
%  \begin{macrocode}
  larsers.ContentBlock = parsers.leader
                       * (parsers.localfilepath + parsers.onlineimageurl)
                       * parsers.contentblock_tail
                       / writer.contentblock

  larsers.DisplayHtml  = C(parsers.displayhtml)
                       / expandtabs / writer.display_html

  larsers.Verbatim     = Cs( (parsers.blanklines
                           * ((parsers.indentedline - parsers.blankline))^1)^1
                           ) / expandtabs / writer.verbatim

  larsers.FencedCode   = (parsers.TildeFencedCode
                         + parsers.BacktickFencedCode)
                       / function(infostring, code)
                           return writer.fencedCode(writer.string(infostring),
                                                    expandtabs(code))
                         end

  larsers.Blockquote   = Cs(larsers.blockquote_body^1)
                       / parse_blocks_toplevel / writer.blockquote

  larsers.HorizontalRule = ( parsers.lineof(parsers.asterisk)
                           + parsers.lineof(parsers.dash)
                           + parsers.lineof(parsers.underscore)
                           ) / writer.hrule

  larsers.Reference    = parsers.define_reference_parser / register_link

  larsers.Paragraph    = parsers.nonindentspace * Ct(parsers.Inline^1)
                       * parsers.newline
                       * ( parsers.blankline^1
                         + #parsers.hash
                         + #(parsers.leader * parsers.more * parsers.space^-1)
                         )
                       / writer.paragraph

  larsers.ToplevelParagraph
                       = parsers.nonindentspace * Ct(parsers.Inline^1)
                       * ( parsers.newline
                       * ( parsers.blankline^1
                         + #parsers.hash
                         + #(parsers.leader * parsers.more * parsers.space^-1)
                         + parsers.eof
                         )
                       + parsers.eof )
                       / writer.paragraph

  larsers.Plain        = parsers.nonindentspace * Ct(parsers.Inline^1)
                       / writer.plain
%    \end{macrocode}
% \paragraph{Lists (local)}
%  \begin{macrocode}
  larsers.starter = parsers.bullet + larsers.enumerator

  -- we use \001 as a separator between a tight list item and a
  -- nested list under it.
  larsers.NestedList            = Cs((parsers.optionallyindentedline
                                     - larsers.starter)^1)
                                / function(a) return "\001"..a end

  larsers.ListBlockLine         = parsers.optionallyindentedline
                                - parsers.blankline - (parsers.indent^-1
                                                      * larsers.starter)

  larsers.ListBlock             = parsers.line * larsers.ListBlockLine^0

  larsers.ListContinuationBlock = parsers.blanklines * (parsers.indent / "")
                                * larsers.ListBlock

  larsers.TightListItem = function(starter)
      return -larsers.HorizontalRule
             * (Cs(starter / "" * larsers.ListBlock * larsers.NestedList^-1)
               / parse_blocks)
             * -(parsers.blanklines * parsers.indent)
  end

  larsers.LooseListItem = function(starter)
      return -larsers.HorizontalRule
             * Cs( starter / "" * larsers.ListBlock * Cc("\n")
               * (larsers.NestedList + larsers.ListContinuationBlock^0)
               * (parsers.blanklines / "\n\n")
               ) / parse_blocks
  end

  larsers.BulletList = ( Ct(larsers.TightListItem(parsers.bullet)^1) * Cc(true)
                       * parsers.skipblanklines * -parsers.bullet
                       + Ct(larsers.LooseListItem(parsers.bullet)^1) * Cc(false)
                       * parsers.skipblanklines )
                     / writer.bulletlist

  local function ordered_list(items,tight,startNumber)
    if options.startNumber then
      startNumber = tonumber(startNumber) or 1  -- fallback for '#'
    else
      startNumber = nil
    end
    return writer.orderedlist(items,tight,startNumber)
  end

  larsers.OrderedList = Cg(larsers.enumerator, "listtype") *
                      ( Ct(larsers.TightListItem(Cb("listtype"))
                          * larsers.TightListItem(larsers.enumerator)^0)
                      * Cc(true) * parsers.skipblanklines * -larsers.enumerator
                      + Ct(larsers.LooseListItem(Cb("listtype"))
                          * larsers.LooseListItem(larsers.enumerator)^0)
                      * Cc(false) * parsers.skipblanklines
                      ) * Cb("listtype") / ordered_list

  local function definition_list_item(term, defs, tight)
    return { term = parse_inlines(term), definitions = defs }
  end

  larsers.DefinitionListItemLoose = C(parsers.line) * parsers.skipblanklines
                                  * Ct((parsers.defstart
                                       * parsers.indented_blocks(parsers.dlchunk)
                                       / parse_blocks_toplevel)^1)
                                  * Cc(false) / definition_list_item

  larsers.DefinitionListItemTight = C(parsers.line)
                                  * Ct((parsers.defstart * parsers.dlchunk
                                       / parse_blocks)^1)
                                  * Cc(true) / definition_list_item

  larsers.DefinitionList = ( Ct(larsers.DefinitionListItemLoose^1) * Cc(false)
                           + Ct(larsers.DefinitionListItemTight^1)
                           * (parsers.skipblanklines
                             * -larsers.DefinitionListItemLoose * Cc(true))
                           ) / writer.definitionlist
%    \end{macrocode}
% \paragraph{Blank (local)}
%  \begin{macrocode}
  larsers.Blank        = parsers.blankline / ""
                       + larsers.NoteBlock
                       + larsers.Reference
                       + (parsers.tightblocksep / "\n")
%    \end{macrocode}
% \paragraph{Headings (local)}
%  \begin{macrocode}
  -- parse atx header
  larsers.AtxHeading = Cg(parsers.HeadingStart,"level")
                     * parsers.optionalspace
                     * (C(parsers.line) / strip_atx_end / parse_inlines)
                     * Cb("level")
                     / writer.heading

  -- parse setext header
  larsers.SetextHeading = #(parsers.line * S("=-"))
                        * Ct(parsers.line / parse_inlines)
                        * parsers.HeadingLevel
                        * parsers.optionalspace * parsers.newline
                        / writer.heading

  larsers.Heading = larsers.AtxHeading + larsers.SetextHeading
%    \end{macrocode}
% \paragraph{Syntax Specification}
%  \begin{macrocode}
  local syntax =
    { "Blocks",

      Blocks                = larsers.Blank^0 * parsers.Block^-1
                            * (larsers.Blank^0 / function()
                                                   return writer.interblocksep
                                                 end
                              * parsers.Block)^0
                            * larsers.Blank^0 * parsers.eof,

      Blank                 = larsers.Blank,

      Block                 = V("ContentBlock")
                            + V("Blockquote")
                            + V("Verbatim")
                            + V("FencedCode")
                            + V("HorizontalRule")
                            + V("BulletList")
                            + V("OrderedList")
                            + V("Heading")
                            + V("DefinitionList")
                            + V("DisplayHtml")
                            + V("Paragraph")
                            + V("Plain"),

      ContentBlock          = larsers.ContentBlock,
      Blockquote            = larsers.Blockquote,
      Verbatim              = larsers.Verbatim,
      FencedCode            = larsers.FencedCode,
      HorizontalRule        = larsers.HorizontalRule,
      BulletList            = larsers.BulletList,
      OrderedList           = larsers.OrderedList,
      Heading               = larsers.Heading,
      DefinitionList        = larsers.DefinitionList,
      DisplayHtml           = larsers.DisplayHtml,
      Paragraph             = larsers.Paragraph,
      Plain                 = larsers.Plain,

      Inline                = V("Str")
                            + V("Space")
                            + V("Endline")
                            + V("UlOrStarLine")
                            + V("Strong")
                            + V("Emph")
                            + V("InlineNote")
                            + V("NoteRef")
                            + V("Citations")
                            + V("Link")
                            + V("Image")
                            + V("Code")
                            + V("AutoLinkUrl")
                            + V("AutoLinkEmail")
                            + V("InlineHtml")
                            + V("HtmlEntity")
                            + V("EscapedChar")
                            + V("Smart")
                            + V("Symbol"),

      Str                   = larsers.Str,
      Space                 = larsers.Space,
      Endline               = larsers.Endline,
      UlOrStarLine          = larsers.UlOrStarLine,
      Strong                = larsers.Strong,
      Emph                  = larsers.Emph,
      InlineNote            = larsers.InlineNote,
      NoteRef               = larsers.NoteRef,
      Citations             = larsers.Citations,
      Link                  = larsers.Link,
      Image                 = larsers.Image,
      Code                  = larsers.Code,
      AutoLinkUrl           = larsers.AutoLinkUrl,
      AutoLinkEmail         = larsers.AutoLinkEmail,
      InlineHtml            = larsers.InlineHtml,
      HtmlEntity            = larsers.HtmlEntity,
      EscapedChar           = larsers.EscapedChar,
      Smart                 = larsers.Smart,
      Symbol                = larsers.Symbol,
    }

  if not options.citations then
    syntax.Citations = parsers.fail
  end

  if not options.contentBlocks then
    syntax.ContentBlock = parsers.fail
  end

  if not options.codeSpans then
    syntax.Code = parsers.fail
  end

  if not options.definitionLists then
    syntax.DefinitionList = parsers.fail
  end

  if not options.fencedCode then
    syntax.FencedCode = parsers.fail
  end

  if not options.footnotes then
    syntax.NoteRef = parsers.fail
  end

  if not options.html then
    syntax.DisplayHtml = parsers.fail
    syntax.InlineHtml = parsers.fail
    syntax.HtmlEntity  = parsers.fail
  end

  if not options.inlineFootnotes then
    syntax.InlineNote = parsers.fail
  end

  if not options.smartEllipses then
    syntax.Smart = parsers.fail
  end

  local blocks_toplevel_t = util.table_copy(syntax)
  blocks_toplevel_t.Paragraph = larsers.ToplevelParagraph
  larsers.blocks_toplevel = Ct(blocks_toplevel_t)

  larsers.blocks = Ct(syntax)

  local inlines_t = util.table_copy(syntax)
  inlines_t[1] = "Inlines"
  inlines_t.Inlines = parsers.Inline^0 * (parsers.spacing^0 * parsers.eof / "")
  larsers.inlines = Ct(inlines_t)

  local inlines_no_link_t = util.table_copy(inlines_t)
  inlines_no_link_t.Link = parsers.fail
  larsers.inlines_no_link = Ct(inlines_no_link_t)

  local inlines_no_inline_note_t = util.table_copy(inlines_t)
  inlines_no_inline_note_t.InlineNote = parsers.fail
  larsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t)

  local inlines_nbsp_t = util.table_copy(inlines_t)
  inlines_nbsp_t.Endline = larsers.NonbreakingEndline
  inlines_nbsp_t.Space = larsers.NonbreakingSpace
  larsers.inlines_nbsp = Ct(inlines_nbsp_t)
%    \end{macrocode}
%
% \paragraph{Exported Conversion Function}
% Define \luamdef{reader->convert} as a function that converts markdown string
% \t`input` into a plain \TeX{} output and returns it. Note that the converter
% assumes that the input has \acro{unix} line endings.
%  \begin{macrocode}
  function self.convert(input)
    references = {}
%    \end{macrocode}
% When determining the name of the cache file, create salt for the hashing
% function out of the package version and the passed options recognized by the
% Lua interface (see Section \ref{sec:luaoptions}). The \Opt{cacheDir} option
% is disregarded.
%  \begin{macrocode}
    local opt_string = {}
    for k,_ in pairs(defaultOptions) do
      local v = options[k]
      if k ~= "cacheDir" then
        opt_string[#opt_string+1] = k .. "=" .. tostring(v)
      end
    end
    table.sort(opt_string)
    local salt = table.concat(opt_string, ",") .. "," .. metadata.version
%    \end{macrocode}
% Produce the cache file, transform its filename via the \luam{writer->pack}
% method, and return the result.
%  \begin{macrocode}
    local name = util.cache(options.cacheDir, input, salt, function(input)
        return util.rope_to_string(parse_blocks_toplevel(input)) .. writer.eof
      end, ".md" .. writer.suffix)
    return writer.pack(name)
  end
  return self
end
%    \end{macrocode}
% \subsubsection{Conversion from Markdown to Plain \TeX{}}
% The \luam{new} method returns the \luam{reader->convert} function of a reader
% object associated with the Lua interface options (see Section
% \ref{sec:luaoptions}) \t`options` and with a writer object associated with
% \t`options`.
%  \begin{macrocode}
function M.new(options)
  local writer = M.writer.new(options)
  local reader = M.reader.new(writer, options)
  return reader.convert
end

return M
%    \end{macrocode}
%
% \iffalse
%</lua>
%<*tex>
% \fi\subsection{Plain \TeX{} Implementation}\label{sec:teximplementation}
% The plain \TeX{} implementation provides macros for the interfacing between
% \TeX{} and Lua and for the buffering of input text. These macros are then
% used to implement the macros for the conversion from markdown to plain \TeX{}
% exposed by the plain \TeX{} interface (see Section \ref{sec:texinterface}).
%
% \subsubsection{Logging Facilities}\label{sec:texinterfacelogging}
%  \begin{macrocode}
\def\markdownInfo#1{%
  \immediate\write-1{(l.\the\inputlineno) markdown.tex info: #1.}}%
\def\markdownWarning#1{%
  \immediate\write16{(l.\the\inputlineno) markdown.tex warning: #1}}%
\def\markdownError#1#2{%
  \errhelp{#2.}%
  \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}%
%    \end{macrocode}
%
% \subsubsection{Token Renderer Prototypes}
% The following definitions should be considered placeholder.
%  \begin{macrocode}
\def\markdownRendererInterblockSeparatorPrototype{\par}%
\def\markdownRendererLineBreakPrototype{\hfil\break}%
\let\markdownRendererEllipsisPrototype\dots
\def\markdownRendererNbspPrototype{~}%
\def\markdownRendererLeftBracePrototype{\char`{}%
\def\markdownRendererRightBracePrototype{\char`}}%
\def\markdownRendererDollarSignPrototype{\char`$}%
\def\markdownRendererPercentSignPrototype{\char`\%}%
\def\markdownRendererAmpersandPrototype{\char`&}%
\def\markdownRendererUnderscorePrototype{\char`_}%
\def\markdownRendererHashPrototype{\char`\#}%
\def\markdownRendererCircumflexPrototype{\char`^}%
\def\markdownRendererBackslashPrototype{\char`\\}%
\def\markdownRendererTildePrototype{\char`~}%
\def\markdownRendererPipePrototype{|}%
\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}%
\def\markdownRendererLinkPrototype#1#2#3#4{#2}%
\def\markdownRendererContentBlockPrototype#1#2#3#4{%
  \markdownInput{#3}}%
\def\markdownRendererContentBlockOnlineImagePrototype{%
  \markdownRendererImage}%
\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{%
  \markdownRendererInputFencedCode{#3}{#2}}%
\def\markdownRendererImagePrototype#1#2#3#4{#2}%
\def\markdownRendererUlBeginPrototype{}%
\def\markdownRendererUlBeginTightPrototype{}%
\def\markdownRendererUlItemPrototype{}%
\def\markdownRendererUlItemEndPrototype{}%
\def\markdownRendererUlEndPrototype{}%
\def\markdownRendererUlEndTightPrototype{}%
\def\markdownRendererOlBeginPrototype{}%
\def\markdownRendererOlBeginTightPrototype{}%
\def\markdownRendererOlItemPrototype{}%
\def\markdownRendererOlItemWithNumberPrototype#1{}%
\def\markdownRendererOlItemEndPrototype{}%
\def\markdownRendererOlEndPrototype{}%
\def\markdownRendererOlEndTightPrototype{}%
\def\markdownRendererDlBeginPrototype{}%
\def\markdownRendererDlBeginTightPrototype{}%
\def\markdownRendererDlItemPrototype#1{#1}%
\def\markdownRendererDlItemEndPrototype{}%
\def\markdownRendererDlDefinitionBeginPrototype{}%
\def\markdownRendererDlDefinitionEndPrototype{\par}%
\def\markdownRendererDlEndPrototype{}%
\def\markdownRendererDlEndTightPrototype{}%
\def\markdownRendererEmphasisPrototype#1{{\it#1}}%
\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}%
\def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}%
\def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}%
\def\markdownRendererInputVerbatimPrototype#1{%
  \par{\tt\input"#1"\relax}\par}%
\def\markdownRendererInputFencedCodePrototype#1#2{%
  \markdownRendererInputVerbatimPrototype{#1}}%
\def\markdownRendererHeadingOnePrototype#1{#1}%
\def\markdownRendererHeadingTwoPrototype#1{#1}%
\def\markdownRendererHeadingThreePrototype#1{#1}%
\def\markdownRendererHeadingFourPrototype#1{#1}%
\def\markdownRendererHeadingFivePrototype#1{#1}%
\def\markdownRendererHeadingSixPrototype#1{#1}%
\def\markdownRendererHorizontalRulePrototype{}%
\def\markdownRendererFootnotePrototype#1{#1}%
\def\markdownRendererCitePrototype#1{}%
\def\markdownRendererTextCitePrototype#1{}%
%    \end{macrocode}
%
% \subsubsection{Lua Snippets}
% The \mdef{markdownLuaOptions} macro expands to a Lua table that
% contains the plain \TeX{} options (see Section \ref{sec:texoptions}) in a
% format recognized by Lua (see Section \ref{sec:luaoptions}).
%  \begin{macrocode}
\def\markdownLuaOptions{{%
\ifx\markdownOptionBlankBeforeBlockquote\undefined\else
  blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote,
\fi
\ifx\markdownOptionBlankBeforeCodeFence\undefined\else
  blankBeforeCodeFence = \markdownOptionBlankBeforeCodeFence,
\fi
\ifx\markdownOptionBlankBeforeHeading\undefined\else
  blankBeforeHeading = \markdownOptionBlankBeforeHeading,
\fi
\ifx\markdownOptionBreakableBlockquotes\undefined\else
  breakableBlockquotes = \markdownOptionBreakableBlockquotes,
\fi
  cacheDir = "\markdownOptionCacheDir",
\ifx\markdownOptionCitations\undefined\else
  citations = \markdownOptionCitations,
\fi
\ifx\markdownOptionCitationNbsps\undefined\else
  citationNbsps = \markdownOptionCitationNbsps,
\fi
\ifx\markdownOptionCodeSpans\undefined\else
  codeSpans = \markdownOptionCodeSpans,
\fi
\ifx\markdownOptionContentBlocks\undefined\else
  contentBlocks = \markdownOptionContentBlocks,
\fi
\ifx\markdownOptionContentBlocksLanguageMap\undefined\else
  contentBlocksLanguageMap =
    "\markdownOptionContentBlocksLanguageMap",
\fi
\ifx\markdownOptionDefinitionLists\undefined\else
  definitionLists = \markdownOptionDefinitionLists,
\fi
\ifx\markdownOptionFootnotes\undefined\else
  footnotes = \markdownOptionFootnotes,
\fi
\ifx\markdownOptionFencedCode\undefined\else
  fencedCode = \markdownOptionFencedCode,
\fi
\ifx\markdownOptionHashEnumerators\undefined\else
  hashEnumerators = \markdownOptionHashEnumerators,
\fi
\ifx\markdownOptionHtml\undefined\else
  html = \markdownOptionHtml,
\fi
\ifx\markdownOptionHybrid\undefined\else
  hybrid = \markdownOptionHybrid,
\fi
\ifx\markdownOptionInlineFootnotes\undefined\else
  inlineFootnotes = \markdownOptionInlineFootnotes,
\fi
  outputDir = "\markdownOptionOutputDir",
\ifx\markdownOptionPreserveTabs\undefined\else
  preserveTabs = \markdownOptionPreserveTabs,
\fi
\ifx\markdownOptionSmartEllipses\undefined\else
  smartEllipses = \markdownOptionSmartEllipses,
\fi
\ifx\markdownOptionStartNumber\undefined\else
  startNumber = \markdownOptionStartNumber,
\fi
\ifx\markdownOptionTightLists\undefined\else
  tightLists = \markdownOptionTightLists,
\fi
\ifx\markdownOptionUnderscores\undefined\else
  underscores = \markdownOptionUnderscores,
\fi}
}%
%    \end{macrocode}
%
% The \mdef{markdownPrepare} macro contains the Lua code that is executed prior
% to any conversion from markdown to plain \TeX{}. It exposes the
% \luam{convert} function for the use by any further Lua code.
%  \begin{macrocode}
\def\markdownPrepare{%
%    \end{macrocode}
% First, ensure that the \m{markdownOptionCacheDir} directory exists.
%  \begin{macrocode}
local lfs = require("lfs")
local cacheDir = "\markdownOptionCacheDir"
if lfs.isdir(cacheDir) == true then else
  assert(lfs.mkdir(cacheDir))
end
%    \end{macrocode}
% Next, load the \t`markdown` module and create a converter function using
% the plain \TeX{} options, which were serialized to a Lua table via the
% \m{markdownLuaOptions} macro.
%  \begin{macrocode}
local md = require("markdown")
local convert = md.new(\markdownLuaOptions)
}%
%    \end{macrocode}
%
% \subsubsection{Buffering Markdown Input}
% The macros \mdef{markdownInputFileStream} and \mdef{markdownOutputFileStream}
% contain the number of the input and output file streams that will be used for
% the IO operations of the package.
%  \begin{macrocode}
\csname newread\endcsname\markdownInputFileStream
\csname newwrite\endcsname\markdownOutputFileStream
%    \end{macrocode}
%
% The \mdef{markdownReadAndConvertTab} macro contains the tab character literal.
%  \begin{macrocode}
\begingroup
  \catcode`\^^I=12%
  \gdef\markdownReadAndConvertTab{^^I}%
\endgroup
%    \end{macrocode}
%
% The \m{markdownReadAndConvert} macro is largely a rewrite of the
% \Hologo{LaTeX2e} \m{filecontents} macro to plain \TeX{}.
%  \begin{macrocode}
\begingroup
%    \end{macrocode}
% Make the newline and tab characters active and swap the character codes of the
% backslash symbol (\t`\textbackslash`) and the pipe symbol (\t`|`), so that
% we can use the backslash as an ordinary character inside the macro definition.
%  \begin{macrocode}
  \catcode`\^^M=13%
  \catcode`\^^I=13%
  \catcode`|=0%
  \catcode`\\=12%
  |gdef|markdownReadAndConvert#1#2{%
    |begingroup%
%    \end{macrocode}
% Open the \m{markdownOptionInputTempFileName} file for writing.
%  \begin{macrocode}
    |immediate|openout|markdownOutputFileStream%
      |markdownOptionInputTempFileName%
    |markdownInfo{Buffering markdown input into the temporary %
      input file "|markdownOptionInputTempFileName" and scanning %
      for the closing token sequence "#1"}%
%    \end{macrocode}
% Locally change the category of the special plain \TeX{} characters to
% \emph{other} in order to prevent unwanted interpretation of the input.
% Change also the category of the space character, so that we can retrieve it
% unaltered.
%  \begin{macrocode}
    |def|do##1{|catcode`##1=12}|dospecials%
    |catcode`| =12%
    |markdownMakeOther%
%    \end{macrocode}
% The \mdef{markdownReadAndConvertProcessLine} macro will process the individual
% lines of output. Note the use of the comments to ensure that the entire macro
% is at a single line and therefore no (active) newline symbols are produced.
%  \begin{macrocode}
    |def|markdownReadAndConvertProcessLine##1#1##2#1##3|relax{%
%    \end{macrocode}
% When the ending token sequence does not appear in the line, store the line in
% the \m{markdownOptionInputTempFileName} file.
%  \begin{macrocode}
      |ifx|relax##3|relax%
        |immediate|write|markdownOutputFileStream{##1}%
      |else%
%    \end{macrocode}
% When the ending token sequence appears in the line, make the next newline
% character close the \m{markdownOptionInputTempFileName} file, return the
% character categories back to the former state, convert the
% \m{markdownOptionInputTempFileName} file from markdown to plain \TeX{},
% \m{input} the result of the conversion, and expand the ending control
% sequence.
%  \begin{macrocode}
        |def^^M{%
          |markdownInfo{The ending token sequence was found}%
          |immediate|closeout|markdownOutputFileStream%
          |endgroup%
          |markdownInput|markdownOptionInputTempFileName%
          #2}%
      |fi%
%    \end{macrocode}
% Repeat with the next line.
%  \begin{macrocode}
      ^^M}%
%    \end{macrocode}
% Make the tab character active at expansion time and make it expand to a
% literal tab character.
%  \begin{macrocode}
    |catcode`|^^I=13%
    |def^^I{|markdownReadAndConvertTab}%
%    \end{macrocode}
% Make the newline character active at expansion time and make it consume the
% rest of the line on expansion. Throw away the rest of the first line and
% pass the second line to the \m{markdownReadAndConvertProcessLine} macro.
%  \begin{macrocode}
    |catcode`|^^M=13%
    |def^^M##1^^M{%
      |def^^M####1^^M{%
        |markdownReadAndConvertProcessLine####1#1#1|relax}%
      ^^M}%
    ^^M}%
%    \end{macrocode}
% Reset the character categories back to the former state.
%  \begin{macrocode}
|endgroup
%    \end{macrocode}
%
% \subsubsection{Lua Shell Escape Bridge}\label{sec:luabridge}
% The following \TeX{} code is intended for \TeX{} engines that do not provide
% direct access to Lua, but expose the shell of the operating system. This
% corresponds to the \m{markdownMode} values of \t`0` and \t`1`.
%
% The \m{markdownLuaExecute} macro defined here and in Section
% \ref{sec:directlua} are meant to be indistinguishable to the remaining code.
%
% The package assumes that although the user is not using the Lua\TeX{} engine,
% their TeX distribution contains it, and uses shell access to produce and
% execute Lua scripts using the \TeX{}Lua interpreter (see
% \cite[Section~3.1.1]{luatex17}).
%  \begin{macrocode}
\ifnum\markdownMode<2\relax
\ifnum\markdownMode=0\relax
  \markdownInfo{Using mode 0: Shell escape via write18}%
\else
  \markdownInfo{Using mode 1: Shell escape via os.execute}%
\fi
%    \end{macrocode}
%
% The \mdef{markdownExecuteShellEscape} macro contains the numeric value indicating
% whether the shell access is enabled (\t`1`), disabled (\t`0`), or restricted
% (\t`2`).
% 
% Inherit the value of the the \m{pdfshellescape} (Lua\TeX{}, \Hologo{pdfTeX})
% or the \m{shellescape} (\Hologo{XeTeX}) commands. If neither of these
% commands is defined and Lua is available, attempt to access the
% \luam{status.shell_escape} configuration item.
%
% If you cannot detect, whether the shell access is enabled, act as if it were.
%  \begin{macrocode}
\ifx\pdfshellescape\undefined
  \ifx\shellescape\undefined
    \ifnum\markdownMode=0\relax
      \def\markdownExecuteShellEscape{1}%
    \else
      \def\markdownExecuteShellEscape{%
        \directlua{tex.sprint(status.shell_escape or "1")}}%
    \fi
  \else
    \let\markdownExecuteShellEscape\shellescape
  \fi
\else
  \let\markdownExecuteShellEscape\pdfshellescape
\fi
%    \end{macrocode}
%
% The \mdef{markdownExecuteDirect} macro executes the code it has received as
% its first argument by writing it to the output file stream 18, if Lua is
% unavailable, or by using the Lua \luam{os.execute} method otherwise.
%  \begin{macrocode}
\ifnum\markdownMode=0\relax
  \def\markdownExecuteDirect#1{\immediate\write18{#1}}%
\else
  \def\markdownExecuteDirect#1{%
    \directlua{os.execute("\luaescapestring{#1}")}}%
\fi
%    \end{macrocode}
%
% The \mdef{markdownExecute} macro is a wrapper on top of
% \m{markdownExecuteDirect} that checks the value of
% \m{markdownExecuteShellEscape} and prints an error message if the shell is
% inaccessible.
%  \begin{macrocode}
\def\markdownExecute#1{%
  \ifnum\markdownExecuteShellEscape=1\relax
    \markdownExecuteDirect{#1}%
  \else
    \markdownError{I can not access the shell}{Either run the TeX
      compiler with the --shell-escape or the --enable-write18 flag,
      or set shell_escape=t in the texmf.cnf file}%
  \fi}%
%    \end{macrocode}
%
% The \mdef{markdownLuaExecute} macro executes the Lua code it has received as
% its first argument. The Lua code may not directly interact with the \TeX{}
% engine, but it can use the \luam{print} function in the same manner it
% would use the \luam{tex.print} method.
%  \begin{macrocode}
\begingroup
%    \end{macrocode}
% Swap the category code of the backslash symbol and the pipe symbol, so that
% we may use the backslash symbol freely inside the Lua code.
%  \begin{macrocode}
  \catcode`|=0%
  \catcode`\\=12%
  |gdef|markdownLuaExecute#1{%
%    \end{macrocode}
% Create the file \m{markdownOptionHelperScriptFileName} and fill it with the
% input Lua code prepended with \pkg{kpathsea} initialization, so that Lua
% modules from the \TeX{} distribution are available.
%  \begin{macrocode}
    |immediate|openout|markdownOutputFileStream=%
      |markdownOptionHelperScriptFileName
    |markdownInfo{Writing a helper Lua script to the file
      "|markdownOptionHelperScriptFileName"}%
    |immediate|write|markdownOutputFileStream{%
      local ran_ok, error = pcall(function()
        local kpse = require('kpse')
        kpse.set_program_name('luatex')
        #1
      end)
%    \end{macrocode}
% If there was an error, use the file \m{markdownOptionErrorTempFileName} to
% store the error message.
%  \begin{macrocode}
      if not ran_ok then
        local file = io.open("%
          |markdownOptionOutputDir
          /|markdownOptionErrorTempFileName", "w")
        if file then
          file:write(error .. "\n")
          file:close()
        end
        print('\\markdownError{An error was encountered while executing
               Lua code}{For further clues, examine the file
               "|markdownOptionOutputDir
               /|markdownOptionErrorTempFileName"}')
      end}%
    |immediate|closeout|markdownOutputFileStream
%    \end{macrocode}
% Execute the generated \m{markdownOptionHelperScriptFileName} Lua script using
% the \TeX{}Lua binary and store the output in the
% \m{markdownOptionOutputTempFileName} file.
%  \begin{macrocode}
    |markdownInfo{Executing a helper Lua script from the file
      "|markdownOptionHelperScriptFileName" and storing the result in the
      file "|markdownOptionOutputTempFileName"}%
    |markdownExecute{texlua "|markdownOptionOutputDir
      /|markdownOptionHelperScriptFileName" > %
      "|markdownOptionOutputDir
      /|markdownOptionOutputTempFileName"}%
%    \end{macrocode}
% \m{input} the generated \m{markdownOptionOutputTempFileName} file.
%  \begin{macrocode}
    |input|markdownOptionOutputTempFileName|relax}%
|endgroup
%    \end{macrocode}
%
% \subsubsection{Direct Lua Access}\label{sec:directlua}
% The following \TeX{} code is intended for \TeX{} engines that provide
% direct access to Lua (Lua\TeX{}). The macro \m{markdownLuaExecute} defined
% here and in Section \ref{sec:luabridge} are meant to be indistinguishable to
% the remaining code. This corresponds to the \m{markdownMode} value of \t`2`.
%  \begin{macrocode}
\else
\markdownInfo{Using mode 2: Direct Lua access}%
%    \end{macrocode}
% The direct Lua access version of the \m{markdownLuaExecute} macro is defined
% in terms of the \m{directlua} primitive. The \luam{print} function is set as
% an alias to the \m{tex.print} method in order to mimic the behaviour of the
% \m{markdownLuaExecute} definition from Section \ref{sec:luabridge},
%  \begin{macrocode}
\def\markdownLuaExecute#1{\directlua{local print = tex.print #1}}%
\fi
%    \end{macrocode}
%
% \subsubsection{Typesetting Markdown}
% The \m{markdownInput} macro uses an implementation of the
% \m{markdownLuaExecute} macro to convert the contents of the file whose
% filename it has received as its single argument from markdown to plain
% \TeX{}.
%  \begin{macrocode}
\begingroup
%    \end{macrocode}
% Swap the category code of the backslash symbol and the pipe symbol, so that
% we may use the backslash symbol freely inside the Lua code.
%  \begin{macrocode}
  \catcode`|=0%
  \catcode`\\=12%
  |gdef|markdownInput#1{%
    |markdownInfo{Including markdown document "#1"}%
%    \end{macrocode}
% Attempt to open the markdown document to record it in the \t`.log` and
% \t`.fls` files. This allows external programs such as \LaTeX Mk to track
% changes to the markdown document.
%  \begin{macrocode}
    |openin|markdownInputFileStream#1
    |closein|markdownInputFileStream
    |markdownLuaExecute{%
      |markdownPrepare
      local input = assert(io.open("#1","r")):read("*a")
%    \end{macrocode}
% Since the Lua converter expects \acro{unix} line endings, normalize the
% input.
%  \begin{macrocode}
      print(convert(input:gsub("\r\n?", "\n")))}}%
|endgroup
%    \end{macrocode}
%
% \iffalse
%</tex>
%<*latex>
% \fi\subsection{\LaTeX{} Implementation}\label{sec:lateximplementation}
% The \LaTeX{} implemenation makes use of the fact that, apart from some subtle
% differences, \LaTeX{} implements the majority of the plain \TeX{} format
% (see \cite[Section~9]{latex17}). As a consequence, we can directly reuse the
% existing plain \TeX{} implementation.
%  \begin{macrocode}
\input markdown
\def\markdownVersionSpace{ }%
\ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v%
  \markdownVersion\markdownVersionSpace markdown renderer]%
%    \end{macrocode}
%
% \subsubsection{Logging Facilities}
% The \LaTeX{} implementation redefines the plain \TeX{} logging macros (see
% Section \ref{sec:texinterfacelogging}) to use the \LaTeX{} \m{PackageInfo},
% \m{PackageWarning}, and \m{PackageError} macros.
%  \begin{macrocode}
\renewcommand\markdownInfo[1]{\PackageInfo{markdown}{#1}}%
\renewcommand\markdownWarning[1]{\PackageWarning{markdown}{#1}}%
\renewcommand\markdownError[2]{\PackageError{markdown}{#1}{#2.}}%
%    \end{macrocode}
%
% \subsubsection{Typesetting Markdown}
% The \mdef{markdownInputPlainTeX} macro is used to store the original plain
% \TeX{} implementation of the \m{markdownInput} macro. The \m{markdownInput}
% is then redefined to accept an optional argument with options recognized by
% the \LaTeX{} interface (see Section \ref{sec:latexoptions}).
%  \begin{macrocode}
\let\markdownInputPlainTeX\markdownInput
\renewcommand\markdownInput[2][]{%
  \begingroup
    \markdownSetup{#1}%
    \markdownInputPlainTeX{#2}%
  \endgroup}%
%    \end{macrocode}
%
% The \env{markdown}, and \env{markdown*} \LaTeX{} environments are implemented
% using the \m{markdownReadAndConvert} macro.
%  \begin{macrocode}
\renewenvironment{markdown}{%
  \markdownReadAndConvert@markdown{}}\relax
\renewenvironment{markdown*}[1]{%
  \markdownSetup{#1}%
  \markdownReadAndConvert@markdown*}\relax
\begingroup
%    \end{macrocode}
% Locally swap the category code of the backslash symbol with the pipe symbol,
% and of the left (\t`\{`) and right brace (\t`\}`) with the less-than (\t`<`)
% and greater-than (\t`>`) signs. This is required in order that all the
% special symbols that appear in the first argument of the
% \t`markdownReadAndConvert` macro have the category code \emph{other}.
%  \begin{macrocode}
  \catcode`\|=0\catcode`\<=1\catcode`\>=2%
  \catcode`\\=12|catcode`|{=12|catcode`|}=12%
  |gdef|markdownReadAndConvert@markdown#1<%
    |markdownReadAndConvert<\end{markdown#1}>%
                           <|end<markdown#1>>>%
|endgroup
%    \end{macrocode}
%
% \subsubsection{Options}
% The supplied package options are processed using the \m{markdownSetup} macro.
%  \begin{macrocode}
\DeclareOption*{%
  \expandafter\markdownSetup\expandafter{\CurrentOption}}%
\ProcessOptions\relax
%    \end{macrocode}
% After processing the options, activate the \t`renderers` and
% \t`rendererPrototypes` keys.
%  \begin{macrocode}
\define@key{markdownOptions}{renderers}{%
  \setkeys{markdownRenderers}{#1}%
  \def\KV@prefix{KV@markdownOptions@}}%
\define@key{markdownOptions}{rendererPrototypes}{%
  \setkeys{markdownRendererPrototypes}{#1}%
  \def\KV@prefix{KV@markdownOptions@}}%
%    \end{macrocode}
%
% \subsubsection{Token Renderer Prototypes}
% The following configuration should be considered placeholder.
%
% If the \m{markdownOptionTightLists} macro expands to \t`false`, do not load
% the \pkg{paralist} package. This is necessary for \Hologo{LaTeX2e} document
% classes that do not play nice with \pkg{paralist}, such as \pkg{beamer}.
% If the \m{markdownOptionTightLists} is undefined and the \pkg{beamer}
% document class is in use, then do not load the \pkg{paralist} package either.
%  \begin{macrocode}
\ifx\markdownOptionTightLists\undefined
  \@ifclassloaded{beamer}{}{
    \RequirePackage{paralist}}
\else
  \ifthenelse{\equal{\markdownOptionTightLists}{false}}{}{
    \RequirePackage{paralist}}
\fi
%    \end{macrocode}
% If we loaded the \pkg{paralist} package, define the respective renderer
% prototypes to make use of the capabilities of the package. Otherwise,
% define the renderer prototypes to fall back on the corresponding renderers
% for the non-tight lists.
%  \begin{macrocode}
\@ifpackageloaded{paralist}{
  \markdownSetup{rendererPrototypes={
    ulBeginTight = {\begin{compactitem}},
    ulEndTight = {\end{compactitem}},
    olBeginTight = {\begin{compactenum}},
    olEndTight = {\end{compactenum}},
    dlBeginTight = {\begin{compactdesc}},
    dlEndTight = {\end{compactdesc}}}}
}{
  \markdownSetup{rendererPrototypes={
    ulBeginTight = {\markdownRendererUlBegin},
    ulEndTight = {\markdownRendererUlEnd},
    olBeginTight = {\markdownRendererOlBegin},
    olEndTight = {\markdownRendererOlEnd},
    dlBeginTight = {\markdownRendererDlBegin},
    dlEndTight = {\markdownRendererDlEnd}}}}
\markdownSetup{rendererPrototypes={
  lineBreak = {\\},
  leftBrace = {\textbraceleft},
  rightBrace = {\textbraceright},
  dollarSign = {\textdollar},
  underscore = {\textunderscore},
  circumflex = {\textasciicircum},
  backslash = {\textbackslash},
  tilde = {\textasciitilde},
  pipe = {\textbar},
  codeSpan = {\texttt{#1}},
  link = {#1\footnote{\ifx\empty#4\empty\else#4:
    \fi\texttt<\url{#3}\texttt>}},
  contentBlock = {%
    \ifthenelse{\equal{#1}{csv}}{%
      \begin{table}%
        \begin{center}%
          \csvautotabular{#3}%
        \end{center}
        \ifx\empty#4\empty\else
          \caption{#4}%
        \fi
        \label{tab:#1}%
      \end{table}}{%
      \markdownInput{#3}}},
  image = {%
    \begin{figure}%
      \begin{center}%
        \includegraphics{#3}%
      \end{center}%
      \ifx\empty#4\empty\else
        \caption{#4}%
      \fi
      \label{fig:#1}%
    \end{figure}},
  ulBegin = {\begin{itemize}},
  ulItem = {\item},
  ulEnd = {\end{itemize}},
  olBegin = {\begin{enumerate}},
  olItem = {\item},
  olItemWithNumber = {\item[#1.]},
  olEnd = {\end{enumerate}},
  dlBegin = {\begin{description}},
  dlItem = {\item[#1]},
  dlEnd = {\end{description}},
  emphasis = {\emph{#1}},
  blockQuoteBegin = {\begin{quotation}},
  blockQuoteEnd = {\end{quotation}},
  inputVerbatim = {\VerbatimInput{#1}},
  inputFencedCode = {%
    \ifx\relax#2\relax
      \VerbatimInput{#1}%
    \else
      \ifx\minted@jobname\undefined
        \ifx\lst@version\undefined
          \markdownRendererInputFencedCode{#1}{}%
%    \end{macrocode}
% When the \pkg{listings} package is loaded, use it for syntax highlighting.
%  \begin{macrocode}
        \else
          \lstinputlisting[language=#2]{#1}%
        \fi
%    \end{macrocode}
% When the \pkg{minted} package is loaded, use it for syntax highlighting.
% The \pkg{minted} package is preferred over \pkg{listings}.
%  \begin{macrocode}
      \else
        \inputminted{#2}{#1}%
      \fi
    \fi},
  horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}},
  footnote = {\footnote{#1}}}}
%    \end{macrocode}
%
% Support the nesting of strong emphasis.
%  \begin{macrocode}
\newif\ifmarkdownLATEXStrongEmphasisNested
\markdownLATEXStrongEmphasisNestedfalse
\markdownSetup{rendererPrototypes={
  strongEmphasis = {%
    \ifmarkdownLATEXStrongEmphasisNested
      \markdownLATEXStrongEmphasisNestedfalse
      \textmd{#1}%
      \markdownLATEXStrongEmphasisNestedtrue
    \else
      \markdownLATEXStrongEmphasisNestedtrue
      \textbf{#1}%
      \markdownLATEXStrongEmphasisNestedfalse
    \fi}}}
%    \end{macrocode}
%
% Support \LaTeX{} document classes that do not provide chapters.
%  \begin{macrocode}
\ifx\chapter\undefined
  \markdownSetup{rendererPrototypes = {
    headingOne = {\section{#1}},
    headingTwo = {\subsection{#1}},
    headingThree = {\subsubsection{#1}},
    headingFour = {\paragraph{#1}},
    headingFive = {\subparagraph{#1}}}}
\else
  \markdownSetup{rendererPrototypes = {
    headingOne = {\chapter{#1}},
    headingTwo = {\section{#1}},
    headingThree = {\subsection{#1}},
    headingFour = {\subsubsection{#1}},
    headingFive = {\paragraph{#1}},
    headingSix = {\subparagraph{#1}}}}
\fi
%    \end{macrocode}
%
% There is a basic implementation for citations that uses the \LaTeX{} \m{cite}
% macro. There is also a more advanced implementation that uses the Bib\LaTeX{}
% \m{autocites} and \m{textcites} macros. This implementation will be used, when
% Bib\LaTeX{} is loaded.
%  \begin{macrocode}
\newcount\markdownLaTeXCitationsCounter

% Basic implementation
\def\markdownLaTeXBasicCitations#1#2#3#4{%
  \advance\markdownLaTeXCitationsCounter by 1\relax
  \ifx\relax#2\relax\else#2~\fi\cite[#3]{#4}%
  \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax
    \expandafter\@gobble
  \fi\markdownLaTeXBasicCitations}
\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations

% BibLaTeX implementation
\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{%
  \advance\markdownLaTeXCitationsCounter by 1\relax
  \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax
    \autocites#1[#3][#4]{#5}%
    \expandafter\@gobbletwo
  \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}}
\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{%
  \advance\markdownLaTeXCitationsCounter by 1\relax
  \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax
    \textcites#1[#3][#4]{#5}%
    \expandafter\@gobbletwo
  \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}}

\markdownSetup{rendererPrototypes = {
  cite = {%
    \markdownLaTeXCitationsCounter=1%
    \def\markdownLaTeXCitationsTotal{#1}%
    \ifx\autocites\undefined
      \expandafter
      \markdownLaTeXBasicCitations
    \else
      \expandafter\expandafter\expandafter
      \markdownLaTeXBibLaTeXCitations
      \expandafter{\expandafter}%
    \fi},
  textCite = {%
    \markdownLaTeXCitationsCounter=1%
    \def\markdownLaTeXCitationsTotal{#1}%
    \ifx\textcites\undefined
      \expandafter
      \markdownLaTeXBasicTextCitations
    \else
      \expandafter\expandafter\expandafter
      \markdownLaTeXBibLaTeXTextCitations
      \expandafter{\expandafter}%
    \fi}}}
%    \end{macrocode}
%
% \subsubsection{Miscellanea}
% When buffering user input, we should disable the bytes with the high bit set,
% since these are made active by the \pkg{inputenc} package. We will do this by
% redefining the \m{markdownMakeOther} macro accordingly. The code is courtesy
% of Scott Pakin, the creator of the \pkg{filecontents} package.
%  \begin{macrocode}
\newcommand\markdownMakeOther{%
  \count0=128\relax
  \loop
    \catcode\count0=11\relax
    \advance\count0 by 1\relax
  \ifnum\count0<256\repeat}%
%    \end{macrocode}
%
% \iffalse
%</latex>
%<*context>
% \fi\subsection{\Hologo{ConTeXt} Implementation}
% \label{sec:contextimplementation}
% The \Hologo{ConTeXt} implementation makes use of the fact that, apart from
% some subtle differences, the Mark II and Mark IV \Hologo{ConTeXt} formats
% \emph{seem} to implement (the documentation is scarce) the majority of the
% plain \TeX{} format required by the plain \TeX{} implementation.  As a
% consequence, we can directly reuse the existing plain \TeX{} implementation
% after supplying the missing plain \TeX{} macros.
%  \begin{macrocode}
\def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&%
  \do\#\do\^\do\_\do\%\do\~}%
\input markdown
%    \end{macrocode}
%
% When buffering user input, we should disable the bytes with the high bit set,
% since these are made active by the \m{enableregime} macro. We will do this
% by redefining the \m{markdownMakeOther} macro accordingly. The code is
% courtesy of Scott Pakin, the creator of the \pkg{filecontents} LaTeX package.
%  \begin{macrocode}
\def\markdownMakeOther{%
  \count0=128\relax
  \loop
    \catcode\count0=11\relax
    \advance\count0 by 1\relax
  \ifnum\count0<256\repeat
%    \end{macrocode}
% On top of that, make the pipe character (\t`|`) inactive during the scanning.
% This is necessary, since the character is active in \Hologo{ConTeXt}.
%  \begin{macrocode}
  \catcode`|=12}%
%    \end{macrocode}
% 
% \subsubsection{Logging Facilities}
% The \Hologo{ConTeXt} implementation redefines the plain \TeX{} logging macros (see
% Section \ref{sec:texinterfacelogging}) to use the \Hologo{ConTeXt}
% \m{writestatus} macro.
%  \begin{macrocode}
\def\markdownInfo#1{\writestatus{markdown}{#1.}}%
\def\markdownWarning#1{\writestatus{markdown\space warn}{#1.}}%
%    \end{macrocode}
%
% \subsubsection{Typesetting Markdown}
% The \m{startmarkdown} and \m{stopmarkdown} macros are implemented using the
% \m{markdownReadAndConvert} macro.
%  \begin{macrocode}
\begingroup
%    \end{macrocode}
% Locally swap the category code of the backslash symbol with the pipe symbol.
% This is required in order that all the special symbols that appear in the
% first argument of the \t`markdownReadAndConvert` macro have the category code
% \emph{other}.
%  \begin{macrocode}
  \catcode`\|=0%
  \catcode`\\=12%
  |gdef|startmarkdown{%
    |markdownReadAndConvert{\stopmarkdown}%
                           {|stopmarkdown}}%
|endgroup
%    \end{macrocode}
%
% \subsubsection{Token Renderer Prototypes}
% The following configuration should be considered placeholder.
%  \begin{macrocode}
\def\markdownRendererLineBreakPrototype{\blank}%
\def\markdownRendererLeftBracePrototype{\textbraceleft}%
\def\markdownRendererRightBracePrototype{\textbraceright}%
\def\markdownRendererDollarSignPrototype{\textdollar}%
\def\markdownRendererPercentSignPrototype{\percent}%
\def\markdownRendererUnderscorePrototype{\textunderscore}%
\def\markdownRendererCircumflexPrototype{\textcircumflex}%
\def\markdownRendererBackslashPrototype{\textbackslash}%
\def\markdownRendererTildePrototype{\textasciitilde}%
\def\markdownRendererPipePrototype{\char`|}%
\def\markdownRendererLinkPrototype#1#2#3#4{%
  \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4:
  \fi\tt<\hyphenatedurl{#3}>}}%
\usemodule[database]
\defineseparatedlist
  [MarkdownConTeXtCSV]
  [separator={,},
   before=\bTABLE,after=\eTABLE,
   first=\bTR,last=\eTR,
   left=\bTD,right=\eTD]
\def\markdownConTeXtCSV{csv}
\def\markdownRendererContentBlockPrototype#1#2#3#4{%
  \def\markdownConTeXtCSV@arg{#1}%
	\ifx\markdownConTeXtCSV@arg\markdownConTeXtCSV
    \placetable[][tab:#1]{#4}{%
      \processseparatedfile[MarkdownConTeXtCSV][#3]}%
	\else
		\markdownInput{#3}%
	\fi}%
\def\markdownRendererImagePrototype#1#2#3#4{%
  \placefigure[][fig:#1]{#4}{\externalfigure[#3]}}%
\def\markdownRendererUlBeginPrototype{\startitemize}%
\def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}%
\def\markdownRendererUlItemPrototype{\item}%
\def\markdownRendererUlEndPrototype{\stopitemize}%
\def\markdownRendererUlEndTightPrototype{\stopitemize}%
\def\markdownRendererOlBeginPrototype{\startitemize[n]}%
\def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}%
\def\markdownRendererOlItemPrototype{\item}%
\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}%
\def\markdownRendererOlEndPrototype{\stopitemize}%
\def\markdownRendererOlEndTightPrototype{\stopitemize}%
\definedescription
  [MarkdownConTeXtDlItemPrototype]
  [location=hanging,
   margin=standard,
   headstyle=bold]%
\definestartstop
  [MarkdownConTeXtDlPrototype]
  [before=\blank,
   after=\blank]%
\definestartstop
  [MarkdownConTeXtDlTightPrototype]
  [before=\blank\startpacked,
   after=\stoppacked\blank]%
\def\markdownRendererDlBeginPrototype{%
  \startMarkdownConTeXtDlPrototype}%
\def\markdownRendererDlBeginTightPrototype{%
  \startMarkdownConTeXtDlTightPrototype}%
\def\markdownRendererDlItemPrototype#1{%
  \startMarkdownConTeXtDlItemPrototype{#1}}%
\def\markdownRendererDlItemEndPrototype{%
  \stopMarkdownConTeXtDlItemPrototype}%
\def\markdownRendererDlEndPrototype{%
  \stopMarkdownConTeXtDlPrototype}%
\def\markdownRendererDlEndTightPrototype{%
  \stopMarkdownConTeXtDlTightPrototype}%
\def\markdownRendererEmphasisPrototype#1{{\em#1}}%
\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}%
\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}%
\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}%
\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}%
\def\markdownRendererInputFencedCodePrototype#1#2{%
  \ifx\relax#2\relax
    \typefile{#1}%
  \else
%    \end{macrocode}
% 
% The code fence infostring is used as a name from the \Hologo{ConTeXt}
% \m{definetyping} macro. This allows the user to set up code highlighting
% mapping as follows:
% \begin{Verbatim}
% % Map the `TEX` syntax highlighter to the `latex` infostring.
% \definetyping [latex]
% \setuptyping  [latex] [option=TEX]
% 
% \starttext
%   \startmarkdown
% ~~~ latex
% \documentclass{article}
% \begin{document}
%   Hello world!
% \end{document}
% ~~~
%   \stopmarkdown
% \stoptext
% \end{Verbatim}
%  \begin{macrocode}
    \typefile[#2][]{#1}%
  \fi}%
\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}%
\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}%
\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}%
\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}%
\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}%
\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}%
\def\markdownRendererHorizontalRulePrototype{%
  \blackrule[height=1pt, width=\hsize]}%
\def\markdownRendererFootnotePrototype#1{\footnote{#1}}%
\stopmodule\protect
%    \end{macrocode}
%
% \iffalse
%</context>
% \fi
