summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/generic/markdown
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2016-06-11 23:15:05 +0000
committerKarl Berry <karl@freefriends.org>2016-06-11 23:15:05 +0000
commita0bab753834e0c87c19800c7748fccccee26b4be (patch)
tree24455a5f82eed5399e434c1ff8f7acefbef5e85e /Master/texmf-dist/source/generic/markdown
parentc636c196ee98440b64ff0252aec19b5d800b749f (diff)
markdown (6jun16)
git-svn-id: svn://tug.org/texlive/trunk@41376 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/generic/markdown')
-rw-r--r--Master/texmf-dist/source/generic/markdown/docstrip.cfg105
-rw-r--r--Master/texmf-dist/source/generic/markdown/markdown.dtx3590
-rw-r--r--Master/texmf-dist/source/generic/markdown/markdown.ins8
3 files changed, 3703 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/generic/markdown/docstrip.cfg b/Master/texmf-dist/source/generic/markdown/docstrip.cfg
new file mode 100644
index 00000000000..64fdc439c76
--- /dev/null
+++ b/Master/texmf-dist/source/generic/markdown/docstrip.cfg
@@ -0,0 +1,105 @@
+\askforoverwritefalse
+\def\luapreamble{%
+-- ^^J%
+-- Copyright (C) 2009-2016 John MacFarlane, Hans Hagen^^J%
+-- ^^J%
+-- Permission is hereby granted, free of charge, to any person obtaining^^J%
+-- a copy of this software and associated documentation files (the^^J%
+-- "Software"), to deal in the Software without restriction, including^^J%
+-- without limitation the rights to use, copy, modify, merge, publish,^^J%
+-- distribute, sublicense, and/or sell copies of the Software, and to^^J%
+-- permit persons to whom the Software is furnished to do so, subject to^^J%
+-- the following conditions:^^J%
+-- ^^J%
+-- The above copyright notice and this permission notice shall be included^^J%
+-- in all copies or substantial portions of the Software.^^J%
+-- ^^J%
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,^^J%
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF^^J%
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.^^J%
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY^^J%
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,^^J%
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE^^J%
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.^^J%
+-- ^^J%
+-- Copyright (C) 2016 Vít Novotný^^J%
+-- ^^J%
+-- This work may be distributed and/or modified under the^^J%
+-- conditions of the LaTeX Project Public License, either version 1.3^^J%
+-- of this license or (at your option) any later version.^^J%
+-- The latest version of this license is in^^J%
+-- ^^J%
+-- \space\space\space\space http://www.latex-project.org/lppl.txt^^J%
+-- ^^J%
+-- and version 1.3 or later is part of all distributions of LaTeX^^J%
+-- version 2005/12/01 or later.^^J%
+-- ^^J%
+-- This work has the LPPL maintenance status `maintained'.^^J%
+-- The Current Maintainer of this work is Vít Novotný.^^J%
+-- ^^J%
+-- Send bug reports, requests for additions and questions^^J%
+-- either to the GitHub issue tracker at^^J%
+-- ^^J%
+-- \space\space\space\space https://github.com/witiko/markdown/issues^^J%
+-- ^^J%
+-- or to the e-mail address <witiko@mail.muni.cz>.^^J%
+-- ^^J%
+-- MODIFICATION ADVICE:^^J%
+-- ^^J%
+-- If you want to customize this file, it is best to make a copy of^^J%
+-- the source file(s) from which it was produced. Use a different^^J%
+-- name for your copy(ies) and modify the copy(ies); this will ensure^^J%
+-- that your modifications do not get overwritten when you install a^^J%
+-- new release of the standard system. You should also ensure that^^J%
+-- your modified source file does not generate any modified file with^^J%
+-- the same name as a standard file.^^J%
+-- ^^J%
+-- You will also need to produce your own, suitably named, .ins file to^^J%
+-- control the generation of files from your source file; this file^^J%
+-- should contain your own preambles for the files it generates, not^^J%
+-- those in the standard .ins files.^^J%
+-- }
+\let\luapostamble\empty
+\declarepreamble\texpreamble
+
+Copyright (C) 2016 Vít Novotný
+
+This work may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3
+of this license or (at your option) any later version.
+The latest version of this license is in
+
+ http://www.latex-project.org/lppl.txt
+
+and version 1.3 or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+This work has the LPPL maintenance status `maintained'.
+The Current Maintainer of this work is Vít Novotný.
+
+Send bug reports, requests for additions and questions
+either to the GitHub issue tracker at
+
+ https://github.com/Witiko/markdown/issues
+
+or to the e-mail address <witiko@mail.muni.cz>.
+
+MODIFICATION ADVICE:
+
+If you want to customize this file, it is best to make a copy of
+the source file(s) from which it was produced. Use a different
+name for your copy(ies) and modify the copy(ies); this will ensure
+that your modifications do not get overwritten when you install a
+new release of the standard system. You should also ensure that
+your modified source file does not generate any modified file with
+the same name as a standard file.
+
+You will also need to produce your own, suitably named, .ins file to
+control the generation of files from your source file; this file
+should contain your own preambles for the files it generates, not
+those in the standard .ins files.
+
+The names of the source files used are shown above.
+
+\endpreamble
+\let\texpostamble\defaultpostamble
diff --git a/Master/texmf-dist/source/generic/markdown/markdown.dtx b/Master/texmf-dist/source/generic/markdown/markdown.dtx
new file mode 100644
index 00000000000..49995231e70
--- /dev/null
+++ b/Master/texmf-dist/source/generic/markdown/markdown.dtx
@@ -0,0 +1,3590 @@
+% \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][]{% An option item definition
+ \phantomsection\label{opt:#2}\optitem[#1]{#2}}
+\newcommand\Valitem[2][]{% 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ý (based on the work of John MacFarlane and Hans Hagen)},
+ email={witiko@mail.muni.cz},
+ revision={\input VERSION},
+ date={\today}}
+\CodelineIndex
+
+% Set up the bibliography.
+\usepackage{filecontents}
+\begin{filecontents}{markdown.bib}
+ @book{luatex16,
+ author = {{Lua\TeX{} development team}},
+ title = {Lua\TeX{} reference manual (0.95.0)},
+ url = {http://www.luatex.org/svn/trunk/manual/luatex.pdf},
+ urldate = {2016-05-12}}
+ @book{latex16,
+ 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 = {2016-03-31},
+ url = {http://mirrors.ctan.org/macros/latex/base/source2e.pdf},
+ urldate = {2016-06-02}}
+ @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-Westley}}
+\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} 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}
+if not modules then modules = { } end modules ['markdown'] = {
+ version = "1.0.1",
+ 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 Vít Novotný",
+ license = "LPPL 1.3"
+}
+% \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 the following Lua modules:
+% \begin{description}
+% \item[\pkg{LPeg}] 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.
+% \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.
+% \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.
+% \begin{macrocode}
+local md5 = require("md5")
+% \end{macrocode}
+% \end{description}
+% All the abovelisted modules are statically linked into the Lua\TeX{} engine
+% (see \cite[Section~3.3]{luatex16}).
+%
+% \iffalse
+%</lua>
+%<*tex>
+% \fi
+% \subsubsection{Plain \TeX{} Prerequisites}\label{sec:texprerequisites}
+% The plain \TeX{} part of the package requires 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.
+%
+% The plain \TeX{} code makes use of the \luam{isDir} method that was added
+% to the module by the Lua\TeX{} engine developers (see
+% \cite[Section~3.2]{luatex16}). This method is not present in the base
+% library.
+% \end{description}
+% The \pkg{Lua File System} module is statically linked into the Lua\TeX{}
+% engine (see \cite[Section~3.3]{luatex16}).
+%
+% The plain \TeX{} part of the package also requires that the plain \TeX{}
+% format (or its superset) is loaded and that either the Lua\TeX{}
+% \m{directlua} primitive or the shell access file stream 18 is available.
+%
+% \iffalse
+%</tex>
+%<*latex>
+% \fi
+% \subsubsection{\LaTeX{} Prerequisites}\label{sec:latexprerequisites}
+% The \LaTeX{} part of the package requires that the \Hologo{LaTeX2e} format is
+% loaded and also, since it uses the plain \TeX{} implementation, all the plain
+% \TeX{} prerequisites (see Section \ref{sec:texprerequisites}).
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}%
+% \end{macrocode}
+%
+% The following \Hologo{LaTeX2e} packages are also required:
+% \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.
+% \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.
+% \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}).
+% \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.
+% \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}).
+% \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 and also, since it uses the plain \TeX{}
+% implementation, all the plain \TeX{} prerequisites (see Section
+% \ref{sec:texprerequisites}).
+%
+% \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 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.
+% \begin{macrocode}
+M.new = {}
+% \end{macrocode}
+%
+% 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}
+% \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]{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}
+%
+% \Valitem[.]{cacheDir}{directory}
+% The path to the directory containing auxiliary cache files.
+%
+% 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}
+%
+% \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]{hashEnumerators}{\opt{true}, \opt{false}}
+% \begin{valuelist}
+% \item[true] Enable the use of hash symbols (\t`\#`) as ordered item
+% list markers.
+% \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]{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]{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]{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}
+% \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\markdownVersion{2016/06/03}%
+% \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 otherwise. 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 \TeX{} engines without the \m{directlua} primitive. 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 \TeX{} engines without the \m{directlua} primitive. 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{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{_markdown-\jobname}%
+% \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.
+% \begin{macrocode}
+\let\markdownOptionBlankBeforeBlockquote\undefined
+\let\markdownOptionBlankBeforeHeading\undefined
+\let\markdownOptionDefinitionLists\undefined
+\let\markdownOptionHashEnumerator\undefined
+\let\markdownOptionHybrid\undefined
+\let\markdownOptionFootnotes\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{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{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
+% three arguments: the label, the \acro{uri}, 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 three
+% arguments: the label, the \acro{url}, and the title of the image.
+% \begin{macrocode}
+\def\markdownRendererImage{%
+ \markdownRendererImagePrototype}%
+% \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{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{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 an item 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{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 Renderer}
+% 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 to input.
+% \begin{macrocode}
+\def\markdownRendererInputVerbatim{%
+ \markdownRendererInputVerbatimPrototype}%
+% \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}
+%
+% \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\markdownRendererLineBreakPrototype{}%
+\def\markdownRendererEllipsisPrototype{}%
+\long\def\markdownRendererCodeSpanPrototype#1{}%
+\long\def\markdownRendererLinkPrototype#1#2#3{}%
+\long\def\markdownRendererImagePrototype#1#2#3{}%
+\def\markdownRendererUlBeginPrototype{}%
+\def\markdownRendererUlBeginTightPrototype{}%
+\def\markdownRendererUlItemPrototype{}%
+\def\markdownRendererUlEndPrototype{}%
+\def\markdownRendererUlEndTightPrototype{}%
+\def\markdownRendererOlBeginPrototype{}%
+\def\markdownRendererOlBeginTightPrototype{}%
+\def\markdownRendererOlItemPrototype{}%
+\long\def\markdownRendererOlItemWithNumberPrototype#1{}%
+\def\markdownRendererOlEndPrototype{}%
+\def\markdownRendererOlEndTightPrototype{}%
+\def\markdownRendererDlBeginPrototype{}%
+\def\markdownRendererDlBeginTightPrototype{}%
+\long\def\markdownRendererDlItemPrototype#1{}%
+\def\markdownRendererDlEndPrototype{}%
+\def\markdownRendererDlEndTightPrototype{}%
+\long\def\markdownRendererEmphasisPrototype#1{}%
+\long\def\markdownRendererStrongEmphasisPrototype#1{}%
+\def\markdownRendererBlockQuoteBeginPrototype{}%
+\def\markdownRendererBlockQuoteEndPrototype{}%
+\long\def\markdownRendererInputVerbatimPrototype#1{}%
+\long\def\markdownRendererHeadingOnePrototype#1{}%
+\long\def\markdownRendererHeadingTwoPrototype#1{}%
+\long\def\markdownRendererHeadingThreePrototype#1{}%
+\long\def\markdownRendererHeadingFourPrototype#1{}%
+\long\def\markdownRendererHeadingFivePrototype#1{}%
+\long\def\markdownRendererHeadingSixPrototype#1{}%
+\def\markdownRendererHorizontalRulePrototype{}%
+\long\def\markdownRendererFootnotePrototype#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{}%
+% \end{macrocode}
+% You may redefine these macros to redirect and process the info, warning, and
+% error messages.
+%
+% \subsubsection{Miscellanea}
+% The \mdef{markdownLuaRegisterIBCallback} and
+% \mdef{markdownLuaUnregisterIBCallback} macros specify the Lua code for
+% registering and unregistering a callback for changing the contents of the
+% line input buffer before a \TeX{} engine that supports direct Lua access via
+% the \m{directlua} macro starts looking at it. The first argument of the
+% \m{markdownLuaRegisterIBCallback} macro corresponds to the callback function
+% being registered.
+%
+% Local members defined within \m{markdownLuaRegisterIBCallback} are guaranteed
+% to be visible from \m{markdownLuaUnregisterIBCallback} and the execution of
+% the two macros alternates, so it is not necessary to consider the case, when
+% one of the macros is called twice in a row.
+% \begin{macrocode}
+\def\markdownLuaRegisterIBCallback#1{%
+ local old_callback = callback.find("process_input_buffer")
+ callback.register("process_input_buffer", #1)}%
+\def\markdownLuaUnregisterIBCallback{%
+ callback.register("process_input_buffer", old_callback)}%
+% \end{macrocode}
+%
+% 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`]`)).
+%
+% \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}).
+%
+% \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}
+\RequirePackage{keyval}
+\define@key{markdownOptions}{helperScriptFileName}{%
+ \def\markdownOptionHelperScriptFileName{#1}}%
+\define@key{markdownOptions}{inputTempFileName}{%
+ \def\markdownOptionInputTempFileName{#1}}%
+\define@key{markdownOptions}{outputTempFileName}{%
+ \def\markdownOptionOutputTempFileName{#1}}%
+\define@key{markdownOptions}{blankBeforeBlockquote}[true]{%
+ \def\markdownOptionBlankBeforeBlockquote{#1}}%
+\define@key{markdownOptions}{blankBeforeHeading}[true]{%
+ \def\markdownOptionBlankBeforeHeading{#1}}%
+\define@key{markdownOptions}{cacheDir}{%
+ \def\markdownOptionCacheDir{#1}}%
+\define@key{markdownOptions}{definitionLists}[true]{%
+ \def\markdownOptionDefinitionLists{#1}}%
+\define@key{markdownOptions}{hashEnumerators}[true]{%
+ \def\markdownOptionHashEnumerators{#1}}%
+\define@key{markdownOptions}{hybrid}[true]{%
+ \def\markdownOptionHybrid{#1}}%
+\define@key{markdownOptions}{footnotes}[true]{%
+ \def\markdownOptionFootnotes{#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}}%
+% \end{macrocode}
+% If the \t`tightLists=false` option is specified, when loading the package,
+% then the \pkg{paralist} package for typesetting tight lists will not be
+% automatically loaded. This precaution is meant to minimize the footprint of
+% this package, since some documentclasses (\pkg{beamer}) do not play nice
+% with the \pkg{paralist} package.
+% \begin{macrocode}
+\define@key{markdownOptions}{tightLists}[true]{%
+ \def\markdownOptionTightLists{#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}
+% 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{markdownOptions}{renderers}{%
+ \setkeys{markdownRenderers}{#1}}%
+\define@key{markdownRenderers}{lineBreak}{%
+ \renewcommand\markdownRendererLineBreak{#1}}%
+\define@key{markdownRenderers}{ellipsis}{%
+ \renewcommand\markdownRendererEllipsis{#1}}%
+\define@key{markdownRenderers}{codeSpan}{%
+ \renewcommand\markdownRendererCodeSpan[1]{#1}}%
+\define@key{markdownRenderers}{link}{%
+ \renewcommand\markdownRendererLink[3]{#1}}%
+\define@key{markdownRenderers}{image}{%
+ \renewcommand\markdownRendererImage[3]{#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}{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}{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}{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}{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}}%
+% \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 = {#3}, % Render links as the link title.
+% emphasis = {\emph{#1}}, % Render emphasized text via `\emph`.
+% }
+% }
+% \end{Verbatim}
+%
+% \paragraph{Plain \TeX{} Markdown Token Renderer Prototypes}
+% 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{markdownOptions}{rendererPrototypes}{%
+ \setkeys{markdownRendererPrototypes}{#1}}%
+\define@key{markdownRendererPrototypes}{lineBreak}{%
+ \renewcommand\markdownRendererLineBreakPrototype{#1}}%
+\define@key{markdownRendererPrototypes}{ellipsis}{%
+ \renewcommand\markdownRendererEllipsisPrototype{#1}}%
+\define@key{markdownRendererPrototypes}{codeSpan}{%
+ \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}%
+\define@key{markdownRendererPrototypes}{link}{%
+ \renewcommand\markdownRendererLink[3]{#1}}%
+\define@key{markdownRendererPrototypes}{image}{%
+ \renewcommand\markdownRendererImage[3]{#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}{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}{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}{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}{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}}%
+% \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{
+% renderers = {
+% 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 Lua code. 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 the 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{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->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 = "\n\n"
+% \end{macrocode}
+%
+% Define \luamdef{writer->containersep} as the output format of a container
+% separator.
+% \begin{macrocode}
+ self.containersep = "\n\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 "
+% \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} containing the mapping from special plain
+% \TeX{} characters to their escaped variants.
+% \begin{macrocode}
+ local escaped = {
+ ["{"] = "\\{",
+ ["}"] = "\\}",
+ ["$"] = "\\$",
+ ["%"] = "\\%",
+ ["&"] = "\\&",
+ ["_"] = "\\_",
+ ["#"] = "\\#",
+ ["^"] = "\\^{}",
+ ["\\"] = "\\char92{}",
+ ["~"] = "\\char126{}",
+ ["|"] = "\\char124{}", }
+% \end{macrocode}
+% Use the \luam{escaped} table to create an escaper function \luamdef{escape}.
+% \begin{macrocode}
+ local escape = util.escaper(escaped)
+% \end{macrocode}
+%
+% Define \luamdef{writer->string} as a function that will transform an input
+% plain text span \t`s` to the output format. If the \Opt{hybrid} option is
+% \t`true`, use an identity function. Otherwise, use the \luam{escape}
+% function.
+% \begin{macrocode}
+ if options.hybrid then
+ self.string = function(s) return s end
+ else
+ self.string = escape
+ 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 thelabel,
+% \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.string(tit),"}"}
+ 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.string(tit),"}"}
+ 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}
+ 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}
+ else
+ return {"\\markdownRendererOlItem ",s}
+ 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->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)
+ return {"\\markdownRendererDlItem{",term,"}\n",defs}
+ end
+
+ function self.definitionlist(items,tight)
+ local buffer = {}
+ for _,item in ipairs(items) do
+ buffer[#buffer + 1] = dlitem(item.term,
+ util.intersperse(item.definitions, self.interblocksep))
+ end
+ local contents = util.intersperse(buffer, self.containersep)
+ if tight and options.tightLists then
+ return {"\\markdownRendererDlBeginTight\n\n", contents,
+ "\n\n\\markdownRendererDlEndTight\n"}
+ else
+ return {"\\markdownRendererDlBegin\n\n", contents,
+ "\n\n\\markdownRendererDlEnd\n"}
+ 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->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->footnote} 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
+
+ return self
+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}
+% \paragraph{Top Level Parsing Functions}
+% \begin{macrocode}
+ local syntax
+ local blocks
+ local inlines
+
+ local parse_blocks =
+ function(str)
+ local res = lpeg.match(blocks, str)
+ if res == nil then
+ error(format("parse_blocks failed on:\n%s", str:sub(1,20)))
+ else
+ return res
+ end
+ end
+
+ local parse_inlines =
+ function(str)
+ local res = lpeg.match(inlines, str)
+ if res == nil then
+ error(format("parse_inlines failed on:\n%s",
+ str:sub(1,20)))
+ else
+ return res
+ end
+ end
+
+ local parse_inlines_no_link =
+ function(str)
+ local res = lpeg.match(inlines_no_link, str)
+ if res == nil then
+ error(format("parse_inlines_no_link failed on:\n%s",
+ str:sub(1,20)))
+ else
+ return res
+ end
+ end
+% \end{macrocode}
+% \paragraph{Generic \acro{peg} Patterns}
+% \begin{macrocode}
+ local percent = P("%")
+ local asterisk = P("*")
+ local dash = P("-")
+ local plus = P("+")
+ local underscore = P("_")
+ local period = P(".")
+ local hash = P("#")
+ local ampersand = P("&")
+ local backtick = P("`")
+ local less = P("<")
+ local more = P(">")
+ local space = P(" ")
+ local squote = P("'")
+ local dquote = P('"')
+ local lparent = P("(")
+ local rparent = P(")")
+ local lbracket = P("[")
+ local rbracket = P("]")
+ local circumflex = P("^")
+ local slash = P("/")
+ local equal = P("=")
+ local colon = P(":")
+ local semicolon = P(";")
+ local exclamation = P("!")
+
+ local digit = R("09")
+ local hexdigit = R("09","af","AF")
+ local letter = R("AZ","az")
+ local alphanumeric = R("AZ","az","09")
+ local keyword = letter * alphanumeric^0
+
+ local doubleasterisks = P("**")
+ local doubleunderscores = P("__")
+ local fourspaces = P(" ")
+
+ local any = P(1)
+ local fail = any - 1
+ local always = P("")
+
+ local escapable = S("\\`*_{}[]()+_.!#-~:^")
+ local anyescaped = P("\\") / "" * escapable
+ + any
+
+ local tab = P("\t")
+ local spacechar = S("\t ")
+ local spacing = S(" \n\r\t")
+ local newline = P("\n")
+ local nonspacechar = any - spacing
+ local tightblocksep = P("\001")
+
+ local specialchar
+ if options.smartEllipses then
+ specialchar = S("*_`&[]!\\.")
+ else
+ specialchar = S("*_`&[]!\\")
+ end
+
+ local normalchar = any -
+ (specialchar + spacing + tightblocksep)
+ local optionalspace = spacechar^0
+ local spaces = spacechar^1
+ local eof = - any
+ local nonindentspace = space^-3 * - spacechar
+ local indent = space^-3 * tab
+ + fourspaces / ""
+ local linechar = P(1 - newline)
+
+ local blankline = optionalspace * newline / "\n"
+ local blanklines = blankline^0
+ local skipblanklines = (optionalspace * newline)^0
+ local indentedline = indent /"" * C(linechar^1 * newline^-1)
+ local optionallyindentedline = indent^-1 /"" * C(linechar^1 * newline^-1)
+ local sp = spacing^0
+ local spnl = optionalspace * (newline * optionalspace)^-1
+ local line = linechar^0 * newline
+ + linechar^1 * eof
+ local nonemptyline = line - blankline
+
+ local chunk = line * (optionallyindentedline - blankline)^0
+
+ -- block followed by 0 or more optionally
+ -- indented blocks with first line indented.
+ local function indented_blocks(bl)
+ return Cs( bl
+ * (blankline^1 * indent * -blankline * bl)^0
+ * blankline^1 )
+ end
+% \end{macrocode}
+% \paragraph{List \acro{peg} Patterns}
+% \begin{macrocode}
+ local bulletchar = C(plus + asterisk + dash)
+
+ local bullet = ( bulletchar * #spacing * (tab + space^-3)
+ + space * bulletchar * #spacing * (tab + space^-2)
+ + space * space * bulletchar * #spacing * (tab + space^-1)
+ + space * space * space * bulletchar * #spacing
+ ) * -bulletchar
+
+ if options.hashEnumerators then
+ dig = digit + hash
+ else
+ dig = digit
+ end
+
+ local enumerator = C(dig^3 * period) * #spacing
+ + C(dig^2 * period) * #spacing * (tab + space^1)
+ + C(dig * period) * #spacing * (tab + space^-2)
+ + space * C(dig^2 * period) * #spacing
+ + space * C(dig * period) * #spacing * (tab + space^-1)
+ + space * space * C(dig^1 * period) * #spacing
+% \end{macrocode}
+% \paragraph{Code Span \acro{peg} Patterns}
+% \begin{macrocode}
+ local openticks = Cg(backtick^1, "ticks")
+
+ local function captures_equal_length(s,i,a,b)
+ return #a == #b and i
+ end
+
+ local closeticks = space^-1 *
+ Cmt(C(backtick^1) * Cb("ticks"), captures_equal_length)
+
+ local intickschar = (any - S(" \n\r`"))
+ + (newline * -blankline)
+ + (space - closeticks)
+ + (backtick^1 - closeticks)
+
+ local inticks = openticks * space^-1 * C(intickschar^1) * closeticks
+% \end{macrocode}
+% \paragraph{Tag \acro{peg} Patterns}
+% \begin{macrocode}
+ local leader = space^-3
+
+ -- in balanced brackets, parentheses, quotes:
+ local bracketed = P{ lbracket
+ * ((anyescaped - (lbracket + rbracket
+ + blankline^2)) + V(1))^0
+ * rbracket }
+
+ local inparens = P{ lparent
+ * ((anyescaped - (lparent + rparent
+ + blankline^2)) + V(1))^0
+ * rparent }
+
+ local squoted = P{ squote * alphanumeric
+ * ((anyescaped - (squote + blankline^2))
+ + V(1))^0
+ * squote }
+
+ local dquoted = P{ dquote * alphanumeric
+ * ((anyescaped - (dquote + blankline^2))
+ + V(1))^0
+ * dquote }
+
+ -- bracketed 'tag' for markdown links, allowing nested brackets:
+ local tag = lbracket
+ * Cs((alphanumeric^1
+ + bracketed
+ + inticks
+ + (anyescaped - (rbracket + blankline^2)))^0)
+ * rbracket
+
+ -- url for markdown links, allowing balanced parentheses:
+ local url = less * Cs((anyescaped-more)^0) * more
+ + Cs((inparens + (anyescaped-spacing-rparent))^1)
+
+ -- quoted text possibly with nested quotes:
+ local title_s = squote * Cs(((anyescaped-squote) + squoted)^0) *
+ squote
+
+ local title_d = dquote * Cs(((anyescaped-dquote) + dquoted)^0) *
+ dquote
+
+ local title_p = lparent
+ * Cs((inparens + (anyescaped-rparent))^0)
+ * rparent
+
+ local title = title_d + title_s + title_p
+
+ local optionaltitle = spnl * title * spacechar^0
+ + Cc("")
+% \end{macrocode}
+% \paragraph{Footnote \acro{peg} Patterns}
+% \begin{macrocode}
+ local rawnotes = {}
+
+ local function strip_first_char(s)
+ return s:sub(2)
+ end
+
+ -- like indirect_link
+ local function lookup_note(ref)
+ return function()
+ local found = rawnotes[normalize_tag(ref)]
+ if found then
+ return writer.note(parse_blocks(found))
+ else
+ return {"[^", ref, "]"}
+ end
+ end
+ end
+
+ local function register_note(ref,rawnote)
+ rawnotes[normalize_tag(ref)] = rawnote
+ return ""
+ end
+
+ local RawNoteRef = #(lbracket * circumflex) * tag / strip_first_char
+
+ local NoteRef = RawNoteRef / lookup_note
+
+ local NoteBlock
+
+ if options.footnotes then
+ NoteBlock = leader * RawNoteRef * colon * spnl *
+ indented_blocks(chunk) / register_note
+ else
+ NoteBlock = fail
+ end
+% \end{macrocode}
+% \paragraph{Link and Image \acro{peg} Patterns}
+% \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
+
+ -- parse a reference definition: [foo]: /bar "title"
+ local define_reference_parser =
+ leader * tag * colon * spacechar^0 * url * optionaltitle * blankline^1
+
+ -- 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 Element \acro{peg} Patterns}
+% \begin{macrocode}
+ local Inline = V("Inline")
+
+ local Str = normalchar^1 / writer.string
+
+ local Ellipsis = P("...") / writer.ellipsis
+
+ local Smart = Ellipsis
+
+ local Symbol = (specialchar - tightblocksep) / writer.string
+
+ local Code = inticks / writer.code
+
+ local bqstart = more
+ local headerstart = hash
+ + (line * (equal^1 + dash^1) * optionalspace * newline)
+
+ if options.blankBeforeBlockquote then
+ bqstart = fail
+ end
+
+ if options.blankBeforeHeading then
+ headerstart = fail
+ end
+
+ local Endline = newline * -( -- newline, but not before...
+ blankline -- paragraph break
+ + tightblocksep -- nested list
+ + eof -- end of document
+ + bqstart
+ + headerstart
+ ) * spacechar^0 / writer.space
+
+% \end{macrocode}
+% Make two and more trailing spaces before a newline produce a forced line
+% break, throw away one or more trailing spaces and an optional newline at the
+% end of a file, and reduce one or more spaces and an optional newline into a
+% single space.
+% \begin{macrocode}
+ local Space = spacechar^2 * Endline / writer.linebreak
+ + spacechar^1 * Endline^-1 * eof / ""
+ + spacechar^1 * Endline^-1 * optionalspace / writer.space
+
+ -- parse many p between starter and ender
+ local function between(p, starter, ender)
+ local ender2 = B(nonspacechar) * ender
+ return (starter * #nonspacechar * Ct(p * (p - ender2)^0) * ender2)
+ end
+
+ local Strong = ( between(Inline, doubleasterisks, doubleasterisks)
+ + between(Inline, doubleunderscores, doubleunderscores)
+ ) / writer.strong
+
+ local Emph = ( between(Inline, asterisk, asterisk)
+ + between(Inline, underscore, underscore)
+ ) / writer.emphasis
+
+ local urlchar = anyescaped - newline - more
+
+ local AutoLinkUrl = less
+ * C(alphanumeric^1 * P("://") * urlchar^1)
+ * more
+ / function(url)
+ return writer.link(writer.string(url), url)
+ end
+
+ local AutoLinkEmail = less
+ * C((alphanumeric + S("-._+"))^1 * P("@") * urlchar^1)
+ * more
+ / function(email)
+ return writer.link(writer.string(email),
+ "mailto:"..email)
+ end
+
+ local DirectLink = (tag / parse_inlines_no_link) -- no links inside links
+ * spnl
+ * lparent
+ * (url + Cc("")) -- link can be empty [foo]()
+ * optionaltitle
+ * rparent
+ / writer.link
+
+ local IndirectLink = tag * (C(spnl) * tag)^-1 / indirect_link
+
+ -- parse a link or image (direct or indirect)
+ local Link = DirectLink + IndirectLink
+
+ local DirectImage = exclamation
+ * (tag / parse_inlines)
+ * spnl
+ * lparent
+ * (url + Cc("")) -- link can be empty [foo]()
+ * optionaltitle
+ * rparent
+ / writer.image
+
+ local IndirectImage = exclamation * tag * (C(spnl) * tag)^-1 /
+ indirect_image
+
+ local Image = DirectImage + IndirectImage
+
+ -- avoid parsing long strings of * or _ as emph/strong
+ local UlOrStarLine = asterisk^4 + underscore^4 / writer.string
+
+ local EscapedChar = S("\\") * C(escapable) / writer.string
+% \end{macrocode}
+% \paragraph{Block Element \acro{peg} Patterns}
+% \begin{macrocode}
+ local Block = V("Block")
+
+ local Verbatim = Cs( (blanklines
+ * ((indentedline - blankline))^1)^1
+ ) / expandtabs / writer.verbatim
+
+ -- strip off leading > and indents, and run through blocks
+ local Blockquote = Cs((
+ ((leader * more * space^-1)/"" * linechar^0 * newline)^1
+ * (-blankline * linechar^1 * newline)^0
+ * blankline^0
+ )^1) / parse_blocks / writer.blockquote
+
+ local function lineof(c)
+ return (leader * (P(c) * optionalspace)^3 * newline * blankline^1)
+ end
+
+ local HorizontalRule = ( lineof(asterisk)
+ + lineof(dash)
+ + lineof(underscore)
+ ) / writer.hrule
+
+ local Reference = define_reference_parser / register_link
+
+ local Paragraph = nonindentspace * Ct(Inline^1) * newline
+ * ( blankline^1
+ + #hash
+ + #(leader * more * space^-1)
+ )
+ / writer.paragraph
+
+ local Plain = nonindentspace * Ct(Inline^1) / writer.plain
+% \end{macrocode}
+% \paragraph{List \acro{peg} Patterns}
+% \begin{macrocode}
+ local starter = bullet + enumerator
+
+ -- we use \001 as a separator between a tight list item and a
+ -- nested list under it.
+ local NestedList = Cs((optionallyindentedline - starter)^1)
+ / function(a) return "\001"..a end
+
+ local ListBlockLine = optionallyindentedline
+ - blankline - (indent^-1 * starter)
+
+ local ListBlock = line * ListBlockLine^0
+
+ local ListContinuationBlock = blanklines * (indent / "") * ListBlock
+
+ local function TightListItem(starter)
+ return -HorizontalRule
+ * (Cs(starter / "" * ListBlock * NestedList^-1) /
+ parse_blocks)
+ * -(blanklines * indent)
+ end
+
+ local function LooseListItem(starter)
+ return -HorizontalRule
+ * Cs( starter / "" * ListBlock * Cc("\n")
+ * (NestedList + ListContinuationBlock^0)
+ * (blanklines / "\n\n")
+ ) / parse_blocks
+ end
+
+ local BulletList = ( Ct(TightListItem(bullet)^1)
+ * Cc(true) * skipblanklines * -bullet
+ + Ct(LooseListItem(bullet)^1)
+ * Cc(false) * skipblanklines ) /
+ writer.bulletlist
+
+ local function orderedlist(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
+
+ local OrderedList = Cg(enumerator, "listtype") *
+ ( Ct(TightListItem(Cb("listtype")) *
+ TightListItem(enumerator)^0)
+ * Cc(true) * skipblanklines * -enumerator
+ + Ct(LooseListItem(Cb("listtype")) *
+ LooseListItem(enumerator)^0)
+ * Cc(false) * skipblanklines
+ ) * Cb("listtype") / orderedlist
+
+ local defstartchar = S("~:")
+ local defstart = ( defstartchar * #spacing * (tab + space^-3)
+ + space * defstartchar * #spacing * (tab + space^-2)
+ + space * space * defstartchar * #spacing *
+ (tab + space^-1)
+ + space * space * space * defstartchar * #spacing
+ )
+
+ local dlchunk = Cs(line * (indentedline - blankline)^0)
+
+ local function definition_list_item(term, defs, tight)
+ return { term = parse_inlines(term), definitions = defs }
+ end
+
+ local DefinitionListItemLoose = C(line) * skipblanklines
+ * Ct((defstart *
+ indented_blocks(dlchunk) /
+ parse_blocks)^1)
+ * Cc(false)
+ / definition_list_item
+
+ local DefinitionListItemTight = C(line)
+ * Ct((defstart * dlchunk /
+ parse_blocks)^1)
+ * Cc(true)
+ / definition_list_item
+
+ local DefinitionList = ( Ct(DefinitionListItemLoose^1) * Cc(false)
+ + Ct(DefinitionListItemTight^1)
+ * (skipblanklines *
+ -DefinitionListItemLoose * Cc(true))
+ ) / writer.definitionlist
+% \end{macrocode}
+% \paragraph{Blank \acro{peg} Patterns}
+% \begin{macrocode}
+ local Blank = blankline / ""
+ + NoteBlock
+ + Reference
+ + (tightblocksep / "\n")
+% \end{macrocode}
+% \paragraph{Heading \acro{peg} Patterns}
+% \begin{macrocode}
+ -- parse Atx heading start and return level
+ local HeadingStart = #hash * C(hash^-6) * -hash / length
+
+ -- parse setext header ending and return level
+ local HeadingLevel = equal^1 * Cc(1) + dash^1 * Cc(2)
+
+ local function strip_atx_end(s)
+ return s:gsub("[#%s]*\n$","")
+ end
+
+ -- parse atx header
+ local AtxHeading = Cg(HeadingStart,"level")
+ * optionalspace
+ * (C(line) / strip_atx_end / parse_inlines)
+ * Cb("level")
+ / writer.heading
+
+ -- parse setext header
+ local SetextHeading = #(line * S("=-"))
+ * Ct(line / parse_inlines)
+ * HeadingLevel
+ * optionalspace * newline
+ / writer.heading
+% \end{macrocode}
+% \paragraph{Top Level \acro{peg} Specification}
+% \begin{macrocode}
+ syntax =
+ { "Blocks",
+
+ Blocks = Blank^0 *
+ Block^-1 *
+ (Blank^0 / function()
+ return writer.interblocksep
+ end * Block)^0 *
+ Blank^0 *
+ eof,
+
+ Blank = Blank,
+
+ Block = V("Blockquote")
+ + V("Verbatim")
+ + V("HorizontalRule")
+ + V("BulletList")
+ + V("OrderedList")
+ + V("Heading")
+ + V("DefinitionList")
+ + V("Paragraph")
+ + V("Plain"),
+
+ Blockquote = Blockquote,
+ Verbatim = Verbatim,
+ HorizontalRule = HorizontalRule,
+ BulletList = BulletList,
+ OrderedList = OrderedList,
+ Heading = AtxHeading + SetextHeading,
+ DefinitionList = DefinitionList,
+ DisplayHtml = DisplayHtml,
+ Paragraph = Paragraph,
+ Plain = Plain,
+
+ Inline = V("Str")
+ + V("Space")
+ + V("Endline")
+ + V("UlOrStarLine")
+ + V("Strong")
+ + V("Emph")
+ + V("NoteRef")
+ + V("Link")
+ + V("Image")
+ + V("Code")
+ + V("AutoLinkUrl")
+ + V("AutoLinkEmail")
+ + V("EscapedChar")
+ + V("Smart")
+ + V("Symbol"),
+
+ Str = Str,
+ Space = Space,
+ Endline = Endline,
+ UlOrStarLine = UlOrStarLine,
+ Strong = Strong,
+ Emph = Emph,
+ NoteRef = NoteRef,
+ Link = Link,
+ Image = Image,
+ Code = Code,
+ AutoLinkUrl = AutoLinkUrl,
+ AutoLinkEmail = AutoLinkEmail,
+ InlineHtml = InlineHtml,
+ HtmlEntity = HtmlEntity,
+ EscapedChar = EscapedChar,
+ Smart = Smart,
+ Symbol = Symbol,
+ }
+
+ if not options.definitionLists then
+ syntax.DefinitionList = fail
+ end
+
+ if not options.footnotes then
+ syntax.NoteRef = fail
+ end
+
+ if not options.smartEllipses then
+ syntax.Smart = fail
+ end
+
+ blocks = Ct(syntax)
+
+ local inlines_t = util.table_copy(syntax)
+ inlines_t[1] = "Inlines"
+ inlines_t.Inlines = Inline^0 * (spacing^0 * eof / "")
+ inlines = Ct(inlines_t)
+
+ inlines_no_link_t = util.table_copy(inlines_t)
+ inlines_no_link_t.Link = fail
+ inlines_no_link = Ct(inlines_no_link_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 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, ",")
+% \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(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{%
+ \message{(l.\the\inputlineno) markdown.tex info: #1.}}%
+\def\markdownWarning#1{%
+ \message{(l.\the\inputlineno) markdown.tex warning: #1}}%
+\def\markdownError#1#2{%
+ \errhelp{#2.}%
+ \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}%
+% \end{macrocode}
+%
+% \subsubsection{Options}
+% The following definitions should be considered placeholder.
+% \begin{macrocode}
+\def\markdownRendererLineBreakPrototype{\hfil\break}%
+\let\markdownRendererEllipsisPrototype\dots
+\long\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}%
+\long\def\markdownRendererLinkPrototype#1#2#3{#1}%
+\long\def\markdownRendererImagePrototype#1#2#3{#1}%
+\def\markdownRendererUlBeginPrototype{}%
+\def\markdownRendererUlBeginTightPrototype{}%
+\def\markdownRendererUlItemPrototype{}%
+\def\markdownRendererUlEndPrototype{}%
+\def\markdownRendererUlEndTightPrototype{}%
+\def\markdownRendererOlBeginPrototype{}%
+\def\markdownRendererOlBeginTightPrototype{}%
+\def\markdownRendererOlItemPrototype{}%
+\long\def\markdownRendererOlItemWithNumberPrototype#1{}%
+\def\markdownRendererOlEndPrototype{}%
+\def\markdownRendererOlEndTightPrototype{}%
+\def\markdownRendererDlBeginPrototype{}%
+\def\markdownRendererDlBeginTightPrototype{}%
+\long\def\markdownRendererDlItemPrototype#1{#1}%
+\def\markdownRendererDlEndPrototype{}%
+\def\markdownRendererDlEndTightPrototype{}%
+\long\def\markdownRendererEmphasisPrototype#1{{\it#1}}%
+\long\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}%
+\def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}%
+\def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}%
+\long\def\markdownRendererInputVerbatimPrototype#1{%
+ \par{\tt\input"#1"\relax}\par}%
+\long\def\markdownRendererHeadingOnePrototype#1{#1}%
+\long\def\markdownRendererHeadingTwoPrototype#1{#1}%
+\long\def\markdownRendererHeadingThreePrototype#1{#1}%
+\long\def\markdownRendererHeadingFourPrototype#1{#1}%
+\long\def\markdownRendererHeadingFivePrototype#1{#1}%
+\long\def\markdownRendererHeadingSixPrototype#1{#1}%
+\def\markdownRendererHorizontalRulePrototype{}%
+\long\def\markdownRendererFootnotePrototype#1{#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}). Note that the
+% boolean options are not sanitized and expect the plain \TeX{} option macros
+% to expand to either \t`true` or \t`false`.
+% \begin{macrocode}
+\def\markdownLuaOptions{{%
+ \ifx\markdownOptionBlankBeforeBlockquote\undefined\else
+ blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote,
+ \fi
+ \ifx\markdownOptionBlankBeforeHeading\undefined\else
+ blankBeforeHeading = \markdownOptionBlankBeforeHeading,
+ \fi
+ \ifx\markdownOptionCacheDir\undefined\else
+ cacheDir = "\markdownOptionCacheDir",
+ \fi
+ \ifx\markdownOptionDefinitionLists\undefined\else
+ definitionLists = \markdownOptionDefinitionLists,
+ \fi
+ \ifx\markdownOptionHashEnumerators\undefined\else
+ hashEnumerators = \markdownOptionHashEnumerators,
+ \fi
+ \ifx\markdownOptionHybrid\undefined\else
+ hybrid = \markdownOptionHybrid,
+ \fi
+ \ifx\markdownOptionFootnotes\undefined\else
+ footnotes = \markdownOptionFootnotes,
+ \fi
+ \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}
+}%
+% \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{Lua \t`\textbackslash write18` 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 through
+% the output file stream 18 (\Hologo{XeTeX}, \hologo{pdfLaTeX}).
+% The \m{markdownLuaExecute} and \m{markdownReadAndConvert} macros defined here
+% and in Section \ref{sec:directlua} are meant to be transparent 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]{luatex16}).
+% \begin{macrocode}
+\ifx\directlua\undefined
+% \end{macrocode}
+%
+% The macro \mdef{markdownLuaExecuteFileStream} contains the number of the output
+% file stream that will be used to store the helper Lua script in the file named
+% \m{markdownOptionHelperScriptFileName} during the expansion of the macro
+% \m{markdownLuaExecute}, and to store the markdown input in the file
+% named \m{markdownOptionInputTempFileName} during the expansion of the macro
+% \m{markdownReadAndConvert}.
+% \begin{macrocode}
+ \csname newwrite\endcsname\markdownLuaExecuteFileStream
+% \end{macrocode}
+%
+% The \mdef{markdownLuaExecuteShellEscape} macro contains the numeric value of
+% either the \m{pdfshellescape} (Lua\TeX{}, \Hologo{pdfTeX}) or the
+% \m{shellescape} (\Hologo{XeTeX}) commands. This value indicates, whether the
+% shell access is enabled (\t`1`), disabled (\t`0`), or restricted (\t`2`). If
+% neither of these commands is defined, act as if the shell access were enabled.
+% \begin{macrocode}
+ \csname newcount\endcsname\markdownLuaExecuteShellEscape
+ \ifx\pdfshellescape\undefined
+ \ifx\shellescape\undefined
+ \markdownLuaExecuteShellEscape=1%
+ \else
+ \markdownLuaExecuteShellEscape=\shellescape
+ \fi
+ \else
+ \markdownLuaExecuteShellEscape=\pdfshellescape
+ \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}
+ \def\markdownLuaExecute#1{%
+% \end{macrocode}
+% If the shell is accessible, 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}
+ \ifnum\markdownLuaExecuteShellEscape=1%
+ \immediate\openout\markdownLuaExecuteFileStream=%
+ \markdownOptionHelperScriptFileName
+ \markdownInfo{Writing a helper Lua script to the file
+ "\markdownOptionHelperScriptFileName"}%
+ \immediate\write\markdownLuaExecuteFileStream{%
+ local kpse = require('kpse')
+ kpse.set_program_name('luatex') #1}%
+ \immediate\closeout\markdownLuaExecuteFileStream
+% \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"}%
+ \immediate\write18{texlua "\markdownOptionHelperScriptFileName" >
+ "\markdownOptionOutputTempFileName"}%
+% \end{macrocode}
+% \m{input} the generated \m{markdownOptionOutputTempFileName} file.
+% \begin{macrocode}
+ \input\markdownOptionOutputTempFileName\relax
+ \else
+% \end{macrocode}
+% If the shell is inaccessible, let the user know and suggest a remedy.
+% \begin{macrocode}
+ \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{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|markdownLuaExecuteFileStream%
+ |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 and tab characters, so that we
+% can retrieve them 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|markdownLuaExecuteFileStream{##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|write|markdownLuaExecuteFileStream{}%
+ |immediate|closeout|markdownLuaExecuteFileStream%
+ |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{Direct Lua Access}\label{sec:directlua}
+% The following \TeX{} code is intended for \TeX{} engines that provide
+% direct access to Lua (Lua\TeX{}). The \m{markdownLuaExecute} and
+% \m{markdownReadAndConvert} defined here and in Section \ref{sec:luabridge}
+% are meant to be transparent to the remaining code.
+% \begin{macrocode}
+\else
+% \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}}%
+% \end{macrocode}
+%
+% In the definition of the direct Lua access version of the
+% \m{markdownReadAndConvert} macro, we will be using the hash symbol
+% (\t`\#`), the underscore symbol (\t`_`), the caret symbol (\t`\^`), the
+% dollar sign (\t`\$`), the backslash symbol (\t`\textbackslash`), the percent
+% sign (\t`\%`), and the braces (\t`\{\}`) as a part of the Lua syntax.
+% \begin{macrocode}
+ \begingroup
+% \end{macrocode}
+%
+% To this end, we will make the underscore symbol, the dollar sign, and caret
+% symbols ordinary characters,
+% \begin{macrocode}
+ \catcode`\_=12%
+ \catcode`\$=12%
+ \catcode`\^=12%
+% \end{macrocode}
+% swap the category code of the hash symbol with the slash symbol (\t`/`).
+% \begin{macrocode}
+ \catcode`\/=6%
+ \catcode`\#=12%
+% \end{macrocode}
+% swap the category code of the percent sign with the at symbol (\t`@`).
+% \begin{macrocode}
+ \catcode`\@=14%
+ \catcode`\%=12%
+% \end{macrocode}
+% swap the category code of the backslash symbol with the pipe symbol (\t`|`),
+% \begin{macrocode}
+ \catcode`|=0@
+ \catcode`\\=12@
+% \end{macrocode}
+% Braces are a part of the plain \TeX{} syntax, but they are not removed during
+% expansion, so we do not need to bother with changing their category codes.
+% \begin{macrocode}
+ |gdef|markdownReadAndConvert/1/2{@
+% \end{macrocode}
+% Make the \mdef{markdownReadAndConvertAfter} macro store the token sequence
+% that will be inserted into the document after the ending token sequence has
+% been found.
+% \begin{macrocode}
+ |def|markdownReadAndConvertAfter{/2}@
+ |markdownInfo{Buffering markdown input and scanning for the
+ closing token sequence "/1"}@
+ |directlua{@
+% \end{macrocode}
+% Set up an empty Lua table that will serve as our buffer.
+% \begin{macrocode}
+ |markdownPrepare
+ local buffer = {}
+% \end{macrocode}
+% Create a regex that will match the ending input sequence. Escape any special
+% regex characters (like a star inside \t`\textbackslash end\{markdown*\}`)
+% inside the input.
+% \begin{macrocode}
+ local ending_sequence = "^.-" .. ([[/1]]):gsub(
+ "([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1")
+% \end{macrocode}
+% Register a callback that will notify you about new lines of input.
+% \begin{macrocode}
+ |markdownLuaRegisterIBCallback{function(line)
+% \end{macrocode}
+% When the ending token sequence appears on a line, unregister the callback,
+% convert the contents of our buffer from markdown to plain \TeX{}, and insert
+% the result into the input line buffer of \TeX{}.
+% \begin{macrocode}
+ if line:match(ending_sequence) then
+ |markdownLuaUnregisterIBCallback
+ local input = table.concat(buffer, "\n") .. "\n\n"
+ local output = convert(input)
+ return [[\markdownInfo{The ending token sequence was found}]] ..
+ output .. [[\markdownReadAndConvertAfter]]
+% \end{macrocode}
+% When the ending token sequence does not appear on a line, store the line in
+% our buffer, and insert either \m{fi}, if this is the first line of input,
+% or an empty token list to the input line buffer of \TeX{}.
+% \begin{macrocode}
+ else
+ buffer[#buffer+1] = line
+ return [[\]] .. (#buffer == 1 and "fi" or "relax")
+ end
+ end}}@
+% \end{macrocode}
+% Insert \m{iffalse} after the \m{markdownReadAndConvert} macro in order to
+% consume the rest of the first line of input.
+% \begin{macrocode}
+ |iffalse}@
+% \end{macrocode}
+% Reset the character categories back to the former state.
+% \begin{macrocode}
+ |endgroup
+\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"}%
+ |markdownLuaExecute{%
+ |markdownPrepare
+ local input = assert(io.open("#1","r")):read("*a") .. "\n\n"
+% \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]{latex16}). As a consequence, we can directly reuse the
+% existing plain \TeX{} implementation.
+% \begin{macrocode}
+\input markdown
+\ProvidesPackage{markdown}[\markdownVersion]%
+% \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}
+%
+% The following configuration should be considered placeholder.
+% \begin{macrocode}
+\RequirePackage{url}
+\RequirePackage{graphicx}
+% \end{macrocode}
+% If the \m{markdownOptionTightLists} macro expands to \t`false`, do not load
+% the \pkg{paralist} package.
+% \begin{macrocode}
+\RequirePackage{ifthen}
+\ifx\markdownOptionTightLists\undefined
+ \RequirePackage{paralist}
+\else
+ \ifthenelse{\equal{\markdownOptionTightLists}{false}}{}{
+ \RequirePackage{paralist}}
+\fi
+\RequirePackage{fancyvrb}
+\markdownSetup{rendererPrototypes={
+ lineBreak = {\\},
+ codeSpan = {\texttt{#1}},
+ link = {#1\footnote{\ifx\empty#3\empty\else#3:
+ \fi\texttt<\url{#2}\texttt>}},
+ image = {\begin{figure}
+ \begin{center}%
+ \includegraphics{#2}%
+ \end{center}%
+ \ifx\empty#3\empty\else
+ \caption{#3}%
+ \fi
+ \label{fig:#1}%
+ \end{figure}},
+ ulBegin = {\begin{itemize}},
+ ulBeginTight = {\begin{compactitem}},
+ ulItem = {\item},
+ ulEnd = {\end{itemize}},
+ ulEndTight = {\end{compactitem}},
+ olBegin = {\begin{enumerate}},
+ olBeginTight = {\begin{compactenum}},
+ olItem = {\item},
+ olItemWithNumber = {\item[#1.]},
+ olEnd = {\end{enumerate}},
+ olEndTight = {\end{compactenum}},
+ dlBegin = {\begin{description}},
+ dlBeginTight = {\begin{compactdesc}},
+ dlItem = {\item[#1]},
+ dlEnd = {\end{description}},
+ dlEndTight = {\end{compactdesc}},
+ emphasis = {\emph{#1}},
+ strongEmphasis = {%
+ \ifx\alert\undefined
+ \textbf{\emph{#1}}%
+ \else % Beamer support
+ \alert{\emph{#1}}
+ \fi},
+ blockQuoteBegin = {\begin{quotation}},
+ blockQuoteEnd = {\end{quotation}},
+ inputVerbatim = {\VerbatimInput{#1}},
+ horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}},
+ footnote = {\footnote{#1}}}}%
+
+\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}
+%
+% \subsubsection{Miscellanea}
+% Unlike base Lua\TeX{}, which only allows for a single registered function per
+% a callback (see \cite[Section~8.1]{luatex16}), the \Hologo{LaTeX2e} format
+% disables the \luam{callback.register} method and exposes the
+% \luam{luatexbase.add_to_callback} and \luam{luatexbase.remove_from_callback}
+% methods that enable the user code to hook several functions on a single
+% callback (see \cite[Section~73.4]{latex16}).
+%
+% To make our code function with the \Hologo{LaTeX2e} format, we need to
+% redefine the \m{markdownLuaRegisterIBCallback} and
+% \m{markdownLuaUnregisterIBCallback} macros accordingly.
+% \begin{macrocode}
+\renewcommand\markdownLuaRegisterIBCallback[1]{%
+ luatexbase.add_to_callback("process_input_buffer", #1, %
+ "The markdown input processor")}
+\renewcommand\markdownLuaUnregisterIBCallback{%
+ luatexbase.remove_from_callback("process_input_buffer",%
+ "The markdown input processor")}
+% \end{macrocode}
+%
+% 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\~}%
+% \end{macrocode}
+% When there is no Lua support, then just load the plain \TeX{} implementation.
+% \begin{macrocode}
+\ifx\directlua\undefined
+ \input markdown
+\else
+% \end{macrocode}
+% When there is Lua support, check if we can set the \t`process_input_buffer`
+% Lua\TeX{} callback.
+% \begin{macrocode}
+ \directlua{%
+ local function unescape(str)
+ return (str:gsub("|", string.char(92))) end
+ local old_callback = callback.find("process_input_buffer")
+ callback.register("process_input_buffer", function() end)
+ local new_callback = callback.find("process_input_buffer")
+% \end{macrocode}
+%
+% If we can not, we are probably using ConTeXt Mark IV. In ConTeXt Mark IV, the
+% \t`process_input_buffer` callback is currently frozen (inaccessible from the
+% user code) and, due to the lack of available documentation, it is unclear to
+% me how to emulate it. Therefore, we will just force the plain \TeX{}
+% implementation to use the \m{write18} bridge (see Section
+% \ref{sec:luabridge}) by locally undefining the \m{directlua} primitive.
+% \begin{macrocode}
+ if new_callback == false then
+ tex.print(unescape([[|let|markdownDirectLua|directlua
+ |let|directlua|undefined
+ |input markdown
+ |let|directlua|markdownDirectLua
+ |let|markdownDirectLua|undefined]]))
+% \end{macrocode}
+%
+% If we can, then just load the plain \TeX{} implementation.
+% \begin{macrocode}
+ else
+ callback.register("process_input_buffer", old_callback)
+ tex.print(unescape("|input markdown"))
+ end}%
+\fi
+% \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{Options}
+% The following configuration should be considered placeholder.
+% \begin{macrocode}
+\def\markdownRendererLineBreakPrototype{\blank}%
+\long\def\markdownRendererLinkPrototype#1#2#3{%
+ \useURL[#1][#2][][#3]#1\footnote[#1]{\ifx\empty#3\empty\else#3:
+ \fi\tt<\hyphenatedurl{#2}>}}%
+\long\def\markdownRendererImagePrototype#1#2#3{%
+ \placefigure[][fig:#1]{#3}{\externalfigure[#2]}}%
+\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}%
+\long\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}%
+\long\long\def\markdownRendererDlItemPrototype#1{%
+ \markdownConTeXtDlItemPrototype{#1}}%
+\def\markdownRendererDlEndPrototype{%
+ \stopMarkdownConTeXtDlPrototype}%
+\def\markdownRendererDlEndTightPrototype{%
+ \stopMarkdownConTeXtDlTightPrototype}%
+\long\def\markdownRendererEmphasisPrototype#1{{\em#1}}%
+\long\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}%
+\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}%
+\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}%
+\long\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}%
+\long\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}%
+\long\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}%
+\long\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}%
+\long\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}%
+\long\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}%
+\long\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}%
+\def\markdownRendererHorizontalRulePrototype{%
+ \blackrule[height=1pt, width=\hsize]}%
+\long\def\markdownRendererFootnotePrototype#1{\footnote{#1}}%
+\stopmodule\protect
+% \end{macrocode}
+%
+% \iffalse
+%</context>
+% \fi
diff --git a/Master/texmf-dist/source/generic/markdown/markdown.ins b/Master/texmf-dist/source/generic/markdown/markdown.ins
new file mode 100644
index 00000000000..76ed44df1ef
--- /dev/null
+++ b/Master/texmf-dist/source/generic/markdown/markdown.ins
@@ -0,0 +1,8 @@
+\input docstrip.tex
+\generate{\usepreamble\luapreamble\usepostamble\luapostamble
+ \file{markdown.lua}{\from{markdown.dtx}{lua}}
+ \usepreamble\texpreamble\usepostamble\texpostamble
+ \file{markdown.tex}{\from{markdown.dtx}{tex}}
+ \file{markdown.sty}{\from{markdown.dtx}{latex}}
+ \file{t-markdown.tex}{\from{markdown.dtx}{context}}}
+\endbatchfile