diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/markdown/markdown.dtx |
Initial commit
Diffstat (limited to 'macros/generic/markdown/markdown.dtx')
-rw-r--r-- | macros/generic/markdown/markdown.dtx | 17226 |
1 files changed, 17226 insertions, 0 deletions
diff --git a/macros/generic/markdown/markdown.dtx b/macros/generic/markdown/markdown.dtx new file mode 100644 index 0000000000..71c06b8154 --- /dev/null +++ b/macros/generic/markdown/markdown.dtx @@ -0,0 +1,17226 @@ +% \iffalse +%<*driver> +\documentclass{ltxdockit} +\usepackage[american]{babel} +\usepackage{amsmath,btxdockit,doc,fancyvrb,hologo,microtype,minted,xcolor} +\usepackage{fontspec} +\defaultfontfeatures[\rmfamily,\sffamily,\ttfamily]{} + +% Set up the style. +\emergencystretch=1em +\fvset{gobble=0,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}\t`#1`} +\newcommand\envm[1]{% A LaTeX environment reference + \hyperref[environment:#1]{\t`#1`}} +\newcommand\luamdef[1]{% A Lua object / method definition + \phantomsection\label{lua:#1}\t`#1`} +\newcommand\luam[1]{% A Lua object / method reference + \hyperref[lua:#1]{\t`#1`}} +\def\inline#1{% Inline code + \textcolor{spot}{\text{\texttt{#1}}}} +\def\t`#1`{\inline{#1}} +\newcommand\Optitem[2][]{\penalty -1000\relax % An option item definition + \phantomsection\label{opt:#2}\optitem[#1]{#2}} +\newcommand\Valitem[2][]{\penalty -1000\relax % A value item definition + \phantomsection\label{opt:#2}\valitem[#1]{#2}} +\newcommand\Opt[1]{% An option / value item reference + \hyperref[opt:#1]{\t`#1`}} +\newcommand\acro[1]{% An acronym + \textsc{\MakeLowercase{#1}}} + +% Set up markdown. +\usepackage[ + citations, + definitionLists, + fencedCode, + headerAttributes, + hybrid, + html, + stripPercentSigns, + underscores=false, +]{markdown} +\markdownSetup{ + renderers = { + codeSpan = {\inline{#1}}, + link = {#1\footnote{See \url{#3}.}}, + headingFour = {% + \paragraph{#1}\leavevmode + \def\markdownRendererInterblockSeparator{% + \let\markdownRendererInterblockSeparator\par + }% + \noindent + }, + }, +} + +% Set up the catcodes. +\catcode`\_=12 % We won't be typesetting much math and Lua contains lots of `_`. +\catcode`\^^B=8 % When we occasionally need subscripts , we will use `^^B` (STX). + +% Set up the title page. +\titlepage{% + title={A Markdown Interpreter for \TeX{}}, + subtitle={}, + url={https://github.com/witiko/markdown}, + author={Vít Novotný}, + email={witiko@mail.muni.cz}, + revision=\markdownVersion, + date={\today}} +\hypersetup{% + pdftitle={A Markdown Interpreter for \TeX{}}, + pdfauthor={Vít Novotný}} +\CodelineIndex + +% Set up the bibliography. +\usepackage{filecontents} +\begin{filecontents}{markdown.bib} +@online{sotkov17, + author = {Sotkov, Anton}, + title = {File transclusion syntax for Markdown}, + date = {2017-01-19}, + url = {https://github.com/iainc/Markdown-Content-Blocks}, + urldate = {2018-01-08}} +@book{luatex17, + author = {{Lua\TeX{} development team}}, + title = {Lua\TeX{} reference manual}, + year = {2017}, + month = {2}, + url = {http://www.luatex.org/svn/trunk/manual/luatex.pdf}, + urldate = {2018-01-08}} +@book{latex17, + author = {Braams, Johannes and Carlisle, David and Jeffrey, Alan and + Lamport, Leslie and Mittelbach, Frank and Rowley, Chris and + Schöpf, Rainer}, + title = {The \Hologo{LaTeX2e} Sources}, + date = {2017-04-15}, + url = {http://mirrors.ctan.org/macros/latex/base/source2e.pdf}, + urldate = {2018-01-08}} +@book{mittelbach17, + author = {Mittelbach, Frank}, + title = {The \texttt{doc} and \texttt{shortvrb} Packages}, + date = {2017-04-15}, + url = {http://mirrors.ctan.org/macros/latex/base/doc.pdf}, + urldate = {2018-02-19}} +@online{novotny15, + author = {Novotný, Vít}, + year = {2015}, + title = {TeXový interpret jazyka Markdown (markdown.sty)}, + location = {Brno, Czech Republic}, + publisher = {Masaryk University}, + url = {https://www.muni.cz/en/research/projects/32984}, + urldate = {2018-02-19}} +@book{ierusalimschy13, + author = {Ierusalimschy, Roberto}, + year = {2013}, + title = {Programming in Lua}, + edition = {3}, + isbn = {978-85-903798-5-0}, + pagetotal = {xviii, 347}, + location = {Rio de Janeiro}, + publisher = {PUC-Rio}} +@book{knuth86, + author = {Knuth, Donald Ervin}, + year = {1986}, + title = {The \TeX{}book}, + edition = {3}, + isbn = {0-201-13447-0}, + pagetotal = {ix, 479}, + publisher = {Addison-Wesley}} +\end{filecontents} +\usepackage[ + backend=biber, + style=numeric, + sorting=none, + autolang=other, + sortlocale=auto]{biblatex} +\addbibresource{markdown.bib} + +\begin{document} +\printtitlepage +\tableofcontents +\DocInput{markdown.dtx} +\printbibliography +\end{document} +%</driver> +%<*manual-css> + +html { + font-size: 100%; + overflow-y: scroll; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + color: #444; + font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', serif; + font-size: 12px; + line-height: 1.7; + padding: 1em; + margin: auto; + max-width: 42em; + background: #fefefe; +} + +a { + color: #0645ad; +} + +a:visited { + color: #0b0080; +} + +a:hover { + color: #06e; +} + +a:active { + color: #faa700; +} + +a:focus { + outline: thin dotted; +} + +*::-moz-selection { + background: rgba(255, 255, 0, 0.3); + color: #000; +} + +*::selection { + background: rgba(255, 255, 0, 0.3); + color: #000; +} + +a::-moz-selection { + background: rgba(255, 255, 0, 0.3); + color: #0645ad; +} + +a::selection { + background: rgba(255, 255, 0, 0.3); + color: #0645ad; +} + +p { + margin: 1em 0; +} + +img { + max-width: 100%; +} + +h1, h2, h3, h4, h5, h6 { + color: #111; + line-height: 125%; + margin-top: 2em; + font-weight: normal; +} + +h4, h5, h6 { + font-weight: bold; +} + +h1 { + font-size: 2.5em; +} + +h2 { + font-size: 2em; +} + +h3 { + font-size: 1.5em; +} + +h4 { + font-size: 1.2em; +} + +h5 { + font-size: 1em; +} + +h6 { + font-size: 0.9em; +} + +blockquote { + color: #666666; + margin: 0; + padding-left: 3em; + border-left: 0.5em #EEE solid; +} + +hr { + display: block; + height: 2px; + border: 0; + border-top: 1px solid #aaa; + border-bottom: 1px solid #eee; + margin: 1em 0; + padding: 0; +} + +pre, code, kbd, samp { + color: #000; + font-family: monospace, monospace; + _font-family: 'courier new', monospace; + font-size: 0.98em; +} + +pre { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; +} + +b, strong { + font-weight: bold; +} + +dfn { + font-style: italic; +} + +ins { + background: #ff9; + color: #000; + text-decoration: none; +} + +mark { + background: #ff0; + color: #000; + font-style: italic; + font-weight: bold; +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +ul, ol { + margin: 1em 0; + padding: 0 0 0 2em; +} + +li p:last-child { + margin-bottom: 0; +} + +ul ul, ol ol { + margin: .3em 0; +} + +dl { + margin-bottom: 1em; +} + +dt { + font-weight: bold; + margin-bottom: .8em; +} + +dd { + margin: 0 0 .8em 2em; +} + +dd:last-child { + margin-bottom: 0; +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; + vertical-align: middle; +} + +figure { + display: block; + text-align: center; + margin: 1em 0; +} + +figure img { + border: none; + margin: 0 auto; +} + +figcaption { + font-size: 0.8em; + font-style: italic; + margin: 0 0 .8em; +} + +table { + margin-bottom: 2em; + border-bottom: 1px solid #ddd; + border-right: 1px solid #ddd; + border-spacing: 0; + border-collapse: collapse; +} + +table th { + padding: .2em 1em; + background-color: #eee; + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; +} + +table td { + padding: .2em 1em; + border-top: 1px solid #ddd; + border-left: 1px solid #ddd; + vertical-align: top; +} + +.author { + font-size: 1.2em; + text-align: center; +} + +@media only screen and (min-width: 480px) { + body { + font-size: 14px; + } +} +@media only screen and (min-width: 768px) { + body { + font-size: 16px; + } +} +@media print { + * { + background: transparent !important; + color: black !important; + filter: none !important; + -ms-filter: none !important; + } + + body { + font-size: 12pt; + max-width: 100%; + } + + a, a:visited { + text-decoration: underline; + } + + hr { + height: 1px; + border: 0; + border-bottom: 1px solid black; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { + content: ""; + } + + pre, blockquote { + border: 1px solid #999; + padding-right: 1em; + page-break-inside: avoid; + } + + tr, img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page :left { + margin: 15mm 20mm 15mm 10mm; +} + + @page :right { + margin: 15mm 10mm 15mm 20mm; +} + + p, h2, h3 { + orphans: 3; + widows: 3; + } + + h2, h3 { + page-break-after: avoid; + } +} + +.tex sub, .latex sub, .latex sup { + text-transform: uppercase; +} + +.tex sub, .latex sub { + vertical-align: -0.1ex; + margin-left: -0.1667em; + margin-right: -0.125em; +} + +.tex, .latex, .tex sub, .latex sub { + font-size: 1em; +} + +.latex sup { + font-size: 0.85em; + vertical-align: -0.35em; + margin-left: -0.36em; + margin-right: -0.15em; +} + +abbr { + text-transform: lowercase; + font-variant: small-caps; +} + +%</manual-css> +%<*manual> + +--- +title: Markdown Package User Manual +author: Vít Novotný +date: v\markdownVersion{} (\markdownLastModified{}) +--- + +% \fi +% \par +% \begin{markdown} + +<link href="https://afeld.github.io/emoji-css/emoji.css" rel="stylesheet" /> + +Introduction +============ +The [Markdown package][pkg] converts [markdown][] markup to \TeX{} commands. The +functionality is provided both as a Lua module and as plain \TeX{}, \LaTeX{}, and +\Hologo{ConTeXt} macro packages that can be used to directly typeset \TeX documents +containing markdown markup. Unlike other convertors, the Markdown package +makes it easy to redefine how each and every markdown element is rendered. +Creative abuse of the markdown syntax is encouraged. ;-) + + [markdown]: https://daringfireball.net/projects/markdown/basics/ + (Daring Fireball: Markdown Basics) + [pkg]: https://ctan.org/pkg/markdown + (CTAN: Package markdown) + +% This document is a technical documentation for the \pkg{Markdown} package. It +% consists of three sections. This section introduces the package and outlines +% its prerequisites. Section \ref{sec:interfaces} describes the interfaces +% exposed by the package. Section \ref{sec:implementation} describes the +% implementation of the package. The technical documentation contains only a +% limited number of tutorials and code examples. You can find more of these in +% the [user manual.][manual] +% +% [manual]: http://mirrors.ctan.org/macros/generic/markdown/markdown.html +% +% \end{markdown} +% \iffalse + +This document is a user manual for the [Markdown package][pkg]. It provides +tutorials and code examples. For an in-depth description of the package +requirements, interfaces, and implementation, please refer to the [technical +documentation][techdoc]. + + [techdoc]: http://mirrors.ctan.org/macros/generic/markdown/markdown.pdf + (A Markdown Interpreter for TeX) + +%</manual> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +local metadata = { + version = "2.8.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-2019 Vít Novotný"}, + license = "LPPL 1.3" +} + +% \end{macrocode} +% \iffalse +%</lua,lua-cli> +%<*lua> +% \fi +% \begin{macrocode} +if not modules then modules = { } end +modules['markdown'] = metadata +% \end{macrocode} +% \par +% \begin{markdown} +% +% Feedback +%--------- +% Please use the \pkg{Markdown} project page on +% [GitHub](https://github.com/witiko/markdown/issues) to report bugs and submit +% feature requests. 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.](https://tex.stackexchange.com) +% +% Acknowledgements +%----------------- +% The Lunamark Lua module provides speedy markdown parsing for the package. I +% would like to thank John Macfarlane, the creator of Lunamark, for releasing +% Lunamark under a permissive license. +% +% Funding by the the Faculty of Informatics at the Masaryk~University +% in~Brno~[@novotny15] is gratefully acknowledged. +% +% The \TeX{} implementation 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. +% +% \end{markdown} +% \iffalse +%</lua> +%<*manual> + +Requirements +------------ + +The package requires a working \TeX{} distribution. [\TeX{} Live][tl] ≥ 2013 is +known to work and so are recent installation of [Mik\TeX{}][mik]. If you are +using a minimal installation of a \TeX{} distribution, please consult the +[technical documentation][techdoc] for a detailed list of required packages. + + [tl]: https://www.tug.org/texlive/ (TeX Live - TeX Users Group) + [mik]: https://miktex.org/ (Home - MiKTeXorg) + +Installation +------------ + +The package comes pre-installed with [\TeX{} Live][tl] ≥ 2016 and with recent +installations of [MikTeX][mik]. Unless you explicitly wish to use the latest +version of the package, you are encouraged to skip this step. + +To install the package, first download the package from the repository +using Git: +``` sh +git clone https://github.com/witiko/markdown +`````` +Next, enter the directory named `markdown` and interpret the file named +`markdown.ins` file using a Unicode-aware \TeX{} engine, such as XeTeX or +LuaTeX: +``` sh +cd markdown +luatex markdown.ins +`````` +This should produce the following files: + + * `markdown.lua`, the Lua module, + * `markdown-cli.lua`, the Lua command-line interface, + * `markdown.tex`, the plain \TeX{} macro package, + * `markdown.sty`, the \LaTeX{} package, and + * `t-markdown.tex`, the \Hologo{ConTeXt} module. + +### Local Installation + +To perform a local installation, place the above files into your \TeX{} +directory structure. This is generally where the individual files should be +placed: + + * `<TEXMF>/tex/luatex/markdown/markdown.lua` + * `<TEXMF>/scripts/markdown/markdown-cli.lua` + * `<TEXMF>/tex/generic/markdown/markdown.tex` + * `<TEXMF>/tex/latex/markdown/markdown.sty` + * `<TEXMF>/tex/context/third/markdown/t-markdown.tex` + +where `<TEXMF>` corresponds to a root of your \TeX{} distribution, such as +`/usr/share/texmf` and `~/texmf` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf` on Windows systems. When in doubt, +consult the manual of your \TeX{} distribution. + +### Portable Installation + +Alternatively, you can also store the above files in the same folder as your +\TeX{} document and distribute them together. This way your document can be +portably typeset on legacy \TeX{} distributions. + +%</manual> +%<*lua> +% \fi +% \par +% \begin{markdown} +% +% Requirements +%------------- +% +% This section gives an overview of all resources required by the package. +% +%### Lua Requirements +% \label{sec:luaprerequisites} +% The Lua part of the package requires that the following Lua modules are +% available from within the Lua\TeX{} engine: +% +% \pkg{LPeg${}\geq{}$0.10} +% +%: A pattern-matching library for the writing of recursive descent parsers +% via the Parsing Expression Grammars (\acro{peg}s). It is used by the +% \pkg{Lunamark} library to parse the markdown input. +% \pkg{LPeg${}\geq{}$0.10} is included in Lua\TeX${}\geq{}$0.72.0 (\TeX +% Live${}\geq{}2013$). +% +% \end{markdown} +% \begin{macrocode} +local lpeg = require("lpeg") +% \end{macrocode} +% \par +% \begin{markdown} +% +% \pkg{Selene Unicode} +% +%: A library that provides support for the processing of wide strings. It is +% used by the \pkg{Lunamark} library to cast image, link, and footnote tags +% to the lower case. \pkg{Selene Unicode} is included in all releases of +% Lua\TeX{} (\TeX Live${}\geq{}2008$). +% +% \end{markdown} +% \begin{macrocode} +local unicode = require("unicode") +% \end{macrocode} +% \par +% \begin{markdown} +% +% \pkg{MD5} +% +%: A library that provides \acro{md5} crypto functions. It is used by the +% \pkg{Lunamark} library to compute the digest of the input for caching +% purposes. \pkg{MD5} is included in all releases of Lua\TeX{} (\TeX +% Live${}\geq{}2008$). +% +% \end{markdown} +% \begin{macrocode} +local md5 = require("md5") +% \end{macrocode} +% \par +% \begin{markdown} +% +% All the abovelisted modules are statically linked into the current version of +% the Lua\TeX{} engine~[@luatex17, Section 3.3]. +% +% \end{markdown} +% \iffalse +%</lua> +%<*tex> +% \fi +% \par +% \begin{markdown} +% +%### Plain \TeX{} Requirements +% \label{sec:texprerequisites} +% The plain \TeX{} part of the package requires that the plain \TeX{} +% format (or its superset) is loaded, all the Lua prerequisites (see +% Section \ref{sec:luaprerequisites}), and the following Lua module: +% +% \pkg{Lua File System} +% +%: A library that provides access to the filesystem via \acro{os}-specific +% syscalls. It is used by the plain \TeX{} code to create the cache +% directory specified by the \m{markdownOptionCacheDir} macro before +% interfacing with the \pkg{Lunamark} library. \pkg{Lua File System} is +% included in all releases of Lua\TeX{} (\TeX Live${}\geq{}2008$). +% +% The plain \TeX{} code makes use of the \luam{isdir} method that was added +% to the \pkg{Lua File System} library by the Lua\TeX{} engine +% developers~[@luatex17, Section 3.2]. +% +% The \pkg{Lua File System} module is statically linked into the Lua\TeX{} +% engine~[@luatex17, Section~3.3]. +% +% Unless you convert markdown documents to \TeX{} manually using the Lua +% command-line interface (see Section~\ref{sec:lua-cli-interface}), the plain +% \TeX{} part of the package will require that either the Lua\TeX{} +% \m{directlua} primitive or the shell access file stream 18 is available in +% your \TeX{} engine. If only the shell access file stream is available in your +% \TeX{} engine (as is the case with \hologo{pdfTeX} and \Hologo{XeTeX}) or if +% you enforce the use of shell using the \m{markdownMode} macro, then unless +% your \TeX{} engine is globally configured to enable shell access, you will +% need to provide the `-shell-escape` parameter to your engine when typesetting +% a document. +% +% \end{markdown} +% \iffalse +%</tex> +%<*latex> +% \fi +% \par +% \begin{markdown} +% +%### \LaTeX{} Requirements +% \label{sec:latexprerequisites} +% The \LaTeX{} part of the package requires that the \Hologo{LaTeX2e} format is +% loaded, +% \end{markdown} +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e}% +% \end{macrocode} +% \begin{markdown} +% all the plain \TeX{} prerequisites (see Section \ref{sec:texprerequisites}), +% and the following \Hologo{LaTeX2e} packages: +% +% \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. +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{keyval} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \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. +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{url} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \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}). +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{graphicx} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \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}). +% +% \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. +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{ifthen} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \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{markdown} +% \begin{macrocode} +\RequirePackage{fancyvrb} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \pkg{csvsimple} +% +%: A package that provides the default token renderer prototype for +% iA\,Writer content blocks with the \acro{csv} filename extension (see +% Section \ref{sec:texrendererprototypes}). +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{csvsimple} +% \end{macrocode} +% \par +% \begin{markdown} +% +% \pkg{gobble} +% +%: A package that provides the \m{\@gobblethree} \TeX{} command. +% +% \end{markdown} +% \begin{macrocode} +\RequirePackage{gobble} +% \end{macrocode} +% \iffalse +%</latex> +%<*context> +% \fi +% \par +% \begin{markdown} +% +%### \Hologo{ConTeXt} Prerequisites +% The \Hologo{ConTeXt} part of the package requires that either the Mark II or +% the Mark IV format is loaded, all the plain \TeX{} prerequisites (see +% Section \ref{sec:texprerequisites}), and the following \Hologo{ConTeXt} +% modules: +% +% \pkg{m-database} +% +%: A module that provides the default token renderer prototype for +% iA\,Writer content blocks with the \acro{csv} filename extension (see +% Section \ref{sec:texrendererprototypes}). +% +% Interfaces +%=========== +% \label{sec:interfaces} +% This part of the documentation 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 documentation and as a promise to the user that +% if they only access the package through the interface, the future minor +% versions of the package should remain backwards compatible. +% +% \end{markdown} +% \iffalse +%</context> +%<*manual> + +First Document +-------------- + +In this section, we will take the necessary steps to typeset our first markdown +document in \TeX{}. This will serve as our first hands-on experience with the +package and also as a reassurance that the package has been correctly installed. + +### Using Lua + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input hello +\bye +``````` + +#### Using the Lua Module + +Using a text editor, create a text document named `hello.lua` with the +following content: +``` lua +#!/usr/bin/env texlua +local kpse = require("kpse") +kpse.set_program_name("luatex") +local markdown = require("markdown") +local convert = markdown.new() +print(convert("Hello *world*!")) +``````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua hello.lua > hello.tex +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text +“Hello *world*!” Invoking pdfTeX should have the same effect: +``` sh +texlua hello.lua > hello.tex +pdftex document.tex +`````` + +#### Using the Lua Command-Line Interface + +Using a text editor, create a text document named `hello.md` with the +following content: +``` md +Hello *world*! +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- hello.md hello.tex +luatex document.tex +`````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + + [Kpathsea]: https://tug.org/kpathsea/ (Kpathsea - TeX Users Group) + +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” Invoking pdfTeX should have the same effect: +``` sh +texlua ⟨CLI pathname⟩ -- hello.md hello.tex +pdftex document.tex +`````` + +### Using Plain \TeX{} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\markdownBegin +Hello *world*! +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text +“Hello *world*!” Invoking pdfTeX should have the same effect: +``` sh +pdftex --shell-escape document.tex +``````` + +### Using \LaTeX{} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} +\begin{markdown} +Hello *world*! +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” Invoking pdfTeX should have the same effect: +``` sh +pdflatex --shell-escape document.tex +`````` + +*** + +As the next step, try typesetting the example documents distributed along with +the Markdown package: +``` sh +git clone https://github.com/witiko/markdown +cd markdown/examples +lualatex latex.tex +`````` +A PDF document named `latex.pdf` should be produced. Open the text documents +`latex.tex` and `example.md` in a text editor to see how the example documents +are structured. Try changing the documents and typesetting them as follows: +``` sh +lualatex latex.tex +`````` +to see the effect of your changes. + +### Using \Hologo{ConTeXt} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext +\startmarkdown +Hello *world*! +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” Invoking pdfTeX should have the same effect: +``` sh +texexec --passon=--shell-escape document.tex +`````` + +*** + +As the next step, try typesetting the example documents distributed along with +the Markdown package: +``` sh +git clone https://github.com/witiko/markdown +cd markdown/examples +context context.tex +`````` +A PDF document named `context.pdf` should be produced. Open the text documents +`context.tex` and `example.md` in a text editor to see how the example documents +are structured. Try changing the documents and typesetting them as follows: +``` sh +context context.tex +`````` +to see the effect of your changes. + +Examples +======== + +In this section, I will describe the individual parts of the Markdown package. +Each part will be shown by example, leaving the implementation details to the +[technical documentation][techdoc]. + + [techdoc]: http://mirrors.ctan.org/macros/generic/markdown/markdown.pdf + (A Markdown Interpreter for \TeX{}) + +/markdown-interfaces.md +/markdown-options.md +/markdown-tokens.md + +%</manual> +%<*lua> +% \fi +% \par +% \begin{markdown} +% +% Lua Interface +%-------------- +% \label{sec:luainterface} +% +% \iffalse +%</lua> +%<*manual-interfaces> + +Interfaces +---------- + +In this section, I will describe the individual interfaces exposed by the +Markdown package starting with the low-level Lua interfaces and all the way up +to the \LaTeX{} and \Hologo{ConTeXt} interfaces intended for the ordinary +user. + +### Lua + +The Lua programming language is what drives the conversion from markdown to +\TeX{} in the Markdown package. Based on the [Lunamark][] Lua library by John +MacFarlane, the Lua implementation is largely independent on \TeX{}, and can be +used separately from typesetting a document. Lua provides two interfaces: a Lua +module and a command-line interface (CLI). + + [Lunamark]: https://github.com/jgm/lunamark + (Lua library for conversion between markup formats) + +%</manual-interfaces> +%<*lua> +% \fi +% +% The Lua interface provides the conversion from \acro{utf}-\oldstylenums8 +% encoded markdown to plain \TeX{}. This interface is used by the plain \TeX{} +% implementation (see Section \ref{sec:teximplementation}) and will be of +% interest to the developers of other packages and Lua modules. +% +% The Lua interface is implemented by the `markdown` Lua module. +% +% \end{markdown} +% \begin{macrocode} +local M = {metadata = metadata} +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Conversion from Markdown to Plain \TeX{} +% \label{sec:luaconversion} +% The Lua interface exposes the \luamdef{new}`(options)` method. This +% method creates converter functions that perform the conversion from markdown +% to plain \TeX{} according to the table `options` that contains options +% recognized by the Lua interface. (see Section \ref{sec:luaoptions}). The +% `options` parameter is optional; when unspecified, the behaviour will be +% the same as if `options` were an empty table. +% +% The following example Lua code converts the markdown string `Hello +% *world*!` to a \TeX{} output using the default options and prints the \TeX{} +% output: +% ``` lua +% local md = require("markdown") +% local convert = md.new() +% print(convert("Hello *world*!")) +% ``````` +% +% \end{markdown} +% \iffalse +%</lua> +%<*manual-interfaces> + +#### Lua Module + +A Lua module is a software library that can be used from in other programs. +The `markdown` Lua module makes it possible to convert markdown to \TeX{} from +within Lua\TeX{} documents and Lua scripts. + +The `markdown` Lua module exposes the `new(`\meta{options}`)` method, which +creates a converter function from markdown to \TeX{}. The properties of the +converter function are specified by the Lua table `options`. The parameter is +optional; when unspecified, the behaviour will be the same as if \meta{options} +were an empty table. + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input example +\bye +``````` +Using a text editor, create a text document named `example.lua` with the +following content: +``` lua +#!/usr/bin/env texlua +local kpse = require("kpse") +kpse.set_program_name("luatex") +local markdown = require("markdown") +local input, convert_safe, convert_unsafe, paragraph + +input = [[$\sqrt{-1}$ *equals* $i$.]] +convert_safe = markdown.new() +convert_unsafe = markdown.new({hybrid = true}) +paragraph = [[\par]] + +print( + convert_safe(input) .. paragraph .. + convert_unsafe(input) +) +``````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua example.lua > example.tex +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +Invoking pdfTeX should have the same effect: +``` sh +texlua example.lua > example.tex +pdftex document.tex +`````` + +*** + +Rather than use the `texlua` interpreter, we can also access the `markdown` Lua +module directly from our document. Using a text editor, create a text document +named `document.tex` with the following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local input, convert_safe, convert_unsafe, paragraph + + input = [[$\string\sqrt{-1}$ *equals* $i$.]] + convert_safe = markdown.new() + convert_unsafe = markdown.new({hybrid = true}) + paragraph = [[\par]] + + tex.sprint( + convert_safe(input) .. paragraph .. + convert_unsafe(input) + ) +} +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +In this case, we cannot use pdfTeX, because pdfTeX does not define the +`\directlua` \TeX{} command. + +#### Lua Command-Line Interface + +The Lua command-line interface (CLI) of the Markdown package makes the +functionality of the Lua module accessible from the command line. This makes +it possible to convert documents from markdown to \TeX{} manually without any +knowledge of the Lua programming language. + +The Lua command-line interface accepts the same options as the `markdown` Lua +module, but now the options are specified as command-line parameters. + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input safe + +\input unsafe +\bye +``````` +Using a text editor, create a text document named `example.md` with the +following content: +``` md +$\sqrt{-1}$ *equals* $i$. +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- example.md safe.tex +texlua ⟨CLI pathname⟩ hybrid=true -- example.md unsafe.tex +luatex document.tex +`````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +Invoking pdfTeX should have the same effect: +``` sh +texlua ⟨CLI pathname⟩ -- example.md safe.tex +texlua ⟨CLI pathname⟩ hybrid=true -- example.md unsafe.tex +pdftex document.tex +`````` + +%</manual-interfaces> +%<*lua> +% \fi +% \begin{markdown} +% +%### 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. +% +% \end{markdown} +% \iffalse +%</lua> +%<*manual-options> + +## Options + +In this section, I will describe all the options recognized by the Markdown +package. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +local defaultOptions = {} +% \end{macrocode} +% \begingroup +% \markdownSetup{ +% renderers = { +% dlBegin = {\begin{optionlist}}, +% dlItem = { +% #1 +% \begingroup +% \markdownSetup{ +% renderers = { +% dlBegin = { +% \begingroup +% \markdownSetup{ +% renderers = { +% dlItem = {\item[####1]}, +% dlItemEnd = {}}} +% \begin{valuelist}}, +% dlEnd = { +% \end{valuelist} +% \endgroup}}}}, +% dlItemEnd = {\endgroup}, +% dlEnd = {\end{optionlist}}}} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +### Lua + +Lua options control the conversion from markdown to \TeX{}. They are supported +by all interfaces of the Markdown package starting with the low-level Lua +interfaces and all the way up to the \LaTeX{} and \Hologo{ConTeXt} interfaces. + +% \fi +% \begin{markdown} +% +%### File and Directory Names +% +% \end{markdown} +% \par +% \iffalse + +#### Option `cacheDir` + +`cacheDir` (default value: `"."`) + +% \fi +% \begin{markdown} +% +% \Valitem[.]{cacheDir}{path} +% +: A path to the directory containing auxiliary cache files. If the last + segment of the path does not exist, it will be created by the Lua + command-line and plain \TeX{} implementations. The Lua implementation + expects that the entire path already exists. + + When iteratively writing and typesetting a markdown document, the cache + files are going to accumulate over time. You are advised to clean the + cache directory every now and then, or to set it to a temporary filesystem + (such as `/tmp` on UN*X systems), which gets periodically emptied. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\directlua{ + local markdown = require("markdown") + local convert = markdown.new({cacheDir = "cache"}) + local input = "Hello *world*!" + tex.sprint(convert(input)) } +\bye +``````` +Create an empty directory named `cache` next to our text document. Then, invoke +LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the text +“Hello *world*!” Several cache files of the Markdown package will also be +produced in the `cache` directory as we requested using the `cacheDir` option. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input hello +\bye +``````` +Using a text editor, create a text document named `hello.md` with the +following content: +``` md +Hello *world*! +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ cacheDir=cache -- hello.md hello.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the text +“Hello *world*!” A directory named `cache` containing several cache files of +the Markdown package will also be produced as we requested using the `cacheDir` +option. + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionCacheDir{cache} +\markdownBegin +Hello *world*! +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” A directory named `cache` containing several cache files of the +Markdown package will also be produced as we requested using the `cacheDir` +option. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[cacheDir=cache]{markdown} +\begin{document} +\begin{markdown} +Hello *world*! +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” A directory named `cache` containing several cache files of the +Markdown package will also be produced as we requested using the `cacheDir` +option. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionCacheDir{cache} +\starttext +\startmarkdown +Hello *world*! +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the text “Hello +*world*!” A directory named `cache` containing several cache files of the +Markdown package will also be produced as we requested using the `cacheDir` +option. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.cacheDir = "." +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> +% \fi +% \begin{markdown} +% +%### Parser Options +% +% \end{markdown} +% \par +% \iffalse + +#### Option `blankBeforeBlockquote` + +`blankBeforeBlockquote` (default value: `false`) + +% \fi +% \begin{markdown} +% \Optitem[false]{blankBeforeBlockquote}{\opt{true}, \opt{false}} +% +: true + + : Require a blank line between a paragraph and the following blockquote. + + false + + : Do not require a blank line between a paragraph and the following + blockquote. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local newline = [[^^J^^J]] + local convert, input + + convert = markdown.new() + input = "A paragraph." .. newline .. + "> A quote." .. newline + tex.sprint(convert(input)) + + convert = markdown.new({blankBeforeBlockquote = true}) + input = "A paragraph." .. newline .. + "> Not a quote." .. newline + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> > A quote. +> +> A paragraph > Not a quote. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +A paragraph. +> A quote? +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ blankBeforeBlockquote=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> > A quote? +> +> A paragraph. > A quote? + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown + +\markdownBegin +A paragraph. +> A quote. +\markdownEnd + +\def\markdownOptionBlankBeforeBlockquote{true} +\markdownBegin +A paragraph. +> Not a quote. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> > A quote. +> +> A paragraph > Not a quote. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +A paragraph. +> A quote. +\end{markdown} + +\begin{markdown*}{blankBeforeBlockquote} +A paragraph. +> Not a quote. +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> > A quote. +> +> A paragraph > Not a quote. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +A paragraph. +> A quote. +\stopmarkdown + +\def\markdownOptionBlankBeforeBlockquote{true} +\startmarkdown +A paragraph. +> Not a quote. +\stopmarkdown + +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> > A quote. +> +> A paragraph > Not a quote. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.blankBeforeBlockquote = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `blankBeforeCodeFence` + +`blankBeforeCodeFence` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{blankBeforeCodeFence}{\opt{true}, \opt{false}} +% +: true + + : Require a blank line between a paragraph and the following fenced code + block. + + false + + : Do not require a blank line between a paragraph and the following + fenced code block. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local newline = [[^^J^^J]] + local convert, input + + convert = markdown.new({fencedCode = true}) + input = "A paragraph." .. newline .. + "```" .. newline .. + "A code fence." .. newline .. + "```" .. newline + tex.sprint(convert(input)) + + convert = markdown.new({ + fencedCode = true, blankBeforeCodeFence = true}) + input = "A paragraph." .. newline .. + "```" .. newline .. + "Not a code fence." .. newline .. + "```" .. newline + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> ``` +> A code fence. +> ``` +> +> A paragraph. ``` Not a code fence. ``` + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +```` md +A paragraph. +``` +A code fence? +``` +``````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ fencedCode=true -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ fencedCode=true blankBeforeCodeFence=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> ``` +> A code fence? +> ``` +> +> A paragraph. ``` A code fence? ``` + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\input markdown +\def\markdownOptionFencedCode{true} + +\markdownBegin +A paragraph. +``` +A code fence. +``` +\markdownEnd + +\def\markdownOptionBlankBeforeCodeFence{true} +\markdownBegin +A paragraph. +``` +Not a code fence. +``` +\markdownEnd + +\bye +```````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> ``` +> A code fence. +> ``` +> +> A paragraph. ``` Not a code fence. ``` + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\documentclass{article} +\usepackage[fencedCode]{markdown} +\begin{document} + +\begin{markdown} +A paragraph. +``` +A code fence. +``` +\end{markdown} + +\begin{markdown*}{blankBeforeCodeFence} +A paragraph. +``` +Not a code fence. +``` +\end{markdown*} + +\end{document} +```````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> ``` +> A code fence. +> ``` +> +> A paragraph. ``` Not a code fence. ``` + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\usemodule[t][markdown] +\def\markdownOptionFencedCode{true} +\starttext + +\startmarkdown +A paragraph. +``` +A code fence. +``` +\stopmarkdown + +\def\markdownOptionBlankBeforeCodeFence{true} +\startmarkdown +A paragraph. +``` +Not a code fence. +``` +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> ``` +> A code fence. +> ``` +> +> A paragraph. ``` Not a code fence. ``` + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.blankBeforeCodeFence = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `blankBeforeHeading` + +`blankBeforeHeading` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{blankBeforeHeading}{\opt{true}, \opt{false}} +% +: true + + : Require a blank line between a paragraph and the following header. + + false + + : Do not require a blank line between a paragraph and the following + header. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\def\markdownRendererHeadingOne#1{{\bf #1}\par} +\directlua{ + local markdown = require("markdown") + local newline = [[^^J^^J]] + local convert, input + + convert = markdown.new() + input = "A paragraph." .. newline .. + "A heading." .. newline .. + "==========" .. newline + tex.sprint(convert(input)) + + convert = markdown.new({blankBeforeHeading = true}) + input = "A paragraph." .. newline .. + "Not a heading." .. newline .. + "==============" .. newline + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> A heading. +> ========== +> +> A paragraph. Not a heading. ============== + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +A paragraph. +A heading? +========== +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ blankBeforeHeading=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> A heading? +> ========== +> +> A paragraph. A heading? ========== + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown + +\markdownBegin +A paragraph. +A heading. +========== +\markdownEnd + +\def\markdownOptionBlankBeforeHeading{true} +\markdownBegin +A paragraph. +Not a heading. +============== +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> A heading. +> ========== +> +> A paragraph. Not a heading. ============== + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +A paragraph. +A heading. +========== +\end{markdown} + +\begin{markdown*}{blankBeforeHeading} +A paragraph. +Not a heading. +============== +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> A heading. +> ========== +> +> A paragraph. Not a heading. ============== + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +A paragraph. +A heading. +========== +\stopmarkdown + +\def\markdownOptionBlankBeforeHeading{true} +\startmarkdown +A paragraph. +Not a heading. +============== +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> A heading. +> ========== +> +> A paragraph. Not a heading. ============== + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.blankBeforeHeading = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `breakableBlockquotes` + +`breakableBlockquotes` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{breakableBlockquotes}{\opt{true}, \opt{false}} +% +: true + + : A blank line separates block quotes. + + false + + : Blank lines in the middle of a block quote are ignored. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\def\markdownRendererHeadingOne#1{{\bf #1}\par} +\directlua{ + local markdown = require("markdown") + local newline = [[^^J^^J]] + local convert, input + + convert = markdown.new() + input = "> A single" .. newline .. newline .. + "> block quote." .. newline + tex.sprint(convert(input)) + + convert = markdown.new({breakableBlockquotes = true}) + input = "> A block quote." .. newline .. newline .. + "> Another block quote." .. newline + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> > A single block quote. +> +> > A block quote. +> +> > Another block quote. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +> A single block quote + +> or two block quotes? +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ breakableBlockquotes=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> > A single block quote or two block quotes? +> +> > A single block quote +> +> > or two block quotes? + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown + +\markdownBegin +> A single + +> block quote. +\markdownEnd + +\def\markdownOptionBreakableBlockquotes{true} +\markdownBegin +> A block quote. + +> Another block quote. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> > A single block quote. +> +> > A block quote. +> +> > Another block quote. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +> A single + +> block quote. +\end{markdown} + +\begin{markdown*}{breakableBlockquotes} +> A block quote. + +> Another block quote. +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> > A single block quote. +> +> > A block quote. +> +> > Another block quote. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +> A single + +> block quote. +\stopmarkdown + +\def\markdownOptionBreakableBlockquotes{true} +\startmarkdown +> A block quote. + +> Another block quote. +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> > A single block quote. +> +> > A block quote. +> +> > Another block quote. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.breakableBlockquotes = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `citationNbsps` + +`citationNbsps` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{citationNbsps}{\opt{true}, \opt{false}} +% +: true + + : Replace regular spaces with non-breakable spaces inside the prenotes + and postnotes of citations produced via the pandoc citation syntax + extension. + + false + + : Do not replace regular spaces with non-breakable spaces inside the + prenotes and postnotes of citations produced via the pandoc citation + syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.bib` with the +following content: +``` bib +@book{knuth:tex, + author = "Knuth, Donald Ervin", + title = "The \TeX book, volume A of Computers and typesetting", + publisher = "Addison-Wesley", + year = "1984" +} +``````` +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[citations]{markdown} +\begin{document} + +\begin{markdown} +The TeXbook [@knuth:tex, p. 123 and 130] is good. +\end{markdown} + +\begin{markdown*}{citationNbsps = false} +The TeXbook [@knuth:tex, p. 123 and 130] is good. +\end{markdown*} + +\bibliographystyle{plain} +\bibliography{document.bib} +\end{document} +``````` +Next, invoke LuaTeX and BibTeX from the terminal: +``` sh +lualatex document.tex +bibtex document.aux +lualatex document.tex +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text, where the middot (`·`) denotes a non-breakable space: + +> The TeXbook [1, p.·123·and·130] is good. +> +> The TeXbook [1, p. 123 and 130] is good. +> +> ### References +> [1] Donald·Ervin Knuth. _The TeXbook, volume A of Computers and typesetting._ +> Addison-Wesley, 1984. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.citationNbsps = true +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `citations` + +`citations` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{citations}{\opt{true}, \opt{false}} +% +: true + + : Enable the pandoc citation syntax extension: + + ``` md + Here is a simple parenthetical citation [@doe99] and here + is a string of several [see @doe99, pp. 33-35; also + @smith04, chap. 1]. + + A parenthetical citation can have a [prenote @doe99] and + a [@smith04 postnote]. The name of the author can be + suppressed by inserting a dash before the name of an + author as follows [-@smith04]. + + Here is a simple text citation @doe99 and here is + a string of several @doe99 [pp. 33-35; also @smith04, + chap. 1]. Here is one with the name of the author + suppressed -@doe99. + `````` + +: false + + : Disable the pandoc citation syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.bib` with the +following content: +``` bib +@book{knuth:tex, + author = "Knuth, Donald Ervin", + title = "The \TeX book, volume A of Computers and typesetting", + publisher = "Addison-Wesley", + year = "1984" +} +``````` +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[backend=biber]{biblatex} +\addbibresource{document.bib} +\usepackage[citations]{markdown} +\begin{document} + +\begin{markdown} +The TeXbook [@knuth:tex, p. 123 and 130] was written by @knuth:tex. +\end{markdown} + +\printbibliography +\end{document} +``````` +Next, invoke LuaTeX and Biber from the terminal: +``` sh +lualatex document.tex +biber document.bcf +lualatex document.tex +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The TeXbook [1, p.·123 and 130] was written by Knuth [1]. +> +> ### References +> [1] Donald Ervin Knuth. _The \TeX{}book, volume A of Computers and typesetting._ +> Addison-Wesley, 1984. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.citations = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `codeSpans` + +`codeSpans` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[true]{codeSpans}{\opt{true}, \opt{false}} +% +: true + + : Enable the code span syntax: + + ~~~ md + Use the `printf()` function. + ``There is a literal backtick (`) here.`` + ~~~ + +: false + + : Disable the code span syntax. This allows you to easily + use the quotation mark ligatures in texts that do not contain code + spans: + + ~~~ + ``This is a quote.'' + ~~~~~~ + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local convert = markdown.new() + local input = + "``This is a code span.'' " .. + "``This is no longer a code span.''" + tex.sprint(convert(input)) } +\par +\directlua{ + local markdown = require("markdown") + local convert = markdown.new({codeSpans = false}) + local input = + "``This is a quote.'' " .. + "``This is another quote.''" + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ``This is a code span.'' ``This is no longer a code span.'' +> +> “This is a quote.” “This is another quote.” + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\par +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +``Is this a code span?'' ``Or a quote?'' +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ codeSpans=false -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> “Is this a code span?” “Or a quote?” +> +> ``Is this a code span?'' ``Or a quote?'' + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown + +\markdownBegin +``This is a code span.'' +``This is no longer a code span.'' +\markdownEnd + +\def\markdownOptionCodeSpans{false} +\markdownBegin +``This is a quote.'' +``This is another quote.'' +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ``This is a code span.'' ``This is no longer a code span.'' +> +> “This is a quote.” “This is another quote.” + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +``This is a code span.'' +``This is no longer a code span.'' +\end{markdown} + +\begin{markdown*}{codeSpans=false} +``This is a quote.'' +``This is another quote.'' +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ``This is a code span.'' ``This is no longer a code span.'' +> +> “This is a quote.” “This is another quote.” + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +``This is a code span.'' +``This is no longer a code span.'' +\stopmarkdown + +\def\markdownOptionCodeSpans{false} +\startmarkdown +``This is a quote.'' +``This is another quote.'' +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ``This is a code span.'' ``This is no longer a code span.'' +> +> “This is a quote.” “This is another quote.” + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.codeSpans = true +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `contentBlocks` + +`contentBlocks` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{contentBlocks}{\opt{true}, \opt{false}} +% +: true + + : Enable the +% iA\,Writer content blocks syntax extension~[@sotkov17]: +% \iffalse + iA\,Writer content blocks syntax extension: +% \fi + + ``` md + http://example.com/minard.jpg (Napoleon's + disastrous Russian campaign of 1812) + /Flowchart.png "Engineering Flowchart" + /Savings Account.csv 'Recent Transactions' + /Example.swift + /Lorem Ipsum.txt + `````` + +: false + + : Disable the + iA\,Writer content blocks syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `table.csv` with the +following content: +``` csv +Name,Surname,Born +Albert,Einstein,1879 +Marie,Curie,1867 +Thomas,Edison,1847 +``````` +Create also a text document named `markdown-languages.json` with the following +content: +``` js +{ + "tex": "LaTeX" +} +`````` +Create also a text document named `code.tex` with the following content: +``` tex +This is an example code listing in \LaTeX. +``````` +Create also a text document named `part.md` with the following content: +``` md +This is a *transcluded markdown document*. +`````` +Create also a text document named `document.tex` with the following content: +``` tex +\documentclass{article} +\usepackage{minted} +\usepackage[contentBlocks]{markdown} +\begin{document} +\begin{markdown} +/table.csv (An example table) +/code.tex (An example code listing) +/part.md (A file transclusion example) +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex --shell-escape document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Name | Surname | Born | +> | ------ | ---------| ---- | +> | Albert | Einstein | 1879 | +> | Marie | Curie | 1867 | +> | Thomas | Edison | 1847 | +> +> Table 1: An example table +> +> ``` tex +> This is an example code listing in \LaTeX. +> ``````` +> +> This is a *transcluded markdown document*. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `table.csv` with the +following content: +``` csv +Name,Surname,Born +Albert,Einstein,1879 +Marie,Curie,1867 +Thomas,Edison,1847 +``````` +Create also a text document named `markdown-languages.json` with the following +content: +``` js +{ + "tex": "ConTeXt" +} +`````` +Create also a text document named `code.tex` with the following content: +``` tex +This is an example code listing in \ConTeXt. +``````` +Create also a text document named `part.md` with the following content: +``` md +This is a *transcluded markdown document*. +`````` +Create also a text document named `document.tex` with the following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionContentBlocks{true} +\definetyping [ConTeXt] +\setuptyping [ConTeXt] [option=TEX] +\starttext +\startmarkdown +/table.csv (An example table) +/code.tex (An example code listing) +/part.md (A file transclusion example) +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Name | Surname | Born | +> | ------ | ---------| ---- | +> | Albert | Einstein | 1879 | +> | Marie | Curie | 1867 | +> | Thomas | Edison | 1847 | +> +> Table 1: An example table +> +> ``` tex +> This is an example code listing in \ConTeXt. +> ``````` +> +> This is a *transcluded markdown document*. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.contentBlocks = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `contentBlocksLanguageMap` + +`contentBlocksLanguageMap` (default value: `"markdown-languages.json"`) + +% \fi +% \begin{markdown} +% +% \Valitem[markdown-languages.json]{contentBlocksLanguageMap}{filename} +% +: The filename of the JSON file that maps filename extensions to + programming language names in the iA\,Writer content blocks. +% See Section~\ref{sec:texcontentblockrenderers} for more information. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `table.csv` with the +following content: +``` csv +Name,Surname,Born +Albert,Einstein,1879 +Marie,Curie,1867 +Thomas,Edison,1847 +``````` +Create also a text document named `language-map.json` with the following +content: +``` js +{ + "tex": "LaTeX" +} +`````` +Create also a text document named `code.tex` with the following content: +``` tex +This is an example code listing in \LaTeX. +``````` +Create also a text document named `part.md` with the following content: +``` md +This is a *transcluded markdown document*. +`````` +Create also a text document named `document.tex` with the following content: +``` tex +\documentclass{article} +\usepackage{minted} +\usepackage[contentBlocks]{markdown} +\markdownSetup{ + contentBlocksLanguageMap = {language-map.json}, +} +\begin{document} +\begin{markdown} +/table.csv (An example table) +/code.tex (An example code listing) +/part.md (A file transclusion example) +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex --shell-escape document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Name | Surname | Born | +> | ------ | ---------| ---- | +> | Albert | Einstein | 1879 | +> | Marie | Curie | 1867 | +> | Thomas | Edison | 1847 | +> +> Table 1: An example table +> +> ``` tex +> This is an example code listing in \LaTeX. +> ``````` +> +> This is a *transcluded markdown document*. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `table.csv` with the +following content: +``` csv +Name,Surname,Born +Albert,Einstein,1879 +Marie,Curie,1867 +Thomas,Edison,1847 +``````` +Create also a text document named `language-map.json` with the following +content: +``` js +{ + "tex": "ConTeXt" +} +`````` +Create also a text document named `code.tex` with the following content: +``` tex +This is an example code listing in \ConTeXt. +``````` +Create also a text document named `part.md` with the following content: +``` md +This is a *transcluded markdown document*. +`````` +Create also a text document named `document.tex` with the following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionContentBlocks{true} +\def\markdownOptionContentBlocksLanguageMap{language-map.json} +\definetyping [ConTeXt] +\setuptyping [ConTeXt] [option=TEX] +\starttext +\startmarkdown +/table.csv (An example table) +/code.tex (An example code listing) +/part.md (A file transclusion example) +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Name | Surname | Born | +> | ------ | ---------| ---- | +> | Albert | Einstein | 1879 | +> | Marie | Curie | 1867 | +> | Thomas | Edison | 1847 | +> +> Table 1: An example table +> +> ``` tex +> This is an example code listing in \ConTeXt. +> ``````` +> +> This is a *transcluded markdown document*. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.contentBlocksLanguageMap = "markdown-languages.json" +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `definitionLists` + +`definitionLists` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{definitionLists}{\opt{true}, \opt{false}} +% +: true + + : Enable the pandoc definition list syntax extension: + + ``` md + Term 1 + + : Definition 1 + + Term 2 with *inline markup* + + : Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. + ````` + +: false + + : Disable the pandoc definition list syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[definitionLists]{markdown} +\begin{document} +\begin{markdown} +Term 1 + +: Definition 1 + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Term 1 +> +> : Definition 1 +> +> Term 2 with *inline markup* +> +> : Definition 2 +> +> { some code, part of Definition 2 } +> +> Third paragraph of definition 2. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionDefinitionLists{true} +\starttext +\startmarkdown +Term 1 + +: Definition 1 + +Term 2 with *inline markup* + +: Definition 2 + + { some code, part of Definition 2 } + + Third paragraph of definition 2. +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Term 1 +> +> : Definition 1 +> +> Term 2 with *inline markup* +> +> : Definition 2 +> +> { some code, part of Definition 2 } +> +> Third paragraph of definition 2. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.definitionLists = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `fencedCode` + +`fencedCode` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{fencedCode}{\opt{true}, \opt{false}} +% +: true + + : Enable the commonmark fenced code block extension: + + ~~~~~~~~ md + ~~~ js + if (a > 3) { + moveShip(5 * gravity, DOWN); + } + ~~~~~~ + + ``` html + <pre> + <code> + // Some comments + line 1 of code + line 2 of code + line 3 of code + </code> + </pre> + ``` + ~~~~~~~~~~~ + +: false + + : Disable the commonmark fenced code block extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\documentclass{article} +\usepackage{minted} +\usepackage[fencedCode]{markdown} +\begin{document} +\begin{markdown} +~~~ js +if (a > 3) { + moveShip(5 * gravity, DOWN); +} +~~~~~~ + + ``` html + <pre> + <code> + // Some comments + line 1 of code + line 2 of code + line 3 of code + </code> + </pre> + ``` +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex --shell-escape document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ~~~ js +> if (a > 3) { +> moveShip(5 * gravity, DOWN); +> } +> ~~~~~~ +> +> ``` html +> <pre> +> <code> +> // Some comments +> line 1 of code +> line 2 of code +> line 3 of code +> </code> +> </pre> +> ``` + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\usemodule[t][markdown] +\def\markdownOptionFencedCode{true} +\definetyping [js] +\definetyping [html] +\setuptyping [html] [option=XML] +\starttext +\startmarkdown +~~~ js +if (a > 3) { + moveShip(5 * gravity, DOWN); +} +~~~~~~ + + ``` html + <pre> + <code> + // Some comments + line 1 of code + line 2 of code + line 3 of code + </code> + </pre> + ``` +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> ~~~ js +> if (a > 3) { +> moveShip(5 * gravity, DOWN); +> } +> ~~~~~~ +> +> ``` html +> <pre> +> <code> +> // Some comments +> line 1 of code +> line 2 of code +> line 3 of code +> </code> +> </pre> +> ``` + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.fencedCode = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `footnotes` + +`footnotes` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{footnotes}{\opt{true}, \opt{false}} +% +: true + + : Enable the pandoc footnote syntax extension: + + ``` md + 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. + `````` + +: false + + : Disable the pandoc footnote syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[footnotes]{markdown} +\begin{document} +\begin{markdown} +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{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> 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. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionFootnotes{true} +\starttext +\startmarkdown +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. +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> 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. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.footnotes = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `hashEnumerators` + +`hashEnumerators` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{hashEnumerators}{\opt{true}, \opt{false}} +% +: true + + : Enable the use of hash symbols (`#`) as ordered item list + markers: + + ``` md + #. Bird + #. McHale + #. Parish + `````` + +: false + + : Disable the use of hash symbols (`#`) as ordered item list + markers. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +. Bird +. McHale +. Parish +\end{markdown} + +\begin{markdown*}{hashEnumerators} +. Bird +. McHale +. Parish +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> . Bird +> ======== +> . McHale +> ======== +> . Parish +> ======== +> +> #. Bird +> #. McHale +> #. Parish + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +. Bird +. McHale +. Parish +\stopmarkdown + +\def\markdownOptionHashEnumerators{true} +\startmarkdown +. Bird +. McHale +. Parish +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> . Bird +> ======== +> . McHale +> ======== +> . Parish +> ======== +> +> #. Bird +> #. McHale +> #. Parish + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.hashEnumerators = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `headerAttributes` {#header-attributes} + +`headerAttributes` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{headerAttributes}{\opt{true}, \opt{false}} +% +: true + + : Enable the assignment of HTML attributes to headings: + + ``` md + # My first heading {#foo} + + ## My second heading ## {#bar .baz} + + Yet another heading {key=value} + =================== + `````` + + These HTML attributes have currently no effect other than enabling +% content slicing, see the \Opt{slice} option. +% \iffalse + [content slicing](#slice). +% \fi + +: false + + : Disable the assignment of HTML attributes to headings. + +% \end{markdown} +% \iffalse +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.headerAttributes = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `html` + +`html` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{html}{\opt{true}, \opt{false}} +% +: true + + : Enable the recognition of HTML tags, block elements, comments, HTML + instructions, and entities in the input. Tags, block elements (along + with contents), HTML instructions, and comments will be ignored and + HTML entities will be replaced with the corresponding Unicode + codepoints. + +: false + + : Disable the recognition of HTML markup. Any HTML markup in the input + will be rendered as plain text. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local convert = markdown.new() + local newline = [[^^J^^J]] + local input = + "<div>*There is no block tag support.*</div>" .. newline .. + "*There is no <inline tag="tag"></inline> support.*" .. newline .. + "_There is no <!-- comment --> support._" .. newline .. + "_There is no <? HTML instruction ?> support._" + tex.sprint(convert(input)) } +\par +\directlua{ + local markdown = require("markdown") + local convert = markdown.new({html = true}) + local input = + "<div>*There is block tag support.*</div>" .. newline .. + "*There is <inline tag="tag"></inline> support.*" .. newline .. + "_There is <!-- comment --> support._" .. newline .. + "_There is <? HTML instruction ?> support._" + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \<div>There is no block tag support.\</div> +> There is no \<inline tag=”tag”>\</inline> support. +> There is no \<!-- comment --> support. +> There is no <? HTML instruction ?> support. +> +> There is support. There is support. There is support. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\par +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` html +<div> +*Is there block tag support?* +</div> +*Is there <inline tag="tag"></inline> support?* +_Is there <!-- comment --> support?_ +_Is there <? HTML instruction ?> support?_ +```````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ html=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \<div>Is there block tag support?\</div> +> Is there \<inline tag=”tag”>\</inline> support? +> Is there \<!-- comment --> support? +> Is there <? HTML instruction ?> support? +> +> Is there support? Is there support? Is there support? + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts + +\markdownBegin +<div> +*There is no block tag support.* +</div> +*There is no <inline tag="tag"></inline> support.* +_There is no <!-- comment --> support._ +_There is no <? HTML instruction ?> support._ +\markdownEnd + +\def\markdownOptionHtml{true} +\markdownBegin +<div> +*There is block tag support.* +</div> +*There is <inline tag="tag"></inline> support.* +_There is <!-- comment --> support._ +_There is <? HTML instruction ?> support._ +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \<div>There is no block tag support.\</div> +> There is no \<inline tag=”tag”>\</inline> support. +> There is no \<!-- comment --> support. +> There is no <? HTML instruction ?> support. +> +> There is support. There is support. There is support. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +<div> +*There is no block tag support.* +</div> +*There is no <inline tag="tag"></inline> support.* +_There is no <!-- comment --> support._ +_There is no <? HTML instruction ?> support._ +\end{markdown} + +\begin{markdown*}{html} +<div> +*There is block tag support.* +</div> +*There is <inline tag="tag"></inline> support.* +_There is <!-- comment --> support._ +_There is <? HTML instruction ?> support._ +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \<div>There is no block tag support.\</div> +> There is no \<inline tag=”tag”>\</inline> support. +> There is no \<!-- comment --> support. +> There is no <? HTML instruction ?> support. +> +> There is support. There is support. There is support. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +<div> +*There is no block tag support.* +</div> +*There is no <inline tag="tag"></inline> support.* +_There is no <!-- comment --> support._ +_There is no <? HTML instruction ?> support._ +\stopmarkdown + +\def\markdownOptionHtml{true} +\startmarkdown +<div> +*There is block tag support.* +</div> +*There is <inline tag="tag"></inline> support.* +_There is <!-- comment --> support._ +_There is <? HTML instruction ?> support._ +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \<div>There is no block tag support.\</div> +> There is no \<inline tag=”tag”>\</inline> support. +> There is no \<!-- comment --> support. +> There is no <? HTML instruction ?> support. +> +> There is support. There is support. There is support. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.html = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `hybrid` + +`hybrid` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{hybrid}{\opt{true}, \opt{false}} +% +: 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. + +: 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{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local input, convert_safe, convert_unsafe, paragraph + + input = [[$\string\sqrt{-1}$ *equals* $i$.]] + convert_safe = markdown.new() + convert_unsafe = markdown.new({hybrid = true}) + paragraph = [[\par]] + + tex.sprint( + convert_safe(input) .. paragraph .. + convert_unsafe(input) + ) +} +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt {-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse + +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +$\sqrt{-1}$ *equals* $i$. +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ hybrid=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt {-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts + +\markdownBegin +$\sqrt{-1}$ *equals* $i$. +\markdownEnd + +\def\markdownOptionHybrid{true} +\markdownBegin +$\sqrt{-1}$ *equals* $i$. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt {-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +$\sqrt{-1}$ *equals* $i$. +\end{markdown} + +\begin{markdown*}{hybrid} +$\sqrt{-1}$ *equals* $i$. +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt {-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +$\sqrt{-1}$ *equals* $i$. +\stopmarkdown + +\def\markdownOptionHybrid{true} +\startmarkdown +$\sqrt{-1}$ *equals* $i$. +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt {-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.hybrid = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `inlineFootnotes` + +`inlineFootnotes` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{inlineFootnotes}{\opt{true}, \opt{false}} +% +: true + + : Enable the pandoc inline footnote syntax extension: + + ``` md + Here is an inline note.^[Inlines notes are easier to + write, since you don't have to pick an identifier and + move down to type the note.] + `````` + +: false + + : Disable the pandoc inline footnote syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[footnotes, inlineFootnotes]{markdown} +\begin{document} +\begin{markdown} +Here is an inline note.^[Inlines notes are easier to +write, since you don't have to pick an identifier and +move down to type the note.] +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Here is an inline note.^[Inlines notes are easier to +> write, since you don't have to pick an identifier and +> move down to type the note.] + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionFootnotes{true} +\def\markdownOptionInlineFootnotes{true} +\starttext +\startmarkdown +Here is an inline note.^[Inlines notes are easier to +write, since you don't have to pick an identifier and +move down to type the note.] +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Here is an inline note.^[Inlines notes are easier to +> write, since you don't have to pick an identifier and +> move down to type the note.] + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.inlineFootnotes = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `pipeTables` {#pipe-tables} + +`pipeTables` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{pipeTables}{\opt{true}, \opt{false}} +% +: true + + : Enable the \acro{PHP} Markdown table syntax extension: + + ``` md + | Right | Left | Default | Center | + |------:|:-----|---------|:------:| + | 12 | 12 | 12 | 12 | + | 123 | 123 | 123 | 123 | + | 1 | 1 | 1 | 1 | + `````` + +: false + + : Disable the \acro{PHP} Markdown table syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[pipeTables]{markdown} +\begin{document} +\begin{markdown} +| Right | Left | Default | Center | +|------:|:-----|---------|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Right | Left | Default | Center | +> |------:|:-----|---------|:------:| +> | 12 | 12 | 12 | 12 | +> | 123 | 123 | 123 | 123 | +> | 1 | 1 | 1 | 1 | + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionPipeTables{true} +\starttext +\startmarkdown +| Right | Left | Default | Center | +|------:|:-----|---------|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Right | Left | Default | Center | +> |------:|:-----|---------|:------:| +> | 12 | 12 | 12 | 12 | +> | 123 | 123 | 123 | 123 | +> | 1 | 1 | 1 | 1 | + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.pipeTables = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `preserveTabs` + +`preserveTabs` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{preserveTabs}{\opt{true}, \opt{false}} +% +: true + + : Preserve tabs in code block and fenced code blocks. + +: false + + : Convert any tabs in the input to spaces. + +% \end{markdown} +% \iffalse +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.preserveTabs = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `shiftHeadings` + +`shiftHeadings` (default value: `0`) + +% \fi +% \begin{markdown} +% +% \Valitem[0]{shiftHeadings}{shift amount} +% +: All headings will be shifted by \meta{shift amount}, which can be both + positive and negative. Headings will not be shifted beyond level 6 or + below level 1. Instead, those headings will be shifted to level 6, when + \meta{shift amount} is positive, and to level 1, when \meta{shift amount} + is negative. + +% \end{markdown} +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `example.md` with the +following content: + +``` md +## A section +``` + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown + +\font\normal=cmr10\normal +\font\big=cmr10 at 12pt +\def\markdownRendererHeadingTwo#1{{\big #1\par}} +\font\bigger=cmr10 scaled 1440 +\def\markdownRendererHeadingOne#1{{\bigger #1\par}} + +\def\markdownOptionShiftHeadings{-1} +\markdownInput{example.md} + +\def\markdownOptionShiftHeadings{0} +\markdownInput{example.md} + +\def\markdownOptionShiftHeadings{+1} +\markdownInput{example.md} + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # A section +> ## A section +> ### A section + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\usepackage{filecontents} +\begin{filecontents*}{example.md} +## A section +\end{filecontents*} +\begin{document} +\markdownInput[shiftHeadings=-1]{example.md} +\markdownInput{example.md} +\markdownInput[shiftHeadings=+1]{example.md} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # A section +> ## A section +> ### A section + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `example.md` with the +following content: + +``` md +## A section +``` + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\def\markdownOptionShiftHeadings{-1} +\markdownInput{example.md} + +\def\markdownOptionShiftHeadings{0} +\markdownInput{example.md} + +\def\markdownOptionShiftHeadings{+1} +\markdownInput{example.md} + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # A section +> ## A section +> ### A section + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.shiftHeadings = 0 +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `slice` {#slice} + +`slice` (default value: `^ $`) + +% \fi +% \begin{markdown} +% +% \Valitem[\textasciicircum{} \$]{slice}{the beginning and the end of a slice} +% +: Two space-separated selectors that specify the slice of a document that + will be processed, whereas the remainder of the document will be ignored. + The following selectors are recognized: + + - The circumflex (`^`) selects the beginning of a document. + - The dollar sign (`$`) selects the end of a document. + - `^`\meta{identifier} selects the beginning of a section with the +% \acro{HTML} attribute `#`\meta{identifier} (see the +% \Opt{headerAttributes} option). +% \iffalse + [\acro{HTML} attribute](#header-attributes) `#`\meta{identifier}. +% \fi + - `$`\meta{identifier} selects the end of a section with the \acro{HTML} + attribute `#`\meta{identifier}. + - \meta{identifier} corresponds to `^`\meta{identifier} for the first + selector and to `$`\meta{identifier} for the second selector. + + Specifying only a single selector, \meta{identifier}, is equivalent + to specifying the two selectors \meta{identifier} \meta{identifier}, + which is equivalent to `^`\meta{identifier} `$`\meta{identifier}, i.e. + the entire section with the \acro{HTML} attribute `#`\meta{identifier} will be + selected. + +% \end{markdown} +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `hamlet.md` with the +following content: + +``` md +# The Tragedy of Hamlet +Shakespeare's longest play. + +## Act III {#act-3} +Hamlet kills Polonius. + +## Act V {#act-5} +Hamlet dies. + +## Act I {#act-1} +Hamlet talks to ghost. +``` + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionHeaderAttributes{true} + +\font\normal=cmr10\normal +\font\big=cmr10 at 12pt +\def\markdownRendererHeadingTwo#1{{\big #1\par}} +\font\bigger=cmr10 scaled 1440 +\def\markdownRendererHeadingOne#1{{\bigger #1\par}} + +\def\markdownOptionSlice{^ ^act-3} +\markdownInput{hamlet.md} + +\def\markdownOptionSlice{act-1} +\markdownInput{hamlet.md} + +\def\markdownOptionSlice{act-3 act-5} +\markdownInput{hamlet.md} + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # The Tragedy of Hamlet +> Shakespeare's longest play. +> +> ## Act I +> Hamlet talks to ghost. +> +> ## Act III +> Hamlet kills Polonius. +> +> ## Act V +> Hamlet dies. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[headerAttributes]{markdown} +\usepackage{filecontents} +\begin{filecontents*}{hamlet.md} +# The Tragedy of Hamlet +Shakespeare's longest play. + +## Act III {#act-3} +Hamlet kills Polonius. + +## Act V {#act-5} +Hamlet dies. + +## Act I {#act-1} +Hamlet talks to ghost. +\end{filecontents*} +\begin{document} +\markdownInput[slice=^ ^act-3]{hamlet.md} +\markdownInput[slice=act-1]{hamlet.md} +\markdownInput[slice=act-3 act-5]{hamlet.md} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # The Tragedy of Hamlet +> Shakespeare's longest play. +> +> ## Act I +> Hamlet talks to ghost. +> +> ## Act III +> Hamlet kills Polonius. +> +> ## Act V +> Hamlet dies. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `hamlet.md` with the +following content: + +``` md +# The Tragedy of Hamlet +Shakespeare's longest play. + +## Act III {#act-3} +Hamlet kills Polonius. + +## Act V {#act-5} +Hamlet dies. + +## Act I {#act-1} +Hamlet talks to ghost. +``` + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionHeaderAttributes{true} +\starttext + +\def\markdownOptionSlice{^ ^act-3} +\markdownInput{hamlet.md} + +\def\markdownOptionSlice{act-1} +\markdownInput{hamlet.md} + +\def\markdownOptionSlice{act-3 act-5} +\markdownInput{hamlet.md} + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> # The Tragedy of Hamlet +> Shakespeare's longest play. +> +> ## Act I +> Hamlet talks to ghost. +> +> ## Act III +> Hamlet kills Polonius. +> +> ## Act V +> Hamlet dies. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.slice = "^ $" +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + + +#### Option `smartEllipses` + +`smartEllipses` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{smartEllipses}{\opt{true}, \opt{false}} +% +: true + + : Convert any ellipses in the input to the + \m{markdownRendererEllipsis} \TeX{} macro. + +: false + + : Preserve all ellipses in the input. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererEllipsis{. . .} +\input lmfonts +\directlua{ + local markdown = require("markdown") + local convert = markdown.new() + local input = "These are just three regular dots ..." + tex.sprint(convert(input)) } +\par +\directlua{ + local markdown = require("markdown") + local convert = markdown.new({smartEllipses = true}) + local input = "... and this is a victorian ellipsis." + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> These are just three regular dots ... +> +> . . . and this is a victorian ellipsis. + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererEllipsis{. . .} +\input lmfonts +\input optionfalse +\par +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +``` md +Are these just three regular dots, a victorian ellipsis, or ... ? +`````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ smartEllipses=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Are these just three regular dots, a victorian ellipsis, or ... ? +> +> Are these just three regular dots, a victorian ellipsis, or . . . ? + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererEllipsis{. . .} + +\markdownBegin +These are just three regular dots ... +\markdownEnd + +\def\markdownOptionSmartEllipses{true} +\markdownBegin +... and this is a victorian ellipsis. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> These are just three regular dots ... +> +> . . . and this is a victorian ellipsis. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + ellipsis = {. . .} }} +\begin{document} + +\begin{markdown} +These are just three regular dots ... +\end{markdown} + +\begin{markdown*}{smartEllipses} +... and this is a victorian ellipsis. +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> These are just three regular dots ... +> +> . . . and this is a victorian ellipsis. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererEllipsis{. . .} +\starttext + +\startmarkdown +These are just three regular dots ... +\stopmarkdown + +\def\markdownOptionSmartEllipses{true} +\startmarkdown +... and this is a victorian ellipsis. +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> These are just three regular dots ... +> +> . . . and this is a victorian ellipsis. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.smartEllipses = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `startNumber` + +`startNumber` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[true]{startNumber}{\opt{true}, \opt{false}} +% +: true + + : Make the number in the first item of an ordered lists significant. The + item numbers will be passed to the + \m{markdownRendererOlItemWithNumber} \TeX{} macro. + +: false + + : Ignore the numbers in the ordered list items. Each item will only + produce a \m{markdownRendererOlItem} \TeX{} macro. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +The following list respects the numbers specified in the markup: + +3. third item +4. fourth item +5. fifth item +\end{markdown} + +\begin{markdown*}{startNumber=false} +The following list does not respect the numbers specified in the +markup: + +3. third item +4. fourth item +5. fifth item +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The following list respects the numbers specified in the markup: +> +> 3. third item +> 4. fourth item +> 5. fifth item +> +> The following list does not respect the numbers specified in the markup: +> +> 1. third item +> 2. fourth item +> 3. fifth item + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +The following list respects the numbers specified in the markup: + +3. third item +4. fourth item +5. fifth item +\stopmarkdown + +\def\markdownOptionStartNumber{false} +\startmarkdown +The following list respects the numbers specified in the markup: + +3. third item +4. fourth item +5. fifth item +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The following list respects the numbers specified in the markup: +> +> 3. third item +> 4. fourth item +> 5. fifth item +> +> The following list does not respect the numbers specified in the markup: +> +> 1. third item +> 2. fourth item +> 3. fifth item + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.startNumber = true +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `tableCaptions` + +`tableCaptions` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{tableCaptions}{\opt{true}, \opt{false}} +% +: true + + : Enable the Pandoc `table_captions` syntax extension for +% pipe tables (see the \Opt{pipeTables} option). +% \iffalse + [pipe tables](#pipe-tables). +% \fi + + ``` md + | Right | Left | Default | Center | + |------:|:-----|---------|:------:| + | 12 | 12 | 12 | 12 | + | 123 | 123 | 123 | 123 | + | 1 | 1 | 1 | 1 | + + : Demonstration of pipe table syntax. + `````` + +: false + + : Enable the Pandoc `table_captions` syntax extension. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[pipeTables, tableCaptions]{markdown} +\begin{document} +\begin{markdown} +| Right | Left | Default | Center | +|------:|:-----|---------|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | + + : Demonstration of pipe table syntax. +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Right | Left | Default | Center | +> |------:|:-----|---------|:------:| +> | 12 | 12 | 12 | 12 | +> | 123 | 123 | 123 | 123 | +> | 1 | 1 | 1 | 1 | +> +> : Demonstration of pipe table syntax. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionPipeTables{true} +\def\markdownOptionTableCaptions{true} +\starttext +\startmarkdown +| Right | Left | Default | Center | +|------:|:-----|---------|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | + + : Demonstration of pipe table syntax. +\stopmarkdown +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> | Right | Left | Default | Center | +> |------:|:-----|---------|:------:| +> | 12 | 12 | 12 | 12 | +> | 123 | 123 | 123 | 123 | +> | 1 | 1 | 1 | 1 | +> +> : Demonstration of pipe table syntax. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.tableCaptions = false +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + + +#### Option `tightLists` + +`tightLists` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[true]{tightLists}{\opt{true}, \opt{false}} +% +: true + + : Lists whose bullets do not consist of multiple paragraphs will be + passed to the + \m{markdownRendererOlBeginTight}, \m{markdownRendererOlEndTight}, + \m{markdownRendererUlBeginTight}, \m{markdownRendererUlEndTight}, + \m{markdownRendererDlBeginTight}, and + \m{markdownRendererDlEndTight} \TeX{} macros. + +: false + + : Lists whose bullets do not consist of multiple paragraphs will be + treated the same way as lists that do consist of multiple paragraphs. + +% \end{markdown} +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +The following list is tight: + + - first item + - second item + - third item + +The following list is loose: + + - first item + - second item that spans + + multiple paragraphs + - third item +\end{markdown} + +\begin{markdown*}{tightLists=false} +The following list is now also loose: + + - first item + - second item + - third item +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The following list is tight: +> +> - first item +> - second item +> - third item +> +> The following list is loose: +> +> - first item +> - second item that spans +> +> multiple paragraphs +> - third item +> +> The following list is now also loose: +> +> - first item +> +> - second item +> +> - third item + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.tightLists = true +% \end{macrocode} +% \par +% \iffalse +%</lua,lua-cli> +%<*manual-options> + +#### Option `underscores` + +`underscores` (default value: `true`) + +% \fi +% \begin{markdown} +% +% \Optitem[true]{underscores}{\opt{true}, \opt{false}} +% +: true + + : Both underscores and asterisks can be used to denote emphasis and + strong emphasis: + + ``` md + *single asterisks* + _single underscores_ + **double asterisks** + __double underscores__ + `````` + +: false + + : Only asterisks can be used to denote emphasis and strong emphasis. + This makes it easy to write math with the \Opt{hybrid} option + without the need to constantly escape subscripts. + +% \end{markdown} +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionHybrid{true} + +\markdownBegin +This is _emphasized text_ and this is a math subscript: $m\_n$. +\markdownEnd + +\def\markdownOptionUnderscores{false} +\markdownBegin +This is *emphasized text* and this is a math subscript: $m_n$. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is _emphasized text_ and this is a math subscript: *mₙ*. +> +> This is _emphasized text_ and this is a math subscript: *mₙ*. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[hybrid]{markdown} +\begin{document} + +\begin{markdown} +This is _emphasized text_ and this is a math subscript: $m\_n$. +\end{markdown} + +\begin{markdown*}{underscores=false} +This is *emphasized text* and this is a math subscript: $m_n$. +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is _emphasized text_ and this is a math subscript: *mₙ*. +> +> This is _emphasized text_ and this is a math subscript: *mₙ*. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionHybrid{true} +\starttext + +\startmarkdown +This is _emphasized text_ and this is a math subscript: $m\_n$. +\stopmarkdown + +\def\markdownOptionUnderscores{false} +\startmarkdown +This is *emphasized text* and this is a math subscript: $m_n$. +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is _emphasized text_ and this is a math subscript: *mₙ*. +> +> This is _emphasized text_ and this is a math subscript: *mₙ*. + +%</manual-options> +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.underscores = true +% \end{macrocode} +% \endgroup +% \iffalse +%</lua,lua-cli> +%<*lua-cli> +% \fi +% \par +% \begin{markdown} +% +%### Command-Line Interface +% \label{sec:lua-cli-interface} +% To provide finer control over the conversion and to simplify debugging, a +% command-line Lua interface for converting a Markdown document to \TeX{} is +% also provided. +% +% \end{markdown} +% \begin{macrocode} + +HELP_STRING = [[ +Usage: texlua ]] .. arg[0] .. [[ [OPTIONS] -- [INPUT_FILE] [OUTPUT_FILE] +where OPTIONS are documented in the Lua interface section of the +technical Markdown package documentation. + +When OUTPUT_FILE is unspecified, the result of the conversion will be +written to the standard output. When INPUT_FILE is also unspecified, the +result of the conversion will be read from the standard input. + +Report bugs to: witiko@mail.muni.cz +Markdown package home page: <https://github.com/witiko/markdown>]] + +VERSION_STRING = [[ +markdown-cli.lua (Markdown) ]] .. metadata.version .. [[ + +Copyright (C) ]] .. table.concat(metadata.copyright, + "\nCopyright (C) ") .. [[ + +License: ]] .. metadata.license + +local function warn(s) + io.stderr:write("Warning: " .. s .. "\n") end + +local function error(s) + io.stderr:write("Error: " .. s .. "\n") + os.exit(1) end + +local process_options = true +local options = {} +local input_filename +local output_filename +for i = 1, #arg do + if process_options then +% \end{macrocode} +% \begin{markdown} +% After the optional `-`{}`-` argument has been specified, the remaining +% arguments are assumed to be input and output filenames. This argument is +% optional, but encouraged, because it helps resolve ambiguities when +% deciding whether an option or a filename has been specified. +% \end{markdown} +% \begin{macrocode} + if arg[i] == "--" then + process_options = false + goto continue +% \end{macrocode} +% \begin{markdown} +% Unless the `-`{}`-` argument has been specified before, an argument +% containing the equals sign (`=`) is assumed to be an option specification in +% a \meta{key}`=`\meta{value} format. The available options are listed in +% Section~\ref{sec:luaoptions}. +% \end{markdown} +% \begin{macrocode} + elseif arg[i]:match("=") then + key, value = arg[i]:match("(.-)=(.*)") +% \end{macrocode} +% \begin{markdown} +% The \luam{defaultOptions} table is consulted to identify whether \meta{value} +% should be parsed as a string or as a boolean. +% \end{markdown} +% \begin{macrocode} + default_type = type(defaultOptions[key]) + if default_type == "boolean" then + options[key] = (value == "true") + else + if default_type ~= "string" then + if default_type == "nil" then + warn('Option "' .. key .. '" not recognized.') + else + warn('Option "' .. key .. '" type not recognized, please file ' .. + 'a report to the package maintainer.') + end + warn('Parsing the ' .. 'value "' .. value ..'" of option "' .. + key .. '" as a string.') + end + options[key] = value + end + goto continue +% \end{macrocode} +% \begin{markdown} +% Unless the `-`{}`-` argument has been specified before, an argument +% `-`{}`-help`, or `-h` causes a brief documentation for how to invoke the +% program to be printed to the standard output. +% \end{markdown} +% \begin{macrocode} + elseif arg[i] == "--help" or arg[i] == "-h" then + print(HELP_STRING) + os.exit() +% \end{macrocode} +% \begin{markdown} +% Unless the `-`{}`-` argument has been specified before, an argument +% `-`{}`-version`, or `-v` causes the program to print information about its +% name, version, origin and legal status, all on standard output. +% \end{markdown} +% \begin{macrocode} + elseif arg[i] == "--version" or arg[i] == "-v" then + print(VERSION_STRING) + os.exit() + end + end +% \end{macrocode} +% \begin{markdown} +% The first argument that matches none of the above patters is assumed to be +% the input filename. The input filename should correspond to the Markdown +% document that is going to be converted to a \TeX{} document. +% \end{markdown} +% \begin{macrocode} + if input_filename == nil then + input_filename = arg[i] +% \end{macrocode} +% \begin{markdown} +% The first argument that matches none of the above patters is assumed to be +% the output filename. The output filename should correspond to the \TeX{} +% document that will result from the conversion. +% \end{markdown} +% \begin{macrocode} + elseif output_filename == nil then + output_filename = arg[i] + else + error('Unexpected argument: "' .. arg[i] .. '".') + end + ::continue:: +end +% \end{macrocode} +% \par +% \begin{markdown} +% +% The command-line Lua interface is implemented by the `markdown-cli.lua` +% file that can be invoked from the command line as follows: +% ``` sh +% texlua /path/to/markdown-cli.lua cacheDir=. -- hello.md hello.tex +% `````` +% \noindent to convert the Markdown document `hello.md` to a \TeX{} document +% `hello.tex`. After the Markdown package for our \TeX{} format has been +% loaded, the converted document can be typeset as follows: +% ``` tex +% \input hello +% ``````` +% +% This shows another advantage of using the command-line interface compared to +% using a higher-level \TeX{} interface: it is unnecessary to provide shell +% access for the \TeX{} engine. +% +% \end{markdown} +% \iffalse +%</lua-cli> +%<*tex> +% \fi +% \par +% \begin{markdown} +% +% Plain \TeX{} Interface +%----------------------- +% \label{sec:texinterface} +% +% \iffalse +%</tex> +%<*manual-interfaces> + +### Plain \TeX{} + +The plain \TeX{} interface provides \TeX{} commands that typeset markdown +documents by using the Lua interface behind the scenes. Unlike the Lua +interface, the plain TeX interface does not provide low-level tools for +converting markdown to \TeX{}. Instead, its goal is to provide high-level +typesetting capabilities. + +The plain \TeX{} interface accepts the same options as the `markdown` Lua +module, in addition to its own options, but now the options are specified as +\TeX{} commands. + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts + +\markdownBegin +$\sqrt{-1}$ *equals* $i$. +\markdownEnd + +\def\markdownOptionHybrid{true} +\markdownBegin +$\sqrt{-1}$ *equals* $i$. +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +Invoking pdfTeX should have the same effect: +``` sh +pdftex --shell-escape document.tex +`````` + +%</manual-interfaces> +%<*tex> +% \fi +% +% 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. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownLastModified{2019/04/30}% +\def\markdownVersion{2.8.1}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The plain \TeX{} interface is implemented by the `markdown.tex` file that can +% be loaded as follows: +% ``` tex +% \input markdown +% ``````` +% \noindent It is expected that the special plain \TeX{} characters have the +% expected category codes, when \m{input}ting the file. +% +%### 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. +% +% \end{markdown} +% \begin{macrocode} +\let\markdownBegin\relax +\let\markdownEnd\relax +% \end{macrocode} +% \par +% \begin{markdown} +% +% You may prepend your own code to the \m{markdownBegin} macro and redefine the +% \m{markdownEnd} macro to produce special effects before and after the +% markdown block. +% +% There are several limitations to the macros you need to be aware of. +% The first limitation concerns the \m{markdownEnd} macro, which must be +% visible directly from the input line buffer (it may not be produced as a +% result of input expansion). Otherwise, it will not be recognized as the end +% of the markdown string. As a corrolary, the \m{markdownEnd} string +% may not appear anywhere inside the markdown input. +% +% Another limitation concerns spaces at the right end of an input line. In +% markdown, these are used to produce a forced line break. However, any such +% spaces are removed before the lines enter the input buffer of +% \TeX{}~[@knuth86, p. 46]. 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 `c`, `e`, and `f` will not appear in the output. +% +% ``` tex +% \input markdown +% a +% b \markdownBegin c +% d +% e \markdownEnd f +% g +% \bye +% ``````` +% +% 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: +% +% ``` tex +% \input markdown +% \markdownBegin +% _Hello_ **world** ... +% \markdownEnd +% \bye +% ``````` +% +% 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{}. +% +% \end{markdown} +% \begin{macrocode} +\let\markdownInput\relax +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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: +% +% ``` tex +% \input markdown +% \markdownInput{hello.md} +% \bye +% ``````` +% +%### Options +% \label{sec:texoptions} +% +% The plain \TeX{} options are represented by \TeX{} commands. 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. +% +% \end{markdown} +% \iffalse +%</tex> +%<*manual-options> + +### Plain \TeX{} + +Plain \TeX{} options control the communication between the \TeX{} interface and +the `markdown` Lua module. They are supported by all higher-level interfaces of +the Markdown package, i.e. the plain \TeX{}, \LaTeX{} and \Hologo{ConTeXt} +interfaces. + +% \fi +% \begin{markdown} + +#### File and Directory Names + +% \end{markdown} +% \iffalse +%</manual-options> +%<*tex> +% \fi +% \begin{markdown} +% +% 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}`.markdown.lua`, where \m{jobname} is the base name +% of the document being typeset. +% +% The expansion of this macro must not contain quotation marks (`"`) or +% backslash symbols (`extbackslash`). Mind that \TeX{} engines tend to +% put quotation marks around \m{jobname}, when it contains spaces. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionHelperScriptFileName{\jobname.markdown.lua}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownOptionInputTempFileName} macro sets the filename of the +% temporary input file that is created during the conversion from markdown to +% plain \TeX{} in \m{markdownMode} other than `2`. It defaults to +% \m{jobname}`.markdown.out`. The same limitations as in the case of the +% \m{markdownOptionHelperScriptFileName} macro apply here. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionInputTempFileName{\jobname.markdown.in}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownOptionOutputTempFileName} macro sets the filename of the +% temporary output file that is created during the conversion from markdown to +% plain \TeX{} in \m{markdownMode} other than `2`. It defaults to +% \m{jobname}`.markdown.out`. The same limitations apply here as in the case +% of the \m{markdownOptionHelperScriptFileName} macro. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionOutputTempFileName{\jobname.markdown.out}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownOptionErrorTempFileName} macro sets the filename of the +% temporary output file that is created when a Lua error is encountered during +% the conversion from markdown to plain \TeX{} in \m{markdownMode} other than +% `2`. It defaults to \m{jobname}`.markdown.err`. The same limitations +% apply here as in the case of the \m{markdownOptionHelperScriptFileName} +% macro. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionErrorTempFileName{\jobname.markdown.err}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownOptionOutputDir} macro sets the path to the directory that +% will contain the cache files produced by the Lua implementation and also the +% auxiliary files produced by the plain \TeX{} implementation. The option +% defaults to `.`. +% +% The path must be set to the same value as the `-output-directory` option of +% your \TeX{} engine for the package to function correctly. We need this macro +% to make the Lua implementation aware where it should store the helper files. +% The same limitations apply here as in the case of the +% \m{markdownOptionHelperScriptFileName} macro. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionOutputDir{.}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownOptionCacheDir} macro corresponds to the Lua interface +% \Opt{cacheDir} option that sets the path to the directory that will contain +% the produced cache files. The option defaults to `_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. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionCacheDir{\markdownOptionOutputDir/_markdown_\jobname}% +% \end{macrocode} +% +% \iffalse +%</tex> +%<*manual-options> + +The plain \TeX{} interface provides the following commands that you can use to +specify the location of temporary files produced during the conversion from +Markdown to \TeX{}: + +- `\markdownOptionHelperScriptFileName`, +- `\markdownOptionInputTempFileName`, +- `\markdownOptionOutputTempFileName`, +- `\markdownOptionErrorTempFileName`, +- `\markdownOptionOutputDir`, and +- `\markdownOptionCacheDir`. + +Using a text editor, create a folder named `output-directory` and a text +document named `document.tex` with the following content: +``` tex +\input lmfonts +\input markdown +\def\markdownOptionHelperScriptFileName{helper-script.lua} +\def\markdownOptionInputTempFileName{temporary-input.md} +\def\markdownOptionOutputTempFileName{temporary-output.tex} +\def\markdownOptionErrorTempFileName{error-output.txt} +\def\markdownOptionOutputDir{output-directory} +\def\markdownOptionCacheDir{output-directory/cache-directory} +\markdownBegin +Hello *world*! +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex --output-directory output-directory document.tex +`````` +A text document named `temporary-input.md` should be produced in the folder +named `output-directory` and contain the following text: + +> Hello \*world\*! + +A folder named `output-directory/cache-directory` should also be produced and +contain fragments of the converted markdown document. LuaTeX does not need +other temporary files to perform the conversion from markdown to \TeX{}. To +produce the remaining temporary files, invoke pdfTeX from the terminal: +``` sh +pdftex --output-directory output-directory --shell-escape document.tex +`````` +Text documents named `helper-script.lua`, and `temporary-output.md` should be +produced in the folder named `output-directory`. The document named +`helper-script.lua` will contain Lua code that was executed to convert markdown +to plain \TeX{}. The document named `temporary-output.tex` will contain the +input markdown document converted to \TeX{}. + +No document named `error-output.txt` should be produced in the folder named +`output-directory`. This document would only be produced if an error had occured +while executing the Lua code. If this happens, please [file a +bug](https://github.com/witiko/markdown/issues). + +%</manual-options> +%<*tex> +% \fi +% \par +% \begin{markdown} +% +%#### Lua Interface Options +% The following macros map directly to the options recognized by the Lua +% interface (see Section \ref{sec:luaoptions}) and are not processed by the +% plain \TeX{} implementation, only passed along to Lua. They are undefined, which +% makes them fall back to the default values provided by the Lua interface. +% +% For the macros that correspond to the non-boolean options recognized by the +% Lua interface, the same limitations apply here in the case of the +% \m{markdownOptionHelperScriptFileName} macro. +% +% \end{markdown} +% \begin{macrocode} +\let\markdownOptionBlankBeforeBlockquote\undefined +\let\markdownOptionBlankBeforeCodeFence\undefined +\let\markdownOptionBlankBeforeHeading\undefined +\let\markdownOptionBreakableBlockquotes\undefined +\let\markdownOptionCitations\undefined +\let\markdownOptionCitationNbsps\undefined +\let\markdownOptionContentBlocks\undefined +\let\markdownOptionContentBlocksLanguageMap\undefined +\let\markdownOptionDefinitionLists\undefined +\let\markdownOptionFootnotes\undefined +\let\markdownOptionFencedCode\undefined +\let\markdownOptionHashEnumerators\undefined +\let\markdownOptionHeaderAttributes\undefined +\let\markdownOptionHtml\undefined +\let\markdownOptionHybrid\undefined +\let\markdownOptionInlineFootnotes\undefined +\let\markdownOptionPipeTables\undefined +\let\markdownOptionPreserveTabs\undefined +\let\markdownOptionShiftHeadings\undefined +\let\markdownOptionSlice\undefined +\let\markdownOptionSmartEllipses\undefined +\let\markdownOptionStartNumber\undefined +\let\markdownOptionTableCaptions\undefined +\let\markdownOptionTightLists\undefined +% \end{macrocode} +% \par +% \iffalse +%</tex> +%<*manual-options> + +#### Package Documentation + +The \mdef{markdownOptionStripPercentSigns} macro controls whether a percent +sign (`%`) at the beginning of a line will be discarded when reading Markdown +input from a \TeX{} document. This enables the use of markdown when writing +\TeX{} package documentation using the [Doc \LaTeX{} package][doc] by Frank +Mittelbach. + + [doc]: https://ctan.org/pkg/doc (doc – Format LaTeX documentation) + +Using a text editor, create a text document named `document.dtx` with the +following content: + + ``` tex + % \iffalse + \documentclass{ltxdoc} + \usepackage[stripPercentSigns]{markdown} + \begin{document} + \DocInput{document.dtx} + \end{document} + % \fi + % + % \begin{markdown} + % Hello *world*! + % \end{markdown} + ``````` + +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.dtx +`````` +A PDF document named `document.pdf` should be produced and contain the text +“Hello *world*!” + +%</manual-options> +%<*tex> +% \fi +% \begin{markdown} +% +%#### Miscellaneous Options +% +% The \mdef{markdownOptionStripPercentSigns} macro controls whether a percent +% sign (`%`) at the beginning of a line will be discarded when buffering +% Markdown input (see Section~\ref{sec:buffering}) or not. Notably, this +% enables the use of markdown when writing \TeX{} package documentation using +% the \pkg{Doc} \LaTeX{}~package~[@mittelbach17] or similar. The recognized +% values of the macro are `true` (discard) and `false` (retain). +% +% \end{markdown} +% \begin{macrocode} +\def\markdownOptionStripPercentSigns{false}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownIfOption}`{`\meta{name}`}` macro is provided for testing, +% whether the value of `\markdownOption`\meta{name} is `true` or `false`. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownIfOption#1{% + \def\next##1##2##3##4##5{% + \expandafter\def\expandafter\next\expandafter{% + \csname iffalse\endcsname}% + \if##1t\if##2r\if##3u\if##4e + \expandafter\def\expandafter\next\expandafter{% + \csname iftrue\endcsname}% + \fi\fi\fi\fi + \next}% + \expandafter\expandafter\expandafter\next + \csname markdownOption#1\endcsname\relax\relax\relax\relax\relax} +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> + +## Markdown Tokens + +A key feature of the Markdown package is the support for manipulating markdown +tokens, such as headings, emphasized text, links, and lists, in \TeX{}. Instead +of reducing \TeX{} to a PDF document producer, the Markdown package allows the +user to specify how every markdown token should be processed and rendered. + +% \fi +% \begin{markdown} + +### Token Renderers + +% \label{sec:texrenderersuser} +% \end{markdown} +% \iffalse + +Token renderers are user-defined \TeX{} macros, which render markdown tokens. +In this section, I will describe the individual token renderers. + +% \fi +% \begin{markdown} +% +% 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}). + +#### Interblock Separator Renderer +The \mdef{markdownRendererInterblockSeparator} macro represents a separator +between two markdown block elements. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererInterblockSeparator{% + \par + {\it(The end of a block)}% + \par +} +\markdownBegin +Hello *world*! + +_Foo_ bar! +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(The end of a block)* +> +> _Foo_ bar! + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + interblockSeparator = {% + \par + \emph{(The end of a block)}% + \par + }, + }, +} +\begin{document} +\begin{markdown} +Hello *world*! + +_Foo_ bar! +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(The end of a block)* +> +> _Foo_ bar! + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererInterblockSeparator{% + \par + \emph{(The end of a block)}% + \par +} +\starttext +\startmarkdown +Hello *world*! + +_Foo_ bar! +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(The end of a block)* +> +> _Foo_ bar! + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererInterblockSeparator{% + \markdownRendererInterblockSeparatorPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Line Break Renderer +The \mdef{markdownRendererLineBreak} macro represents a forced line break. +The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererLineBreak{% + \par + {\it(A forced linebreak)}% + \par +} +\markdownInput{example.md} +\bye +``````` +Using a text editor, create a text document named `example.md` with the +following content. Note the two spaces at the end of the first line, which +specify a hard linebreak. Due to the limitations of the \TeX{} input +processor, hard linebreaks would be ignored if we typed them directly into the +`document.tex` document. + +<pre><code>Hello world! <br/>_Foo_ bar!</code></pre> + +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(A forced linebreak)* +> +> _Foo_ bar! + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + lineBreak = {% + \par + \emph{(A forced linebreak)}% + \par + }, + }, +} +\begin{document} +\markdownInput{example.md} +\end{document} +``````` +Using a text editor, create a text document named `example.md` with the +following content. Note the two spaces at the end of the first line, which +specify a hard linebreak. Due to the limitations of the \TeX{} input +processor, hard linebreaks would be ignored if we typed them directly into the +`document.tex` document. + +<pre><code>Hello world! <br/>_Foo_ bar!</code></pre> + +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(A forced linebreak)* +> +> _Foo_ bar! + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererLineBreak{% + \par + \emph{(A forced linebreak)}% + \par +} +\starttext +\markdownInput{example.md} +\stoptext +``````` +Using a text editor, create a text document named `example.md` with the +following content. Note the two spaces at the end of the first line, which +specify a hard linebreak. Due to the limitations of the \TeX{} input +processor, hard linebreaks would be ignored if we typed them directly into the +`document.tex` document. + +<pre><code>Hello world! <br/>_Foo_ bar!</code></pre> + +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(A forced linebreak)* +> +> _Foo_ bar! + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererLineBreak{% + \markdownRendererLineBreakPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### 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 `true`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionSmartEllipses{true} +\def\markdownRendererEllipsis{{\it SHAZAM}!} +\markdownBegin +The secret word is ... +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The secret word is *SHAZAM*! + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[smartEllipses]{markdown} +\markdownSetup{ + renderers = { + ellipsis = \emph{SHAZAM}!, + }, +} +\begin{document} +\begin{markdown} +The secret word is ... +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The secret word is *SHAZAM*! + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionSmartEllipses{true} +\def\markdownRendererEllipsis{\emph{SHAZAM}!} +\starttext +\startmarkdown +The secret word is ... +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Hello *world*! +> +> *(The end of a block)* +> +> _Foo_ bar! + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererEllipsis{% + \markdownRendererEllipsisPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Non-Breaking Space Renderer +The \mdef{markdownRendererNbsp} macro represents a non-breaking space. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.bib` with the +following content: +``` bib +@book{knuth:tex, + author = "Knuth, Donald Ervin", + title = "The \TeX book, volume A of Computers and typesetting", + publisher = "Addison-Wesley", + year = "1984" +} +``````` +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[ + citations, + citationNbsps, +]{markdown} +\markdownSetup{ + renderers = { + nbsp = {$\cdot$}, + }, +} +\begin{document} + +\begin{markdown} +The TeXbook [@knuth:tex, p. 123 and 130] is good. +\end{markdown} + +\bibliographystyle{plain} +\bibliography{document.bib} + +\end{document} +``````` +Next, invoke LuaTeX and BibTeX from the terminal: +``` sh +lualatex document.tex +bibtex document.aux +lualatex document.tex +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> The TeXbook [1, p.·123·and·130] is good. +> +> ### References +> [1] Donald Ervin Knuth. _The TeXbook, volume A of Computers and typesetting._ +> Addison-Wesley, 1984. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererNbsp{% + \markdownRendererNbspPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Special Character Renderers +The following macros replace any special plain \TeX{} characters, including +% \iffalse +the active pipe character (`|`) of \Hologo{ConTeXt}, in the input text: + +- \mdef{markdownRendererAmpersand} replaces the ampersand (`&`). +- \mdef{markdownRendererBackslash} replaces the backslash (`\`). +- \mdef{markdownRendererCircumflex} replaces the circumflex (`^`). +- \mdef{markdownRendererDollarSign} replaces the dollar sign (`$`). +- \mdef{markdownRendererHash} replaces the hash sign (`#`). +- \mdef{markdownRendererLeftBrace} replaces the left brace (`{`). +- \mdef{markdownRendererPercentSign} replaces the percent sign (`%`). +- \mdef{markdownRendererPipe} replaces the pipe character (`|`). +- \mdef{markdownRendererRightBrace} replaces the right brace (`}`). +- \mdef{markdownRendererTilde} replaces the tilde (`~`). +- \mdef{markdownRendererUnderscore} replaces the underscore (`_`). + +% \fi +% the active pipe character (`|`) of \Hologo{ConTeXt}, in the input text. +% These macros will only be produced, when the \Opt{hybrid} option is +% `false`. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content. We will make the tilde behave as if it were written in +\TeX{}, where it represents a non-breaking space. +``` tex +\input markdown +\def\markdownRendererTilde{~} +\markdownBegin +Bartel~Leendert van~der~Waerden +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text, where the middot (`·`) denotes a non-breakable space: + +> Bartel·Leendert van·der·Waerden + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content. We will make the tilde behave as if it were written in +\TeX{}, where it represents a non-breaking space. +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + tilde = ~, + }, +} +\begin{document} +\begin{markdown} +Bartel~Leendert van~der~Waerden +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text, where the middot (`·`) denotes a non-breakable space: + +> Bartel·Leendert van·der·Waerden + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content. We will make the tilde behave as if it were written in +\TeX{}, where it represents a non-breaking space. +``` tex +\usemodule[t][markdown] +\def\markdownRendererTilde{~} +\starttext +\startmarkdown +Bartel~Leendert van~der~Waerden +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text, where the middot (`·`) denotes a non-breakable space: + +> Bartel·Leendert van·der·Waerden + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererLeftBrace{% + \markdownRendererLeftBracePrototype}% +\def\markdownRendererRightBrace{% + \markdownRendererRightBracePrototype}% +\def\markdownRendererDollarSign{% + \markdownRendererDollarSignPrototype}% +\def\markdownRendererPercentSign{% + \markdownRendererPercentSignPrototype}% +\def\markdownRendererAmpersand{% + \markdownRendererAmpersandPrototype}% +\def\markdownRendererUnderscore{% + \markdownRendererUnderscorePrototype}% +\def\markdownRendererHash{% + \markdownRendererHashPrototype}% +\def\markdownRendererCircumflex{% + \markdownRendererCircumflexPrototype}% +\def\markdownRendererBackslash{% + \markdownRendererBackslashPrototype}% +\def\markdownRendererTilde{% + \markdownRendererTildePrototype}% +\def\markdownRendererPipe{% + \markdownRendererPipePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### 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. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts + +\def\markdownRendererCodeSpan#1{#1} + +\markdownBegin +`$\sqrt{-1}$ *equals* $i$` + +$\sqrt{-1}$ *equals* $i$ +\markdownEnd + +\def\markdownOptionHybrid{true} +\markdownBegin +$\sqrt{-1}$ *equals* $i$ +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ \*equals\* \$i\$. +> +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[smartEllipses]{markdown} +\markdownSetup{ + renderers = { + codeSpan = {#1}, + }, +} +\begin{document} + +\begin{markdown} +`$\sqrt{-1}$ *equals* $i$` + +$\sqrt{-1}$ *equals* $i$ +\end{markdown} + +\begin{markdown*}{hybrid} +$\sqrt{-1}$ *equals* $i$ +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ \*equals\* \$i\$. +> +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererCodeSpan#1{#1} +\starttext + +\startmarkdown +`$\sqrt{-1}$ *equals* $i$` + +$\sqrt{-1}$ *equals* $i$ +\stopmarkdown + +\def\markdownOptionHybrid{true} +\startmarkdown +$\sqrt{-1}$ *equals* $i$ +\stopmarkdown + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ \*equals\* \$i\$. +> +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererCodeSpan{% + \markdownRendererCodeSpanPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Link Renderer +The \mdef{markdownRendererLink} macro represents a hyperlink. It receives +four arguments: the label, the fully escaped \acro{uri} that can be directly +typeset, the raw \acro{uri} that can be used outside typesetting, and the +title of the link. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererLink#1#2#3#4{% + #1 {\tt#2} titled {\it#4}% +} +\markdownBegin +Please visit [the link][ctan]. + + [ctan]: https://ctan.org/ + (the Comprehensive TeX Archive Network) +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Please visit the link <https://ctan.org/> titled *the Comprehensive TeX +> Archive Network*. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + link = {% + #1 \texttt{#2} titled \emph{#4}% + }, + }, +} +\begin{document} +\begin{markdown} +Please visit [the link][ctan]. + + [ctan]: https://ctan.org/ + (the Comprehensive TeX Archive Network) +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Please visit the link <https://ctan.org/> titled *the Comprehensive TeX +> Archive Network*. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererLink#1#2#3#4{% + #1 {\tt#2} titled \emph{#4}% +} +\starttext +\startmarkdown +Please visit [the link][ctan]. + + [ctan]: https://ctan.org/ + (the Comprehensive TeX Archive Network) +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Please visit the link <https://ctan.org/> titled *the Comprehensive TeX +> Archive Network*. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererLink{% + \markdownRendererLinkPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Image Renderer +The \mdef{markdownRendererImage} macro represents an image. It receives +four arguments: the label, the fully escaped \acro{uri} that can be directly +typeset, the raw \acro{uri} that can be used outside typesetting, and the +title of the link. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begingroup +\catcode`\@=11 +\catcode`\%=12 +\catcode`\^^A=14 +\global\def\markdownRendererImage#1#2#3#4{^^A + \immediate\write18{^^A + if printf '%s' "#3" | grep -q ^http; then + OUTPUT="$(printf '%s' "#3" | md5sum | cut -d' ' -f1).^^A + $(printf '%s' "#3" | sed 's/.*[.]//')"; + if ! [ -e "$OUTPUT" ]; then + wget -O "$OUTPUT" '#3' || rm "$OUTPUT"; + convert "$OUTPUT" png:"$OUTPUT"; + fi; + printf '%s%%' "$OUTPUT" > \jobname.fetched; + else + printf '%s%%' "#3" > \jobname.fetched; + fi^^A + }^^A + {^^A + \everyeof={\noexpand}^^A + \edef\filename{\@@input"\jobname.fetched" }^^A + \includegraphics[width=\textwidth]{\filename}^^A + }^^A +} +\endgroup +\begin{document} +\begin{markdown} +![TUGboat](https://tug.org/tugboat/noword.jpg) +\end{markdown} +\end{document} +`````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex --shell-escape document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following content. This assumes that you use a Unix-like operating system with +Bourne or Bourne again shell as the default shell of the current user. It also +assumes that the `md5sum`, `wget`, and `convert` binaries are installed and +that the \TeX{} engine has shell access. + +> ![](https://tug.org/tugboat/noword.jpg "The Communications of the TeX Users Group") + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererImage{% + \markdownRendererImagePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Content Block Renderers +\label{sec:texcontentblockrenderers} +The \mdef{markdownRendererContentBlock} macro represents an iA\,Writer content +block. It receives four arguments: the local file or online image filename +extension cast to the lower case, the fully escaped \acro{uri} that can be +directly typeset, the raw \acro{uri} that can be used outside typesetting, +and the title of the content block. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererContentBlock{% + \markdownRendererContentBlockPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererContentBlockOnlineImage} macro represents an +iA\,Writer online image content block. The macro receives the same arguments +as \m{markdownRendererContentBlock}. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererContentBlockOnlineImage{% + \markdownRendererContentBlockOnlineImagePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererContentBlockCode} macro represents an iA\,Writer +content block that was recognized as a file in a known programming language +by its filename extension $s$. If any `markdown-languages.json` file found +by \pkg{kpathsea}\footnote{Local files take precedence. Filenames other +than `markdown-languages.json` may be specified using the +`contentBlocksLanguageMap` Lua option.} contains a record $(k, v)$, then a +non-online-image content block with the filename extension $s, +s$`:lower()`${}=k$ is considered to be in a known programming language $v$. +The macro receives five arguments: the local file name extension $s$ cast to +the lower case, the language $v$, the fully escaped \acro{uri} that can be +directly typeset, the raw \acro{uri} that can be used outside typesetting, +and the title of the content block. + +Note that you will need to place place a `markdown-languages.json` file +inside your working directory or inside your local \TeX{} directory +structure. In this file, you will define a mapping between filename +extensions and the language names recognized by your favorite syntax +highlighter; there may exist other creative uses beside syntax highlighting. +% The `Languages.json` file provided by @sotkov17 is a good starting point. +% \end{markdown} +% +% \iffalse +[The `Languages.json` file provided by Anton Sotkov][sotkov17] is a good +starting point. + + [sotkov17]: https://github.com/iainc/Markdown-Content-Blocks + (File transclusion syntax for Markdown) + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionContentBlocks{true} +\def\markdownRendererContentBlock#1#2#3#4{% + This is {\tt #2}, #4. +} +\def\markdownRendererContentBlockOnlineImage#1#2#3#4{% + This is the image {\tt #2}, #4. +} +\def\markdownRendererContentBlockCode#1#2#3#4#5{% + This is the #2 (\uppercase{#1}) document {\tt #3}, #5. +} +\markdownBegin +/document.tex (the document that we are currently typesetting) +/markdown-languages.json (the mapping between filename extensions + and programming language names) +https://tug.org/tugboat/noword.jpg (the logotype of TUGboat) +\markdownEnd +\bye +``````` +Create also a text document named `markdown-languages.json` with the following +content: +``` js +{ + "json": "JavaScript Object Notation", +} +`````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is `document.tex`, the document that we are currently typesetting. +> +> This is the JavaScript Object Notation (JSON) document +> `markdown-languages.json`, the mapping between filename extensions and +> programming language names. +> +> This is the image `https://tug.org/tugboat/noword.jpg`, the logotype of +> TUGboat. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{filecontents} +\begin{filecontents*}{markdown-languages.json} +{ + "json": "JavaScript Object Notation", +} +\end{filecontents*} +\usepackage[contentBlocks]{markdown} +\markdownSetup{ + renderers = { + contentBlock = {This is \texttt{#2}, #4.}, + contentBlockOnlineImage = {This is the image \texttt{#2}, #4.}, + contentBlockCode = {% + This is the #2 (\MakeUppercase{#1}) document \texttt{#3}, #5. + }, + }, +} +\begin{document} +\begin{markdown} +/document.tex (the document that we are currently typesetting) +/markdown-languages.json (the mapping between filename extensions + and programming language names) +https://tug.org/tugboat/noword.jpg (the logotype of TUGboat) +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is `document.tex`, the document that we are currently typesetting. +> +> This is the JavaScript Object Notation (JSON) document +> `markdown-languages.json`, the mapping between filename extensions and +> programming language names. +> +> This is the image `https://tug.org/tugboat/noword.jpg`, the logotype of +> TUGboat. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionContentBlocks{true} +\def\markdownRendererContentBlock#1#2#3#4{% + This is {\tt #2}, #4. +} +\def\markdownRendererContentBlockOnlineImage#1#2#3#4{% + This is the image {\tt #2}, #4. +} +\def\markdownRendererContentBlockCode#1#2#3#4#5{% + This is the #2 (\uppercase{#1}) document {\tt #3}, #5. +} +\starttext +\startmarkdown +/document.tex (the document that we are currently typesetting) +/markdown-languages.json (the mapping between filename extensions + and programming language names) +https://tug.org/tugboat/noword.jpg (the logotype of TUGboat) +\stopmarkdown +\stoptext +``````` +Create also a text document named `markdown-languages.json` with the following +content: +``` js +{ + "json": "JavaScript Object Notation", +} +`````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is `document.tex`, the document that we are currently typesetting. +> +> This is the JavaScript Object Notation (JSON) document +> `markdown-languages.json`, the mapping between filename extensions and +> programming language names. +> +> This is the image `https://tug.org/tugboat/noword.jpg`, the logotype of +> TUGboat. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererContentBlockCode{% + \markdownRendererContentBlockCodePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### 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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlBegin{% + \markdownRendererUlBeginPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 `false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlBeginTight{% + \markdownRendererUlBeginTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererUlItem} macro represents an item in a bulleted +list. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlItem{% + \markdownRendererUlItemPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererUlItemEnd} macro represents the end of an item in a +bulleted list. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlItemEnd{% + \markdownRendererUlItemEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlEnd{% + \markdownRendererUlEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 +`false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionTightLists{true} + +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererUlBeginTight{ (} +\def\markdownRendererUlItem{% + \def\markdownRendererUlItem{% + , + \def\markdownRendererUlItem{, and }% + }% +} +\def\markdownRendererUlItemEnd{} +\def\markdownRendererUlEndTight{).} + +\markdownBegin +This is a tight list + +- the first item +- the second item +- the third item +\markdownEnd + +\def\markdownRendererInterblockSeparator{% + :\par + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererUlBegin{} +\def\markdownRendererUlItem{--\kern 0.5em} +\def\markdownRendererUlItemEnd{.\par} +\def\markdownRendererUlEnd{} + +\markdownBegin +This is a loose list + +- This is the first item + +- This is the second item + +- This is the third item +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> - This is the first item. +> +> - This is the second item. +> +> - This is the third item. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[tightLists]{markdown} +\begin{document} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {}, + ulBeginTight = { (}, + ulItem = {% + \def\markdownRendererUlItem{% + , + \def\markdownRendererUlItem{, and }% + }% + }, + ulItemEnd = {}, + ulEndTight = {).}, + }, +} +This is a tight list + +- the first item +- the second item +- the third item +\end{markdown*} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {% + :\par + \def\markdownRendererInterblockSeparator{\par}% + }, + ulBeginTight = {\begin{itemize}}, + ulItem = {\item}, + ulItemEnd = {.}, + ulEnd = {\end{itemize}}, + }, +} +This is a loose list + +- This is the first item + +- This is the second item + +- This is the third item +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> - This is the first item. +> +> - This is the second item. +> +> - This is the third item. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionTightLists{true} +\starttext + +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererUlBeginTight{ (} +\def\markdownRendererUlItem{% + \def\markdownRendererUlItem{% + , + \def\markdownRendererUlItem{, and }% + }% +} +\def\markdownRendererUlItemEnd{} +\def\markdownRendererUlEndTight{).} + +\startmarkdown +This is a tight list + +- the first item +- the second item +- the third item +\stopmarkdown + +\def\markdownRendererInterblockSeparator{% + :\par + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererUlBegin{\startitemize} +\def\markdownRendererUlItem{\item} +\def\markdownRendererUlItemEnd{.} +\def\markdownRendererUlEnd{\stopitemize} + +\startmarkdown +This is a loose list + +- This is the first item + +- This is the second item + +- This is the third item +\stopmarkdown + +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> - This is the first item. +> +> - This is the second item. +> +> - This is the third item. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererUlEndTight{% + \markdownRendererUlEndTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### 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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlBegin{% + \markdownRendererOlBeginPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 `false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlBeginTight{% + \markdownRendererOlBeginTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererOlItem} macro represents an item in an ordered list. +This macro will only be produced, when the \Opt{startNumber} option is +`false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlItem{% + \markdownRendererOlItemPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererOlItemEnd} macro represents the end of an item in +an ordered list. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlItemEnd{% + \markdownRendererOlItemEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererOlItemWithNumber} macro represents an item in an +ordered list. This macro will only be produced, when the \Opt{startNumber} +option is `true`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlItemWithNumber{% + \markdownRendererOlItemWithNumberPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlEnd{% + \markdownRendererOlEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 +`false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionTightLists{true} +\def\markdownOptionStartNumber{true} + +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererOlBeginTight{ (} +\def\markdownRendererOlItemWithNumber#1{% + \ifnum #1=1\relax + the first + \else + \ifnum #1=2\relax + , the second + \else + , and the third + \fi + \fi +} +\def\markdownRendererOlItemEnd{} +\def\markdownRendererOlEndTight{).} + +\markdownBegin +This is a tight list + +1. item +2. item +3. item +\markdownEnd + +\def\markdownRendererInterblockSeparator{% + :\par + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererOlBegin{} +\def\markdownRendererOlItemWithNumber#1{% + #1.\kern 0.5em% + This is the + \ifnum #1=1\relax + first + \else + \ifnum #1=2\relax + second + \else + third + \fi + \fi +} +\def\markdownRendererOlItemEnd{.\par} +\def\markdownRendererOlEnd{} + +\markdownBegin +This is a loose list + +1. item + +2. item + +3. item +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> 1. This is the first item. +> +> 2. This is the second item. +> +> 3. This is the third item. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[tightLists, startNumber]{markdown} +\begin{document} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {}, + olBeginTight = { (}, + olItemWithNumber = {% + \ifnum #1=1\relax + the first + \else + \ifnum #1=2\relax + , the second + \else + , and the third + \fi + \fi + }, + olItemEnd = {}, + olEndTight = {).}, + }, +} +This is a tight list + +1. item +2. item +3. item +\end{markdown*} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {% + :\par + \def\markdownRendererInterblockSeparator{\par}% + }, + olBeginTight = {\begin{enumerate}}, + olItemWithNumber = {% + \item This is the + \ifnum #1=1\relax + first + \else + \ifnum #1=2\relax + second + \else + third + \fi + \fi + }, + olItemEnd = {.}, + olEnd = {\end{enumerate}}, + }, +} +This is a loose list + +1. item + +2. item + +3. item +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> 1. This is the first item. +> +> 2. This is the second item. +> +> 3. This is the third item. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionTightLists{true} +\def\markdownOptionStartNumber{true} +\starttext + +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererOlBeginTight{ (} +\def\markdownRendererOlItemWithNumber#1{% + \ifnum #1=1\relax + the first + \else + \ifnum #1=2\relax + , the second + \else + , and the third + \fi + \fi +} +\def\markdownRendererOlItemEnd{} +\def\markdownRendererOlEndTight{).} + +\startmarkdown +This is a tight list + +1. item +2. item +3. item +\stopmarkdown + +\def\markdownRendererInterblockSeparator{% + :\par + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererOlBegin{\startitemize} +\def\markdownRendererOlItemWithNumber#1{% + \sym{#1.} + This is the + \ifnum #1=1\relax + first + \else + \ifnum #1=2\relax + second + \else + third + \fi + \fi +} +\def\markdownRendererOlItemEnd{.\par} +\def\markdownRendererOlEnd{\stopitemize} + +\startmarkdown +This is a loose list + +1. item + +2. item + +3. item +\stopmarkdown + +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight list (the first item, the second item, and the third item). +> +> This is a loose list: +> +> 1. This is the first item. +> +> 2. This is the second item. +> +> 3. This is the third item. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererOlEndTight{% + \markdownRendererOlEndTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Definition List Renderers +The following macros are only produced, when the \Opt{definitionLists} option +is `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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlBegin{% + \markdownRendererDlBeginPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 `false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlBeginTight{% + \markdownRendererDlBeginTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererDlItem} macro represents a term in a definition +list. The macro receives a single argument that corresponds to the term +being defined. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlItem{% + \markdownRendererDlItemPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererDlItemEnd} macro represents the end of a list of +definitions for a single term. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlItemEnd{% + \markdownRendererDlItemEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererDlDefinitionBegin} macro represents the beginning +of a definition in a definition list. There can be several definitions for +a single term. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlDefinitionBegin{% + \markdownRendererDlDefinitionBeginPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererDlDefinitionEnd} macro represents the end of a +definition in a definition list. There can be several definitions for a +single term. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlDefinitionEnd{% + \markdownRendererDlDefinitionEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlEnd{% + \markdownRendererDlEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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 `false`. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionDefinitionLists{true} +\def\markdownOptionTightLists{true} + +\def\markdownRendererInterblockSeparator{% + :% + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererDlBeginTight{% + \begingroup + \parindent=0pt +} +\def\markdownRendererDlItem#1{% + \par{\bf#1}% + \def\markdownRendererDlDefinitionEnd{% + , + \def\markdownRendererDlDefinitionEnd{% + , and + \def\markdownRendererDlDefinitionEnd{.}% + }% + }% +} +\def\markdownRendererDlItemEnd{} +\def\markdownRendererDlDefinitionBegin{\par--\kern 0.5em} +\def\markdownRendererDlEndTight{\endgroup} + +\markdownBegin +This is a tight definition list + +Coffee +: black hot drink +: prepared from roasted coffee beans +: one of the most traded agricultural commodities in the world + +Milk +: white cold drink +: nutrient-rich +: produced on an industrial scale +\markdownEnd + +\def\markdownRendererInterblockSeparator{% + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererDlBegin{} +\def\markdownRendererDlItem#1{% + . #1 is a + \def\markdownRendererDlDefinitionBegin{% + \def\markdownRendererDlDefinitionBegin{% + , + \def\markdownRendererDlDefinitionBegin{, and }% + }% + }% +} +\def\markdownRendererDlItemEnd{} +\def\markdownRendererDlDefinitionEnd{} +\def\markdownRendererDlEnd{.} + +\markdownBegin +This is a loose definition list + +Coffee + +: black hot drink + +: prepared from roasted coffee beans + +: one of the most traded agricultural commodities in the world + +Milk + +: white cold drink + +: nutrient-rich + +: produced on an industrial scale +\markdownEnd + +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight definition list: +> +> **Coffee** +> +> - black hot drink, +> - prepared from roasted coffee beans, and +> - one of the most traded agricultural commodities in the world. +> +> **Milk** +> +> - white cold drink, +> - nutrient-rich, and +> - produced on an industrial scale. +> +> This is a loose definition list. Coffee is a black hot drink, prepared from +> roasted coffee beans, and one of the most traded agricultural commodities in +> the world. Milk is a white cold drink, nutrient-rich, and produced on an +> industrial scale. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[definitionLists, tightLists]{markdown} +\begin{document} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {% + :% + \def\markdownRendererInterblockSeparator{\par}% + }, + dlBeginTight = {\begin{description}}, + dlItem = {% + \item[#1] + \begin{itemize} + \def\markdownRendererDlDefinitionEnd{% + , + \def\markdownRendererDlDefinitionEnd{% + , and + \def\markdownRendererDlDefinitionEnd{.}% + }% + }% + }, + dlItemEnd = {\end{itemize}}, + dlDefinitionBegin = \item, + dlEndTight = {\end{description}}, + }, +} +This is a tight definition list + +Coffee +: black hot drink +: prepared from roasted coffee beans +: one of the most traded agricultural commodities in the world + +Milk +: white cold drink +: nutrient-rich +: produced on an industrial scale +\end{markdown*} + +\begin{markdown*}{ + renderers = { + interblockSeparator = {% + \def\markdownRendererInterblockSeparator{\par}% + }, + dlBegin = {}, + dlItem = {% + . #1 is a + \def\markdownRendererDlDefinitionBegin{% + \def\markdownRendererDlDefinitionBegin{% + , + \def\markdownRendererDlDefinitionBegin{, and }% + }% + }% + }, + dlItemEnd = {}, + dlDefinitionEnd = {}, + dlEnd = {.}, + }, +} +This is a loose definition list + +Coffee + +: black hot drink + +: prepared from roasted coffee beans + +: one of the most traded agricultural commodities in the world + +Milk + +: white cold drink + +: nutrient-rich + +: produced on an industrial scale +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight definition list: +> +> **Coffee** +> +> - black hot drink, +> - prepared from roasted coffee beans, and +> - one of the most traded agricultural commodities in the world. +> +> **Milk** +> +> - white cold drink, +> - nutrient-rich, and +> - produced on an industrial scale. +> +> This is a loose definition list. Coffee is a black hot drink, prepared from +> roasted coffee beans, and one of the most traded agricultural commodities in +> the world. Milk is a white cold drink, nutrient-rich, and produced on an +> industrial scale. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionDefinitionLists{true} +\def\markdownOptionTightLists{true} +\starttext + +\def\markdownRendererInterblockSeparator{% + :% + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererDlBeginTight{} +\def\markdownRendererDlItem#1{% + \par{\bf#1}% + \startitemize + \def\markdownRendererDlDefinitionEnd{% + , + \def\markdownRendererDlDefinitionEnd{% + , and + \def\markdownRendererDlDefinitionEnd{.}% + }% + }% +} +\def\markdownRendererDlItemEnd{\stopitemize} +\def\markdownRendererDlDefinitionBegin{\item} +\def\markdownRendererDlEndTight{} + +\startmarkdown +This is a tight definition list + +Coffee +: black hot drink +: prepared from roasted coffee beans +: one of the most traded agricultural commodities in the world + +Milk +: white cold drink +: nutrient-rich +: produced on an industrial scale +\stopmarkdown + +\def\markdownRendererInterblockSeparator{% + \def\markdownRendererInterblockSeparator{\par}% +} +\def\markdownRendererDlBegin{} +\def\markdownRendererDlItem#1{% + . #1 is a + \def\markdownRendererDlDefinitionBegin{% + \def\markdownRendererDlDefinitionBegin{% + , + \def\markdownRendererDlDefinitionBegin{, and }% + }% + }% +} +\def\markdownRendererDlItemEnd{} +\def\markdownRendererDlDefinitionEnd{} +\def\markdownRendererDlEnd{.} + +\startmarkdown +This is a loose definition list + +Coffee + +: black hot drink + +: prepared from roasted coffee beans + +: one of the most traded agricultural commodities in the world + +Milk + +: white cold drink + +: nutrient-rich + +: produced on an industrial scale +\stopmarkdown + +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a tight definition list: +> +> **Coffee** +> +> - black hot drink, +> - prepared from roasted coffee beans, and +> - one of the most traded agricultural commodities in the world. +> +> **Milk** +> +> - white cold drink, +> - nutrient-rich, and +> - produced on an industrial scale. +> +> This is a loose definition list. Coffee is a black hot drink, prepared from +> roasted coffee beans, and one of the most traded agricultural commodities in +> the world. Milk is a white cold drink, nutrient-rich, and produced on an +> industrial scale. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererDlEndTight{% + \markdownRendererDlEndTightPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### 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. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererEmphasis#1{{\it#1}} +\def\markdownRendererStrongEmphasis#1{{\bf#1}} +\markdownBegin +This is *emphasis*. + +This is **strong emphasis**. +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is *emphasis*. +> +> This is **strong emphasis**. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + emphasis = {\emph{#1}}, + strongEmphasis = {\textbf{#1}}, + }, +} +\begin{document} +\begin{markdown} +This is *emphasis*. + +This is **strong emphasis**. +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is *emphasis*. +> +> This is **strong emphasis**. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererEmphasis#1{\emph{#1}} +\def\markdownRendererStrongEmphasis#1{\bold{#1}} +\starttext +\startmarkdown +This is *emphasis*. + +This is **strong emphasis**. +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is *emphasis*. +> +> This is **strong emphasis**. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererEmphasis{% + \markdownRendererEmphasisPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +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. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererStrongEmphasis{% + \markdownRendererStrongEmphasisPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Block Quote Renderers +The \mdef{markdownRendererBlockQuoteBegin} macro represents the beginning of +a block quote. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererBlockQuoteBegin{% + \begingroup + \vskip\parindent + \leftskip=2\parindent + \parindent=0pt +} +\def\markdownRendererBlockQuoteEnd{% + \par + \vskip\parindent + \endgroup +} +\markdownBegin +A quote from William Shakespeare's King Lear: + +> This is the excellent foppery of the world that when we are +> sick in fortune---often the surfeit of our own behavior---we +> make guilty of our disasters the sun, the moon, and the +> stars [...] +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A quote from William Shakespeare's King Lear: +> +> > This is the excellent foppery of the world that when we are +> > sick in fortune—often the surfeit of our own behavior—we +> > make guilty of our disasters the sun, the moon, and the +> > stars [...] + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + blockQuoteBegin = {\begin{quote}}, + blockQuoteEnd = {\end{quote}}, + }, +} +\begin{document} +\begin{markdown} +A quote from William Shakespeare's King Lear: + +> This is the excellent foppery of the world that when we are +> sick in fortune---often the surfeit of our own behavior---we +> make guilty of our disasters the sun, the moon, and the +> stars [...] +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A quote from William Shakespeare's King Lear: +> +> > This is the excellent foppery of the world that when we are +> > sick in fortune—often the surfeit of our own behavior—we +> > make guilty of our disasters the sun, the moon, and the +> > stars [...] + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererBlockQuoteBegin{\startquotation} +\def\markdownRendererBlockQuoteEnd{\stopquotation} +\starttext +\startmarkdown +A quote from William Shakespeare's King Lear: + +> This is the excellent foppery of the world that when we are +> sick in fortune---often the surfeit of our own behavior---we +> make guilty of our disasters the sun, the moon, and the +> stars [...] +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A quote from William Shakespeare's King Lear: +> +> > This is the excellent foppery of the world that when we are +> > sick in fortune—often the surfeit of our own behavior—we +> > make guilty of our disasters the sun, the moon, and the +> > stars [...] + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererBlockQuoteBegin{% + \markdownRendererBlockQuoteBeginPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererBlockQuoteEnd} macro represents the end of a block +quote. The macro receives no arguments. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererBlockQuoteEnd{% + \markdownRendererBlockQuoteEndPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Code Block Renderers +The \mdef{markdownRendererInputVerbatim} macro represents a code +block. The macro receives a single argument that corresponds to the +filename of a file contaning the code block contents. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererInputVerbatim{% + \markdownRendererInputVerbatimPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererInputFencedCode} macro represents a fenced code +block. This macro will only be produced, when the \Opt{fencedCode} option is +`true`. The macro receives two arguments that correspond to the filename of +a file contaning the code block contents and to the code fence infostring. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{verbatim} +\usepackage[hyphens]{url} +\usepackage[fencedCode]{markdown} +\markdownSetup{ + renderers = { + interblockSeparator = { + \def\markdownRendererInterblockSeparator{% + \par + \def\markdownRendererInterblockSeparator{% + \def\markdownRendererInterblockSeparator{% + \par + }% + }% + }% + }, + inputVerbatim = { + is contained in file \url{#1}:% + \verbatiminput{#1}% + }, + inputFencedCode = { + in #2 \markdownRendererInputVerbatim{#1}% + }, + }, +} +\begin{document} +\begin{markdown} +The following code + + def foo(bar): + if len(bar) <= 1: + return bar[0] + elif len(bar) == 2: + return sorted(bar) + else: + baz = len(bar) // 2 + return foo(bar[baz:], bar[:baz]) + +The following code + +~~~ Python +>>> foo([4, 2, 1, 3]) +[1, 2, 3, 4] +~~~~~~~~~~ +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text except for the filename, which may differ: + +> The following code is contained in file +> `./_markdown_document/882453149edcf288976647f6fe147ada.verbatim`: +> ``` py +> def foo(bar): +> if len(bar) <= 1: +> return bar[:1] +> elif len(bar) == 2: +> return sorted(bar) +> else: +> baz = bar[len(bar) // 2] +> return ( +> foo([qux for qux in bar if qux < baz]) + [baz] + +> foo([qux for qux in bar if qux > baz]) +> ) +> `````` +> The following code in Python contained in file +> `./_markdown_document/cf2a96e2120cef5b1fae5fea36fcc27b.verbatim`: +> ``` py +> >>> foo([4, 2, 1, 3]) +> [1, 2, 3, 4] +> `````` + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererInputFencedCode{% + \markdownRendererInputFencedCodePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Heading Renderers +The \mdef{markdownRendererHeadingOne} macro represents a first level heading. +The macro receives a single argument that corresponds to the heading text. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingOne{% + \markdownRendererHeadingOnePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererHeadingTwo} macro represents a second level +heading. The macro receives a single argument that corresponds to the heading +text. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingTwo{% + \markdownRendererHeadingTwoPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererHeadingThree} macro represents a third level +heading. The macro receives a single argument that corresponds to the heading +text. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingThree{% + \markdownRendererHeadingThreePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererHeadingFour} macro represents a fourth level +heading. The macro receives a single argument that corresponds to the heading +text. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingFour{% + \markdownRendererHeadingFourPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererHeadingFive} macro represents a fifth level +heading. The macro receives a single argument that corresponds to the heading +text. + +% \end{markdown} +% +% \iffalse +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingFive{% + \markdownRendererHeadingFivePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +The \mdef{markdownRendererHeadingSix} macro represents a sixth level +heading. The macro receives a single argument that corresponds to the heading +text. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererHeadingOne{1} +\def\markdownRendererHeadingTwo{2} +\def\markdownRendererHeadingThree{3} +\def\markdownRendererHeadingFour{4} +\def\markdownRendererHeadingFive{5} +\def\markdownRendererHeadingSix{6} +\markdownBegin +###### +##### +##### +### +###### +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> 65536 + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + interblockSeparator = {}, + headingOne = 1, + headingTwo = 2, + headingThree = 3, + headingFour = 4, + headingFive = 5, + headingSix = 6, + }, +} +\begin{document} +\begin{markdown} +###### +##### +##### +### +###### +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> 65536 + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererInterblockSeparator{} +\def\markdownRendererHeadingOne{1} +\def\markdownRendererHeadingTwo{2} +\def\markdownRendererHeadingThree{3} +\def\markdownRendererHeadingFour{4} +\def\markdownRendererHeadingFive{5} +\def\markdownRendererHeadingSix{6} +\starttext +\startmarkdown +###### +##### +##### +### +###### +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> 65536 + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHeadingSix{% + \markdownRendererHeadingSixPrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Horizontal Rule Renderer +The \mdef{markdownRendererHorizontalRule} macro represents a horizontal rule. +The macro receives no arguments. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererHorizontalRule{\vfil\break} +\markdownBegin +This is the first page. + +*** + +This is the second page. +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is the first page. +> +> *** +> +> This is the second page. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + renderers = { + horizontalRule = \newpage, + }, +} +\begin{document} +\begin{markdown} +This is the first page. + +*** + +This is the second page. +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is the first page. +> +> *** +> +> This is the second page. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererHorizontalRule{\page[yes]} +\starttext +\startmarkdown +This is the first page. + +*** + +This is the second page. +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is the first page. +> +> *** +> +> This is the second page. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererHorizontalRule{% + \markdownRendererHorizontalRulePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Footnote Renderer +The \mdef{markdownRendererFootnote} macro represents a footnote. This macro +will only be produced, when the \Opt{footnotes} option is `true`. The +macro receives a single argument that corresponds to the footnote text. + +% \end{markdown} +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownOptionFootnotes{true} +\def\markdownRendererFootnote#1{ (and \lowercase{#1})} +\markdownBegin +This is some text[^1] and this is some other text[^2]. + + [^1]: this is a footnote + + [^2]: this is some other footnote +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is some text (and this is a footnote) and this is some other +> text (and this is some other footnote). + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[footnotes]{markdown} +\markdownSetup{ + renderers = { + footnote = { (and \MakeLowercase{#1})}, + }, +} +\begin{document} +\begin{markdown} +This is some text[^1] and this is some other text[^2]. + + [^1]: this is a footnote + + [^2]: this is some other footnote +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is some text (and this is a footnote) and this is some other +> text (and this is some other footnote). + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownOptionFootnotes{true} +\def\markdownRendererFootnote#1{ (and \lowercase{#1})} +\starttext +\startmarkdown +This is some text[^1] and this is some other text[^2]. + + [^1]: this is a footnote + + [^2]: this is some other footnote +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is some text (and this is a footnote) and this is some other +> text (and this is some other footnote). + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererFootnote{% + \markdownRendererFootnotePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Parenthesized Citations Renderer +The \mdef{markdownRendererCite} macro represents a string of one or more +parenthetical citations. This macro will only be produced, when the +\Opt{citations} option is `true`. The macro receives the parameter +`{`\meta{number of citations}`}` followed by \meta{suppress +author}`{`\meta{prenote}`}{`\meta{postnote}`}{`\meta{name}`}` repeated +\meta{number of citations} times. The \meta{suppress author} parameter is +either the token `-`, when the author's name is to be suppressed, or `+` +otherwise. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[citations]{markdown} +\newcount\citationsCounter +\newcount\citationsTotal +\makeatletter +\def\citations#1#2#3#4{% + a parenthesized citation \emph{#4} + \advance\citationsCounter by 1\relax + \ifx\relax#2\relax + \ifx\relax#3\relax\else + with a postfix \emph{#3}% + \fi + \else + with a prefix \emph{#2}% + \ifx\relax#3\relax\else + \ and a postfix \emph{#3}% + \fi + \fi + \ifnum\citationsCounter>\citationsTotal\relax + .% + \expandafter\@gobble + \else + , and + \fi\citations} +\makeatother +\markdownSetup{ + renderers = { + cite = {% + \citationsCounter=1% + \citationsTotal=#1% + This is + \expandafter\citations + }, + }, +} +\begin{document} +\begin{markdown} +[see @abrahams90, pp. 12; @eijkhout91, pp. 34] +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a parenthesized citation *abrahams90* with a prefix see +> and a postfix *pp. > 12*, and a citation *eijkhout91* with a +> postfix *pp. 34*. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererCite{% + \markdownRendererCitePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Text Citations Renderer +The \mdef{markdownRendererTextCite} macro represents a string of one or more +text citations. This macro will only be produced, when the +\Opt{citations} option is `true`. The macro receives parameters in the same +format as the \m{markdownRendererCite} macro. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[citations]{markdown} +\newcount\citationsCounter +\newcount\citationsTotal +\makeatletter +\def\citations#1#2#3#4{% + a text citation \emph{#4} + \advance\citationsCounter by 1\relax + \ifx\relax#2\relax + \ifx\relax#3\relax\else + with a postfix \emph{#3}% + \fi + \else + with a prefix \emph{#2}% + \ifx\relax#3\relax\else + \ and a postfix \emph{#3}% + \fi + \fi + \ifnum\citationsCounter>\citationsTotal\relax + .% + \expandafter\@gobble + \else + , and + \fi\citations} +\makeatother +\markdownSetup{ + renderers = { + textCite = {% + \citationsCounter=1% + \citationsTotal=#1% + This is + \expandafter\citations + }, + }, +} +\begin{document} +\begin{markdown} +@abrahams90 [pp. 12; also @eijkhout91] +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a text citation *abrahams90* with a postfix *pp. 12*, +> and a citation *eijkhout91* with a prefix *also*. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererTextCite{% + \markdownRendererTextCitePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +#### Table Renderer +The \mdef{markdownRendererTable} macro represents a table. This macro will only +be produced, when the \Opt{pipeTables} option is `true`. The macro receives the +parameters `{`\meta{caption}`}{`\meta{number of rows}`}{`\meta{number of columns}`}` +followed by `{`\meta{alignments}`}` and then by `{`\meta{row}`}` repeated +\meta{number of rows} times, where \meta{row} is `{`\meta{column}`}` repeated +\meta{number of columns} times, \meta{alignments} is \meta{alignment} repeated +\meta{number of columns} times, and \meta{alignment} is one of the following: + +- `d` -- The corresponding column has an unspecified (default) alignment. +- `l` -- The corresponding column is left-aligned. +- `c` -- The corresponding column is centered. +- `r` -- The corresponding column is right-aligned. + +% \end{markdown} +% +% \iffalse + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage[pipeTables, tableCaptions]{markdown} +\newcount\rowCounter +\newcount\columnCounter +\makeatletter +\def\processRow#1{% + \columnCounter=1% + \ifnum\rowCounter=0\relax + As for the alignment, + \else + In row \the\rowCounter, + \fi + \processColumn#1 + \advance\rowCounter by 1\relax + \ifnum\rowCounter>\rowTotal\relax + \expandafter\@gobble + \fi\processRow}% +\def\processColumn#1{% + column number \the\columnCounter{} + \ifnum\rowCounter=0\relax + \if#1d{}has default alignment\fi + \if#1l{}is left-aligned\fi + \if#1c{}is centered\fi + \if#1r{}is right-aligned\fi + \else + says \emph{#1}% + \fi + \advance\columnCounter by 1\relax + \ifnum\columnCounter<\columnTotal\relax, \fi + \ifnum\columnCounter=\columnTotal\relax, and \fi + \ifnum\columnCounter>\columnTotal\relax + .\expandafter\@gobble + \fi\processColumn}% +\makeatother +\markdownSetup{ + renderers = { + table = {% + This is a table with caption \emph{#1} that is #3 colums wide + and #2 rows long. + \rowCounter=0% + \def\rowTotal{#2}% + \def\columnTotal{#3}% + \processRow + }, + }, +} +\begin{document} +\begin{markdown} +| Right | Left | Default | Center | +|------:|:-----|---------|:------:| +| 12 | 12 | 12 | 12 | +| 123 | 123 | 123 | 123 | +| 1 | 1 | 1 | 1 | + + : Demonstration of pipe table syntax +\end{markdown} +\end{document} +\end{markdown} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> This is a table with caption *Demonstration of pipe table syntax* that is 4 +> colums wide and 4 rows long. As for the alignment, column number 1 is +> right-aligned, column number 2 is left-aligned, column number 3 has default +> alignment, and column number 4 is centered. In row 1, column number 1 says +> *Right*, column number 2 says *Left*, column number 3 says *Default*, and +> column number 4 says *Center*. In row 2, column number 1 says *12*, column +> number 2 says *12*, column number 3 says *12*, and column number 4 says *12*. +> In row 3, column number 1 says *123*, column number 2 says *123*, column +> number 3 says *123*, and column number 4 says *123*. In row 4, column number +> 1 says *1*, column number 2 says *1*, column number 3 says *1*, and column +> number 4 says *1*. + + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{macrocode} +\def\markdownRendererTable{% + \markdownRendererTablePrototype}% +% \end{macrocode} +% \par +% +% \iffalse +%</tex> +%<*manual-tokens> +% \fi +% +% \begin{markdown} + +### Token Renderer Prototypes + +% \label{sec:texrendererprototypes} +% +% \end{markdown} +% \iffalse + +By default, token renderers point to package-defined \TeX{} macros, further +referred to as *prototypes*, which provide useful default definitions. + +% \fi +% +% \iffalse + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\def\markdownRendererTildePrototype{% + Packages can specify token renderer prototypes.% +} +\markdownBegin +~ +\markdownEnd + +\def\markdownRendererTilde{% + User-defined token renderers take precedence.% +} +\markdownBegin +~ +\markdownEnd +\bye +``````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Packages can specify token renderer prototypes. +> +> User-defined token renderers take precedence. + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\markdownSetup{ + rendererPrototypes = { + tilde = {Packages can specify token renderer prototypes.}, + }, +} +\begin{document} +\begin{markdown} +~ +\end{markdown} + +\begin{markdown*}{ + renderers = { + tilde = {User-defined token renderers take precedence.}, + }, +} +~ +\end{markdown*} +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Packages can specify token renderer prototypes. +> +> User-defined token renderers take precedence. + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\def\markdownRendererTildePrototype{% + Packages can specify token renderer prototypes.% +} +\starttext +\startmarkdown +~ +\stopmarkdown + +\def\markdownRendererTilde{% + User-defined token renderers take precedence.% +} +\startmarkdown +~ +\stopmarkdown +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> Packages can specify token renderer prototypes. +> +> User-defined token renderers take precedence. + +%</manual-tokens> +%<*tex> +% \fi +% +% \begin{markdown} +% +% 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}). +% +% \end{markdown} +% \begin{macrocode} +\def\markdownRendererInterblockSeparatorPrototype{}% +\def\markdownRendererLineBreakPrototype{}% +\def\markdownRendererEllipsisPrototype{}% +\def\markdownRendererNbspPrototype{}% +\def\markdownRendererLeftBracePrototype{}% +\def\markdownRendererRightBracePrototype{}% +\def\markdownRendererDollarSignPrototype{}% +\def\markdownRendererPercentSignPrototype{}% +\def\markdownRendererAmpersandPrototype{}% +\def\markdownRendererUnderscorePrototype{}% +\def\markdownRendererHashPrototype{}% +\def\markdownRendererCircumflexPrototype{}% +\def\markdownRendererBackslashPrototype{}% +\def\markdownRendererTildePrototype{}% +\def\markdownRendererPipePrototype{}% +\def\markdownRendererCodeSpanPrototype#1{}% +\def\markdownRendererLinkPrototype#1#2#3#4{}% +\def\markdownRendererImagePrototype#1#2#3#4{}% +\def\markdownRendererContentBlockPrototype#1#2#3#4{}% +\def\markdownRendererContentBlockOnlineImagePrototype#1#2#3#4{}% +\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{}% +\def\markdownRendererUlBeginPrototype{}% +\def\markdownRendererUlBeginTightPrototype{}% +\def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% +\def\markdownRendererUlEndPrototype{}% +\def\markdownRendererUlEndTightPrototype{}% +\def\markdownRendererOlBeginPrototype{}% +\def\markdownRendererOlBeginTightPrototype{}% +\def\markdownRendererOlItemPrototype{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% +\def\markdownRendererOlEndPrototype{}% +\def\markdownRendererOlEndTightPrototype{}% +\def\markdownRendererDlBeginPrototype{}% +\def\markdownRendererDlBeginTightPrototype{}% +\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemEndPrototype{}% +\def\markdownRendererDlDefinitionBeginPrototype{}% +\def\markdownRendererDlDefinitionEndPrototype{}% +\def\markdownRendererDlEndPrototype{}% +\def\markdownRendererDlEndTightPrototype{}% +\def\markdownRendererEmphasisPrototype#1{}% +\def\markdownRendererStrongEmphasisPrototype#1{}% +\def\markdownRendererBlockQuoteBeginPrototype{}% +\def\markdownRendererBlockQuoteEndPrototype{}% +\def\markdownRendererInputVerbatimPrototype#1{}% +\def\markdownRendererInputFencedCodePrototype#1#2{}% +\def\markdownRendererHeadingOnePrototype#1{}% +\def\markdownRendererHeadingTwoPrototype#1{}% +\def\markdownRendererHeadingThreePrototype#1{}% +\def\markdownRendererHeadingFourPrototype#1{}% +\def\markdownRendererHeadingFivePrototype#1{}% +\def\markdownRendererHeadingSixPrototype#1{}% +\def\markdownRendererHorizontalRulePrototype{}% +\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% +\def\markdownRendererTablePrototype#1#2#3{}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Logging Facilities +% The \mdef{markdownInfo}, \mdef{markdownWarning}, and \mdef{markdownError} +% macros perform logging for the Markdown package. Their first argument +% specifies the text of the info, warning, or error message. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownInfo#1{}% +\def\markdownWarning#1{}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \m{markdownError} macro receives a second argument that provides a help +% text. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownError#1#2{}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% You may redefine these macros to redirect and process the info, warning, and +% error messages. +% +%### Miscellanea +% The \mdef{markdownMakeOther} macro is used by the package, when a \TeX{} +% engine that does not support direct Lua access is starting to buffer a text. +% The plain \TeX{} implementation changes the category code of plain \TeX{} +% special characters to other, but there may be other active characters that +% may break the output. This macro should temporarily change the category of +% these to *other*. +% +% \end{markdown} +% \begin{macrocode} +\let\markdownMakeOther\relax +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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 *other*. The second argument specifies the token sequence +% that will actually be inserted into the document, when the ending token +% sequence has been found. +% +% \end{markdown} +% \begin{macrocode} +\let\markdownReadAndConvert\relax +\begingroup +% \end{macrocode} +% \begin{markdown} +% Locally swap the category code of the backslash symbol (`\`) with the pipe +% symbol (`|`). This is required in order that all the special symbols in the +% first argument of the `markdownReadAndConvert` macro have the category code +% *other*. +% +% \end{markdown} +% \begin{macrocode} + \catcode`\|=0\catcode`\\=12% + |gdef|markdownBegin{% + |markdownReadAndConvert{\markdownEnd}% + {|markdownEnd}}% +|endgroup +% \end{macrocode} +% \begin{markdown} +% 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 `]]` (regardless of the category code of the bracket symbol (`]`)). +% +% The \mdef{markdownMode} macro specifies how the plain \TeX{} implementation +% interfaces with the Lua interface. The valid values and their meaning are +% as follows: +% +% - `0` – Shell escape via the 18 output file stream +% - `1` – Shell escape via the Lua \luam{os.execute} method +% - `2` – Direct Lua access +% +% By defining the macro, the user can coerce the package to use a specific mode. +% If the user does not define the macro prior to loading the plain \TeX{} +% implementation, the correct value will be automatically detected. The outcome +% of changing the value of \m{markdownMode} after the implementation has been +% loaded is undefined. +% +% \end{markdown} +% \begin{macrocode} +\ifx\markdownMode\undefined + \ifx\directlua\undefined + \def\markdownMode{0}% + \else + \def\markdownMode{2}% + \fi +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% The following macros are no longer a part of the plain \TeX{} interface and +% are only defined for backwards compatibility: +% +% \end{markdown} +% \begin{macrocode} +\def\markdownLuaRegisterIBCallback#1{\relax}% +\def\markdownLuaUnregisterIBCallback#1{\relax}% +% \end{macrocode} +% \iffalse +%</tex> +% \fi +% \par +% \begin{markdown} +% +% \LaTeX{} Interface +%------------------- +% \label{sec:latexinterface} +% +% \end{markdown} +% \iffalse +%<*manual-interfaces> + +### \LaTeX{} + +The \LaTeX{} interface provides the same level of functionality as the plain +\TeX{} interface by using the plain \TeX{} interface behind the scenes. Unlike +the plain \TeX{} interface, the \LaTeX{} interface uses familiar \LaTeX{} +idioms, such as package options and environments. + +The \LaTeX{} interface accepts the same options as the plain \TeX{} interface, +but now the options are specified as \meta{key}${}={}$\meta{value} pairs and +they are passed either as package options, in the \m{markdownSetup} command, or +as parameters for the \envm{markdown*} \LaTeX{} environment. + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +$\sqrt{-1}$ *equals* $i$ +\end{markdown} + +\begin{markdown*}{hybrid} +$\sqrt{-1}$ *equals* $i$ +\end{markdown*} + +\end{document} +``````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +Invoking pdfTeX should have the same effect: +``` sh +pdflatex --shell-escape document.tex +`````` + +%</manual-interfaces> +%<*latex> +% \fi +% \begin{markdown} +% +% 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 `markdown.sty` file, which +% can be loaded from the \LaTeX{} document preamble as follows: +% \end{markdown} +% \begin{Verbatim}[commandchars=\\\{\},gobble=2] +% \textbackslash{}usepackage[\textrm{\meta{options}}]\{markdown\} +% \end{Verbatim} +% \begin{markdown} +% where \meta{options} are the \LaTeX{} interface options (see Section +% \ref{sec:latexoptions}). Note that \meta{options} inside the \m{usepackage} +% macro may not set the `markdownRenderers` (see Section +% \ref{sec:latexrenderers}) and `markdownRendererPrototypes` (see Section +% \ref{sec:latexrendererprototypes}) keys. This limitation is due to the way +% \Hologo{LaTeX2e} parses package options. +% +% \end{markdown} +% \par +% \begin{markdown} +% +%### 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 influence this markdown document fragment. +% +% \end{markdown} +% \begin{macrocode} +\newenvironment{markdown}\relax\relax +\newenvironment{markdown*}[1]\relax\relax +% \end{macrocode} +% \markdownBegin +% +% 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: +% ``` tex +% \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} +% ``````` +% +% 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: +% ``` tex +% \documentclass{article} +% \usepackage{markdown} +% \begin{document} +% % ... +% \markdownInput[smartEllipses]{hello.md} +% % ... +% \end{document} +% ``````` +% +%### Options +% \label{sec:latexoptions} +% +% The \LaTeX{} options are represented by a comma-delimited list of +% \meta{key}`=`\meta{value} pairs. For boolean options, the `=`\meta{value} +% part is optional, and \meta{key} will be interpreted as \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. +% +% \markdownEnd +% \begin{macrocode} +\newcommand\markdownSetup[1]{% + \setkeys{markdownOptions}{#1}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Plain \TeX{} Interface Options +% The following options map directly to the option macros exposed by the plain +% \TeX{} interface (see Section \ref{sec:texoptions}). +% +% \end{markdown} +% \begin{macrocode} +\define@key{markdownOptions}{helperScriptFileName}{% + \def\markdownOptionHelperScriptFileName{#1}}% +\define@key{markdownOptions}{inputTempFileName}{% + \def\markdownOptionInputTempFileName{#1}}% +\define@key{markdownOptions}{outputTempFileName}{% + \def\markdownOptionOutputTempFileName{#1}}% +\define@key{markdownOptions}{errorTempFileName}{% + \def\markdownOptionErrorTempFileName{#1}}% +\define@key{markdownOptions}{cacheDir}{% + \def\markdownOptionCacheDir{#1}}% +\define@key{markdownOptions}{outputDir}{% + \def\markdownOptionOutputDir{#1}}% +\define@key{markdownOptions}{blankBeforeBlockquote}[true]{% + \def\markdownOptionBlankBeforeBlockquote{#1}}% +\define@key{markdownOptions}{blankBeforeCodeFence}[true]{% + \def\markdownOptionBlankBeforeCodeFence{#1}}% +\define@key{markdownOptions}{blankBeforeHeading}[true]{% + \def\markdownOptionBlankBeforeHeading{#1}}% +\define@key{markdownOptions}{breakableBlockquotes}[true]{% + \def\markdownOptionBreakableBlockquotes{#1}}% +\define@key{markdownOptions}{citations}[true]{% + \def\markdownOptionCitations{#1}}% +\define@key{markdownOptions}{citationNbsps}[true]{% + \def\markdownOptionCitationNbsps{#1}}% +\define@key{markdownOptions}{contentBlocks}[true]{% + \def\markdownOptionContentBlocks{#1}}% +\define@key{markdownOptions}{codeSpans}[true]{% + \def\markdownOptionCodeSpans{#1}}% +\define@key{markdownOptions}{contentBlocksLanguageMap}{% + \def\markdownOptionContentBlocksLanguageMap{#1}}% +\define@key{markdownOptions}{definitionLists}[true]{% + \def\markdownOptionDefinitionLists{#1}}% +\define@key{markdownOptions}{footnotes}[true]{% + \def\markdownOptionFootnotes{#1}}% +\define@key{markdownOptions}{fencedCode}[true]{% + \def\markdownOptionFencedCode{#1}}% +\define@key{markdownOptions}{hashEnumerators}[true]{% + \def\markdownOptionHashEnumerators{#1}}% +\define@key{markdownOptions}{headerAttributes}[true]{% + \def\markdownOptionHeaderAttributes{#1}}% +\define@key{markdownOptions}{html}[true]{% + \def\markdownOptionHtml{#1}}% +\define@key{markdownOptions}{hybrid}[true]{% + \def\markdownOptionHybrid{#1}}% +\define@key{markdownOptions}{inlineFootnotes}[true]{% + \def\markdownOptionInlineFootnotes{#1}}% +\define@key{markdownOptions}{pipeTables}[true]{% + \def\markdownOptionPipeTables{#1}}% +\define@key{markdownOptions}{preserveTabs}[true]{% + \def\markdownOptionPreserveTabs{#1}}% +\define@key{markdownOptions}{smartEllipses}[true]{% + \def\markdownOptionSmartEllipses{#1}}% +\define@key{markdownOptions}{shiftHeadings}{% + \def\markdownOptionShiftHeadings{#1}}% +\define@key{markdownOptions}{slice}{% + \def\markdownOptionSlice{#1}}% +\define@key{markdownOptions}{startNumber}[true]{% + \def\markdownOptionStartNumber{#1}}% +\define@key{markdownOptions}{tableCaptions}[true]{% + \def\markdownOptionTableCaptions{#1}}% +\define@key{markdownOptions}{tightLists}[true]{% + \def\markdownOptionTightLists{#1}}% +\define@key{markdownOptions}{underscores}[true]{% + \def\markdownOptionUnderscores{#1}}% +\define@key{markdownOptions}{stripPercentSigns}[true]{% + \def\markdownOptionStripPercentSigns{#1}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The following example \LaTeX{} code showcases a possible configuration of +% plain \TeX{} interface options \m{markdownOptionHybrid}, +% \m{markdownOptionSmartEllipses}, and \m{markdownOptionCacheDir}. +% ``` tex +% \markdownSetup{ +% hybrid, +% smartEllipses, +% cacheDir = /tmp, +% } +% ``````` +% +%#### Plain \TeX{} Markdown Token Renderers +% \label{sec:latexrenderers} +% +% The \LaTeX{} interface recognizes an option with the `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}). +% +% \end{markdown} +% \begin{macrocode} +\define@key{markdownRenderers}{interblockSeparator}{% + \renewcommand\markdownRendererInterblockSeparator{#1}}% +\define@key{markdownRenderers}{lineBreak}{% + \renewcommand\markdownRendererLineBreak{#1}}% +\define@key{markdownRenderers}{ellipsis}{% + \renewcommand\markdownRendererEllipsis{#1}}% +\define@key{markdownRenderers}{nbsp}{% + \renewcommand\markdownRendererNbsp{#1}}% +\define@key{markdownRenderers}{leftBrace}{% + \renewcommand\markdownRendererLeftBrace{#1}}% +\define@key{markdownRenderers}{rightBrace}{% + \renewcommand\markdownRendererRightBrace{#1}}% +\define@key{markdownRenderers}{dollarSign}{% + \renewcommand\markdownRendererDollarSign{#1}}% +\define@key{markdownRenderers}{percentSign}{% + \renewcommand\markdownRendererPercentSign{#1}}% +\define@key{markdownRenderers}{ampersand}{% + \renewcommand\markdownRendererAmpersand{#1}}% +\define@key{markdownRenderers}{underscore}{% + \renewcommand\markdownRendererUnderscore{#1}}% +\define@key{markdownRenderers}{hash}{% + \renewcommand\markdownRendererHash{#1}}% +\define@key{markdownRenderers}{circumflex}{% + \renewcommand\markdownRendererCircumflex{#1}}% +\define@key{markdownRenderers}{backslash}{% + \renewcommand\markdownRendererBackslash{#1}}% +\define@key{markdownRenderers}{tilde}{% + \renewcommand\markdownRendererTilde{#1}}% +\define@key{markdownRenderers}{pipe}{% + \renewcommand\markdownRendererPipe{#1}}% +\define@key{markdownRenderers}{codeSpan}{% + \renewcommand\markdownRendererCodeSpan[1]{#1}}% +\define@key{markdownRenderers}{link}{% + \renewcommand\markdownRendererLink[4]{#1}}% +\define@key{markdownRenderers}{contentBlock}{% + \renewcommand\markdownRendererContentBlock[4]{#1}}% +\define@key{markdownRenderers}{contentBlockOnlineImage}{% + \renewcommand\markdownRendererContentBlockOnlineImage[4]{#1}}% +\define@key{markdownRenderers}{contentBlockCode}{% + \renewcommand\markdownRendererContentBlockCode[5]{#1}}% +\define@key{markdownRenderers}{image}{% + \renewcommand\markdownRendererImage[4]{#1}}% +\define@key{markdownRenderers}{ulBegin}{% + \renewcommand\markdownRendererUlBegin{#1}}% +\define@key{markdownRenderers}{ulBeginTight}{% + \renewcommand\markdownRendererUlBeginTight{#1}}% +\define@key{markdownRenderers}{ulItem}{% + \renewcommand\markdownRendererUlItem{#1}}% +\define@key{markdownRenderers}{ulItemEnd}{% + \renewcommand\markdownRendererUlItemEnd{#1}}% +\define@key{markdownRenderers}{ulEnd}{% + \renewcommand\markdownRendererUlEnd{#1}}% +\define@key{markdownRenderers}{ulEndTight}{% + \renewcommand\markdownRendererUlEndTight{#1}}% +\define@key{markdownRenderers}{olBegin}{% + \renewcommand\markdownRendererOlBegin{#1}}% +\define@key{markdownRenderers}{olBeginTight}{% + \renewcommand\markdownRendererOlBeginTight{#1}}% +\define@key{markdownRenderers}{olItem}{% + \renewcommand\markdownRendererOlItem{#1}}% +\define@key{markdownRenderers}{olItemWithNumber}{% + \renewcommand\markdownRendererOlItemWithNumber[1]{#1}}% +\define@key{markdownRenderers}{olItemEnd}{% + \renewcommand\markdownRendererOlItemEnd{#1}}% +\define@key{markdownRenderers}{olEnd}{% + \renewcommand\markdownRendererOlEnd{#1}}% +\define@key{markdownRenderers}{olEndTight}{% + \renewcommand\markdownRendererOlEndTight{#1}}% +\define@key{markdownRenderers}{dlBegin}{% + \renewcommand\markdownRendererDlBegin{#1}}% +\define@key{markdownRenderers}{dlBeginTight}{% + \renewcommand\markdownRendererDlBeginTight{#1}}% +\define@key{markdownRenderers}{dlItem}{% + \renewcommand\markdownRendererDlItem[1]{#1}}% +\define@key{markdownRenderers}{dlItemEnd}{% + \renewcommand\markdownRendererDlItemEnd{#1}}% +\define@key{markdownRenderers}{dlDefinitionBegin}{% + \renewcommand\markdownRendererDlDefinitionBegin{#1}}% +\define@key{markdownRenderers}{dlDefinitionEnd}{% + \renewcommand\markdownRendererDlDefinitionEnd{#1}}% +\define@key{markdownRenderers}{dlEnd}{% + \renewcommand\markdownRendererDlEnd{#1}}% +\define@key{markdownRenderers}{dlEndTight}{% + \renewcommand\markdownRendererDlEndTight{#1}}% +\define@key{markdownRenderers}{emphasis}{% + \renewcommand\markdownRendererEmphasis[1]{#1}}% +\define@key{markdownRenderers}{strongEmphasis}{% + \renewcommand\markdownRendererStrongEmphasis[1]{#1}}% +\define@key{markdownRenderers}{blockQuoteBegin}{% + \renewcommand\markdownRendererBlockQuoteBegin{#1}}% +\define@key{markdownRenderers}{blockQuoteEnd}{% + \renewcommand\markdownRendererBlockQuoteEnd{#1}}% +\define@key{markdownRenderers}{inputVerbatim}{% + \renewcommand\markdownRendererInputVerbatim[1]{#1}}% +\define@key{markdownRenderers}{inputFencedCode}{% + \renewcommand\markdownRendererInputFencedCode[2]{#1}}% +\define@key{markdownRenderers}{headingOne}{% + \renewcommand\markdownRendererHeadingOne[1]{#1}}% +\define@key{markdownRenderers}{headingTwo}{% + \renewcommand\markdownRendererHeadingTwo[1]{#1}}% +\define@key{markdownRenderers}{headingThree}{% + \renewcommand\markdownRendererHeadingThree[1]{#1}}% +\define@key{markdownRenderers}{headingFour}{% + \renewcommand\markdownRendererHeadingFour[1]{#1}}% +\define@key{markdownRenderers}{headingFive}{% + \renewcommand\markdownRendererHeadingFive[1]{#1}}% +\define@key{markdownRenderers}{headingSix}{% + \renewcommand\markdownRendererHeadingSix[1]{#1}}% +\define@key{markdownRenderers}{horizontalRule}{% + \renewcommand\markdownRendererHorizontalRule{#1}}% +\define@key{markdownRenderers}{footnote}{% + \renewcommand\markdownRendererFootnote[1]{#1}}% +\define@key{markdownRenderers}{cite}{% + \renewcommand\markdownRendererCite[1]{#1}}% +\define@key{markdownRenderers}{textCite}{% + \renewcommand\markdownRendererTextCite[1]{#1}}% +\define@key{markdownRenderers}{table}{% + \renewcommand\markdownRendererTable[3]{#1}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The following example \LaTeX{} code showcases a possible configuration of the +% \m{markdownRendererLink} and \m{markdownRendererEmphasis} markdown token +% renderers. +% ``` tex +% \markdownSetup{ +% renderers = { +% link = {#4}, % Render links as the link title. +% emphasis = {\emph{#1}}, % Render emphasized text via `\emph`. +% } +% } +% ``````` +% +%#### Plain \TeX{} Markdown Token Renderer Prototypes +% \label{sec:latexrendererprototypes} +% The \LaTeX{} interface recognizes an option with the `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}). +% +% \end{markdown} +% \begin{macrocode} +\define@key{markdownRendererPrototypes}{interblockSeparator}{% + \renewcommand\markdownRendererInterblockSeparatorPrototype{#1}}% +\define@key{markdownRendererPrototypes}{lineBreak}{% + \renewcommand\markdownRendererLineBreakPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ellipsis}{% + \renewcommand\markdownRendererEllipsisPrototype{#1}}% +\define@key{markdownRendererPrototypes}{nbsp}{% + \renewcommand\markdownRendererNbspPrototype{#1}}% +\define@key{markdownRendererPrototypes}{leftBrace}{% + \renewcommand\markdownRendererLeftBracePrototype{#1}}% +\define@key{markdownRendererPrototypes}{rightBrace}{% + \renewcommand\markdownRendererRightBracePrototype{#1}}% +\define@key{markdownRendererPrototypes}{dollarSign}{% + \renewcommand\markdownRendererDollarSignPrototype{#1}}% +\define@key{markdownRendererPrototypes}{percentSign}{% + \renewcommand\markdownRendererPercentSignPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ampersand}{% + \renewcommand\markdownRendererAmpersandPrototype{#1}}% +\define@key{markdownRendererPrototypes}{underscore}{% + \renewcommand\markdownRendererUnderscorePrototype{#1}}% +\define@key{markdownRendererPrototypes}{hash}{% + \renewcommand\markdownRendererHashPrototype{#1}}% +\define@key{markdownRendererPrototypes}{circumflex}{% + \renewcommand\markdownRendererCircumflexPrototype{#1}}% +\define@key{markdownRendererPrototypes}{backslash}{% + \renewcommand\markdownRendererBackslashPrototype{#1}}% +\define@key{markdownRendererPrototypes}{tilde}{% + \renewcommand\markdownRendererTildePrototype{#1}}% +\define@key{markdownRendererPrototypes}{pipe}{% + \renewcommand\markdownRendererPipePrototype{#1}}% +\define@key{markdownRendererPrototypes}{codeSpan}{% + \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{link}{% + \renewcommand\markdownRendererLinkPrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlock}{% + \renewcommand\markdownRendererContentBlockPrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlockOnlineImage}{% + \renewcommand\markdownRendererContentBlockOnlineImagePrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{contentBlockCode}{% + \renewcommand\markdownRendererContentBlockCodePrototype[5]{#1}}% +\define@key{markdownRendererPrototypes}{image}{% + \renewcommand\markdownRendererImagePrototype[4]{#1}}% +\define@key{markdownRendererPrototypes}{ulBegin}{% + \renewcommand\markdownRendererUlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulBeginTight}{% + \renewcommand\markdownRendererUlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulItem}{% + \renewcommand\markdownRendererUlItemPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulItemEnd}{% + \renewcommand\markdownRendererUlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulEnd}{% + \renewcommand\markdownRendererUlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{ulEndTight}{% + \renewcommand\markdownRendererUlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olBegin}{% + \renewcommand\markdownRendererOlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olBeginTight}{% + \renewcommand\markdownRendererOlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olItem}{% + \renewcommand\markdownRendererOlItemPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olItemWithNumber}{% + \renewcommand\markdownRendererOlItemWithNumberPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{olItemEnd}{% + \renewcommand\markdownRendererOlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olEnd}{% + \renewcommand\markdownRendererOlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{olEndTight}{% + \renewcommand\markdownRendererOlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlBegin}{% + \renewcommand\markdownRendererDlBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlBeginTight}{% + \renewcommand\markdownRendererDlBeginTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlItem}{% + \renewcommand\markdownRendererDlItemPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{dlItemEnd}{% + \renewcommand\markdownRendererDlItemEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlDefinitionBegin}{% + \renewcommand\markdownRendererDlDefinitionBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlDefinitionEnd}{% + \renewcommand\markdownRendererDlDefinitionEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlEnd}{% + \renewcommand\markdownRendererDlEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{dlEndTight}{% + \renewcommand\markdownRendererDlEndTightPrototype{#1}}% +\define@key{markdownRendererPrototypes}{emphasis}{% + \renewcommand\markdownRendererEmphasisPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{strongEmphasis}{% + \renewcommand\markdownRendererStrongEmphasisPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{blockQuoteBegin}{% + \renewcommand\markdownRendererBlockQuoteBeginPrototype{#1}}% +\define@key{markdownRendererPrototypes}{blockQuoteEnd}{% + \renewcommand\markdownRendererBlockQuoteEndPrototype{#1}}% +\define@key{markdownRendererPrototypes}{inputVerbatim}{% + \renewcommand\markdownRendererInputVerbatimPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{inputFencedCode}{% + \renewcommand\markdownRendererInputFencedCodePrototype[2]{#1}}% +\define@key{markdownRendererPrototypes}{headingOne}{% + \renewcommand\markdownRendererHeadingOnePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingTwo}{% + \renewcommand\markdownRendererHeadingTwoPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingThree}{% + \renewcommand\markdownRendererHeadingThreePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingFour}{% + \renewcommand\markdownRendererHeadingFourPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingFive}{% + \renewcommand\markdownRendererHeadingFivePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{headingSix}{% + \renewcommand\markdownRendererHeadingSixPrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{horizontalRule}{% + \renewcommand\markdownRendererHorizontalRulePrototype{#1}}% +\define@key{markdownRendererPrototypes}{footnote}{% + \renewcommand\markdownRendererFootnotePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{cite}{% + \renewcommand\markdownRendererCitePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{textCite}{% + \renewcommand\markdownRendererTextCitePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{table}{% + \renewcommand\markdownRendererTablePrototype[3]{#1}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The following example \LaTeX{} code showcases a possible configuration of the +% \m{markdownRendererImagePrototype} and \m{markdownRendererCodeSpanPrototype} +% markdown token renderer prototypes. +% ``` tex +% \markdownSetup{ +% rendererPrototypes = { +% image = {\includegraphics{#2}}, +% codeSpan = {\texttt{#1}}, % Render inline code via `\texttt`. +% } +% } +% ``````` +% +% \iffalse +%</latex> +%<*context> +% \fi +% \Hologo{ConTeXt} Interface +%--------------------------- +% \label{sec:contextinterface} +% +% \iffalse +%</context> +%<*manual-interfaces> + +### \Hologo{ConTeXt} + +The \Hologo{ConTeXt} interface provides the same level of functionality as the +plain \TeX{} interface by using the plain \TeX{} interface behind the scenes. +Unlike the plain \TeX{} interface, the \Hologo{ConTeXt} interface uses familiar +\Hologo{ConTeXt} idioms, such as environments. + +The \Hologo{ConTeXt} interface accepts the same options as the plain \TeX{} +interface. + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +$\sqrt{-1}$ *equals* $i$. +\stopmarkdown + +\def\markdownOptionHybrid{true} +\startmarkdown +$\sqrt{-1}$ *equals* $i$. +\stopmarkdown + +\stoptext +``````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> \$\\sqrt{-1}\$ *equals* \$i\$. +> +> √-̅1̅ *equals* $i$. + +Invoking pdfTeX should have the same effect: +``` sh +texexec --passon=--shell-escape document.tex +`````` + +%</manual-interfaces> +%<*context> +% \fi +% +% 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}). +% +% \end{markdown} +% \begin{macrocode} +\writestatus{loading}{ConTeXt User Module / markdown}% +\unprotect +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \Hologo{ConTeXt} interface is implemented by the +% `t-markdown.tex` \Hologo{ConTeXt} module file that can be loaded as follows: +% ``` tex +% \usemodule[t][markdown] +% ``````` +% \noindent It is expected that the special plain \TeX{} characters have the +% expected category codes, when \m{input}ting the file. +% +%### Typesetting Markdown +% The interface exposes the \mdef{startmarkdown} and \mdef{stopmarkdown} macro +% pair for the typesetting of a markdown document fragment. +% +% \end{markdown} +% \begin{macrocode} +\let\startmarkdown\relax +\let\stopmarkdown\relax +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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: +% ``` tex +% \usemodule[t][markdown] +% \starttext +% \startmarkdown +% _Hello_ **world** ... +% \stopmarkdown +% \stoptext +% ``````` +% +% Implementation +%=============== +% \label{sec:implementation} +% This part of the documentation 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 +% +% 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}). +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +%### Utility Functions +% This section documents the utility functions used by the plain \TeX{} +% writer and the markdown reader. These functions are encapsulated in the +% `util` object. The functions were originally located in the +% `lunamark/util.lua` file in the Lunamark Lua module. +% +% \end{markdown} +% \begin{macrocode} +local util = {} +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \luamdef{util.err} method prints an error message `msg` and exits. +% If `exit_code` is provided, it specifies the exit code. Otherwise, the +% exit code will be 1. +% +% \end{markdown} +% \begin{macrocode} +function util.err(msg, exit_code) + io.stderr:write("markdown.lua: " .. msg .. "\n") + os.exit(exit_code or 1) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \luamdef{util.cache} method computes the digest of `string` and +% `salt`, adds the `suffix` and looks into the directory `dir`, whether a +% file with such a name exists. If it does not, it gets created with +% `transform(string)` as its content. The filename is then returned. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{util.table_copy} method creates a shallow copy of a table `t` +% and its metatable. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{util.expand_tabs_in_line} expands tabs in string `s`. If +% `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 @ierusalimschy13 [Chapter 21]. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{util.walk} method walks a rope `t`, applying a function `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. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{util.flatten} method flattens an array `ary` that does not +% contain cycles and returns the result. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{util.rope_to_string} method converts a rope `rope` to a +% string and returns it. For the definition of a rope, see the definition of +% the \luam{util.walk} method. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% 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. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% Given an array `ary` and a string `x`, the \luamdef{util.intersperse} +% method returns an array `new`, such that `ary[i] == new[2*(i-1)+1]` and +% `new[2*i] == x` for all $1\leq`i`\leq`#ary`$. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% Given an array `ary` and a function `f`, the \luamdef{util.map} method +% returns an array `new`, such that `new[i] == f(ary[i])` for all +% $1\leq`i`\leq`#ary`$. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% Given a table `char_escapes` mapping escapable characters to escaped +% strings and optionally a table `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 `string.gsub` +% built-in method. +% +% \end{markdown} +% \begin{macrocode} +function util.escaper(char_escapes, string_escapes) +% \end{macrocode} +% \begin{markdown} +% Build a string of escapable characters. +% \end{markdown} +% \begin{macrocode} + local char_escapes_list = "" + for i,_ in pairs(char_escapes) do + char_escapes_list = char_escapes_list .. i + end +% \end{macrocode} +% \begin{markdown} +% Create an \pkg{LPeg} capture `escapable` that produces the escaped string +% corresponding to the matched escapable character. +% \end{markdown} +% \begin{macrocode} + local escapable = S(char_escapes_list) / char_escapes +% \end{macrocode} +% \begin{markdown} +% If `string_escapes` is provided, turn `escapable` into the +% $$\sum^^B{(`k`, `v`)\in`string_escapes`}`P(k) / v` + `escapable`$$ +% capture that replaces any occurance of the string `k` with the string +% `v` for each $(`k`, `v`)\in`string_escapes`$. Note that the pattern +% summation is not commutative and its operands are inspected in the +% summation order during the matching. As a corrolary, the strings always +% take precedence over the characters. +% +% \end{markdown} +% \begin{macrocode} + if string_escapes then + for k,v in pairs(string_escapes) do + escapable = P(k) / v + escapable + end + end +% \end{macrocode} +% \begin{markdown} +% Create an \pkg{LPeg} capture `escape_string` that captures anything +% `escapable` does and matches any other unmatched characters. +% \end{markdown} +% \begin{macrocode} + local escape_string = Cs((escapable + any)^0) +% \end{macrocode} +% \begin{markdown} +% Return a function that matches the input string `s` against the +% `escape_string` capture. +% \end{markdown} +% \begin{macrocode} + return function(s) + return lpeg.match(escape_string, s) + end +end +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \luamdef{util.pathname} method produces a pathname out of a directory +% name `dir` and a filename `file` and returns it. +% +% \end{markdown} +% \begin{macrocode} +function util.pathname(dir, file) + if #dir == 0 then + return file + else + return dir .. "/" .. file + end +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%### HTML Entities +% This section documents the \acro{HTML} entities recognized by the +% markdown reader. These functions are encapsulated in the `entities` +% object. The functions were originally located in the +% `lunamark/entities.lua` file in the Lunamark Lua module. +% +% \end{markdown} +% \begin{macrocode} +local entities = {} + +local character_entities = { + ["Tab"] = 9, + ["NewLine"] = 10, + ["excl"] = 33, + ["quot"] = 34, + ["QUOT"] = 34, + ["num"] = 35, + ["dollar"] = 36, + ["percnt"] = 37, + ["amp"] = 38, + ["AMP"] = 38, + ["apos"] = 39, + ["lpar"] = 40, + ["rpar"] = 41, + ["ast"] = 42, + ["midast"] = 42, + ["plus"] = 43, + ["comma"] = 44, + ["period"] = 46, + ["sol"] = 47, + ["colon"] = 58, + ["semi"] = 59, + ["lt"] = 60, + ["LT"] = 60, + ["equals"] = 61, + ["gt"] = 62, + ["GT"] = 62, + ["quest"] = 63, + ["commat"] = 64, + ["lsqb"] = 91, + ["lbrack"] = 91, + ["bsol"] = 92, + ["rsqb"] = 93, + ["rbrack"] = 93, + ["Hat"] = 94, + ["lowbar"] = 95, + ["grave"] = 96, + ["DiacriticalGrave"] = 96, + ["lcub"] = 123, + ["lbrace"] = 123, + ["verbar"] = 124, + ["vert"] = 124, + ["VerticalLine"] = 124, + ["rcub"] = 125, + ["rbrace"] = 125, + ["nbsp"] = 160, + ["NonBreakingSpace"] = 160, + ["iexcl"] = 161, + ["cent"] = 162, + ["pound"] = 163, + ["curren"] = 164, + ["yen"] = 165, + ["brvbar"] = 166, + ["sect"] = 167, + ["Dot"] = 168, + ["die"] = 168, + ["DoubleDot"] = 168, + ["uml"] = 168, + ["copy"] = 169, + ["COPY"] = 169, + ["ordf"] = 170, + ["laquo"] = 171, + ["not"] = 172, + ["shy"] = 173, + ["reg"] = 174, + ["circledR"] = 174, + ["REG"] = 174, + ["macr"] = 175, + ["OverBar"] = 175, + ["strns"] = 175, + ["deg"] = 176, + ["plusmn"] = 177, + ["pm"] = 177, + ["PlusMinus"] = 177, + ["sup2"] = 178, + ["sup3"] = 179, + ["acute"] = 180, + ["DiacriticalAcute"] = 180, + ["micro"] = 181, + ["para"] = 182, + ["middot"] = 183, + ["centerdot"] = 183, + ["CenterDot"] = 183, + ["cedil"] = 184, + ["Cedilla"] = 184, + ["sup1"] = 185, + ["ordm"] = 186, + ["raquo"] = 187, + ["frac14"] = 188, + ["frac12"] = 189, + ["half"] = 189, + ["frac34"] = 190, + ["iquest"] = 191, + ["Agrave"] = 192, + ["Aacute"] = 193, + ["Acirc"] = 194, + ["Atilde"] = 195, + ["Auml"] = 196, + ["Aring"] = 197, + ["AElig"] = 198, + ["Ccedil"] = 199, + ["Egrave"] = 200, + ["Eacute"] = 201, + ["Ecirc"] = 202, + ["Euml"] = 203, + ["Igrave"] = 204, + ["Iacute"] = 205, + ["Icirc"] = 206, + ["Iuml"] = 207, + ["ETH"] = 208, + ["Ntilde"] = 209, + ["Ograve"] = 210, + ["Oacute"] = 211, + ["Ocirc"] = 212, + ["Otilde"] = 213, + ["Ouml"] = 214, + ["times"] = 215, + ["Oslash"] = 216, + ["Ugrave"] = 217, + ["Uacute"] = 218, + ["Ucirc"] = 219, + ["Uuml"] = 220, + ["Yacute"] = 221, + ["THORN"] = 222, + ["szlig"] = 223, + ["agrave"] = 224, + ["aacute"] = 225, + ["acirc"] = 226, + ["atilde"] = 227, + ["auml"] = 228, + ["aring"] = 229, + ["aelig"] = 230, + ["ccedil"] = 231, + ["egrave"] = 232, + ["eacute"] = 233, + ["ecirc"] = 234, + ["euml"] = 235, + ["igrave"] = 236, + ["iacute"] = 237, + ["icirc"] = 238, + ["iuml"] = 239, + ["eth"] = 240, + ["ntilde"] = 241, + ["ograve"] = 242, + ["oacute"] = 243, + ["ocirc"] = 244, + ["otilde"] = 245, + ["ouml"] = 246, + ["divide"] = 247, + ["div"] = 247, + ["oslash"] = 248, + ["ugrave"] = 249, + ["uacute"] = 250, + ["ucirc"] = 251, + ["uuml"] = 252, + ["yacute"] = 253, + ["thorn"] = 254, + ["yuml"] = 255, + ["Amacr"] = 256, + ["amacr"] = 257, + ["Abreve"] = 258, + ["abreve"] = 259, + ["Aogon"] = 260, + ["aogon"] = 261, + ["Cacute"] = 262, + ["cacute"] = 263, + ["Ccirc"] = 264, + ["ccirc"] = 265, + ["Cdot"] = 266, + ["cdot"] = 267, + ["Ccaron"] = 268, + ["ccaron"] = 269, + ["Dcaron"] = 270, + ["dcaron"] = 271, + ["Dstrok"] = 272, + ["dstrok"] = 273, + ["Emacr"] = 274, + ["emacr"] = 275, + ["Edot"] = 278, + ["edot"] = 279, + ["Eogon"] = 280, + ["eogon"] = 281, + ["Ecaron"] = 282, + ["ecaron"] = 283, + ["Gcirc"] = 284, + ["gcirc"] = 285, + ["Gbreve"] = 286, + ["gbreve"] = 287, + ["Gdot"] = 288, + ["gdot"] = 289, + ["Gcedil"] = 290, + ["Hcirc"] = 292, + ["hcirc"] = 293, + ["Hstrok"] = 294, + ["hstrok"] = 295, + ["Itilde"] = 296, + ["itilde"] = 297, + ["Imacr"] = 298, + ["imacr"] = 299, + ["Iogon"] = 302, + ["iogon"] = 303, + ["Idot"] = 304, + ["imath"] = 305, + ["inodot"] = 305, + ["IJlig"] = 306, + ["ijlig"] = 307, + ["Jcirc"] = 308, + ["jcirc"] = 309, + ["Kcedil"] = 310, + ["kcedil"] = 311, + ["kgreen"] = 312, + ["Lacute"] = 313, + ["lacute"] = 314, + ["Lcedil"] = 315, + ["lcedil"] = 316, + ["Lcaron"] = 317, + ["lcaron"] = 318, + ["Lmidot"] = 319, + ["lmidot"] = 320, + ["Lstrok"] = 321, + ["lstrok"] = 322, + ["Nacute"] = 323, + ["nacute"] = 324, + ["Ncedil"] = 325, + ["ncedil"] = 326, + ["Ncaron"] = 327, + ["ncaron"] = 328, + ["napos"] = 329, + ["ENG"] = 330, + ["eng"] = 331, + ["Omacr"] = 332, + ["omacr"] = 333, + ["Odblac"] = 336, + ["odblac"] = 337, + ["OElig"] = 338, + ["oelig"] = 339, + ["Racute"] = 340, + ["racute"] = 341, + ["Rcedil"] = 342, + ["rcedil"] = 343, + ["Rcaron"] = 344, + ["rcaron"] = 345, + ["Sacute"] = 346, + ["sacute"] = 347, + ["Scirc"] = 348, + ["scirc"] = 349, + ["Scedil"] = 350, + ["scedil"] = 351, + ["Scaron"] = 352, + ["scaron"] = 353, + ["Tcedil"] = 354, + ["tcedil"] = 355, + ["Tcaron"] = 356, + ["tcaron"] = 357, + ["Tstrok"] = 358, + ["tstrok"] = 359, + ["Utilde"] = 360, + ["utilde"] = 361, + ["Umacr"] = 362, + ["umacr"] = 363, + ["Ubreve"] = 364, + ["ubreve"] = 365, + ["Uring"] = 366, + ["uring"] = 367, + ["Udblac"] = 368, + ["udblac"] = 369, + ["Uogon"] = 370, + ["uogon"] = 371, + ["Wcirc"] = 372, + ["wcirc"] = 373, + ["Ycirc"] = 374, + ["ycirc"] = 375, + ["Yuml"] = 376, + ["Zacute"] = 377, + ["zacute"] = 378, + ["Zdot"] = 379, + ["zdot"] = 380, + ["Zcaron"] = 381, + ["zcaron"] = 382, + ["fnof"] = 402, + ["imped"] = 437, + ["gacute"] = 501, + ["jmath"] = 567, + ["circ"] = 710, + ["caron"] = 711, + ["Hacek"] = 711, + ["breve"] = 728, + ["Breve"] = 728, + ["dot"] = 729, + ["DiacriticalDot"] = 729, + ["ring"] = 730, + ["ogon"] = 731, + ["tilde"] = 732, + ["DiacriticalTilde"] = 732, + ["dblac"] = 733, + ["DiacriticalDoubleAcute"] = 733, + ["DownBreve"] = 785, + ["UnderBar"] = 818, + ["Alpha"] = 913, + ["Beta"] = 914, + ["Gamma"] = 915, + ["Delta"] = 916, + ["Epsilon"] = 917, + ["Zeta"] = 918, + ["Eta"] = 919, + ["Theta"] = 920, + ["Iota"] = 921, + ["Kappa"] = 922, + ["Lambda"] = 923, + ["Mu"] = 924, + ["Nu"] = 925, + ["Xi"] = 926, + ["Omicron"] = 927, + ["Pi"] = 928, + ["Rho"] = 929, + ["Sigma"] = 931, + ["Tau"] = 932, + ["Upsilon"] = 933, + ["Phi"] = 934, + ["Chi"] = 935, + ["Psi"] = 936, + ["Omega"] = 937, + ["alpha"] = 945, + ["beta"] = 946, + ["gamma"] = 947, + ["delta"] = 948, + ["epsiv"] = 949, + ["varepsilon"] = 949, + ["epsilon"] = 949, + ["zeta"] = 950, + ["eta"] = 951, + ["theta"] = 952, + ["iota"] = 953, + ["kappa"] = 954, + ["lambda"] = 955, + ["mu"] = 956, + ["nu"] = 957, + ["xi"] = 958, + ["omicron"] = 959, + ["pi"] = 960, + ["rho"] = 961, + ["sigmav"] = 962, + ["varsigma"] = 962, + ["sigmaf"] = 962, + ["sigma"] = 963, + ["tau"] = 964, + ["upsi"] = 965, + ["upsilon"] = 965, + ["phi"] = 966, + ["phiv"] = 966, + ["varphi"] = 966, + ["chi"] = 967, + ["psi"] = 968, + ["omega"] = 969, + ["thetav"] = 977, + ["vartheta"] = 977, + ["thetasym"] = 977, + ["Upsi"] = 978, + ["upsih"] = 978, + ["straightphi"] = 981, + ["piv"] = 982, + ["varpi"] = 982, + ["Gammad"] = 988, + ["gammad"] = 989, + ["digamma"] = 989, + ["kappav"] = 1008, + ["varkappa"] = 1008, + ["rhov"] = 1009, + ["varrho"] = 1009, + ["epsi"] = 1013, + ["straightepsilon"] = 1013, + ["bepsi"] = 1014, + ["backepsilon"] = 1014, + ["IOcy"] = 1025, + ["DJcy"] = 1026, + ["GJcy"] = 1027, + ["Jukcy"] = 1028, + ["DScy"] = 1029, + ["Iukcy"] = 1030, + ["YIcy"] = 1031, + ["Jsercy"] = 1032, + ["LJcy"] = 1033, + ["NJcy"] = 1034, + ["TSHcy"] = 1035, + ["KJcy"] = 1036, + ["Ubrcy"] = 1038, + ["DZcy"] = 1039, + ["Acy"] = 1040, + ["Bcy"] = 1041, + ["Vcy"] = 1042, + ["Gcy"] = 1043, + ["Dcy"] = 1044, + ["IEcy"] = 1045, + ["ZHcy"] = 1046, + ["Zcy"] = 1047, + ["Icy"] = 1048, + ["Jcy"] = 1049, + ["Kcy"] = 1050, + ["Lcy"] = 1051, + ["Mcy"] = 1052, + ["Ncy"] = 1053, + ["Ocy"] = 1054, + ["Pcy"] = 1055, + ["Rcy"] = 1056, + ["Scy"] = 1057, + ["Tcy"] = 1058, + ["Ucy"] = 1059, + ["Fcy"] = 1060, + ["KHcy"] = 1061, + ["TScy"] = 1062, + ["CHcy"] = 1063, + ["SHcy"] = 1064, + ["SHCHcy"] = 1065, + ["HARDcy"] = 1066, + ["Ycy"] = 1067, + ["SOFTcy"] = 1068, + ["Ecy"] = 1069, + ["YUcy"] = 1070, + ["YAcy"] = 1071, + ["acy"] = 1072, + ["bcy"] = 1073, + ["vcy"] = 1074, + ["gcy"] = 1075, + ["dcy"] = 1076, + ["iecy"] = 1077, + ["zhcy"] = 1078, + ["zcy"] = 1079, + ["icy"] = 1080, + ["jcy"] = 1081, + ["kcy"] = 1082, + ["lcy"] = 1083, + ["mcy"] = 1084, + ["ncy"] = 1085, + ["ocy"] = 1086, + ["pcy"] = 1087, + ["rcy"] = 1088, + ["scy"] = 1089, + ["tcy"] = 1090, + ["ucy"] = 1091, + ["fcy"] = 1092, + ["khcy"] = 1093, + ["tscy"] = 1094, + ["chcy"] = 1095, + ["shcy"] = 1096, + ["shchcy"] = 1097, + ["hardcy"] = 1098, + ["ycy"] = 1099, + ["softcy"] = 1100, + ["ecy"] = 1101, + ["yucy"] = 1102, + ["yacy"] = 1103, + ["iocy"] = 1105, + ["djcy"] = 1106, + ["gjcy"] = 1107, + ["jukcy"] = 1108, + ["dscy"] = 1109, + ["iukcy"] = 1110, + ["yicy"] = 1111, + ["jsercy"] = 1112, + ["ljcy"] = 1113, + ["njcy"] = 1114, + ["tshcy"] = 1115, + ["kjcy"] = 1116, + ["ubrcy"] = 1118, + ["dzcy"] = 1119, + ["ensp"] = 8194, + ["emsp"] = 8195, + ["emsp13"] = 8196, + ["emsp14"] = 8197, + ["numsp"] = 8199, + ["puncsp"] = 8200, + ["thinsp"] = 8201, + ["ThinSpace"] = 8201, + ["hairsp"] = 8202, + ["VeryThinSpace"] = 8202, + ["ZeroWidthSpace"] = 8203, + ["NegativeVeryThinSpace"] = 8203, + ["NegativeThinSpace"] = 8203, + ["NegativeMediumSpace"] = 8203, + ["NegativeThickSpace"] = 8203, + ["zwnj"] = 8204, + ["zwj"] = 8205, + ["lrm"] = 8206, + ["rlm"] = 8207, + ["hyphen"] = 8208, + ["dash"] = 8208, + ["ndash"] = 8211, + ["mdash"] = 8212, + ["horbar"] = 8213, + ["Verbar"] = 8214, + ["Vert"] = 8214, + ["lsquo"] = 8216, + ["OpenCurlyQuote"] = 8216, + ["rsquo"] = 8217, + ["rsquor"] = 8217, + ["CloseCurlyQuote"] = 8217, + ["lsquor"] = 8218, + ["sbquo"] = 8218, + ["ldquo"] = 8220, + ["OpenCurlyDoubleQuote"] = 8220, + ["rdquo"] = 8221, + ["rdquor"] = 8221, + ["CloseCurlyDoubleQuote"] = 8221, + ["ldquor"] = 8222, + ["bdquo"] = 8222, + ["dagger"] = 8224, + ["Dagger"] = 8225, + ["ddagger"] = 8225, + ["bull"] = 8226, + ["bullet"] = 8226, + ["nldr"] = 8229, + ["hellip"] = 8230, + ["mldr"] = 8230, + ["permil"] = 8240, + ["pertenk"] = 8241, + ["prime"] = 8242, + ["Prime"] = 8243, + ["tprime"] = 8244, + ["bprime"] = 8245, + ["backprime"] = 8245, + ["lsaquo"] = 8249, + ["rsaquo"] = 8250, + ["oline"] = 8254, + ["caret"] = 8257, + ["hybull"] = 8259, + ["frasl"] = 8260, + ["bsemi"] = 8271, + ["qprime"] = 8279, + ["MediumSpace"] = 8287, + ["NoBreak"] = 8288, + ["ApplyFunction"] = 8289, + ["af"] = 8289, + ["InvisibleTimes"] = 8290, + ["it"] = 8290, + ["InvisibleComma"] = 8291, + ["ic"] = 8291, + ["euro"] = 8364, + ["tdot"] = 8411, + ["TripleDot"] = 8411, + ["DotDot"] = 8412, + ["Copf"] = 8450, + ["complexes"] = 8450, + ["incare"] = 8453, + ["gscr"] = 8458, + ["hamilt"] = 8459, + ["HilbertSpace"] = 8459, + ["Hscr"] = 8459, + ["Hfr"] = 8460, + ["Poincareplane"] = 8460, + ["quaternions"] = 8461, + ["Hopf"] = 8461, + ["planckh"] = 8462, + ["planck"] = 8463, + ["hbar"] = 8463, + ["plankv"] = 8463, + ["hslash"] = 8463, + ["Iscr"] = 8464, + ["imagline"] = 8464, + ["image"] = 8465, + ["Im"] = 8465, + ["imagpart"] = 8465, + ["Ifr"] = 8465, + ["Lscr"] = 8466, + ["lagran"] = 8466, + ["Laplacetrf"] = 8466, + ["ell"] = 8467, + ["Nopf"] = 8469, + ["naturals"] = 8469, + ["numero"] = 8470, + ["copysr"] = 8471, + ["weierp"] = 8472, + ["wp"] = 8472, + ["Popf"] = 8473, + ["primes"] = 8473, + ["rationals"] = 8474, + ["Qopf"] = 8474, + ["Rscr"] = 8475, + ["realine"] = 8475, + ["real"] = 8476, + ["Re"] = 8476, + ["realpart"] = 8476, + ["Rfr"] = 8476, + ["reals"] = 8477, + ["Ropf"] = 8477, + ["rx"] = 8478, + ["trade"] = 8482, + ["TRADE"] = 8482, + ["integers"] = 8484, + ["Zopf"] = 8484, + ["ohm"] = 8486, + ["mho"] = 8487, + ["Zfr"] = 8488, + ["zeetrf"] = 8488, + ["iiota"] = 8489, + ["angst"] = 8491, + ["bernou"] = 8492, + ["Bernoullis"] = 8492, + ["Bscr"] = 8492, + ["Cfr"] = 8493, + ["Cayleys"] = 8493, + ["escr"] = 8495, + ["Escr"] = 8496, + ["expectation"] = 8496, + ["Fscr"] = 8497, + ["Fouriertrf"] = 8497, + ["phmmat"] = 8499, + ["Mellintrf"] = 8499, + ["Mscr"] = 8499, + ["order"] = 8500, + ["orderof"] = 8500, + ["oscr"] = 8500, + ["alefsym"] = 8501, + ["aleph"] = 8501, + ["beth"] = 8502, + ["gimel"] = 8503, + ["daleth"] = 8504, + ["CapitalDifferentialD"] = 8517, + ["DD"] = 8517, + ["DifferentialD"] = 8518, + ["dd"] = 8518, + ["ExponentialE"] = 8519, + ["exponentiale"] = 8519, + ["ee"] = 8519, + ["ImaginaryI"] = 8520, + ["ii"] = 8520, + ["frac13"] = 8531, + ["frac23"] = 8532, + ["frac15"] = 8533, + ["frac25"] = 8534, + ["frac35"] = 8535, + ["frac45"] = 8536, + ["frac16"] = 8537, + ["frac56"] = 8538, + ["frac18"] = 8539, + ["frac38"] = 8540, + ["frac58"] = 8541, + ["frac78"] = 8542, + ["larr"] = 8592, + ["leftarrow"] = 8592, + ["LeftArrow"] = 8592, + ["slarr"] = 8592, + ["ShortLeftArrow"] = 8592, + ["uarr"] = 8593, + ["uparrow"] = 8593, + ["UpArrow"] = 8593, + ["ShortUpArrow"] = 8593, + ["rarr"] = 8594, + ["rightarrow"] = 8594, + ["RightArrow"] = 8594, + ["srarr"] = 8594, + ["ShortRightArrow"] = 8594, + ["darr"] = 8595, + ["downarrow"] = 8595, + ["DownArrow"] = 8595, + ["ShortDownArrow"] = 8595, + ["harr"] = 8596, + ["leftrightarrow"] = 8596, + ["LeftRightArrow"] = 8596, + ["varr"] = 8597, + ["updownarrow"] = 8597, + ["UpDownArrow"] = 8597, + ["nwarr"] = 8598, + ["UpperLeftArrow"] = 8598, + ["nwarrow"] = 8598, + ["nearr"] = 8599, + ["UpperRightArrow"] = 8599, + ["nearrow"] = 8599, + ["searr"] = 8600, + ["searrow"] = 8600, + ["LowerRightArrow"] = 8600, + ["swarr"] = 8601, + ["swarrow"] = 8601, + ["LowerLeftArrow"] = 8601, + ["nlarr"] = 8602, + ["nleftarrow"] = 8602, + ["nrarr"] = 8603, + ["nrightarrow"] = 8603, + ["rarrw"] = 8605, + ["rightsquigarrow"] = 8605, + ["Larr"] = 8606, + ["twoheadleftarrow"] = 8606, + ["Uarr"] = 8607, + ["Rarr"] = 8608, + ["twoheadrightarrow"] = 8608, + ["Darr"] = 8609, + ["larrtl"] = 8610, + ["leftarrowtail"] = 8610, + ["rarrtl"] = 8611, + ["rightarrowtail"] = 8611, + ["LeftTeeArrow"] = 8612, + ["mapstoleft"] = 8612, + ["UpTeeArrow"] = 8613, + ["mapstoup"] = 8613, + ["map"] = 8614, + ["RightTeeArrow"] = 8614, + ["mapsto"] = 8614, + ["DownTeeArrow"] = 8615, + ["mapstodown"] = 8615, + ["larrhk"] = 8617, + ["hookleftarrow"] = 8617, + ["rarrhk"] = 8618, + ["hookrightarrow"] = 8618, + ["larrlp"] = 8619, + ["looparrowleft"] = 8619, + ["rarrlp"] = 8620, + ["looparrowright"] = 8620, + ["harrw"] = 8621, + ["leftrightsquigarrow"] = 8621, + ["nharr"] = 8622, + ["nleftrightarrow"] = 8622, + ["lsh"] = 8624, + ["Lsh"] = 8624, + ["rsh"] = 8625, + ["Rsh"] = 8625, + ["ldsh"] = 8626, + ["rdsh"] = 8627, + ["crarr"] = 8629, + ["cularr"] = 8630, + ["curvearrowleft"] = 8630, + ["curarr"] = 8631, + ["curvearrowright"] = 8631, + ["olarr"] = 8634, + ["circlearrowleft"] = 8634, + ["orarr"] = 8635, + ["circlearrowright"] = 8635, + ["lharu"] = 8636, + ["LeftVector"] = 8636, + ["leftharpoonup"] = 8636, + ["lhard"] = 8637, + ["leftharpoondown"] = 8637, + ["DownLeftVector"] = 8637, + ["uharr"] = 8638, + ["upharpoonright"] = 8638, + ["RightUpVector"] = 8638, + ["uharl"] = 8639, + ["upharpoonleft"] = 8639, + ["LeftUpVector"] = 8639, + ["rharu"] = 8640, + ["RightVector"] = 8640, + ["rightharpoonup"] = 8640, + ["rhard"] = 8641, + ["rightharpoondown"] = 8641, + ["DownRightVector"] = 8641, + ["dharr"] = 8642, + ["RightDownVector"] = 8642, + ["downharpoonright"] = 8642, + ["dharl"] = 8643, + ["LeftDownVector"] = 8643, + ["downharpoonleft"] = 8643, + ["rlarr"] = 8644, + ["rightleftarrows"] = 8644, + ["RightArrowLeftArrow"] = 8644, + ["udarr"] = 8645, + ["UpArrowDownArrow"] = 8645, + ["lrarr"] = 8646, + ["leftrightarrows"] = 8646, + ["LeftArrowRightArrow"] = 8646, + ["llarr"] = 8647, + ["leftleftarrows"] = 8647, + ["uuarr"] = 8648, + ["upuparrows"] = 8648, + ["rrarr"] = 8649, + ["rightrightarrows"] = 8649, + ["ddarr"] = 8650, + ["downdownarrows"] = 8650, + ["lrhar"] = 8651, + ["ReverseEquilibrium"] = 8651, + ["leftrightharpoons"] = 8651, + ["rlhar"] = 8652, + ["rightleftharpoons"] = 8652, + ["Equilibrium"] = 8652, + ["nlArr"] = 8653, + ["nLeftarrow"] = 8653, + ["nhArr"] = 8654, + ["nLeftrightarrow"] = 8654, + ["nrArr"] = 8655, + ["nRightarrow"] = 8655, + ["lArr"] = 8656, + ["Leftarrow"] = 8656, + ["DoubleLeftArrow"] = 8656, + ["uArr"] = 8657, + ["Uparrow"] = 8657, + ["DoubleUpArrow"] = 8657, + ["rArr"] = 8658, + ["Rightarrow"] = 8658, + ["Implies"] = 8658, + ["DoubleRightArrow"] = 8658, + ["dArr"] = 8659, + ["Downarrow"] = 8659, + ["DoubleDownArrow"] = 8659, + ["hArr"] = 8660, + ["Leftrightarrow"] = 8660, + ["DoubleLeftRightArrow"] = 8660, + ["iff"] = 8660, + ["vArr"] = 8661, + ["Updownarrow"] = 8661, + ["DoubleUpDownArrow"] = 8661, + ["nwArr"] = 8662, + ["neArr"] = 8663, + ["seArr"] = 8664, + ["swArr"] = 8665, + ["lAarr"] = 8666, + ["Lleftarrow"] = 8666, + ["rAarr"] = 8667, + ["Rrightarrow"] = 8667, + ["zigrarr"] = 8669, + ["larrb"] = 8676, + ["LeftArrowBar"] = 8676, + ["rarrb"] = 8677, + ["RightArrowBar"] = 8677, + ["duarr"] = 8693, + ["DownArrowUpArrow"] = 8693, + ["loarr"] = 8701, + ["roarr"] = 8702, + ["hoarr"] = 8703, + ["forall"] = 8704, + ["ForAll"] = 8704, + ["comp"] = 8705, + ["complement"] = 8705, + ["part"] = 8706, + ["PartialD"] = 8706, + ["exist"] = 8707, + ["Exists"] = 8707, + ["nexist"] = 8708, + ["NotExists"] = 8708, + ["nexists"] = 8708, + ["empty"] = 8709, + ["emptyset"] = 8709, + ["emptyv"] = 8709, + ["varnothing"] = 8709, + ["nabla"] = 8711, + ["Del"] = 8711, + ["isin"] = 8712, + ["isinv"] = 8712, + ["Element"] = 8712, + ["in"] = 8712, + ["notin"] = 8713, + ["NotElement"] = 8713, + ["notinva"] = 8713, + ["niv"] = 8715, + ["ReverseElement"] = 8715, + ["ni"] = 8715, + ["SuchThat"] = 8715, + ["notni"] = 8716, + ["notniva"] = 8716, + ["NotReverseElement"] = 8716, + ["prod"] = 8719, + ["Product"] = 8719, + ["coprod"] = 8720, + ["Coproduct"] = 8720, + ["sum"] = 8721, + ["Sum"] = 8721, + ["minus"] = 8722, + ["mnplus"] = 8723, + ["mp"] = 8723, + ["MinusPlus"] = 8723, + ["plusdo"] = 8724, + ["dotplus"] = 8724, + ["setmn"] = 8726, + ["setminus"] = 8726, + ["Backslash"] = 8726, + ["ssetmn"] = 8726, + ["smallsetminus"] = 8726, + ["lowast"] = 8727, + ["compfn"] = 8728, + ["SmallCircle"] = 8728, + ["radic"] = 8730, + ["Sqrt"] = 8730, + ["prop"] = 8733, + ["propto"] = 8733, + ["Proportional"] = 8733, + ["vprop"] = 8733, + ["varpropto"] = 8733, + ["infin"] = 8734, + ["angrt"] = 8735, + ["ang"] = 8736, + ["angle"] = 8736, + ["angmsd"] = 8737, + ["measuredangle"] = 8737, + ["angsph"] = 8738, + ["mid"] = 8739, + ["VerticalBar"] = 8739, + ["smid"] = 8739, + ["shortmid"] = 8739, + ["nmid"] = 8740, + ["NotVerticalBar"] = 8740, + ["nsmid"] = 8740, + ["nshortmid"] = 8740, + ["par"] = 8741, + ["parallel"] = 8741, + ["DoubleVerticalBar"] = 8741, + ["spar"] = 8741, + ["shortparallel"] = 8741, + ["npar"] = 8742, + ["nparallel"] = 8742, + ["NotDoubleVerticalBar"] = 8742, + ["nspar"] = 8742, + ["nshortparallel"] = 8742, + ["and"] = 8743, + ["wedge"] = 8743, + ["or"] = 8744, + ["vee"] = 8744, + ["cap"] = 8745, + ["cup"] = 8746, + ["int"] = 8747, + ["Integral"] = 8747, + ["Int"] = 8748, + ["tint"] = 8749, + ["iiint"] = 8749, + ["conint"] = 8750, + ["oint"] = 8750, + ["ContourIntegral"] = 8750, + ["Conint"] = 8751, + ["DoubleContourIntegral"] = 8751, + ["Cconint"] = 8752, + ["cwint"] = 8753, + ["cwconint"] = 8754, + ["ClockwiseContourIntegral"] = 8754, + ["awconint"] = 8755, + ["CounterClockwiseContourIntegral"] = 8755, + ["there4"] = 8756, + ["therefore"] = 8756, + ["Therefore"] = 8756, + ["becaus"] = 8757, + ["because"] = 8757, + ["Because"] = 8757, + ["ratio"] = 8758, + ["Colon"] = 8759, + ["Proportion"] = 8759, + ["minusd"] = 8760, + ["dotminus"] = 8760, + ["mDDot"] = 8762, + ["homtht"] = 8763, + ["sim"] = 8764, + ["Tilde"] = 8764, + ["thksim"] = 8764, + ["thicksim"] = 8764, + ["bsim"] = 8765, + ["backsim"] = 8765, + ["ac"] = 8766, + ["mstpos"] = 8766, + ["acd"] = 8767, + ["wreath"] = 8768, + ["VerticalTilde"] = 8768, + ["wr"] = 8768, + ["nsim"] = 8769, + ["NotTilde"] = 8769, + ["esim"] = 8770, + ["EqualTilde"] = 8770, + ["eqsim"] = 8770, + ["sime"] = 8771, + ["TildeEqual"] = 8771, + ["simeq"] = 8771, + ["nsime"] = 8772, + ["nsimeq"] = 8772, + ["NotTildeEqual"] = 8772, + ["cong"] = 8773, + ["TildeFullEqual"] = 8773, + ["simne"] = 8774, + ["ncong"] = 8775, + ["NotTildeFullEqual"] = 8775, + ["asymp"] = 8776, + ["ap"] = 8776, + ["TildeTilde"] = 8776, + ["approx"] = 8776, + ["thkap"] = 8776, + ["thickapprox"] = 8776, + ["nap"] = 8777, + ["NotTildeTilde"] = 8777, + ["napprox"] = 8777, + ["ape"] = 8778, + ["approxeq"] = 8778, + ["apid"] = 8779, + ["bcong"] = 8780, + ["backcong"] = 8780, + ["asympeq"] = 8781, + ["CupCap"] = 8781, + ["bump"] = 8782, + ["HumpDownHump"] = 8782, + ["Bumpeq"] = 8782, + ["bumpe"] = 8783, + ["HumpEqual"] = 8783, + ["bumpeq"] = 8783, + ["esdot"] = 8784, + ["DotEqual"] = 8784, + ["doteq"] = 8784, + ["eDot"] = 8785, + ["doteqdot"] = 8785, + ["efDot"] = 8786, + ["fallingdotseq"] = 8786, + ["erDot"] = 8787, + ["risingdotseq"] = 8787, + ["colone"] = 8788, + ["coloneq"] = 8788, + ["Assign"] = 8788, + ["ecolon"] = 8789, + ["eqcolon"] = 8789, + ["ecir"] = 8790, + ["eqcirc"] = 8790, + ["cire"] = 8791, + ["circeq"] = 8791, + ["wedgeq"] = 8793, + ["veeeq"] = 8794, + ["trie"] = 8796, + ["triangleq"] = 8796, + ["equest"] = 8799, + ["questeq"] = 8799, + ["ne"] = 8800, + ["NotEqual"] = 8800, + ["equiv"] = 8801, + ["Congruent"] = 8801, + ["nequiv"] = 8802, + ["NotCongruent"] = 8802, + ["le"] = 8804, + ["leq"] = 8804, + ["ge"] = 8805, + ["GreaterEqual"] = 8805, + ["geq"] = 8805, + ["lE"] = 8806, + ["LessFullEqual"] = 8806, + ["leqq"] = 8806, + ["gE"] = 8807, + ["GreaterFullEqual"] = 8807, + ["geqq"] = 8807, + ["lnE"] = 8808, + ["lneqq"] = 8808, + ["gnE"] = 8809, + ["gneqq"] = 8809, + ["Lt"] = 8810, + ["NestedLessLess"] = 8810, + ["ll"] = 8810, + ["Gt"] = 8811, + ["NestedGreaterGreater"] = 8811, + ["gg"] = 8811, + ["twixt"] = 8812, + ["between"] = 8812, + ["NotCupCap"] = 8813, + ["nlt"] = 8814, + ["NotLess"] = 8814, + ["nless"] = 8814, + ["ngt"] = 8815, + ["NotGreater"] = 8815, + ["ngtr"] = 8815, + ["nle"] = 8816, + ["NotLessEqual"] = 8816, + ["nleq"] = 8816, + ["nge"] = 8817, + ["NotGreaterEqual"] = 8817, + ["ngeq"] = 8817, + ["lsim"] = 8818, + ["LessTilde"] = 8818, + ["lesssim"] = 8818, + ["gsim"] = 8819, + ["gtrsim"] = 8819, + ["GreaterTilde"] = 8819, + ["nlsim"] = 8820, + ["NotLessTilde"] = 8820, + ["ngsim"] = 8821, + ["NotGreaterTilde"] = 8821, + ["lg"] = 8822, + ["lessgtr"] = 8822, + ["LessGreater"] = 8822, + ["gl"] = 8823, + ["gtrless"] = 8823, + ["GreaterLess"] = 8823, + ["ntlg"] = 8824, + ["NotLessGreater"] = 8824, + ["ntgl"] = 8825, + ["NotGreaterLess"] = 8825, + ["pr"] = 8826, + ["Precedes"] = 8826, + ["prec"] = 8826, + ["sc"] = 8827, + ["Succeeds"] = 8827, + ["succ"] = 8827, + ["prcue"] = 8828, + ["PrecedesSlantEqual"] = 8828, + ["preccurlyeq"] = 8828, + ["sccue"] = 8829, + ["SucceedsSlantEqual"] = 8829, + ["succcurlyeq"] = 8829, + ["prsim"] = 8830, + ["precsim"] = 8830, + ["PrecedesTilde"] = 8830, + ["scsim"] = 8831, + ["succsim"] = 8831, + ["SucceedsTilde"] = 8831, + ["npr"] = 8832, + ["nprec"] = 8832, + ["NotPrecedes"] = 8832, + ["nsc"] = 8833, + ["nsucc"] = 8833, + ["NotSucceeds"] = 8833, + ["sub"] = 8834, + ["subset"] = 8834, + ["sup"] = 8835, + ["supset"] = 8835, + ["Superset"] = 8835, + ["nsub"] = 8836, + ["nsup"] = 8837, + ["sube"] = 8838, + ["SubsetEqual"] = 8838, + ["subseteq"] = 8838, + ["supe"] = 8839, + ["supseteq"] = 8839, + ["SupersetEqual"] = 8839, + ["nsube"] = 8840, + ["nsubseteq"] = 8840, + ["NotSubsetEqual"] = 8840, + ["nsupe"] = 8841, + ["nsupseteq"] = 8841, + ["NotSupersetEqual"] = 8841, + ["subne"] = 8842, + ["subsetneq"] = 8842, + ["supne"] = 8843, + ["supsetneq"] = 8843, + ["cupdot"] = 8845, + ["uplus"] = 8846, + ["UnionPlus"] = 8846, + ["sqsub"] = 8847, + ["SquareSubset"] = 8847, + ["sqsubset"] = 8847, + ["sqsup"] = 8848, + ["SquareSuperset"] = 8848, + ["sqsupset"] = 8848, + ["sqsube"] = 8849, + ["SquareSubsetEqual"] = 8849, + ["sqsubseteq"] = 8849, + ["sqsupe"] = 8850, + ["SquareSupersetEqual"] = 8850, + ["sqsupseteq"] = 8850, + ["sqcap"] = 8851, + ["SquareIntersection"] = 8851, + ["sqcup"] = 8852, + ["SquareUnion"] = 8852, + ["oplus"] = 8853, + ["CirclePlus"] = 8853, + ["ominus"] = 8854, + ["CircleMinus"] = 8854, + ["otimes"] = 8855, + ["CircleTimes"] = 8855, + ["osol"] = 8856, + ["odot"] = 8857, + ["CircleDot"] = 8857, + ["ocir"] = 8858, + ["circledcirc"] = 8858, + ["oast"] = 8859, + ["circledast"] = 8859, + ["odash"] = 8861, + ["circleddash"] = 8861, + ["plusb"] = 8862, + ["boxplus"] = 8862, + ["minusb"] = 8863, + ["boxminus"] = 8863, + ["timesb"] = 8864, + ["boxtimes"] = 8864, + ["sdotb"] = 8865, + ["dotsquare"] = 8865, + ["vdash"] = 8866, + ["RightTee"] = 8866, + ["dashv"] = 8867, + ["LeftTee"] = 8867, + ["top"] = 8868, + ["DownTee"] = 8868, + ["bottom"] = 8869, + ["bot"] = 8869, + ["perp"] = 8869, + ["UpTee"] = 8869, + ["models"] = 8871, + ["vDash"] = 8872, + ["DoubleRightTee"] = 8872, + ["Vdash"] = 8873, + ["Vvdash"] = 8874, + ["VDash"] = 8875, + ["nvdash"] = 8876, + ["nvDash"] = 8877, + ["nVdash"] = 8878, + ["nVDash"] = 8879, + ["prurel"] = 8880, + ["vltri"] = 8882, + ["vartriangleleft"] = 8882, + ["LeftTriangle"] = 8882, + ["vrtri"] = 8883, + ["vartriangleright"] = 8883, + ["RightTriangle"] = 8883, + ["ltrie"] = 8884, + ["trianglelefteq"] = 8884, + ["LeftTriangleEqual"] = 8884, + ["rtrie"] = 8885, + ["trianglerighteq"] = 8885, + ["RightTriangleEqual"] = 8885, + ["origof"] = 8886, + ["imof"] = 8887, + ["mumap"] = 8888, + ["multimap"] = 8888, + ["hercon"] = 8889, + ["intcal"] = 8890, + ["intercal"] = 8890, + ["veebar"] = 8891, + ["barvee"] = 8893, + ["angrtvb"] = 8894, + ["lrtri"] = 8895, + ["xwedge"] = 8896, + ["Wedge"] = 8896, + ["bigwedge"] = 8896, + ["xvee"] = 8897, + ["Vee"] = 8897, + ["bigvee"] = 8897, + ["xcap"] = 8898, + ["Intersection"] = 8898, + ["bigcap"] = 8898, + ["xcup"] = 8899, + ["Union"] = 8899, + ["bigcup"] = 8899, + ["diam"] = 8900, + ["diamond"] = 8900, + ["Diamond"] = 8900, + ["sdot"] = 8901, + ["sstarf"] = 8902, + ["Star"] = 8902, + ["divonx"] = 8903, + ["divideontimes"] = 8903, + ["bowtie"] = 8904, + ["ltimes"] = 8905, + ["rtimes"] = 8906, + ["lthree"] = 8907, + ["leftthreetimes"] = 8907, + ["rthree"] = 8908, + ["rightthreetimes"] = 8908, + ["bsime"] = 8909, + ["backsimeq"] = 8909, + ["cuvee"] = 8910, + ["curlyvee"] = 8910, + ["cuwed"] = 8911, + ["curlywedge"] = 8911, + ["Sub"] = 8912, + ["Subset"] = 8912, + ["Sup"] = 8913, + ["Supset"] = 8913, + ["Cap"] = 8914, + ["Cup"] = 8915, + ["fork"] = 8916, + ["pitchfork"] = 8916, + ["epar"] = 8917, + ["ltdot"] = 8918, + ["lessdot"] = 8918, + ["gtdot"] = 8919, + ["gtrdot"] = 8919, + ["Ll"] = 8920, + ["Gg"] = 8921, + ["ggg"] = 8921, + ["leg"] = 8922, + ["LessEqualGreater"] = 8922, + ["lesseqgtr"] = 8922, + ["gel"] = 8923, + ["gtreqless"] = 8923, + ["GreaterEqualLess"] = 8923, + ["cuepr"] = 8926, + ["curlyeqprec"] = 8926, + ["cuesc"] = 8927, + ["curlyeqsucc"] = 8927, + ["nprcue"] = 8928, + ["NotPrecedesSlantEqual"] = 8928, + ["nsccue"] = 8929, + ["NotSucceedsSlantEqual"] = 8929, + ["nsqsube"] = 8930, + ["NotSquareSubsetEqual"] = 8930, + ["nsqsupe"] = 8931, + ["NotSquareSupersetEqual"] = 8931, + ["lnsim"] = 8934, + ["gnsim"] = 8935, + ["prnsim"] = 8936, + ["precnsim"] = 8936, + ["scnsim"] = 8937, + ["succnsim"] = 8937, + ["nltri"] = 8938, + ["ntriangleleft"] = 8938, + ["NotLeftTriangle"] = 8938, + ["nrtri"] = 8939, + ["ntriangleright"] = 8939, + ["NotRightTriangle"] = 8939, + ["nltrie"] = 8940, + ["ntrianglelefteq"] = 8940, + ["NotLeftTriangleEqual"] = 8940, + ["nrtrie"] = 8941, + ["ntrianglerighteq"] = 8941, + ["NotRightTriangleEqual"] = 8941, + ["vellip"] = 8942, + ["ctdot"] = 8943, + ["utdot"] = 8944, + ["dtdot"] = 8945, + ["disin"] = 8946, + ["isinsv"] = 8947, + ["isins"] = 8948, + ["isindot"] = 8949, + ["notinvc"] = 8950, + ["notinvb"] = 8951, + ["isinE"] = 8953, + ["nisd"] = 8954, + ["xnis"] = 8955, + ["nis"] = 8956, + ["notnivc"] = 8957, + ["notnivb"] = 8958, + ["barwed"] = 8965, + ["barwedge"] = 8965, + ["Barwed"] = 8966, + ["doublebarwedge"] = 8966, + ["lceil"] = 8968, + ["LeftCeiling"] = 8968, + ["rceil"] = 8969, + ["RightCeiling"] = 8969, + ["lfloor"] = 8970, + ["LeftFloor"] = 8970, + ["rfloor"] = 8971, + ["RightFloor"] = 8971, + ["drcrop"] = 8972, + ["dlcrop"] = 8973, + ["urcrop"] = 8974, + ["ulcrop"] = 8975, + ["bnot"] = 8976, + ["profline"] = 8978, + ["profsurf"] = 8979, + ["telrec"] = 8981, + ["target"] = 8982, + ["ulcorn"] = 8988, + ["ulcorner"] = 8988, + ["urcorn"] = 8989, + ["urcorner"] = 8989, + ["dlcorn"] = 8990, + ["llcorner"] = 8990, + ["drcorn"] = 8991, + ["lrcorner"] = 8991, + ["frown"] = 8994, + ["sfrown"] = 8994, + ["smile"] = 8995, + ["ssmile"] = 8995, + ["cylcty"] = 9005, + ["profalar"] = 9006, + ["topbot"] = 9014, + ["ovbar"] = 9021, + ["solbar"] = 9023, + ["angzarr"] = 9084, + ["lmoust"] = 9136, + ["lmoustache"] = 9136, + ["rmoust"] = 9137, + ["rmoustache"] = 9137, + ["tbrk"] = 9140, + ["OverBracket"] = 9140, + ["bbrk"] = 9141, + ["UnderBracket"] = 9141, + ["bbrktbrk"] = 9142, + ["OverParenthesis"] = 9180, + ["UnderParenthesis"] = 9181, + ["OverBrace"] = 9182, + ["UnderBrace"] = 9183, + ["trpezium"] = 9186, + ["elinters"] = 9191, + ["blank"] = 9251, + ["oS"] = 9416, + ["circledS"] = 9416, + ["boxh"] = 9472, + ["HorizontalLine"] = 9472, + ["boxv"] = 9474, + ["boxdr"] = 9484, + ["boxdl"] = 9488, + ["boxur"] = 9492, + ["boxul"] = 9496, + ["boxvr"] = 9500, + ["boxvl"] = 9508, + ["boxhd"] = 9516, + ["boxhu"] = 9524, + ["boxvh"] = 9532, + ["boxH"] = 9552, + ["boxV"] = 9553, + ["boxdR"] = 9554, + ["boxDr"] = 9555, + ["boxDR"] = 9556, + ["boxdL"] = 9557, + ["boxDl"] = 9558, + ["boxDL"] = 9559, + ["boxuR"] = 9560, + ["boxUr"] = 9561, + ["boxUR"] = 9562, + ["boxuL"] = 9563, + ["boxUl"] = 9564, + ["boxUL"] = 9565, + ["boxvR"] = 9566, + ["boxVr"] = 9567, + ["boxVR"] = 9568, + ["boxvL"] = 9569, + ["boxVl"] = 9570, + ["boxVL"] = 9571, + ["boxHd"] = 9572, + ["boxhD"] = 9573, + ["boxHD"] = 9574, + ["boxHu"] = 9575, + ["boxhU"] = 9576, + ["boxHU"] = 9577, + ["boxvH"] = 9578, + ["boxVh"] = 9579, + ["boxVH"] = 9580, + ["uhblk"] = 9600, + ["lhblk"] = 9604, + ["block"] = 9608, + ["blk14"] = 9617, + ["blk12"] = 9618, + ["blk34"] = 9619, + ["squ"] = 9633, + ["square"] = 9633, + ["Square"] = 9633, + ["squf"] = 9642, + ["squarf"] = 9642, + ["blacksquare"] = 9642, + ["FilledVerySmallSquare"] = 9642, + ["EmptyVerySmallSquare"] = 9643, + ["rect"] = 9645, + ["marker"] = 9646, + ["fltns"] = 9649, + ["xutri"] = 9651, + ["bigtriangleup"] = 9651, + ["utrif"] = 9652, + ["blacktriangle"] = 9652, + ["utri"] = 9653, + ["triangle"] = 9653, + ["rtrif"] = 9656, + ["blacktriangleright"] = 9656, + ["rtri"] = 9657, + ["triangleright"] = 9657, + ["xdtri"] = 9661, + ["bigtriangledown"] = 9661, + ["dtrif"] = 9662, + ["blacktriangledown"] = 9662, + ["dtri"] = 9663, + ["triangledown"] = 9663, + ["ltrif"] = 9666, + ["blacktriangleleft"] = 9666, + ["ltri"] = 9667, + ["triangleleft"] = 9667, + ["loz"] = 9674, + ["lozenge"] = 9674, + ["cir"] = 9675, + ["tridot"] = 9708, + ["xcirc"] = 9711, + ["bigcirc"] = 9711, + ["ultri"] = 9720, + ["urtri"] = 9721, + ["lltri"] = 9722, + ["EmptySmallSquare"] = 9723, + ["FilledSmallSquare"] = 9724, + ["starf"] = 9733, + ["bigstar"] = 9733, + ["star"] = 9734, + ["phone"] = 9742, + ["female"] = 9792, + ["male"] = 9794, + ["spades"] = 9824, + ["spadesuit"] = 9824, + ["clubs"] = 9827, + ["clubsuit"] = 9827, + ["hearts"] = 9829, + ["heartsuit"] = 9829, + ["diams"] = 9830, + ["diamondsuit"] = 9830, + ["sung"] = 9834, + ["flat"] = 9837, + ["natur"] = 9838, + ["natural"] = 9838, + ["sharp"] = 9839, + ["check"] = 10003, + ["checkmark"] = 10003, + ["cross"] = 10007, + ["malt"] = 10016, + ["maltese"] = 10016, + ["sext"] = 10038, + ["VerticalSeparator"] = 10072, + ["lbbrk"] = 10098, + ["rbbrk"] = 10099, + ["lobrk"] = 10214, + ["LeftDoubleBracket"] = 10214, + ["robrk"] = 10215, + ["RightDoubleBracket"] = 10215, + ["lang"] = 10216, + ["LeftAngleBracket"] = 10216, + ["langle"] = 10216, + ["rang"] = 10217, + ["RightAngleBracket"] = 10217, + ["rangle"] = 10217, + ["Lang"] = 10218, + ["Rang"] = 10219, + ["loang"] = 10220, + ["roang"] = 10221, + ["xlarr"] = 10229, + ["longleftarrow"] = 10229, + ["LongLeftArrow"] = 10229, + ["xrarr"] = 10230, + ["longrightarrow"] = 10230, + ["LongRightArrow"] = 10230, + ["xharr"] = 10231, + ["longleftrightarrow"] = 10231, + ["LongLeftRightArrow"] = 10231, + ["xlArr"] = 10232, + ["Longleftarrow"] = 10232, + ["DoubleLongLeftArrow"] = 10232, + ["xrArr"] = 10233, + ["Longrightarrow"] = 10233, + ["DoubleLongRightArrow"] = 10233, + ["xhArr"] = 10234, + ["Longleftrightarrow"] = 10234, + ["DoubleLongLeftRightArrow"] = 10234, + ["xmap"] = 10236, + ["longmapsto"] = 10236, + ["dzigrarr"] = 10239, + ["nvlArr"] = 10498, + ["nvrArr"] = 10499, + ["nvHarr"] = 10500, + ["Map"] = 10501, + ["lbarr"] = 10508, + ["rbarr"] = 10509, + ["bkarow"] = 10509, + ["lBarr"] = 10510, + ["rBarr"] = 10511, + ["dbkarow"] = 10511, + ["RBarr"] = 10512, + ["drbkarow"] = 10512, + ["DDotrahd"] = 10513, + ["UpArrowBar"] = 10514, + ["DownArrowBar"] = 10515, + ["Rarrtl"] = 10518, + ["latail"] = 10521, + ["ratail"] = 10522, + ["lAtail"] = 10523, + ["rAtail"] = 10524, + ["larrfs"] = 10525, + ["rarrfs"] = 10526, + ["larrbfs"] = 10527, + ["rarrbfs"] = 10528, + ["nwarhk"] = 10531, + ["nearhk"] = 10532, + ["searhk"] = 10533, + ["hksearow"] = 10533, + ["swarhk"] = 10534, + ["hkswarow"] = 10534, + ["nwnear"] = 10535, + ["nesear"] = 10536, + ["toea"] = 10536, + ["seswar"] = 10537, + ["tosa"] = 10537, + ["swnwar"] = 10538, + ["rarrc"] = 10547, + ["cudarrr"] = 10549, + ["ldca"] = 10550, + ["rdca"] = 10551, + ["cudarrl"] = 10552, + ["larrpl"] = 10553, + ["curarrm"] = 10556, + ["cularrp"] = 10557, + ["rarrpl"] = 10565, + ["harrcir"] = 10568, + ["Uarrocir"] = 10569, + ["lurdshar"] = 10570, + ["ldrushar"] = 10571, + ["LeftRightVector"] = 10574, + ["RightUpDownVector"] = 10575, + ["DownLeftRightVector"] = 10576, + ["LeftUpDownVector"] = 10577, + ["LeftVectorBar"] = 10578, + ["RightVectorBar"] = 10579, + ["RightUpVectorBar"] = 10580, + ["RightDownVectorBar"] = 10581, + ["DownLeftVectorBar"] = 10582, + ["DownRightVectorBar"] = 10583, + ["LeftUpVectorBar"] = 10584, + ["LeftDownVectorBar"] = 10585, + ["LeftTeeVector"] = 10586, + ["RightTeeVector"] = 10587, + ["RightUpTeeVector"] = 10588, + ["RightDownTeeVector"] = 10589, + ["DownLeftTeeVector"] = 10590, + ["DownRightTeeVector"] = 10591, + ["LeftUpTeeVector"] = 10592, + ["LeftDownTeeVector"] = 10593, + ["lHar"] = 10594, + ["uHar"] = 10595, + ["rHar"] = 10596, + ["dHar"] = 10597, + ["luruhar"] = 10598, + ["ldrdhar"] = 10599, + ["ruluhar"] = 10600, + ["rdldhar"] = 10601, + ["lharul"] = 10602, + ["llhard"] = 10603, + ["rharul"] = 10604, + ["lrhard"] = 10605, + ["udhar"] = 10606, + ["UpEquilibrium"] = 10606, + ["duhar"] = 10607, + ["ReverseUpEquilibrium"] = 10607, + ["RoundImplies"] = 10608, + ["erarr"] = 10609, + ["simrarr"] = 10610, + ["larrsim"] = 10611, + ["rarrsim"] = 10612, + ["rarrap"] = 10613, + ["ltlarr"] = 10614, + ["gtrarr"] = 10616, + ["subrarr"] = 10617, + ["suplarr"] = 10619, + ["lfisht"] = 10620, + ["rfisht"] = 10621, + ["ufisht"] = 10622, + ["dfisht"] = 10623, + ["lopar"] = 10629, + ["ropar"] = 10630, + ["lbrke"] = 10635, + ["rbrke"] = 10636, + ["lbrkslu"] = 10637, + ["rbrksld"] = 10638, + ["lbrksld"] = 10639, + ["rbrkslu"] = 10640, + ["langd"] = 10641, + ["rangd"] = 10642, + ["lparlt"] = 10643, + ["rpargt"] = 10644, + ["gtlPar"] = 10645, + ["ltrPar"] = 10646, + ["vzigzag"] = 10650, + ["vangrt"] = 10652, + ["angrtvbd"] = 10653, + ["ange"] = 10660, + ["range"] = 10661, + ["dwangle"] = 10662, + ["uwangle"] = 10663, + ["angmsdaa"] = 10664, + ["angmsdab"] = 10665, + ["angmsdac"] = 10666, + ["angmsdad"] = 10667, + ["angmsdae"] = 10668, + ["angmsdaf"] = 10669, + ["angmsdag"] = 10670, + ["angmsdah"] = 10671, + ["bemptyv"] = 10672, + ["demptyv"] = 10673, + ["cemptyv"] = 10674, + ["raemptyv"] = 10675, + ["laemptyv"] = 10676, + ["ohbar"] = 10677, + ["omid"] = 10678, + ["opar"] = 10679, + ["operp"] = 10681, + ["olcross"] = 10683, + ["odsold"] = 10684, + ["olcir"] = 10686, + ["ofcir"] = 10687, + ["olt"] = 10688, + ["ogt"] = 10689, + ["cirscir"] = 10690, + ["cirE"] = 10691, + ["solb"] = 10692, + ["bsolb"] = 10693, + ["boxbox"] = 10697, + ["trisb"] = 10701, + ["rtriltri"] = 10702, + ["LeftTriangleBar"] = 10703, + ["RightTriangleBar"] = 10704, + ["race"] = 10714, + ["iinfin"] = 10716, + ["infintie"] = 10717, + ["nvinfin"] = 10718, + ["eparsl"] = 10723, + ["smeparsl"] = 10724, + ["eqvparsl"] = 10725, + ["lozf"] = 10731, + ["blacklozenge"] = 10731, + ["RuleDelayed"] = 10740, + ["dsol"] = 10742, + ["xodot"] = 10752, + ["bigodot"] = 10752, + ["xoplus"] = 10753, + ["bigoplus"] = 10753, + ["xotime"] = 10754, + ["bigotimes"] = 10754, + ["xuplus"] = 10756, + ["biguplus"] = 10756, + ["xsqcup"] = 10758, + ["bigsqcup"] = 10758, + ["qint"] = 10764, + ["iiiint"] = 10764, + ["fpartint"] = 10765, + ["cirfnint"] = 10768, + ["awint"] = 10769, + ["rppolint"] = 10770, + ["scpolint"] = 10771, + ["npolint"] = 10772, + ["pointint"] = 10773, + ["quatint"] = 10774, + ["intlarhk"] = 10775, + ["pluscir"] = 10786, + ["plusacir"] = 10787, + ["simplus"] = 10788, + ["plusdu"] = 10789, + ["plussim"] = 10790, + ["plustwo"] = 10791, + ["mcomma"] = 10793, + ["minusdu"] = 10794, + ["loplus"] = 10797, + ["roplus"] = 10798, + ["Cross"] = 10799, + ["timesd"] = 10800, + ["timesbar"] = 10801, + ["smashp"] = 10803, + ["lotimes"] = 10804, + ["rotimes"] = 10805, + ["otimesas"] = 10806, + ["Otimes"] = 10807, + ["odiv"] = 10808, + ["triplus"] = 10809, + ["triminus"] = 10810, + ["tritime"] = 10811, + ["iprod"] = 10812, + ["intprod"] = 10812, + ["amalg"] = 10815, + ["capdot"] = 10816, + ["ncup"] = 10818, + ["ncap"] = 10819, + ["capand"] = 10820, + ["cupor"] = 10821, + ["cupcap"] = 10822, + ["capcup"] = 10823, + ["cupbrcap"] = 10824, + ["capbrcup"] = 10825, + ["cupcup"] = 10826, + ["capcap"] = 10827, + ["ccups"] = 10828, + ["ccaps"] = 10829, + ["ccupssm"] = 10832, + ["And"] = 10835, + ["Or"] = 10836, + ["andand"] = 10837, + ["oror"] = 10838, + ["orslope"] = 10839, + ["andslope"] = 10840, + ["andv"] = 10842, + ["orv"] = 10843, + ["andd"] = 10844, + ["ord"] = 10845, + ["wedbar"] = 10847, + ["sdote"] = 10854, + ["simdot"] = 10858, + ["congdot"] = 10861, + ["easter"] = 10862, + ["apacir"] = 10863, + ["apE"] = 10864, + ["eplus"] = 10865, + ["pluse"] = 10866, + ["Esim"] = 10867, + ["Colone"] = 10868, + ["Equal"] = 10869, + ["eDDot"] = 10871, + ["ddotseq"] = 10871, + ["equivDD"] = 10872, + ["ltcir"] = 10873, + ["gtcir"] = 10874, + ["ltquest"] = 10875, + ["gtquest"] = 10876, + ["les"] = 10877, + ["LessSlantEqual"] = 10877, + ["leqslant"] = 10877, + ["ges"] = 10878, + ["GreaterSlantEqual"] = 10878, + ["geqslant"] = 10878, + ["lesdot"] = 10879, + ["gesdot"] = 10880, + ["lesdoto"] = 10881, + ["gesdoto"] = 10882, + ["lesdotor"] = 10883, + ["gesdotol"] = 10884, + ["lap"] = 10885, + ["lessapprox"] = 10885, + ["gap"] = 10886, + ["gtrapprox"] = 10886, + ["lne"] = 10887, + ["lneq"] = 10887, + ["gne"] = 10888, + ["gneq"] = 10888, + ["lnap"] = 10889, + ["lnapprox"] = 10889, + ["gnap"] = 10890, + ["gnapprox"] = 10890, + ["lEg"] = 10891, + ["lesseqqgtr"] = 10891, + ["gEl"] = 10892, + ["gtreqqless"] = 10892, + ["lsime"] = 10893, + ["gsime"] = 10894, + ["lsimg"] = 10895, + ["gsiml"] = 10896, + ["lgE"] = 10897, + ["glE"] = 10898, + ["lesges"] = 10899, + ["gesles"] = 10900, + ["els"] = 10901, + ["eqslantless"] = 10901, + ["egs"] = 10902, + ["eqslantgtr"] = 10902, + ["elsdot"] = 10903, + ["egsdot"] = 10904, + ["el"] = 10905, + ["eg"] = 10906, + ["siml"] = 10909, + ["simg"] = 10910, + ["simlE"] = 10911, + ["simgE"] = 10912, + ["LessLess"] = 10913, + ["GreaterGreater"] = 10914, + ["glj"] = 10916, + ["gla"] = 10917, + ["ltcc"] = 10918, + ["gtcc"] = 10919, + ["lescc"] = 10920, + ["gescc"] = 10921, + ["smt"] = 10922, + ["lat"] = 10923, + ["smte"] = 10924, + ["late"] = 10925, + ["bumpE"] = 10926, + ["pre"] = 10927, + ["preceq"] = 10927, + ["PrecedesEqual"] = 10927, + ["sce"] = 10928, + ["succeq"] = 10928, + ["SucceedsEqual"] = 10928, + ["prE"] = 10931, + ["scE"] = 10932, + ["prnE"] = 10933, + ["precneqq"] = 10933, + ["scnE"] = 10934, + ["succneqq"] = 10934, + ["prap"] = 10935, + ["precapprox"] = 10935, + ["scap"] = 10936, + ["succapprox"] = 10936, + ["prnap"] = 10937, + ["precnapprox"] = 10937, + ["scnap"] = 10938, + ["succnapprox"] = 10938, + ["Pr"] = 10939, + ["Sc"] = 10940, + ["subdot"] = 10941, + ["supdot"] = 10942, + ["subplus"] = 10943, + ["supplus"] = 10944, + ["submult"] = 10945, + ["supmult"] = 10946, + ["subedot"] = 10947, + ["supedot"] = 10948, + ["subE"] = 10949, + ["subseteqq"] = 10949, + ["supE"] = 10950, + ["supseteqq"] = 10950, + ["subsim"] = 10951, + ["supsim"] = 10952, + ["subnE"] = 10955, + ["subsetneqq"] = 10955, + ["supnE"] = 10956, + ["supsetneqq"] = 10956, + ["csub"] = 10959, + ["csup"] = 10960, + ["csube"] = 10961, + ["csupe"] = 10962, + ["subsup"] = 10963, + ["supsub"] = 10964, + ["subsub"] = 10965, + ["supsup"] = 10966, + ["suphsub"] = 10967, + ["supdsub"] = 10968, + ["forkv"] = 10969, + ["topfork"] = 10970, + ["mlcp"] = 10971, + ["Dashv"] = 10980, + ["DoubleLeftTee"] = 10980, + ["Vdashl"] = 10982, + ["Barv"] = 10983, + ["vBar"] = 10984, + ["vBarv"] = 10985, + ["Vbar"] = 10987, + ["Not"] = 10988, + ["bNot"] = 10989, + ["rnmid"] = 10990, + ["cirmid"] = 10991, + ["midcir"] = 10992, + ["topcir"] = 10993, + ["nhpar"] = 10994, + ["parsim"] = 10995, + ["parsl"] = 11005, + ["fflig"] = 64256, + ["filig"] = 64257, + ["fllig"] = 64258, + ["ffilig"] = 64259, + ["ffllig"] = 64260, + ["Ascr"] = 119964, + ["Cscr"] = 119966, + ["Dscr"] = 119967, + ["Gscr"] = 119970, + ["Jscr"] = 119973, + ["Kscr"] = 119974, + ["Nscr"] = 119977, + ["Oscr"] = 119978, + ["Pscr"] = 119979, + ["Qscr"] = 119980, + ["Sscr"] = 119982, + ["Tscr"] = 119983, + ["Uscr"] = 119984, + ["Vscr"] = 119985, + ["Wscr"] = 119986, + ["Xscr"] = 119987, + ["Yscr"] = 119988, + ["Zscr"] = 119989, + ["ascr"] = 119990, + ["bscr"] = 119991, + ["cscr"] = 119992, + ["dscr"] = 119993, + ["fscr"] = 119995, + ["hscr"] = 119997, + ["iscr"] = 119998, + ["jscr"] = 119999, + ["kscr"] = 120000, + ["lscr"] = 120001, + ["mscr"] = 120002, + ["nscr"] = 120003, + ["pscr"] = 120005, + ["qscr"] = 120006, + ["rscr"] = 120007, + ["sscr"] = 120008, + ["tscr"] = 120009, + ["uscr"] = 120010, + ["vscr"] = 120011, + ["wscr"] = 120012, + ["xscr"] = 120013, + ["yscr"] = 120014, + ["zscr"] = 120015, + ["Afr"] = 120068, + ["Bfr"] = 120069, + ["Dfr"] = 120071, + ["Efr"] = 120072, + ["Ffr"] = 120073, + ["Gfr"] = 120074, + ["Jfr"] = 120077, + ["Kfr"] = 120078, + ["Lfr"] = 120079, + ["Mfr"] = 120080, + ["Nfr"] = 120081, + ["Ofr"] = 120082, + ["Pfr"] = 120083, + ["Qfr"] = 120084, + ["Sfr"] = 120086, + ["Tfr"] = 120087, + ["Ufr"] = 120088, + ["Vfr"] = 120089, + ["Wfr"] = 120090, + ["Xfr"] = 120091, + ["Yfr"] = 120092, + ["afr"] = 120094, + ["bfr"] = 120095, + ["cfr"] = 120096, + ["dfr"] = 120097, + ["efr"] = 120098, + ["ffr"] = 120099, + ["gfr"] = 120100, + ["hfr"] = 120101, + ["ifr"] = 120102, + ["jfr"] = 120103, + ["kfr"] = 120104, + ["lfr"] = 120105, + ["mfr"] = 120106, + ["nfr"] = 120107, + ["ofr"] = 120108, + ["pfr"] = 120109, + ["qfr"] = 120110, + ["rfr"] = 120111, + ["sfr"] = 120112, + ["tfr"] = 120113, + ["ufr"] = 120114, + ["vfr"] = 120115, + ["wfr"] = 120116, + ["xfr"] = 120117, + ["yfr"] = 120118, + ["zfr"] = 120119, + ["Aopf"] = 120120, + ["Bopf"] = 120121, + ["Dopf"] = 120123, + ["Eopf"] = 120124, + ["Fopf"] = 120125, + ["Gopf"] = 120126, + ["Iopf"] = 120128, + ["Jopf"] = 120129, + ["Kopf"] = 120130, + ["Lopf"] = 120131, + ["Mopf"] = 120132, + ["Oopf"] = 120134, + ["Sopf"] = 120138, + ["Topf"] = 120139, + ["Uopf"] = 120140, + ["Vopf"] = 120141, + ["Wopf"] = 120142, + ["Xopf"] = 120143, + ["Yopf"] = 120144, + ["aopf"] = 120146, + ["bopf"] = 120147, + ["copf"] = 120148, + ["dopf"] = 120149, + ["eopf"] = 120150, + ["fopf"] = 120151, + ["gopf"] = 120152, + ["hopf"] = 120153, + ["iopf"] = 120154, + ["jopf"] = 120155, + ["kopf"] = 120156, + ["lopf"] = 120157, + ["mopf"] = 120158, + ["nopf"] = 120159, + ["oopf"] = 120160, + ["popf"] = 120161, + ["qopf"] = 120162, + ["ropf"] = 120163, + ["sopf"] = 120164, + ["topf"] = 120165, + ["uopf"] = 120166, + ["vopf"] = 120167, + ["wopf"] = 120168, + ["xopf"] = 120169, + ["yopf"] = 120170, + ["zopf"] = 120171, +} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Given a string `s` of decimal digits, the \luamdef{entities.dec_entity} +% returns the corresponding \acro{utf}8-encoded Unicode codepoint. +% +% \end{markdown} +% \begin{macrocode} +function entities.dec_entity(s) + return unicode.utf8.char(tonumber(s)) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Given a string `s` of hexadecimal digits, the +% \luamdef{entities.hex_entity} returns the corresponding +% \acro{utf}8-encoded Unicode codepoint. +% +% \end{markdown} +% \begin{macrocode} +function entities.hex_entity(s) + return unicode.utf8.char(tonumber("0x"..s)) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Given a character entity name `s` (like `ouml`), the +% \luamdef{entities.char_entity} returns the corresponding +% \acro{utf}8-encoded Unicode codepoint. +% +% \end{markdown} +% \begin{macrocode} +function entities.char_entity(s) + local n = character_entities[s] + if n == nil then + return "&" .. s .. ";" + end + return unicode.utf8.char(n) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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 +% `lunamark/writer/generic.lua`, `lunamark/writer/tex.lua`, and +% `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. +% +% \end{markdown} +% \begin{macrocode} +M.writer = {} +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \luamdef{writer.new} method creates and returns a new \TeX{} writer +% object associated with the Lua interface options (see Section +% \ref{sec:luaoptions}) `options`. When `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 `writer->`\meta{member}. +% +% \end{markdown} +% \begin{macrocode} +function M.writer.new(options) + local self = {} + options = options or {} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Make the `options` table inherit from the \luam{defaultOptions} table. +% +% \end{markdown} +% \begin{macrocode} + setmetatable(options, { __index = function (_, key) + return defaultOptions[key] end }) +% \end{macrocode} +% \par +% \begin{markdown} +% +% Parse the \Opt{slice} option and define \luamdef{writer->slice\_begin} +% \luamdef{writer->slice\_end}, and \luamdef{writer->is\_writing}. +% +% \end{markdown} +% \begin{macrocode} + local slice_specifiers = {} + for specifier in options.slice:gmatch("[^%s]+") do + table.insert(slice_specifiers, specifier) + end + + if #slice_specifiers == 2 then + self.slice_begin, self.slice_end = table.unpack(slice_specifiers) + local slice_begin_type = self.slice_begin:sub(1, 1) + if slice_begin_type ~= "^" and slice_begin_type ~= "$" then + self.slice_begin = "^" .. self.slice_begin + end + local slice_end_type = self.slice_end:sub(1, 1) + if slice_end_type ~= "^" and slice_end_type ~= "$" then + self.slice_end = "$" .. self.slice_end + end + elseif #slice_specifiers == 1 then + self.slice_begin = "^" .. slice_specifiers[1] + self.slice_end = "$" .. slice_specifiers[1] + end + + if self.slice_begin == "^" and self.slice_end ~= "^" then + self.is_writing = true + else + self.is_writing = false + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->suffix} as the suffix of the produced cache files. +% +% \end{markdown} +% \begin{macrocode} + self.suffix = ".tex" +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->space} as the output format of a space character. +% +% \end{markdown} +% \begin{macrocode} + self.space = " " +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->nbsp} as the output format of a non-breaking space +% character. +% +% \end{markdown} +% \begin{macrocode} + self.nbsp = "\\markdownRendererNbsp{}" +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->plain} as a function that will transform an input +% plain text block `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.plain(s) + return s + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->paragraph} as a function that will transform an +% input paragraph `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.paragraph(s) + if not self.is_writing then return "" end + return s + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->pack} as a function that will take the filename +% `name` of the output file prepared by the reader and transform it to the +% output format. +% +% \end{markdown} +% \begin{macrocode} + function self.pack(name) + return [[\input ]] .. name .. [[\relax{}]] + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->interblocksep} as the output format of a block +% element separator. +% +% \end{markdown} +% \begin{macrocode} + function self.interblocksep() + if not self.is_writing then return "" end + return "\\markdownRendererInterblockSeparator\n{}" + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->eof} as the end of file marker in the output format. +% +% \end{markdown} +% \begin{macrocode} + self.eof = [[\relax]] +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->linebreak} as the output format of a forced line break. +% +% \end{markdown} +% \begin{macrocode} + self.linebreak = "\\markdownRendererLineBreak\n{}" +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->ellipsis} as the output format of an ellipsis. +% +% \end{markdown} +% \begin{macrocode} + self.ellipsis = "\\markdownRendererEllipsis{}" +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->hrule} as the output format of a horizontal rule. +% +% \end{markdown} +% \begin{macrocode} + function self.hrule() + if not self.is_writing then return "" end + return "\\markdownRendererHorizontalRule{}" + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define a table \luamdef{escaped_chars} containing the mapping from special +% plain \TeX{} characters (including the active pipe character (`|`) of +% \Hologo{ConTeXt}) to their escaped variants. Define tables +% \luamdef{escaped_minimal_chars} and \luamdef{escaped_minimal_strings} +% containing the mapping from special plain characters and character strings +% that need to be escaped even in content that will not be typeset. +% +% \end{markdown} +% \begin{macrocode} + local escaped_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["$"] = "\\markdownRendererDollarSign{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["&"] = "\\markdownRendererAmpersand{}", + ["_"] = "\\markdownRendererUnderscore{}", + ["#"] = "\\markdownRendererHash{}", + ["^"] = "\\markdownRendererCircumflex{}", + ["\\"] = "\\markdownRendererBackslash{}", + ["~"] = "\\markdownRendererTilde{}", + ["|"] = "\\markdownRendererPipe{}", + } + local escaped_uri_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + local escaped_citation_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["#"] = "\\markdownRendererHash{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + local escaped_minimal_strings = { + ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", + } +% \end{macrocode} +% \par +% \begin{markdown} +% +% Use the \luam{escaped_chars} table to create an escaper function +% \luamdef{escape} and the \luam{escaped_minimal_chars} and +% \luam{escaped_minimal_strings} tables to create an escaper function +% \luamdef{escape_minimal}. +% +% \end{markdown} +% \begin{macrocode} + local escape = util.escaper(escaped_chars) + local escape_citation = util.escaper(escaped_citation_chars, + escaped_minimal_strings) + local escape_uri = util.escaper(escaped_uri_chars, escaped_minimal_strings) +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->string} as a function that will transform an input +% plain text span `s` to the output format and \luamdef{writer->uri} as a +% function that will transform an input \acro{uri} `u` to the output format. +% If the \Opt{hybrid} option is `true`, use identity functions. Otherwise, +% use the \luam{escape} and \luam{escape_minimal} functions. +% +% \end{markdown} +% \begin{macrocode} + if options.hybrid then + self.string = function(s) return s end + self.citation = function(c) return c end + self.uri = function(u) return u end + else + self.string = escape + self.citation = escape_citation + self.uri = escape_uri + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->code} as a function that will transform an input +% inlined code span `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.code(s) + return {"\\markdownRendererCodeSpan{",escape(s),"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->link} as a function that will transform an input +% hyperlink to the output format, where `lab` corresponds to the label, +% `src` to \acro{uri}, and `tit` to the title of the link. +% +% \end{markdown} +% \begin{macrocode} + function self.link(lab,src,tit) + return {"\\markdownRendererLink{",lab,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->table} as a function that will transform an input +% table to the output format, where `rows` is a sequence of columns and a +% column is a sequence of cell texts. +% +% \end{markdown} +% \begin{macrocode} + function self.table(rows, caption) + local buffer = {"\\markdownRendererTable{", + caption or "", "}{", #rows - 1, "}{", #rows[1], "}"} + local temp = rows[2] -- put alignments on the first row + rows[2] = rows[1] + rows[1] = temp + for i, row in ipairs(rows) do + table.insert(buffer, "{") + for _, column in ipairs(row) do + if i > 1 then -- do not use braces for alignments + table.insert(buffer, "{") + end + table.insert(buffer, column) + if i > 1 then + table.insert(buffer, "}%\n") + end + end + table.insert(buffer, "}%\n") + end + return buffer + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->image} as a function that will transform an input +% image to the output format, where `lab` corresponds to the label, `src` +% to the \acro{url}, and `tit` to the title of the image. +% +% \end{markdown} +% \begin{macrocode} + function self.image(lab,src,tit) + return {"\\markdownRendererImage{",lab,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \luamdef{languages_json} table maps programming language filename +% extensions to fence infostrings. All \luam{options.contentBlocksLanguageMap} +% files located by \pkg{kpathsea} are loaded into a chain of tables. +% \luam{languages_json} corresponds to the first table and is chained with +% the rest via Lua metatables. +% +% \end{markdown} +% \begin{macrocode} + local languages_json = (function() + local kpse = require("kpse") + kpse.set_program_name("luatex") + local base, prev, curr + for _, file in ipairs{kpse.lookup(options.contentBlocksLanguageMap, + { all=true })} do + json = io.open(file, "r"):read("*all") + :gsub('("[^\n]-"):','[%1]=') + curr = (function() + local _ENV={ json=json, load=load } -- run in sandbox + return load("return "..json)() + end)() + if type(curr) == "table" then + if base == nil then + base = curr + else + setmetatable(prev, { __index = curr }) + end + prev = curr + end + end + return base or {} + end)() +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->contentblock} as a function that will transform an +% input iA\,Writer content block to the output format, where `src` +% corresponds to the \acro{uri} prefix, `suf` to the \acro{uri} extension, +% `type` to the type of the content block (`localfile` or `onlineimage`), +% and `tit` to the title of the content block. +% +% \end{markdown} +% \begin{macrocode} + function self.contentblock(src,suf,type,tit) + if not self.is_writing then return "" end + src = src.."."..suf + suf = suf:lower() + if type == "onlineimage" then + return {"\\markdownRendererContentBlockOnlineImage{",suf,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + elseif languages_json[suf] then + return {"\\markdownRendererContentBlockCode{",suf,"}", + "{",self.string(languages_json[suf]),"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + else + return {"\\markdownRendererContentBlock{",suf,"}", + "{",self.string(src),"}", + "{",self.uri(src),"}", + "{",self.string(tit or ""),"}"} + end + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->bulletlist} as a function that will transform an input +% bulleted list to the output format, where `items` is an array of the list +% items and `tight` specifies, whether the list is tight or not. +% +% \end{markdown} +% \begin{macrocode} + local function ulitem(s) + return {"\\markdownRendererUlItem ",s, + "\\markdownRendererUlItemEnd "} + end + + function self.bulletlist(items,tight) + if not self.is_writing then return "" end + 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} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->ollist} as a function that will transform an input +% ordered list to the output format, where `items` is an array of the list +% items and `tight` specifies, whether the list is tight or not. If the +% optional parameter `startnum` is present, it should be used as the number +% of the first list item. +% +% \end{markdown} +% \begin{macrocode} + local function olitem(s,num) + if num ~= nil then + return {"\\markdownRendererOlItemWithNumber{",num,"}",s, + "\\markdownRendererOlItemEnd "} + else + return {"\\markdownRendererOlItem ",s, + "\\markdownRendererOlItemEnd "} + end + end + + function self.orderedlist(items,tight,startnum) + if not self.is_writing then return "" end + 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} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->inline_html} and \luamdef{writer->display_html} +% as functions that will transform an inline or block \acro{html} element +% respectively to the output format, where `html` is the \acro{html} +% input. +% +% \end{markdown} +% \begin{macrocode} + function self.inline_html(html) return "" end + function self.display_html(html) return "" end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->definitionlist} as a function that will transform an +% input definition list to the output format, where `items` is an array of +% tables, each of the form `{ term = t, definitions = defs }`, where `t` +% is a term and `defs` is an array of definitions. `tight` specifies, +% whether the list is tight or not. +% +% \end{markdown} +% \begin{macrocode} + local function dlitem(term, defs) + local retVal = {"\\markdownRendererDlItem{",term,"}"} + for _, def in ipairs(defs) do + retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def, + "\\markdownRendererDlDefinitionEnd "} + end + retVal[#retVal+1] = "\\markdownRendererDlItemEnd " + return retVal + end + + function self.definitionlist(items,tight) + if not self.is_writing then return "" end + local buffer = {} + for _,item in ipairs(items) do + buffer[#buffer + 1] = dlitem(item.term, item.definitions) + end + if tight and options.tightLists then + return {"\\markdownRendererDlBeginTight\n", buffer, + "\n\\markdownRendererDlEndTight"} + else + return {"\\markdownRendererDlBegin\n", buffer, + "\n\\markdownRendererDlEnd"} + end + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->emphasis} as a function that will transform an +% emphasized span `s` of input text to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.emphasis(s) + return {"\\markdownRendererEmphasis{",s,"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->strong} as a function that will transform a strongly +% emphasized span `s` of input text to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.strong(s) + return {"\\markdownRendererStrongEmphasis{",s,"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->blockquote} as a function that will transform an +% input block quote `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.blockquote(s) + if #util.rope_to_string(s) == 0 then return "" end + return {"\\markdownRendererBlockQuoteBegin\n",s, + "\n\\markdownRendererBlockQuoteEnd "} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->verbatim} as a function that will transform an +% input code block `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.verbatim(s) + if not self.is_writing then return "" end + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputVerbatim{",name,"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->codeFence} as a function that will transform an +% input fenced code block `s` with the infostring `i` to the output +% format. +% +% \end{markdown} +% \begin{macrocode} + function self.fencedCode(i, s) + if not self.is_writing then return "" end + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->active_headings} as a stack of identifiers +% of the headings that are currently active. +% +% \end{markdown} +% \begin{macrocode} + self.active_headings = {} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->heading} as a function that will transform an +% input heading `s` at level `level` with identifiers `identifiers` to the +% output format. +% +% \end{markdown} +% \begin{macrocode} + function self.heading(s,level,attributes) + local active_headings = self.active_headings + local slice_begin_type = self.slice_begin:sub(1, 1) + local slice_begin_identifier = self.slice_begin:sub(2) or "" + local slice_end_type = self.slice_end:sub(1, 1) + local slice_end_identifier = self.slice_end:sub(2) or "" + + while #active_headings < level do + -- push empty identifiers for implied sections + table.insert(active_headings, {}) + end + + while #active_headings >= level do + -- pop identifiers for sections that have ended + local active_identifiers = active_headings[#active_headings] + if active_identifiers[slice_begin_identifier] ~= nil + and slice_begin_type == "$" then + self.is_writing = true + end + if active_identifiers[slice_end_identifier] ~= nil + and slice_end_type == "$" then + self.is_writing = false + end + table.remove(active_headings, #active_headings) + end + + -- push identifiers for the new section + attributes = attributes or {} + local identifiers = {} + for index = 1, #attributes do + attribute = attributes[index] + identifiers[attribute:sub(2)] = true + end + if identifiers[slice_begin_identifier] ~= nil + and slice_begin_type == "^" then + self.is_writing = true + end + if identifiers[slice_end_identifier] ~= nil + and slice_end_type == "^" then + self.is_writing = false + end + table.insert(active_headings, identifiers) + + if not self.is_writing then return "" end + + local cmd + level = level + options.shiftHeadings + 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} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->note} as a function that will transform an +% input footnote `s` to the output format. +% +% \end{markdown} +% \begin{macrocode} + function self.note(s) + return {"\\markdownRendererFootnote{",s,"}"} + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->citations} as a function that will transform an +% input array of citations `cites` to the output format. If `text_cites` +% is `true`, the citations should be rendered in-text, when applicable. +% The `cites` array contains tables with the following keys and values: +% \begin{itemize} +% \item`suppress_author` -- If the value of the key is true, then the +% author of the work should be omitted in the citation, when applicable. +% \item`prenote` -- The value of the key is either `nil` or a rope +% that should be inserted before the citation. +% \item`postnote` -- The value of the key is either `nil` or a rope +% that should be inserted after the citation. +% \item`name` -- The value of this key is the citation name. +% \end{itemize} +% +% \end{markdown} +% \begin{macrocode} + function self.citations(text_cites, cites) + local buffer = {"\\markdownRenderer", text_cites and "TextCite" or "Cite", + "{", #cites, "}"} + for _,cite in ipairs(cites) do + buffer[#buffer+1] = {cite.suppress_author and "-" or "+", "{", + cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"} + end + return buffer + end + + return self +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Parsers +% The \luamdef{parsers} hash table stores \acro{peg} patterns that are +% static and can be reused between different \luam{reader} objects. +% +% \end{markdown} +% \begin{macrocode} +local parsers = {} +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Basic Parsers +% +% \end{markdown} +% \begin{macrocode} +parsers.percent = P("%") +parsers.at = P("@") +parsers.comma = P(",") +parsers.asterisk = P("*") +parsers.dash = P("-") +parsers.plus = P("+") +parsers.underscore = P("_") +parsers.period = P(".") +parsers.hash = P("#") +parsers.ampersand = P("&") +parsers.backtick = P("`") +parsers.less = P("<") +parsers.more = P(">") +parsers.space = P(" ") +parsers.squote = P("'") +parsers.dquote = P('"') +parsers.lparent = P("(") +parsers.rparent = P(")") +parsers.lbracket = P("[") +parsers.rbracket = P("]") +parsers.lbrace = P("{") +parsers.rbrace = P("}") +parsers.circumflex = P("^") +parsers.slash = P("/") +parsers.equal = P("=") +parsers.colon = P(":") +parsers.semicolon = P(";") +parsers.exclamation = P("!") +parsers.pipe = P("|") +parsers.tilde = P("~") +parsers.tab = P("\t") +parsers.newline = P("\n") +parsers.tightblocksep = P("\001") + +parsers.digit = R("09") +parsers.hexdigit = R("09","af","AF") +parsers.letter = R("AZ","az") +parsers.alphanumeric = R("AZ","az","09") +parsers.keyword = parsers.letter + * parsers.alphanumeric^0 +parsers.citation_chars = parsers.alphanumeric + + S("#$%&-+<>~/_") +parsers.internal_punctuation = S(":;,.?") + +parsers.doubleasterisks = P("**") +parsers.doubleunderscores = P("__") +parsers.fourspaces = P(" ") + +parsers.any = P(1) +parsers.fail = parsers.any - 1 + +parsers.escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") +parsers.anyescaped = P("\\") / "" * parsers.escapable + + parsers.any + +parsers.spacechar = S("\t ") +parsers.spacing = S(" \n\r\t") +parsers.nonspacechar = parsers.any - parsers.spacing +parsers.optionalspace = parsers.spacechar^0 + +parsers.specialchar = S("*_`&[]<!\\.@-^") + +parsers.normalchar = parsers.any - (parsers.specialchar + + parsers.spacing + + parsers.tightblocksep) +parsers.eof = -parsers.any +parsers.nonindentspace = parsers.space^-3 * - parsers.spacechar +parsers.indent = parsers.space^-3 * parsers.tab + + parsers.fourspaces / "" +parsers.linechar = P(1 - parsers.newline) + +parsers.blankline = parsers.optionalspace + * parsers.newline / "\n" +parsers.blanklines = parsers.blankline^0 +parsers.skipblanklines = (parsers.optionalspace * parsers.newline)^0 +parsers.indentedline = parsers.indent /"" + * C(parsers.linechar^1 * parsers.newline^-1) +parsers.optionallyindentedline = parsers.indent^-1 /"" + * C(parsers.linechar^1 * parsers.newline^-1) +parsers.sp = parsers.spacing^0 +parsers.spnl = parsers.optionalspace + * (parsers.newline * parsers.optionalspace)^-1 +parsers.line = parsers.linechar^0 * parsers.newline +parsers.nonemptyline = parsers.line - parsers.blankline + +parsers.chunk = parsers.line * (parsers.optionallyindentedline + - parsers.blankline)^0 + +parsers.css_identifier_char = R("AZ", "az", "09") + S("-_") +parsers.css_identifier = (parsers.hash + parsers.period) + * (((parsers.css_identifier_char + - parsers.dash - parsers.digit) + * parsers.css_identifier_char^1) + + (parsers.dash + * (parsers.css_identifier_char + - parsers.digit) + * parsers.css_identifier_char^0)) +parsers.attribute_name_char = parsers.any - parsers.space + - parsers.squote - parsers.dquote + - parsers.more - parsers.slash + - parsers.equal +parsers.attribute_value_char = parsers.any - parsers.dquote + - parsers.more + +-- block followed by 0 or more optionally +-- indented blocks with first line indented. +parsers.indented_blocks = function(bl) + return Cs( bl + * (parsers.blankline^1 * parsers.indent * -parsers.blankline * bl)^0 + * (parsers.blankline^1 + parsers.eof) ) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Markdown Lists +% +% \end{markdown} +% \begin{macrocode} +parsers.bulletchar = C(parsers.plus + parsers.asterisk + parsers.dash) + +parsers.bullet = ( parsers.bulletchar * #parsers.spacing + * (parsers.tab + parsers.space^-3) + + parsers.space * parsers.bulletchar * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * parsers.space * parsers.bulletchar + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * parsers.space + * parsers.bulletchar * #parsers.spacing + ) +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Markdown Code Spans +% +% \end{markdown} +% \begin{macrocode} +parsers.openticks = Cg(parsers.backtick^1, "ticks") + +local function captures_equal_length(s,i,a,b) + return #a == #b and i +end + +parsers.closeticks = parsers.space^-1 + * Cmt(C(parsers.backtick^1) + * Cb("ticks"), captures_equal_length) + +parsers.intickschar = (parsers.any - S(" \n\r`")) + + (parsers.newline * -parsers.blankline) + + (parsers.space - parsers.closeticks) + + (parsers.backtick^1 - parsers.closeticks) + +parsers.inticks = parsers.openticks * parsers.space^-1 + * C(parsers.intickschar^0) * parsers.closeticks +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Fenced Code Blocks +% +% \end{markdown} +% \begin{macrocode} +local function captures_geq_length(s,i,a,b) + return #a >= #b and i +end + +parsers.infostring = (parsers.linechar - (parsers.backtick + + parsers.space^1 * (parsers.newline + parsers.eof)))^0 + +local fenceindent +parsers.fencehead = function(char) + return C(parsers.nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * parsers.optionalspace * C(parsers.infostring) + * parsers.optionalspace * (parsers.newline + parsers.eof) +end + +parsers.fencetail = function(char) + return parsers.nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) + * parsers.optionalspace * (parsers.newline + parsers.eof) + + parsers.eof +end + +parsers.fencedline = function(char) + return C(parsers.line - parsers.fencetail(char)) + / function(s) + i = 1 + remaining = fenceindent + while true do + c = s:sub(i, i) + if c == " " and remaining > 0 then + remaining = remaining - 1 + i = i + 1 + elseif c == "\t" and remaining > 3 then + remaining = remaining - 4 + i = i + 1 + else + break + end + end + return s:sub(i) + end +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Markdown Tags and Links +% +% \end{markdown} +% \begin{macrocode} +parsers.leader = parsers.space^-3 + +-- content in balanced brackets, parentheses, or quotes: +parsers.bracketed = P{ parsers.lbracket + * ((parsers.anyescaped - (parsers.lbracket + + parsers.rbracket + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rbracket } + +parsers.inparens = P{ parsers.lparent + * ((parsers.anyescaped - (parsers.lparent + + parsers.rparent + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rparent } + +parsers.squoted = P{ parsers.squote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.squote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.squote } + +parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.dquote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.dquote } + +-- bracketed tag for markdown links, allowing nested brackets: +parsers.tag = parsers.lbracket + * Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.blankline^2)))^0) + * parsers.rbracket + +-- url for markdown links, allowing nested brackets: +parsers.url = parsers.less * Cs((parsers.anyescaped + - parsers.more)^0) + * parsers.more + + Cs((parsers.inparens + (parsers.anyescaped + - parsers.spacing + - parsers.rparent))^1) + +-- quoted text, possibly with nested quotes: +parsers.title_s = parsers.squote * Cs(((parsers.anyescaped-parsers.squote) + + parsers.squoted)^0) + * parsers.squote + +parsers.title_d = parsers.dquote * Cs(((parsers.anyescaped-parsers.dquote) + + parsers.dquoted)^0) + * parsers.dquote + +parsers.title_p = parsers.lparent + * Cs((parsers.inparens + (parsers.anyescaped-parsers.rparent))^0) + * parsers.rparent + +parsers.title = parsers.title_d + parsers.title_s + parsers.title_p + +parsers.optionaltitle + = parsers.spnl * parsers.title * parsers.spacechar^0 + + Cc("") +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for iA\,Writer Content Blocks +% +% \end{markdown} +% \begin{macrocode} +parsers.contentblock_tail + = parsers.optionaltitle + * (parsers.newline + parsers.eof) + +-- case insensitive online image suffix: +parsers.onlineimagesuffix + = (function(...) + local parser = nil + for _,suffix in ipairs({...}) do + local pattern=nil + for i=1,#suffix do + local char=suffix:sub(i,i) + char = S(char:lower()..char:upper()) + if pattern == nil then + pattern = char + else + pattern = pattern * char + end + end + if parser == nil then + parser = pattern + else + parser = parser + pattern + end + end + return parser + end)("png", "jpg", "jpeg", "gif", "tif", "tiff") + +-- online image url for iA Writer content blocks with mandatory suffix, +-- allowing nested brackets: +parsers.onlineimageurl + = (parsers.less + * Cs((parsers.anyescaped + - parsers.more + - #(parsers.period + * parsers.onlineimagesuffix + * parsers.more + * parsers.contentblock_tail))^0) + * parsers.period + * Cs(parsers.onlineimagesuffix) + * parsers.more + + (Cs((parsers.inparens + + (parsers.anyescaped + - parsers.spacing + - parsers.rparent + - #(parsers.period + * parsers.onlineimagesuffix + * parsers.contentblock_tail)))^0) + * parsers.period + * Cs(parsers.onlineimagesuffix)) + ) * Cc("onlineimage") + +-- filename for iA Writer content blocks with mandatory suffix: +parsers.localfilepath + = parsers.slash + * Cs((parsers.anyescaped + - parsers.tab + - parsers.newline + - #(parsers.period + * parsers.alphanumeric^1 + * parsers.contentblock_tail))^1) + * parsers.period + * Cs(parsers.alphanumeric^1) + * Cc("localfile") +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Citations +% +% \end{markdown} +% \begin{macrocode} +parsers.citation_name = Cs(parsers.dash^-1) * parsers.at + * Cs(parsers.citation_chars + * (((parsers.citation_chars + parsers.internal_punctuation + - parsers.comma - parsers.semicolon) + * -#((parsers.internal_punctuation - parsers.comma + - parsers.semicolon)^0 + * -(parsers.citation_chars + parsers.internal_punctuation + - parsers.comma - parsers.semicolon)))^0 + * parsers.citation_chars)^-1) + +parsers.citation_body_prenote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.blankline^2)) + - (parsers.spnl * parsers.dash^-1 * parsers.at))^0) + +parsers.citation_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.semicolon + + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_body_chunk + = parsers.citation_body_prenote + * parsers.spnl * parsers.citation_name + * (parsers.internal_punctuation - parsers.semicolon)^-1 + * parsers.spnl * parsers.citation_body_postnote + +parsers.citation_body + = parsers.citation_body_chunk + * (parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 + +parsers.citation_headless_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.at + + parsers.semicolon + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_headless_body + = parsers.citation_headless_body_postnote + * (parsers.sp * parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Footnotes +% +% \end{markdown} +% \begin{macrocode} +local function strip_first_char(s) + return s:sub(2) +end + +parsers.RawNoteRef = #(parsers.lbracket * parsers.circumflex) + * parsers.tag / strip_first_char +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Tables +% +% \end{markdown} +% \begin{macrocode} +local function make_pipe_table_rectangular(rows) + local num_columns = #rows[2] + local rectangular_rows = {} + for i = 1, #rows do + local row = rows[i] + local rectangular_row = {} + for j = 1, num_columns do + rectangular_row[j] = row[j] or "" + end + table.insert(rectangular_rows, rectangular_row) + end + return rectangular_rows +end + +local function pipe_table_row(allow_empty_first_column + , nonempty_column + , column_separator + , column) + local row_beginning + if allow_empty_first_column then + row_beginning = -- empty first column + #(parsers.spacechar^4 + * column_separator) + * parsers.optionalspace + * column + * parsers.optionalspace + -- non-empty first column + + parsers.nonindentspace + * nonempty_column^-1 + * parsers.optionalspace + else + row_beginning = parsers.nonindentspace + * nonempty_column^-1 + * parsers.optionalspace + end + + return Ct(row_beginning + * (-- single column with no leading pipes + #(column_separator + * parsers.optionalspace + * parsers.newline) + * column_separator + * parsers.optionalspace + -- single column with leading pipes or + -- more than a single column + + (column_separator + * parsers.optionalspace + * column + * parsers.optionalspace)^1 + * (column_separator + * parsers.optionalspace)^-1)) +end + +parsers.table_hline_separator = parsers.pipe + parsers.plus +parsers.table_hline_column = (parsers.dash + - #(parsers.dash + * (parsers.spacechar + + parsers.table_hline_separator + + parsers.newline)))^1 + * (parsers.colon * Cc("r") + + parsers.dash * Cc("d")) + + parsers.colon + * (parsers.dash + - #(parsers.dash + * (parsers.spacechar + + parsers.table_hline_separator + + parsers.newline)))^1 + * (parsers.colon * Cc("c") + + parsers.dash * Cc("l")) +parsers.table_hline = pipe_table_row(false + , parsers.table_hline_column + , parsers.table_hline_separator + , parsers.table_hline_column) +parsers.table_caption_beginning = parsers.skipblanklines + * parsers.nonindentspace + * (P("Table")^-1 * parsers.colon) + * parsers.optionalspace +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for HTML +% +% \end{markdown} +% \begin{macrocode} +-- case-insensitive match (we assume s is lowercase). must be single byte encoding +parsers.keyword_exact = function(s) + local parser = P(0) + for i=1,#s do + local c = s:sub(i,i) + local m = c .. upper(c) + parser = parser * S(m) + end + return parser +end + +parsers.block_keyword = + parsers.keyword_exact("address") + parsers.keyword_exact("blockquote") + + parsers.keyword_exact("center") + parsers.keyword_exact("del") + + parsers.keyword_exact("dir") + parsers.keyword_exact("div") + + parsers.keyword_exact("p") + parsers.keyword_exact("pre") + + parsers.keyword_exact("li") + parsers.keyword_exact("ol") + + parsers.keyword_exact("ul") + parsers.keyword_exact("dl") + + parsers.keyword_exact("dd") + parsers.keyword_exact("form") + + parsers.keyword_exact("fieldset") + parsers.keyword_exact("isindex") + + parsers.keyword_exact("ins") + parsers.keyword_exact("menu") + + parsers.keyword_exact("noframes") + parsers.keyword_exact("frameset") + + parsers.keyword_exact("h1") + parsers.keyword_exact("h2") + + parsers.keyword_exact("h3") + parsers.keyword_exact("h4") + + parsers.keyword_exact("h5") + parsers.keyword_exact("h6") + + parsers.keyword_exact("hr") + parsers.keyword_exact("script") + + parsers.keyword_exact("noscript") + parsers.keyword_exact("table") + + parsers.keyword_exact("tbody") + parsers.keyword_exact("tfoot") + + parsers.keyword_exact("thead") + parsers.keyword_exact("th") + + parsers.keyword_exact("td") + parsers.keyword_exact("tr") + +-- There is no reason to support bad html, so we expect quoted attributes +parsers.htmlattributevalue + = parsers.squote * (parsers.any - (parsers.blankline + + parsers.squote))^0 + * parsers.squote + + parsers.dquote * (parsers.any - (parsers.blankline + + parsers.dquote))^0 + * parsers.dquote + +parsers.htmlattribute = parsers.spacing^1 + * (parsers.alphanumeric + S("_-"))^1 + * parsers.sp * parsers.equal * parsers.sp + * parsers.htmlattributevalue + +parsers.htmlcomment = P("<!--") * (parsers.any - P("-->"))^0 * P("-->") + +parsers.htmlinstruction = P("<?") * (parsers.any - P("?>" ))^0 * P("?>" ) + +parsers.openelt_any = parsers.less * parsers.keyword * parsers.htmlattribute^0 + * parsers.sp * parsers.more + +parsers.openelt_exact = function(s) + return parsers.less * parsers.sp * parsers.keyword_exact(s) + * parsers.htmlattribute^0 * parsers.sp * parsers.more +end + +parsers.openelt_block = parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.more + +parsers.closeelt_any = parsers.less * parsers.sp * parsers.slash + * parsers.keyword * parsers.sp * parsers.more + +parsers.closeelt_exact = function(s) + return parsers.less * parsers.sp * parsers.slash * parsers.keyword_exact(s) + * parsers.sp * parsers.more +end + +parsers.emptyelt_any = parsers.less * parsers.sp * parsers.keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.emptyelt_block = parsers.less * parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.displaytext = (parsers.any - parsers.less)^1 + +-- return content between two matched HTML tags +parsers.in_matched = function(s) + return { parsers.openelt_exact(s) + * (V(1) + parsers.displaytext + + (parsers.less - parsers.closeelt_exact(s)))^0 + * parsers.closeelt_exact(s) } +end + +local function parse_matched_tags(s,pos) + local t = string.lower(lpeg.match(C(parsers.keyword),s,pos)) + return lpeg.match(parsers.in_matched(t),s,pos-1) +end + +parsers.in_matched_block_tags = parsers.less + * Cmt(#parsers.openelt_block, parse_matched_tags) + +parsers.displayhtml = parsers.htmlcomment + + parsers.emptyelt_block + + parsers.openelt_exact("hr") + + parsers.in_matched_block_tags + + parsers.htmlinstruction + +parsers.inlinehtml = parsers.emptyelt_any + + parsers.htmlcomment + + parsers.htmlinstruction + + parsers.openelt_any + + parsers.closeelt_any +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for HTML Entities +% +% \end{markdown} +% \begin{macrocode} +parsers.hexentity = parsers.ampersand * parsers.hash * S("Xx") + * C(parsers.hexdigit^1) * parsers.semicolon +parsers.decentity = parsers.ampersand * parsers.hash + * C(parsers.digit^1) * parsers.semicolon +parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) + * parsers.semicolon +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Helpers for References +% +% \end{markdown} +% \begin{macrocode} +-- parse a reference definition: [foo]: /bar "title" +parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * parsers.blankline^1 +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Inline Elements +% +% \end{markdown} +% \begin{macrocode} +parsers.Inline = V("Inline") +parsers.IndentedInline = V("IndentedInline") + +-- parse many p between starter and ender +parsers.between = function(p, starter, ender) + local ender2 = B(parsers.nonspacechar) * ender + return (starter * #parsers.nonspacechar * Ct(p * (p - ender2)^0) * ender2) +end + +parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Block Elements +% +% \end{markdown} +% \begin{macrocode} +parsers.Block = V("Block") + +parsers.OnlineImageURL + = parsers.leader + * parsers.onlineimageurl + * parsers.optionaltitle + +parsers.LocalFilePath + = parsers.leader + * parsers.localfilepath + * parsers.optionaltitle + +parsers.TildeFencedCode + = parsers.fencehead(parsers.tilde) + * Cs(parsers.fencedline(parsers.tilde)^0) + * parsers.fencetail(parsers.tilde) + +parsers.BacktickFencedCode + = parsers.fencehead(parsers.backtick) + * Cs(parsers.fencedline(parsers.backtick)^0) + * parsers.fencetail(parsers.backtick) + +parsers.lineof = function(c) + return (parsers.leader * (P(c) * parsers.optionalspace)^3 + * (parsers.newline * parsers.blankline^1 + + parsers.newline^-1 * parsers.eof)) +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Lists +% +% \end{markdown} +% \begin{macrocode} +parsers.defstartchar = S("~:") +parsers.defstart = ( parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-3) + + parsers.space * parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * parsers.space * parsers.defstartchar + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * parsers.space + * parsers.defstartchar * #parsers.spacing + ) + +parsers.dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0) +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Headings +% +% \end{markdown} +% \begin{macrocode} +parsers.heading_attribute = C(parsers.css_identifier) + + C((parsers.attribute_name_char + - parsers.rbrace)^1 + * parsers.equal + * (parsers.attribute_value_char + - parsers.rbrace)^1) +parsers.HeadingAttributes = parsers.lbrace + * parsers.heading_attribute + * (parsers.spacechar^1 + * parsers.heading_attribute)^0 + * parsers.rbrace + +-- parse Atx heading start and return level +parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6) + * -parsers.hash / length + +-- parse setext header ending and return level +parsers.HeadingLevel = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) + +local function strip_atx_end(s) + return s:gsub("[#%s]*\n$","") +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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 +% `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}) `options` and with a writer object `writer`. When +% `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 `reader->`\meta{member}. +% +% \end{markdown} +% \begin{macrocode} +M.reader = {} +function M.reader.new(writer, options) + local self = {} + options = options or {} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Make the `options` table inherit from the \luam{defaultOptions} table. +% +% \end{markdown} +% \begin{macrocode} + setmetatable(options, { __index = function (_, key) + return defaultOptions[key] end }) +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### 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. +% +% \end{markdown} +% \begin{macrocode} + local function normalize_tag(tag) + return unicode.utf8.lower( + gsub(util.rope_to_string(tag), "[ \n\r\t]+", " ")) + end +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{expandtabs} either as an identity function, when the +% \Opt{preserveTabs} Lua inrerface option is `true`, or to a function that +% expands tabs into spaces otherwise. +% +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +% The \luamdef{larsers} (as in ``local \luam{parsers}'') hash table stores +% \acro{peg} patterns that depend on the received `options`, which impedes +% their reuse between different \luam{reader} objects. +% +% \end{markdown} +% \begin{macrocode} + local larsers = {} +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Top-Level Parser Functions +% +% \end{markdown} +% \begin{macrocode} + local function create_parser(name, grammar) + return function(str) + local res = lpeg.match(grammar(), str) + if res == nil then + error(format("%s failed on:\n%s", name, str:sub(1,20))) + else + return res + end + end + end + + local parse_blocks + = create_parser("parse_blocks", + function() + return larsers.blocks + end) + + local parse_blocks_toplevel + = create_parser("parse_blocks_toplevel", + function() + return larsers.blocks_toplevel + end) + + local parse_inlines + = create_parser("parse_inlines", + function() + return larsers.inlines + end) + + local parse_inlines_no_link + = create_parser("parse_inlines_no_link", + function() + return larsers.inlines_no_link + end) + + local parse_inlines_no_inline_note + = create_parser("parse_inlines_no_inline_note", + function() + return larsers.inlines_no_inline_note + end) + + local parse_inlines_nbsp + = create_parser("parse_inlines_nbsp", + function() + return larsers.inlines_nbsp + end) +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Markdown Lists (local) +% +% \end{markdown} +% \begin{macrocode} + if options.hashEnumerators then + larsers.dig = parsers.digit + parsers.hash + else + larsers.dig = parsers.digit + end + + larsers.enumerator = C(larsers.dig^3 * parsers.period) * #parsers.spacing + + C(larsers.dig^2 * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^1) + + C(larsers.dig * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * C(larsers.dig^2 * parsers.period) + * #parsers.spacing + + parsers.space * C(larsers.dig * parsers.period) + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * C(larsers.dig^1 + * parsers.period) * #parsers.spacing +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Blockquotes (local) +% +% \end{markdown} +% \begin{macrocode} + -- strip off leading > and indents, and run through blocks + larsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/"" + * parsers.linechar^0 * parsers.newline)^1 + * (-(parsers.leader * parsers.more + + parsers.blankline) * parsers.linechar^1 + * parsers.newline)^0 + + if not options.breakableBlockquotes then + larsers.blockquote_body = larsers.blockquote_body + * (parsers.blankline^0 / "") + end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Citations (local) +% +% \end{markdown} +% \begin{macrocode} + larsers.citations = function(text_cites, raw_cites) + local function normalize(str) + if str == "" then + str = nil + else + str = (options.citationNbsps and parse_inlines_nbsp or + parse_inlines)(str) + end + return str + end + + local cites = {} + for i = 1,#raw_cites,4 do + cites[#cites+1] = { + prenote = normalize(raw_cites[i]), + suppress_author = raw_cites[i+1] == "-", + name = writer.citation(raw_cites[i+2]), + postnote = normalize(raw_cites[i+3]), + } + end + return writer.citations(text_cites, cites) + end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Footnotes (local) +% +% \end{markdown} +% \begin{macrocode} + local rawnotes = {} + + -- like indirect_link + local function lookup_note(ref) + return function() + local found = rawnotes[normalize_tag(ref)] + if found then + return writer.note(parse_blocks_toplevel(found)) + else + return {"[", parse_inlines("^" .. ref), "]"} + end + end + end + + local function register_note(ref,rawnote) + rawnotes[normalize_tag(ref)] = rawnote + return "" + end + + larsers.NoteRef = parsers.RawNoteRef / lookup_note + + + larsers.NoteBlock = parsers.leader * parsers.RawNoteRef * parsers.colon + * parsers.spnl * parsers.indented_blocks(parsers.chunk) + / register_note + + larsers.InlineNote = parsers.circumflex + * (parsers.tag / parse_inlines_no_inline_note) -- no notes inside notes + / writer.note +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Tables (local) +% +% \end{markdown} +% \begin{macrocode} +larsers.table_row = pipe_table_row(true + , (C((parsers.linechar - parsers.pipe)^1) + / parse_inlines) + , parsers.pipe + , (C((parsers.linechar - parsers.pipe)^0) + / parse_inlines)) + +if options.tableCaptions then + larsers.table_caption = #parsers.table_caption_beginning + * parsers.table_caption_beginning + * Ct(parsers.IndentedInline^1) + * parsers.newline +else + larsers.table_caption = parsers.fail +end + +larsers.PipeTable = Ct(larsers.table_row * parsers.newline + * parsers.table_hline + * (parsers.newline * larsers.table_row)^0) + / make_pipe_table_rectangular + * larsers.table_caption^-1 + / writer.table +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Helpers for Links and References (local) +% +% \end{markdown} +% \begin{macrocode} + -- List of references defined in the document + local references + + -- add a reference to the list + local function register_link(tag,url,title) + references[normalize_tag(tag)] = { url = url, title = title } + return "" + end + + -- lookup link reference and return either + -- the link or nil and fallback text. + local function lookup_reference(label,sps,tag) + local tagpart + if not tag then + tag = label + tagpart = "" + elseif tag == "" then + tag = label + tagpart = "[]" + else + tagpart = {"[", parse_inlines(tag), "]"} + end + if sps then + tagpart = {sps, tagpart} + end + local r = references[normalize_tag(tag)] + if r then + return r + else + return nil, {"[", parse_inlines(label), "]", tagpart} + end + end + + -- lookup link reference and return a link, if the reference is found, + -- or a bracketed label otherwise. + local function indirect_link(label,sps,tag) + return function() + local r,fallback = lookup_reference(label,sps,tag) + if r then + return writer.link(parse_inlines_no_link(label), r.url, r.title) + else + return fallback + end + end + end + + -- lookup image reference and return an image, if the reference is found, + -- or a bracketed label otherwise. + local function indirect_image(label,sps,tag) + return function() + local r,fallback = lookup_reference(label,sps,tag) + if r then + return writer.image(writer.string(label), r.url, r.title) + else + return {"!", fallback} + end + end + end +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Inline Elements (local) +% +% \end{markdown} +% \begin{macrocode} + larsers.Str = parsers.normalchar^1 / writer.string + + larsers.Symbol = (parsers.specialchar - parsers.tightblocksep) + / writer.string + + larsers.Ellipsis = P("...") / writer.ellipsis + + larsers.Smart = larsers.Ellipsis + + larsers.Code = parsers.inticks / writer.code + + if options.blankBeforeBlockquote then + larsers.bqstart = parsers.fail + else + larsers.bqstart = parsers.more + end + + if options.blankBeforeHeading then + larsers.headerstart = parsers.fail + else + larsers.headerstart = parsers.hash + + (parsers.line * (parsers.equal^1 + parsers.dash^1) + * parsers.optionalspace * parsers.newline) + end + + if not options.fencedCode or options.blankBeforeCodeFence then + larsers.fencestart = parsers.fail + else + larsers.fencestart = parsers.fencehead(parsers.backtick) + + parsers.fencehead(parsers.tilde) + end + + larsers.Endline = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.space + + larsers.OptionalIndent + = parsers.spacechar^1 / writer.space + + larsers.Space = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.space + + larsers.NonbreakingEndline + = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.nbsp + + larsers.NonbreakingSpace + = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.nbsp + + if options.underscores then + larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, + parsers.doubleasterisks) + + parsers.between(parsers.Inline, parsers.doubleunderscores, + parsers.doubleunderscores) + ) / writer.strong + + larsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, + parsers.asterisk) + + parsers.between(parsers.Inline, parsers.underscore, + parsers.underscore) + ) / writer.emphasis + else + larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, + parsers.doubleasterisks) + ) / writer.strong + + larsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, + parsers.asterisk) + ) / writer.emphasis + end + + larsers.AutoLinkUrl = parsers.less + * C(parsers.alphanumeric^1 * P("://") * parsers.urlchar^1) + * parsers.more + / function(url) + return writer.link(writer.string(url), url) + end + + larsers.AutoLinkEmail = parsers.less + * C((parsers.alphanumeric + S("-._+"))^1 + * P("@") * parsers.urlchar^1) + * parsers.more + / function(email) + return writer.link(writer.string(email), + "mailto:"..email) + end + + larsers.DirectLink = (parsers.tag / parse_inlines_no_link) -- no links inside links + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.link + + larsers.IndirectLink = parsers.tag * (C(parsers.spnl) * parsers.tag)^-1 + / indirect_link + + -- parse a link or image (direct or indirect) + larsers.Link = larsers.DirectLink + larsers.IndirectLink + + larsers.DirectImage = parsers.exclamation + * (parsers.tag / parse_inlines) + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.image + + larsers.IndirectImage = parsers.exclamation * parsers.tag + * (C(parsers.spnl) * parsers.tag)^-1 / indirect_image + + larsers.Image = larsers.DirectImage + larsers.IndirectImage + + larsers.TextCitations = Ct(Cc("") + * parsers.citation_name + * ((parsers.spnl + * parsers.lbracket + * parsers.citation_headless_body + * parsers.rbracket) + Cc(""))) + / function(raw_cites) + return larsers.citations(true, raw_cites) + end + + larsers.ParenthesizedCitations + = Ct(parsers.lbracket + * parsers.citation_body + * parsers.rbracket) + / function(raw_cites) + return larsers.citations(false, raw_cites) + end + + larsers.Citations = larsers.TextCitations + larsers.ParenthesizedCitations + + -- avoid parsing long strings of * or _ as emph/strong + larsers.UlOrStarLine = parsers.asterisk^4 + parsers.underscore^4 + / writer.string + + larsers.EscapedChar = S("\\") * C(parsers.escapable) / writer.string + + larsers.InlineHtml = C(parsers.inlinehtml) / writer.inline_html + + larsers.HtmlEntity = parsers.hexentity / entities.hex_entity / writer.string + + parsers.decentity / entities.dec_entity / writer.string + + parsers.tagentity / entities.char_entity / writer.string +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Block Elements (local) +% +% \end{markdown} +% \begin{macrocode} + larsers.ContentBlock = parsers.leader + * (parsers.localfilepath + parsers.onlineimageurl) + * parsers.contentblock_tail + / writer.contentblock + + larsers.DisplayHtml = C(parsers.displayhtml) + / expandtabs / writer.display_html + + larsers.Verbatim = Cs( (parsers.blanklines + * ((parsers.indentedline - parsers.blankline))^1)^1 + ) / expandtabs / writer.verbatim + + larsers.FencedCode = (parsers.TildeFencedCode + + parsers.BacktickFencedCode) + / function(infostring, code) + return writer.fencedCode(writer.string(infostring), + expandtabs(code)) + end + + larsers.Blockquote = Cs(larsers.blockquote_body^1) + / parse_blocks_toplevel / writer.blockquote + + larsers.HorizontalRule = ( parsers.lineof(parsers.asterisk) + + parsers.lineof(parsers.dash) + + parsers.lineof(parsers.underscore) + ) / writer.hrule + + larsers.Reference = parsers.define_reference_parser / register_link + + larsers.Paragraph = parsers.nonindentspace * Ct(parsers.Inline^1) + * parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + ) + / writer.paragraph + + larsers.ToplevelParagraph + = parsers.nonindentspace * Ct(parsers.Inline^1) + * ( parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + + parsers.eof + ) + + parsers.eof ) + / writer.paragraph + + larsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) + / writer.plain +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Lists (local) +% +% \end{markdown} +% \begin{macrocode} + larsers.starter = parsers.bullet + larsers.enumerator + + -- we use \001 as a separator between a tight list item and a + -- nested list under it. + larsers.NestedList = Cs((parsers.optionallyindentedline + - larsers.starter)^1) + / function(a) return "\001"..a end + + larsers.ListBlockLine = parsers.optionallyindentedline + - parsers.blankline - (parsers.indent^-1 + * larsers.starter) + + larsers.ListBlock = parsers.line * larsers.ListBlockLine^0 + + larsers.ListContinuationBlock = parsers.blanklines * (parsers.indent / "") + * larsers.ListBlock + + larsers.TightListItem = function(starter) + return -larsers.HorizontalRule + * (Cs(starter / "" * larsers.ListBlock * larsers.NestedList^-1) + / parse_blocks) + * -(parsers.blanklines * parsers.indent) + end + + larsers.LooseListItem = function(starter) + return -larsers.HorizontalRule + * Cs( starter / "" * larsers.ListBlock * Cc("\n") + * (larsers.NestedList + larsers.ListContinuationBlock^0) + * (parsers.blanklines / "\n\n") + ) / parse_blocks + end + + larsers.BulletList = ( Ct(larsers.TightListItem(parsers.bullet)^1) * Cc(true) + * parsers.skipblanklines * -parsers.bullet + + Ct(larsers.LooseListItem(parsers.bullet)^1) * Cc(false) + * parsers.skipblanklines ) + / writer.bulletlist + + local function ordered_list(items,tight,startNumber) + if options.startNumber then + startNumber = tonumber(startNumber) or 1 -- fallback for '#' + if startNumber ~= nil then + startNumber = math.floor(startNumber) + end + else + startNumber = nil + end + return writer.orderedlist(items,tight,startNumber) + end + + larsers.OrderedList = Cg(larsers.enumerator, "listtype") * + ( Ct(larsers.TightListItem(Cb("listtype")) + * larsers.TightListItem(larsers.enumerator)^0) + * Cc(true) * parsers.skipblanklines * -larsers.enumerator + + Ct(larsers.LooseListItem(Cb("listtype")) + * larsers.LooseListItem(larsers.enumerator)^0) + * Cc(false) * parsers.skipblanklines + ) * Cb("listtype") / ordered_list + + local function definition_list_item(term, defs, tight) + return { term = parse_inlines(term), definitions = defs } + end + + larsers.DefinitionListItemLoose = C(parsers.line) * parsers.skipblanklines + * Ct((parsers.defstart + * parsers.indented_blocks(parsers.dlchunk) + / parse_blocks_toplevel)^1) + * Cc(false) / definition_list_item + + larsers.DefinitionListItemTight = C(parsers.line) + * Ct((parsers.defstart * parsers.dlchunk + / parse_blocks)^1) + * Cc(true) / definition_list_item + + larsers.DefinitionList = ( Ct(larsers.DefinitionListItemLoose^1) * Cc(false) + + Ct(larsers.DefinitionListItemTight^1) + * (parsers.skipblanklines + * -larsers.DefinitionListItemLoose * Cc(true)) + ) / writer.definitionlist +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Blank (local) +% +% \end{markdown} +% \begin{macrocode} + larsers.Blank = parsers.blankline / "" + + larsers.NoteBlock + + larsers.Reference + + (parsers.tightblocksep / "\n") +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Headings (local) +% +% \end{markdown} +% \begin{macrocode} + -- parse atx header + if options.headerAttributes then + larsers.AtxHeading = Cg(parsers.HeadingStart,"level") + * parsers.optionalspace + * (C(((parsers.linechar + - ((parsers.hash^1 + * parsers.optionalspace + * parsers.HeadingAttributes^-1 + + parsers.HeadingAttributes) + * parsers.optionalspace + * parsers.newline)) + * (parsers.linechar + - parsers.hash + - parsers.lbrace)^0)^1) + / parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.hash^1 + * parsers.optionalspace + * parsers.HeadingAttributes^-1 + + parsers.HeadingAttributes) + * parsers.optionalspace + * parsers.newline), "attributes") + * Cb("level") + * Cb("attributes") + / writer.heading + + larsers.SetextHeading = #(parsers.line * S("=-")) + * (C(((parsers.linechar + - (parsers.HeadingAttributes + * parsers.optionalspace + * parsers.newline)) + * (parsers.linechar + - parsers.lbrace)^0)^1) + / parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.HeadingAttributes + * parsers.optionalspace + * parsers.newline)), "attributes") + * parsers.HeadingLevel + * Cb("attributes") + * parsers.optionalspace + * parsers.newline + / writer.heading + else + larsers.AtxHeading = Cg(parsers.HeadingStart,"level") + * parsers.optionalspace + * (C(parsers.line) / strip_atx_end / parse_inlines) + * Cb("level") + / writer.heading + + larsers.SetextHeading = #(parsers.line * S("=-")) + * Ct(parsers.linechar^1 / parse_inlines) + * parsers.newline + * parsers.HeadingLevel + * parsers.optionalspace + * parsers.newline + / writer.heading + end + + larsers.Heading = larsers.AtxHeading + larsers.SetextHeading +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Syntax Specification +% +% \end{markdown} +% \begin{macrocode} + local syntax = + { "Blocks", + + Blocks = larsers.Blank^0 * parsers.Block^-1 + * (larsers.Blank^0 / writer.interblocksep + * parsers.Block)^0 + * larsers.Blank^0 * parsers.eof, + + Blank = larsers.Blank, + + Block = V("ContentBlock") + + V("Blockquote") + + V("PipeTable") + + V("Verbatim") + + V("FencedCode") + + V("HorizontalRule") + + V("BulletList") + + V("OrderedList") + + V("Heading") + + V("DefinitionList") + + V("DisplayHtml") + + V("Paragraph") + + V("Plain"), + + ContentBlock = larsers.ContentBlock, + Blockquote = larsers.Blockquote, + Verbatim = larsers.Verbatim, + FencedCode = larsers.FencedCode, + HorizontalRule = larsers.HorizontalRule, + BulletList = larsers.BulletList, + OrderedList = larsers.OrderedList, + Heading = larsers.Heading, + DefinitionList = larsers.DefinitionList, + DisplayHtml = larsers.DisplayHtml, + Paragraph = larsers.Paragraph, + PipeTable = larsers.PipeTable, + Plain = larsers.Plain, + + Inline = V("Str") + + V("Space") + + V("Endline") + + V("UlOrStarLine") + + V("Strong") + + V("Emph") + + V("InlineNote") + + V("NoteRef") + + V("Citations") + + V("Link") + + V("Image") + + V("Code") + + V("AutoLinkUrl") + + V("AutoLinkEmail") + + V("InlineHtml") + + V("HtmlEntity") + + V("EscapedChar") + + V("Smart") + + V("Symbol"), + + IndentedInline = V("Str") + + V("OptionalIndent") + + V("Endline") + + V("UlOrStarLine") + + V("Strong") + + V("Emph") + + V("InlineNote") + + V("NoteRef") + + V("Citations") + + V("Link") + + V("Image") + + V("Code") + + V("AutoLinkUrl") + + V("AutoLinkEmail") + + V("InlineHtml") + + V("HtmlEntity") + + V("EscapedChar") + + V("Smart") + + V("Symbol"), + + Str = larsers.Str, + Space = larsers.Space, + OptionalIndent = larsers.OptionalIndent, + Endline = larsers.Endline, + UlOrStarLine = larsers.UlOrStarLine, + Strong = larsers.Strong, + Emph = larsers.Emph, + InlineNote = larsers.InlineNote, + NoteRef = larsers.NoteRef, + Citations = larsers.Citations, + Link = larsers.Link, + Image = larsers.Image, + Code = larsers.Code, + AutoLinkUrl = larsers.AutoLinkUrl, + AutoLinkEmail = larsers.AutoLinkEmail, + InlineHtml = larsers.InlineHtml, + HtmlEntity = larsers.HtmlEntity, + EscapedChar = larsers.EscapedChar, + Smart = larsers.Smart, + Symbol = larsers.Symbol, + } + + if not options.citations then + syntax.Citations = parsers.fail + end + + if not options.contentBlocks then + syntax.ContentBlock = parsers.fail + end + + if not options.codeSpans then + syntax.Code = parsers.fail + end + + if not options.definitionLists then + syntax.DefinitionList = parsers.fail + end + + if not options.fencedCode then + syntax.FencedCode = parsers.fail + end + + if not options.footnotes then + syntax.NoteRef = parsers.fail + end + + if not options.html then + syntax.DisplayHtml = parsers.fail + syntax.InlineHtml = parsers.fail + syntax.HtmlEntity = parsers.fail + end + + if not options.inlineFootnotes then + syntax.InlineNote = parsers.fail + end + + if not options.smartEllipses then + syntax.Smart = parsers.fail + end + + if not options.pipeTables then + syntax.PipeTable = parsers.fail + end + + local blocks_toplevel_t = util.table_copy(syntax) + blocks_toplevel_t.Paragraph = larsers.ToplevelParagraph + larsers.blocks_toplevel = Ct(blocks_toplevel_t) + + larsers.blocks = Ct(syntax) + + local inlines_t = util.table_copy(syntax) + inlines_t[1] = "Inlines" + inlines_t.Inlines = parsers.Inline^0 * (parsers.spacing^0 * parsers.eof / "") + larsers.inlines = Ct(inlines_t) + + local inlines_no_link_t = util.table_copy(inlines_t) + inlines_no_link_t.Link = parsers.fail + larsers.inlines_no_link = Ct(inlines_no_link_t) + + local inlines_no_inline_note_t = util.table_copy(inlines_t) + inlines_no_inline_note_t.InlineNote = parsers.fail + larsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t) + + local inlines_nbsp_t = util.table_copy(inlines_t) + inlines_nbsp_t.Endline = larsers.NonbreakingEndline + inlines_nbsp_t.Space = larsers.NonbreakingSpace + larsers.inlines_nbsp = Ct(inlines_nbsp_t) +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Exported Conversion Function +% Define \luamdef{reader->convert} as a function that converts markdown string +% `input` into a plain \TeX{} output and returns it. Note that the converter +% assumes that the input has \acro{unix} line endings. +% +% \end{markdown} +% \begin{macrocode} + function self.convert(input) + references = {} +% \end{macrocode} +% \begin{markdown} +% When determining the name of the cache file, create salt for the hashing +% function out of the package version and the passed options recognized by the +% Lua interface (see Section \ref{sec:luaoptions}). The \Opt{cacheDir} option +% is disregarded. +% \end{markdown} +% \begin{macrocode} + local opt_string = {} + for k,_ in pairs(defaultOptions) do + local v = options[k] + if k ~= "cacheDir" then + opt_string[#opt_string+1] = k .. "=" .. tostring(v) + end + end + table.sort(opt_string) + local salt = table.concat(opt_string, ",") .. "," .. metadata.version +% \end{macrocode} +% \begin{markdown} +% Produce the cache file, transform its filename via the \luam{writer->pack} +% method, and return the result. +% \end{markdown} +% \begin{macrocode} + local name = util.cache(options.cacheDir, input, salt, function(input) + return util.rope_to_string(parse_blocks_toplevel(input)) .. writer.eof + end, ".md" .. writer.suffix) + return writer.pack(name) + end + return self +end +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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}) `options` and with a writer object associated with +% `options`. +% +% \end{markdown} +% \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> +%<*lua-cli> +% \fi +% \par +% \begin{markdown} +% +%### Command-Line Implementation +% \label{sec:lua-cli-implementation} +% The command-line implementation provides the actual conversion routine for +% the command-line interface described in Section~\ref{sec:lua-cli-interface}. +% +% \end{markdown} +% \begin{macrocode} + +local input +if input_filename then + local input_file = io.open(input_filename, "r") + input = assert(input_file:read("*a")) + input_file:close() +else + input = assert(io.read("*a")) +end + +% \end{macrocode} +% \begin{markdown} +% First, ensure that the `options.cacheDir` directory exists. +% \end{markdown} +% \begin{macrocode} +local lfs = require("lfs") +if options.cacheDir and not lfs.isdir(options.cacheDir) then + assert(lfs.mkdir(options["cacheDir"])) +end + +local kpse = require("kpse") +kpse.set_program_name("luatex") +local md = require("markdown") +% \end{macrocode} +% \begin{markdown} +% Since we are loading the rest of the Lua implementation dynamically, +% check that both the `markdown` module and the command line implementation +% are the same version. +% \end{markdown} +% \begin{macrocode} +if metadata.version ~= md.metadata.version then + warn("markdown-cli.lua " .. metadata.version .. " used with " .. + "markdown.lua " .. md.metadata.version .. ".") +end +local convert = md.new(options) +local output = convert(input:gsub("\r\n?", "\n")) + +if output_filename then + local output_file = io.open(output_filename, "w") + assert(output_file:write(output)) + assert(output_file:close()) +else + assert(io.write(output)) +end +% \end{macrocode} +% \iffalse +%</lua-cli> +%<*tex> +% \fi +% \par +% \begin{markdown} +% +% 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}). +% +%### Logging Facilities +% \label{sec:texinterfacelogging} +% +% \end{markdown} +% \begin{macrocode} +\def\markdownInfo#1{% + \immediate\write-1{(l.\the\inputlineno) markdown.tex info: #1.}}% +\def\markdownWarning#1{% + \immediate\write16{(l.\the\inputlineno) markdown.tex warning: #1}}% +\def\markdownError#1#2{% + \errhelp{#2.}% + \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Token Renderer Prototypes +% The following definitions should be considered placeholder. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownRendererInterblockSeparatorPrototype{\par}% +\def\markdownRendererLineBreakPrototype{\hfil\break}% +\let\markdownRendererEllipsisPrototype\dots +\def\markdownRendererNbspPrototype{~}% +\def\markdownRendererLeftBracePrototype{\char`\{}% +\def\markdownRendererRightBracePrototype{\char`\}}% +\def\markdownRendererDollarSignPrototype{\char`$}% +\def\markdownRendererPercentSignPrototype{\char`\%}% +\def\markdownRendererAmpersandPrototype{\char`&}% +\def\markdownRendererUnderscorePrototype{\char`_}% +\def\markdownRendererHashPrototype{\char`\#}% +\def\markdownRendererCircumflexPrototype{\char`^}% +\def\markdownRendererBackslashPrototype{\char`\\}% +\def\markdownRendererTildePrototype{\char`~}% +\def\markdownRendererPipePrototype{|}% +\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% +\def\markdownRendererLinkPrototype#1#2#3#4{#2}% +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \markdownInput{#3}}% +\def\markdownRendererContentBlockOnlineImagePrototype{% + \markdownRendererImage}% +\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{% + \markdownRendererInputFencedCode{#3}{#2}}% +\def\markdownRendererImagePrototype#1#2#3#4{#2}% +\def\markdownRendererUlBeginPrototype{}% +\def\markdownRendererUlBeginTightPrototype{}% +\def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% +\def\markdownRendererUlEndPrototype{}% +\def\markdownRendererUlEndTightPrototype{}% +\def\markdownRendererOlBeginPrototype{}% +\def\markdownRendererOlBeginTightPrototype{}% +\def\markdownRendererOlItemPrototype{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% +\def\markdownRendererOlEndPrototype{}% +\def\markdownRendererOlEndTightPrototype{}% +\def\markdownRendererDlBeginPrototype{}% +\def\markdownRendererDlBeginTightPrototype{}% +\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemEndPrototype{}% +\def\markdownRendererDlDefinitionBeginPrototype{}% +\def\markdownRendererDlDefinitionEndPrototype{\par}% +\def\markdownRendererDlEndPrototype{}% +\def\markdownRendererDlEndTightPrototype{}% +\def\markdownRendererEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% +\def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% +\def\markdownRendererInputVerbatimPrototype#1{% + \par{\tt\input#1\relax{}}\par}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \markdownRendererInputVerbatimPrototype{#1}}% +\def\markdownRendererHeadingOnePrototype#1{#1}% +\def\markdownRendererHeadingTwoPrototype#1{#1}% +\def\markdownRendererHeadingThreePrototype#1{#1}% +\def\markdownRendererHeadingFourPrototype#1{#1}% +\def\markdownRendererHeadingFivePrototype#1{#1}% +\def\markdownRendererHeadingSixPrototype#1{#1}% +\def\markdownRendererHorizontalRulePrototype{}% +\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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}). +% +% \end{markdown} +% \begin{macrocode} +\def\markdownLuaOptions{{% +\ifx\markdownOptionBlankBeforeBlockquote\undefined\else + blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote, +\fi +\ifx\markdownOptionBlankBeforeCodeFence\undefined\else + blankBeforeCodeFence = \markdownOptionBlankBeforeCodeFence, +\fi +\ifx\markdownOptionBlankBeforeHeading\undefined\else + blankBeforeHeading = \markdownOptionBlankBeforeHeading, +\fi +\ifx\markdownOptionBreakableBlockquotes\undefined\else + breakableBlockquotes = \markdownOptionBreakableBlockquotes, +\fi + cacheDir = "\markdownOptionCacheDir", +\ifx\markdownOptionCitations\undefined\else + citations = \markdownOptionCitations, +\fi +\ifx\markdownOptionCitationNbsps\undefined\else + citationNbsps = \markdownOptionCitationNbsps, +\fi +\ifx\markdownOptionCodeSpans\undefined\else + codeSpans = \markdownOptionCodeSpans, +\fi +\ifx\markdownOptionContentBlocks\undefined\else + contentBlocks = \markdownOptionContentBlocks, +\fi +\ifx\markdownOptionContentBlocksLanguageMap\undefined\else + contentBlocksLanguageMap = + "\markdownOptionContentBlocksLanguageMap", +\fi +\ifx\markdownOptionDefinitionLists\undefined\else + definitionLists = \markdownOptionDefinitionLists, +\fi +\ifx\markdownOptionFootnotes\undefined\else + footnotes = \markdownOptionFootnotes, +\fi +\ifx\markdownOptionFencedCode\undefined\else + fencedCode = \markdownOptionFencedCode, +\fi +\ifx\markdownOptionHashEnumerators\undefined\else + hashEnumerators = \markdownOptionHashEnumerators, +\fi +\ifx\markdownOptionHeaderAttributes\undefined\else + headerAttributes = \markdownOptionHeaderAttributes, +\fi +\ifx\markdownOptionHtml\undefined\else + html = \markdownOptionHtml, +\fi +\ifx\markdownOptionHybrid\undefined\else + hybrid = \markdownOptionHybrid, +\fi +\ifx\markdownOptionInlineFootnotes\undefined\else + inlineFootnotes = \markdownOptionInlineFootnotes, +\fi +\ifx\markdownOptionPipeTables\undefined\else + pipeTables = \markdownOptionPipeTables, +\fi +\ifx\markdownOptionPreserveTabs\undefined\else + preserveTabs = \markdownOptionPreserveTabs, +\fi +\ifx\markdownOptionShiftHeadings\undefined\else + shiftHeadings = "\markdownOptionShiftHeadings", +\fi +\ifx\markdownOptionSlice\undefined\else + slice = "\markdownOptionSlice", +\fi +\ifx\markdownOptionSmartEllipses\undefined\else + smartEllipses = \markdownOptionSmartEllipses, +\fi +\ifx\markdownOptionStartNumber\undefined\else + startNumber = \markdownOptionStartNumber, +\fi +\ifx\markdownOptionTableCaptions\undefined\else + tableCaptions = \markdownOptionTableCaptions, +\fi +\ifx\markdownOptionTightLists\undefined\else + tightLists = \markdownOptionTightLists, +\fi +\ifx\markdownOptionUnderscores\undefined\else + underscores = \markdownOptionUnderscores, +\fi} +}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownPrepare{% +% \end{macrocode} +% \begin{markdown} +% First, ensure that the \m{markdownOptionCacheDir} directory exists. +% \end{markdown} +% \begin{macrocode} +local lfs = require("lfs") +local cacheDir = "\markdownOptionCacheDir" +if not lfs.isdir(cacheDir) then + assert(lfs.mkdir(cacheDir)) +end +% \end{macrocode} +% \begin{markdown} +% Next, load the `markdown` module and create a converter function using +% the plain \TeX{} options, which were serialized to a Lua table via the +% \m{markdownLuaOptions} macro. +% \end{markdown} +% \begin{macrocode} +local md = require("markdown") +local convert = md.new(\markdownLuaOptions) +}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Buffering Markdown Input +% \label{sec:buffering} +% The macros \mdef{markdownInputFileStream} and \mdef{markdownOutputFileStream} +% contain the number of the input and output file streams that will be used for +% the IO operations of the package. +% +% \end{markdown} +% \begin{macrocode} +\csname newread\endcsname\markdownInputFileStream +\csname newwrite\endcsname\markdownOutputFileStream +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownReadAndConvertTab} macro contains the tab character literal. +% +% \end{markdown} +% \begin{macrocode} +\begingroup + \catcode`\^^I=12% + \gdef\markdownReadAndConvertTab{^^I}% +\endgroup +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \m{markdownReadAndConvert} macro is largely a rewrite of the +% \Hologo{LaTeX2e} \m{filecontents} macro to plain \TeX{}. +% +% \end{markdown} +% \begin{macrocode} +\begingroup +% \end{macrocode} +% \begin{markdown} +% Make the newline and tab characters active and swap the character codes of +% the backslash symbol (`\`) and the pipe symbol (`|`), so that we can use the +% backslash as an ordinary character inside the macro definition. Likewise, +% swap the character codes of the percent sign (`%`) and the ampersand (`@`), +% so that we can remove percent signs from the beginning of lines when +% \m{markdownOptionStripPercentSigns} is `true`. +% \end{markdown} +% \begin{macrocode} + \catcode`\^^M=13% + \catcode`\^^I=13% + \catcode`|=0% + \catcode`\\=12% + |catcode`@=14% + |catcode`|%=12@ + |gdef|markdownReadAndConvert#1#2{@ + |begingroup@ +% \end{macrocode} +% \begin{markdown} +% Open the \m{markdownOptionInputTempFileName} file for writing. +% \end{markdown} +% \begin{macrocode} + |immediate|openout|markdownOutputFileStream@ + |markdownOptionInputTempFileName|relax@ + |markdownInfo{Buffering markdown input into the temporary @ + input file "|markdownOptionInputTempFileName" and scanning @ + for the closing token sequence "#1"}@ +% \end{macrocode} +% \begin{markdown} +% Locally change the category of the special plain \TeX{} characters to +% *other* in order to prevent unwanted interpretation of the input. Change +% also the category of the space character, so that we can retrieve it +% unaltered. +% \end{markdown} +% \begin{macrocode} + |def|do##1{|catcode`##1=12}|dospecials@ + |catcode`| =12@ + |markdownMakeOther@ +% \end{macrocode} +% \begin{markdown} +% The \mdef{markdownReadAndConvertStripPercentSigns} macro will process the +% individual lines of output, stipping away leading percent signs (`%`) when +% \m{markdownOptionStripPercentSigns} is `true`. +% Notice the use of the comments (`@`) to ensure that the entire macro is at +% a single line and therefore no (active) newline symbols +% (`^^M`) are produced. +% \end{markdown} +% \begin{macrocode} + |def|markdownReadAndConvertStripPercentSign##1{@ + |markdownIfOption{StripPercentSigns}@ + |if##1%@ + |expandafter|expandafter|expandafter@ + |markdownReadAndConvertProcessLine@ + |else@ + |expandafter|expandafter|expandafter@ + |markdownReadAndConvertProcessLine@ + |expandafter|expandafter|expandafter##1@ + |fi@ + |else@ + |expandafter@ + |markdownReadAndConvertProcessLine@ + |expandafter##1@ + |fi}@ +% \end{macrocode} +% \begin{markdown} +% The \mdef{markdownReadAndConvertProcessLine} macro will process the individual +% lines of output. +% Notice the use of the comments (`@`) to ensure that the entire macro is at +% a single line and therefore no (active) newline symbols +% (`^^M`) are produced. +% \end{markdown} +% \begin{macrocode} + |def|markdownReadAndConvertProcessLine##1#1##2#1##3|relax{@ +% \end{macrocode} +% \begin{markdown} +% When the ending token sequence does not appear in the line, store the line in +% the \m{markdownOptionInputTempFileName} file. +% \end{markdown} +% \begin{macrocode} + |ifx|relax##3|relax@ + |immediate|write|markdownOutputFileStream{##1}@ + |else@ +% \end{macrocode} +% \begin{markdown} +% 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. +% \end{markdown} +% \begin{macrocode} + |def^^M{@ + |markdownInfo{The ending token sequence was found}@ + |immediate|closeout|markdownOutputFileStream@ + |endgroup@ + |markdownInput|markdownOptionInputTempFileName@ + #2}@ + |fi@ +% \end{macrocode} +% \begin{markdown} +% Repeat with the next line. +% \end{markdown} +% \begin{macrocode} + ^^M}@ +% \end{macrocode} +% \begin{markdown} +% Make the tab character active at expansion time and make it expand to a +% literal tab character. +% \end{markdown} +% \begin{macrocode} + |catcode`|^^I=13@ + |def^^I{|markdownReadAndConvertTab}@ +% \end{macrocode} +% \begin{markdown} +% 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. +% \end{markdown} +% \begin{macrocode} + |catcode`|^^M=13@ + |def^^M##1^^M{@ + |def^^M####1^^M{@ + |markdownReadAndConvertStripPercentSign####1#1#1|relax}@ + ^^M}@ + ^^M}@ +% \end{macrocode} +% \begin{markdown} +% Reset the character categories back to the former state. +% \end{markdown} +% \begin{macrocode} +|endgroup +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Lua Shell Escape Bridge +% \label{sec:luabridge} +% The following \TeX{} code is intended for \TeX{} engines that do not provide +% direct access to Lua, but expose the shell of the operating system. This +% corresponds to the \m{markdownMode} values of `0` and `1`. +% +% The \m{markdownLuaExecute} macro defined here and in Section +% \ref{sec:directlua} are meant to be indistinguishable to the remaining code. +% +% The package assumes that although the user is not using the Lua\TeX{} engine, +% their \TeX{} distribution contains it, and uses shell access to produce and +% execute Lua scripts using the \TeX{}Lua interpreter~[@luatex17, Section +% 3.1.1]. +% +% \end{markdown} +% \begin{macrocode} +\ifnum\markdownMode<2\relax +\ifnum\markdownMode=0\relax + \markdownInfo{Using mode 0: Shell escape via write18}% +\else + \markdownInfo{Using mode 1: Shell escape via os.execute}% +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownExecuteShellEscape} macro contains the numeric value indicating +% whether the shell access is enabled (`1`), disabled (`0`), or restricted +% (`2`). +% +% Inherit the value of the the \m{pdfshellescape} (Lua\TeX{}, \Hologo{pdfTeX}) +% or the \m{shellescape} (\Hologo{XeTeX}) commands. If neither of these +% commands is defined and Lua is available, attempt to access the +% \luam{status.shell_escape} configuration item. +% +% If you cannot detect, whether the shell access is enabled, act as if it were. +% +% \end{markdown} +% \begin{macrocode} +\ifx\pdfshellescape\undefined + \ifx\shellescape\undefined + \ifnum\markdownMode=0\relax + \def\markdownExecuteShellEscape{1}% + \else + \def\markdownExecuteShellEscape{% + \directlua{tex.sprint(status.shell_escape or "1")}}% + \fi + \else + \let\markdownExecuteShellEscape\shellescape + \fi +\else + \let\markdownExecuteShellEscape\pdfshellescape +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownExecuteDirect} macro executes the code it has received as +% its first argument by writing it to the output file stream 18, if Lua is +% unavailable, or by using the Lua \luam{os.execute} method otherwise. +% +% \end{markdown} +% \begin{macrocode} +\ifnum\markdownMode=0\relax + \def\markdownExecuteDirect#1{\immediate\write18{#1}}% +\else + \def\markdownExecuteDirect#1{% + \directlua{os.execute("\luaescapestring{#1}")}}% +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \mdef{markdownExecute} macro is a wrapper on top of +% \m{markdownExecuteDirect} that checks the value of +% \m{markdownExecuteShellEscape} and prints an error message if the shell is +% inaccessible. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownExecute#1{% + \ifnum\markdownExecuteShellEscape=1\relax + \markdownExecuteDirect{#1}% + \else + \markdownError{I can not access the shell}{Either run the TeX + compiler with the --shell-escape or the --enable-write18 flag, + or set shell_escape=t in the texmf.cnf file}% + \fi}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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. +% +% \end{markdown} +% \begin{macrocode} +\begingroup +% \end{macrocode} +% \begin{markdown} +% 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. +% \end{markdown} +% \begin{macrocode} + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownLuaExecute#1{% +% \end{macrocode} +% \begin{markdown} +% 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. +% \end{markdown} +% \begin{macrocode} + |immediate|openout|markdownOutputFileStream=% + |markdownOptionHelperScriptFileName + |markdownInfo{Writing a helper Lua script to the file + "|markdownOptionHelperScriptFileName"}% + |immediate|write|markdownOutputFileStream{% + local ran_ok, error = pcall(function() + local kpse = require("kpse") + kpse.set_program_name("luatex") + #1 + end) +% \end{macrocode} +% \begin{markdown} +% If there was an error, use the file \m{markdownOptionErrorTempFileName} to +% store the error message. +% \end{markdown} +% \begin{macrocode} + if not ran_ok then + local file = io.open("% + |markdownOptionOutputDir + /|markdownOptionErrorTempFileName", "w") + if file then + file:write(error .. "\n") + file:close() + end + print('\\markdownError{An error was encountered while executing + Lua code}{For further clues, examine the file + "|markdownOptionOutputDir + /|markdownOptionErrorTempFileName"}') + end}% + |immediate|closeout|markdownOutputFileStream +% \end{macrocode} +% \begin{markdown} +% Execute the generated \m{markdownOptionHelperScriptFileName} Lua script using +% the \TeX{}Lua binary and store the output in the +% \m{markdownOptionOutputTempFileName} file. +% \end{markdown} +% \begin{macrocode} + |markdownInfo{Executing a helper Lua script from the file + "|markdownOptionHelperScriptFileName" and storing the result in the + file "|markdownOptionOutputTempFileName"}% + |markdownExecute{texlua "|markdownOptionOutputDir + /|markdownOptionHelperScriptFileName" > % + "|markdownOptionOutputDir + /|markdownOptionOutputTempFileName"}% +% \end{macrocode} +% \begin{markdown} +% \m{input} the generated \m{markdownOptionOutputTempFileName} file. +% \end{markdown} +% \begin{macrocode} + |input|markdownOptionOutputTempFileName|relax}% +|endgroup +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Direct Lua Access +% \label{sec:directlua} +% The following \TeX{} code is intended for \TeX{} engines that provide +% direct access to Lua (Lua\TeX{}). The macro \m{markdownLuaExecute} defined +% here and in Section \ref{sec:luabridge} are meant to be indistinguishable to +% the remaining code. This corresponds to the \m{markdownMode} value of `2`. +% +% \end{markdown} +% \begin{macrocode} +\else +\markdownInfo{Using mode 2: Direct Lua access}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% 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}, +% +% \end{markdown} +% \begin{macrocode} +\def\markdownLuaExecute#1{\directlua{local print = tex.print #1}}% +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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{}. +% +% \end{markdown} +% \begin{macrocode} +\begingroup +% \end{macrocode} +% \begin{markdown} +% 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. +% \end{markdown} +% \begin{macrocode} + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownInput#1{% + |markdownInfo{Including markdown document "#1"}% +% \end{macrocode} +% \begin{markdown} +% Attempt to open the markdown document to record it in the `.log` and +% `.fls` files. This allows external programs such as \LaTeX Mk to track +% changes to the markdown document. +% \end{markdown} +% \begin{macrocode} + |openin|markdownInputFileStream#1 + |closein|markdownInputFileStream + |markdownLuaExecute{% + |markdownPrepare + local input = assert(io.open("% + |markdownOptionOutputDir + /#1", "r"):read("*a")) +% \end{macrocode} +% \begin{markdown} +% Since the Lua converter expects \acro{unix} line endings, normalize the +% input. +% \end{markdown} +% \begin{macrocode} + print(convert(input:gsub("\r\n?", "\n")))}}% +|endgroup +% \end{macrocode} +% \iffalse +%</tex> +%<*latex> +% \fi +% \par +% \begin{markdown} +% +% \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~[@latex17, Section 9]. As a consequence, we can directly reuse the +% existing plain \TeX{} implementation. +% +% \end{markdown} +% \begin{macrocode} +\input markdown +\def\markdownVersionSpace{ }% +\ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v% + \markdownVersion\markdownVersionSpace markdown renderer]% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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. +% +% \end{markdown} +% \begin{macrocode} +\renewcommand\markdownInfo[1]{\PackageInfo{markdown}{#1}}% +\renewcommand\markdownWarning[1]{\PackageWarning{markdown}{#1}}% +\renewcommand\markdownError[2]{\PackageError{markdown}{#1}{#2.}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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}). +% +% \end{markdown} +% \begin{macrocode} +\let\markdownInputPlainTeX\markdownInput +\renewcommand\markdownInput[2][]{% + \begingroup + \markdownSetup{#1}% + \markdownInputPlainTeX{#2}% + \endgroup}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% The \envm{markdown}, and \envm{markdown*} \LaTeX{} environments are +% implemented using the \m{markdownReadAndConvert} macro. +% +% \end{markdown} +% \begin{macrocode} +\renewenvironment{markdown}{% + \markdownReadAndConvert@markdown{}}\relax +\renewenvironment{markdown*}[1]{% + \markdownSetup{#1}% + \markdownReadAndConvert@markdown*}\relax +\begingroup +% \end{macrocode} +% \begin{markdown} +% Locally swap the category code of the backslash symbol with the pipe symbol, +% and of the left (`{`) and right brace (`}`) with the less-than (`<`) +% and greater-than (`>`) signs. This is required in order that all the +% special symbols that appear in the first argument of the +% `markdownReadAndConvert` macro have the category code *other*. +% \end{markdown} +% \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} +% \par +% \begin{markdown} +% +%### Options +% The supplied package options are processed using the \m{markdownSetup} macro. +% +% \end{markdown} +% \begin{macrocode} +\DeclareOption*{% + \expandafter\markdownSetup\expandafter{\CurrentOption}}% +\ProcessOptions\relax +% \end{macrocode} +% \par +% \begin{markdown} +% +% After processing the options, activate the `renderers` and +% `rendererPrototypes` keys. +% +% \end{markdown} +% \begin{macrocode} +\define@key{markdownOptions}{renderers}{% + \setkeys{markdownRenderers}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +\define@key{markdownOptions}{rendererPrototypes}{% + \setkeys{markdownRendererPrototypes}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Token Renderer Prototypes +% The following configuration should be considered placeholder. +% +% If the \m{markdownOptionTightLists} macro expands to `false`, do not load +% the \pkg{paralist} package. This is necessary for \Hologo{LaTeX2e} document +% classes that do not play nice with \pkg{paralist}, such as \pkg{beamer}. +% If the \m{markdownOptionTightLists} is undefined and the \pkg{beamer} +% document class is in use, then do not load the \pkg{paralist} package either. +% +% \end{markdown} +% \begin{macrocode} +\ifx\markdownOptionTightLists\undefined + \@ifclassloaded{beamer}{}{ + \RequirePackage{paralist}} +\else + \ifthenelse{\equal{\markdownOptionTightLists}{false}}{}{ + \RequirePackage{paralist}} +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% If we loaded the \pkg{paralist} package, define the respective renderer +% prototypes to make use of the capabilities of the package. Otherwise, +% define the renderer prototypes to fall back on the corresponding renderers +% for the non-tight lists. +% +% \end{markdown} +% \begin{macrocode} +\@ifpackageloaded{paralist}{ + \markdownSetup{rendererPrototypes={ + ulBeginTight = {\begin{compactitem}}, + ulEndTight = {\end{compactitem}}, + olBeginTight = {\begin{compactenum}}, + olEndTight = {\end{compactenum}}, + dlBeginTight = {\begin{compactdesc}}, + dlEndTight = {\end{compactdesc}}}} +}{ + \markdownSetup{rendererPrototypes={ + ulBeginTight = {\markdownRendererUlBegin}, + ulEndTight = {\markdownRendererUlEnd}, + olBeginTight = {\markdownRendererOlBegin}, + olEndTight = {\markdownRendererOlEnd}, + dlBeginTight = {\markdownRendererDlBegin}, + dlEndTight = {\markdownRendererDlEnd}}}} +\markdownSetup{rendererPrototypes={ + lineBreak = {\\}, + leftBrace = {\textbraceleft}, + rightBrace = {\textbraceright}, + dollarSign = {\textdollar}, + underscore = {\textunderscore}, + circumflex = {\textasciicircum}, + backslash = {\textbackslash}, + tilde = {\textasciitilde}, + pipe = {\textbar}, + codeSpan = {\texttt{#1}}, + contentBlock = {% + \ifthenelse{\equal{#1}{csv}}{% + \begin{table}% + \begin{center}% + \csvautotabular{#3}% + \end{center} + \ifx\empty#4\empty\else + \caption{#4}% + \fi + \label{tab:#1}% + \end{table}}{% + \markdownInput{#3}}}, + image = {% + \begin{figure}% + \begin{center}% + \includegraphics{#3}% + \end{center}% + \ifx\empty#4\empty\else + \caption{#4}% + \fi + \label{fig:#1}% + \end{figure}}, + ulBegin = {\begin{itemize}}, + ulItem = {\item}, + ulEnd = {\end{itemize}}, + olBegin = {\begin{enumerate}}, + olItem = {\item}, + olItemWithNumber = {\item[#1.]}, + olEnd = {\end{enumerate}}, + dlBegin = {\begin{description}}, + dlItem = {\item[#1]}, + dlEnd = {\end{description}}, + emphasis = {\emph{#1}}, + blockQuoteBegin = {\begin{quotation}}, + blockQuoteEnd = {\end{quotation}}, + inputVerbatim = {\VerbatimInput{#1}}, + inputFencedCode = {% + \ifx\relax#2\relax + \VerbatimInput{#1}% + \else + \ifx\minted@code\undefined + \ifx\lst@version\undefined + \markdownRendererInputFencedCode{#1}{}% +% \end{macrocode} +% \par +% \begin{markdown} +% +% When the \pkg{listings} package is loaded, use it for syntax highlighting. +% +% \end{markdown} +% \begin{macrocode} + \else + \lstinputlisting[language=#2]{#1}% + \fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% When the \pkg{minted} package is loaded, use it for syntax highlighting. +% The \pkg{minted} package is preferred over \pkg{listings}. +% +% \end{markdown} +% \begin{macrocode} + \else + \inputminted{#2}{#1}% + \fi + \fi}, + horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, + footnote = {\footnote{#1}}}} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Support the nesting of strong emphasis. +% +% \end{markdown} +% \begin{macrocode} +\newif\ifmarkdownLATEXStrongEmphasisNested +\markdownLATEXStrongEmphasisNestedfalse +\markdownSetup{rendererPrototypes={ + strongEmphasis = {% + \ifmarkdownLATEXStrongEmphasisNested + \markdownLATEXStrongEmphasisNestedfalse + \textmd{#1}% + \markdownLATEXStrongEmphasisNestedtrue + \else + \markdownLATEXStrongEmphasisNestedtrue + \textbf{#1}% + \markdownLATEXStrongEmphasisNestedfalse + \fi}}} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Support \LaTeX{} document classes that do not provide chapters. +% +% \end{markdown} +% \begin{macrocode} +\ifx\chapter\undefined + \markdownSetup{rendererPrototypes = { + headingOne = {\section{#1}}, + headingTwo = {\subsection{#1}}, + headingThree = {\subsubsection{#1}}, + headingFour = {\paragraph{#1}\leavevmode}, + headingFive = {\subparagraph{#1}\leavevmode}}} +\else + \markdownSetup{rendererPrototypes = { + headingOne = {\chapter{#1}}, + headingTwo = {\section{#1}}, + headingThree = {\subsection{#1}}, + headingFour = {\subsubsection{#1}}, + headingFive = {\paragraph{#1}\leavevmode}, + headingSix = {\subparagraph{#1}\leavevmode}}} +\fi +% \end{macrocode} +% \par +% \begin{markdown} +% +% There is a basic implementation for citations that uses the \LaTeX{} \m{cite} +% macro. There are also implementations that use the \pkg{natbib} \m{citep}, +% and \m{citet} macros, and the Bib\LaTeX{} \m{autocites} and \m{textcites} +% macros. These implementations will be used, when the respective packages are +% loaded. +% +% \end{markdown} +% \begin{macrocode} +\newcount\markdownLaTeXCitationsCounter + +% Basic implementation +\def\markdownLaTeXBasicCitations#1#2#3#4#5#6{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#4\relax + \ifx\relax#5\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \cite{#1#2#6}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobblethree + \fi + \else% Before a postnote (#5), dump the accumulator + \ifx\relax#1\relax\else + \cite{#1}% + \fi + \cite[#5]{#6}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobblethree + \fi + \else% Before a prenote (#4), dump the accumulator + \ifx\relax#1\relax\else + \cite{#1}% + \fi + \ifnum\markdownLaTeXCitationsCounter>1\relax + \space % Insert a space before the prenote in later citations + \fi + #4~\expandafter\cite\ifx\relax#5\relax{#6}\else[#5]{#6}\fi + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \fi + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobblethree + \fi\markdownLaTeXBasicCitations{#1#2#6},} +\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations + +% Natbib implementation +\def\markdownLaTeXNatbibCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#3\relax + \ifx\relax#4\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \citep{#1,#5}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% Before a postnote (#4), dump the accumulator + \ifx\relax#1\relax\else + \citep{#1}% + \fi + \citep[][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% Before a prenote (#3), dump the accumulator + \ifx\relax#1\relax\relax\else + \citep{#1}% + \fi + \citep[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \fi + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobbletwo + \fi\markdownLaTeXNatbibCitations{#1,#5}} +\def\markdownLaTeXNatbibTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#3\relax + \ifx\relax#4\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \citet{#1,#5}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% After a prenote or a postnote, dump the accumulator + \ifx\relax#1\relax\else + \citet{#1}% + \fi + , \citet[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax + , + \else + \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax + , + \fi + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% After a prenote or a postnote, dump the accumulator + \ifx\relax#1\relax\relax\else + \citet{#1}% + \fi + , \citet[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax + , + \else + \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax + , + \fi + \fi + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobbletwo + \fi\markdownLaTeXNatbibTextCitations{#1,#5}} + +% BibLaTeX implementation +\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \autocites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} +\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \textcites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} + +\markdownSetup{rendererPrototypes = { + cite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\autocites\undefined + \ifx\citep\undefined + \expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \else + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \fi + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXCitations + \expandafter{\expandafter}% + \fi}, + textCite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\autocites\undefined + \ifx\citep\undefined + \expandafter\expandafter\expandafter + \markdownLaTeXBasicTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \else + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \fi + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXTextCitations + \expandafter{\expandafter}% + \fi}}} +% \end{macrocode} +% \par +% \begin{markdown} +% +% Before consuming the parameters for the hyperlink renderer, we change the +% category code of the hash sign (`#`) to other, so that it cannot be +% mistaken for a parameter character. After the hyperlink has been typeset, +% we restore the original catcode. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownRendererLinkPrototype{% + \begingroup + \catcode`\#=12 + \def\next##1##2##3##4{% + ##1\footnote{% + \ifx\empty##4\empty\else##4: \fi\texttt<\url{##3}\texttt>}% + \endgroup}% + \next} +% \end{macrocode} +% \par +% \begin{markdown} +% +% There is a basic implementation of tables. If the \pkg{booktabs} package is +% loaded, then it is used to produce horizontal lines. +% +% \end{markdown} +% \begin{macrocode} +\newcount\markdownLaTeXRowCounter +\newcount\markdownLaTeXRowTotal +\newcount\markdownLaTeXColumnCounter +\newcount\markdownLaTeXColumnTotal +\newtoks\markdownLaTeXTable +\newtoks\markdownLaTeXTableAlignment +\newtoks\markdownLaTeXTableEnd +\@ifpackageloaded{booktabs}{ + \let\markdownLaTeXTopRule\toprule + \let\markdownLaTeXMidRule\midrule + \let\markdownLaTeXBottomRule\bottomrule +}{ + \let\markdownLaTeXTopRule\hline + \let\markdownLaTeXMidRule\hline + \let\markdownLaTeXBottomRule\hline +} +\markdownSetup{rendererPrototypes={ + table = {% + \markdownLaTeXTable={}% + \markdownLaTeXTableAlignment={}% + \markdownLaTeXTableEnd={% + \markdownLaTeXBottomRule + \end{tabular}}% + \ifx\empty#1\empty\else + \addto@hook\markdownLaTeXTable{% + \begin{table} + \centering}% + \addto@hook\markdownLaTeXTableEnd{% + \caption{#1} + \end{table}}% + \fi + \addto@hook\markdownLaTeXTable{\begin{tabular}}% + \markdownLaTeXRowCounter=0% + \markdownLaTeXRowTotal=#2% + \markdownLaTeXColumnTotal=#3% + \markdownLaTeXRenderTableRow + } +}} +\def\markdownLaTeXRenderTableRow#1{% + \markdownLaTeXColumnCounter=0% + \ifnum\markdownLaTeXRowCounter=0\relax + \markdownLaTeXReadAlignments#1% + \markdownLaTeXTable=\expandafter\expandafter\expandafter{% + \expandafter\the\expandafter\markdownLaTeXTable\expandafter{% + \the\markdownLaTeXTableAlignment}}% + \addto@hook\markdownLaTeXTable{\markdownLaTeXTopRule}% + \else + \markdownLaTeXRenderTableCell#1% + \fi + \ifnum\markdownLaTeXRowCounter=1\relax + \addto@hook\markdownLaTeXTable\markdownLaTeXMidRule + \fi + \advance\markdownLaTeXRowCounter by 1\relax + \ifnum\markdownLaTeXRowCounter>\markdownLaTeXRowTotal\relax + \markdownInfo{\the\markdownLaTeXTable} + \markdownInfo{\the\markdownLaTeXTableEnd} + \the\markdownLaTeXTable + \the\markdownLaTeXTableEnd + \expandafter\@gobble + \fi\markdownLaTeXRenderTableRow} +\def\markdownLaTeXReadAlignments#1{% + \advance\markdownLaTeXColumnCounter by 1\relax + \if#1d% + \addto@hook\markdownLaTeXTableAlignment{l}% + \else + \addto@hook\markdownLaTeXTableAlignment{#1}% + \fi + \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax\else + \expandafter\@gobble + \fi\markdownLaTeXReadAlignments} +\def\markdownLaTeXRenderTableCell#1{% + \advance\markdownLaTeXColumnCounter by 1\relax + \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax + \addto@hook\markdownLaTeXTable{#1&}% + \else + \addto@hook\markdownLaTeXTable{#1\\}% + \expandafter\@gobble + \fi\markdownLaTeXRenderTableCell} +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Miscellanea +% When buffering user input, we should disable the bytes with the high bit set, +% since these are made active by the \pkg{inputenc} package. We will do this by +% redefining the \m{markdownMakeOther} macro accordingly. The code is courtesy +% of Scott Pakin, the creator of the \pkg{filecontents} package. +% +% \end{markdown} +% \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 +% \par +% \begin{markdown} +% +% \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 +% *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. +% +% \end{markdown} +% \begin{macrocode} +\def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\_\do\%\do\~}% +\input markdown +% \end{macrocode} +% \par +% \begin{markdown} +% +% When buffering user input, we should disable the bytes with the high bit set, +% since these are made active by the \m{enableregime} macro. We will do this +% by redefining the \m{markdownMakeOther} macro accordingly. The code is +% courtesy of Scott Pakin, the creator of the \pkg{filecontents} \LaTeX{} +% package. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownMakeOther{% + \count0=128\relax + \loop + \catcode\count0=11\relax + \advance\count0 by 1\relax + \ifnum\count0<256\repeat +% \end{macrocode} +% \par +% \begin{markdown} +% +% On top of that, make the pipe character (`|`) inactive during the scanning. +% This is necessary, since the character is active in \Hologo{ConTeXt}. +% +% \end{markdown} +% \begin{macrocode} + \catcode`|=12}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### 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. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownInfo#1{\writestatus{markdown}{#1.}}% +\def\markdownWarning#1{\writestatus{markdown\space warn}{#1.}}% +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Typesetting Markdown +% The \m{startmarkdown} and \m{stopmarkdown} macros are implemented using the +% \m{markdownReadAndConvert} macro. +% +% \end{markdown} +% \begin{macrocode} +\begingroup +% \end{macrocode} +% \begin{markdown} +% 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 `markdownReadAndConvert` macro have the category code +% *other*. +% \end{markdown} +% \begin{macrocode} + \catcode`\|=0% + \catcode`\\=12% + |gdef|startmarkdown{% + |markdownReadAndConvert{\stopmarkdown}% + {|stopmarkdown}}% +|endgroup +% \end{macrocode} +% \par +% \begin{markdown} +% +%### Token Renderer Prototypes +% The following configuration should be considered placeholder. +% +% \end{markdown} +% \begin{macrocode} +\def\markdownRendererLineBreakPrototype{\blank}% +\def\markdownRendererLeftBracePrototype{\textbraceleft}% +\def\markdownRendererRightBracePrototype{\textbraceright}% +\def\markdownRendererDollarSignPrototype{\textdollar}% +\def\markdownRendererPercentSignPrototype{\percent}% +\def\markdownRendererUnderscorePrototype{\textunderscore}% +\def\markdownRendererCircumflexPrototype{\textcircumflex}% +\def\markdownRendererBackslashPrototype{\textbackslash}% +\def\markdownRendererTildePrototype{\textasciitilde}% +\def\markdownRendererPipePrototype{\char`|}% +\def\markdownRendererLinkPrototype#1#2#3#4{% + \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: + \fi\tt<\hyphenatedurl{#3}>}}% +\usemodule[database] +\defineseparatedlist + [MarkdownConTeXtCSV] + [separator={,}, + before=\bTABLE,after=\eTABLE, + first=\bTR,last=\eTR, + left=\bTD,right=\eTD] +\def\markdownConTeXtCSV{csv} +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \def\markdownConTeXtCSV@arg{#1}% + \ifx\markdownConTeXtCSV@arg\markdownConTeXtCSV + \placetable[][tab:#1]{#4}{% + \processseparatedfile[MarkdownConTeXtCSV][#3]}% + \else + \markdownInput{#3}% + \fi}% +\def\markdownRendererImagePrototype#1#2#3#4{% + \placefigure[][fig:#1]{#4}{\externalfigure[#3]}}% +\def\markdownRendererUlBeginPrototype{\startitemize}% +\def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% +\def\markdownRendererUlItemPrototype{\item}% +\def\markdownRendererUlEndPrototype{\stopitemize}% +\def\markdownRendererUlEndTightPrototype{\stopitemize}% +\def\markdownRendererOlBeginPrototype{\startitemize[n]}% +\def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% +\def\markdownRendererOlItemPrototype{\item}% +\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% +\def\markdownRendererOlEndPrototype{\stopitemize}% +\def\markdownRendererOlEndTightPrototype{\stopitemize}% +\definedescription + [MarkdownConTeXtDlItemPrototype] + [location=hanging, + margin=standard, + headstyle=bold]% +\definestartstop + [MarkdownConTeXtDlPrototype] + [before=\blank, + after=\blank]% +\definestartstop + [MarkdownConTeXtDlTightPrototype] + [before=\blank\startpacked, + after=\stoppacked\blank]% +\def\markdownRendererDlBeginPrototype{% + \startMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlBeginTightPrototype{% + \startMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererDlItemPrototype#1{% + \startMarkdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemEndPrototype{% + \stopMarkdownConTeXtDlItemPrototype}% +\def\markdownRendererDlEndPrototype{% + \stopMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlEndTightPrototype{% + \stopMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererEmphasisPrototype#1{{\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% +\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% +\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \ifx\relax#2\relax + \typefile{#1}% + \else +% \end{macrocode} +% \par +% \begin{markdown} +% +% The code fence infostring is used as a name from the \Hologo{ConTeXt} +% \m{definetyping} macro. This allows the user to set up code highlighting +% mapping as follows: +% ````` tex +% % Map the `TEX` syntax highlighter to the `latex` infostring. +% \definetyping [latex] +% \setuptyping [latex] [option=TEX] +% +% \starttext +% \startmarkdown +% ~~~ latex +% \documentclass{article} +% \begin{document} +% Hello world! +% \end{document} +% ~~~ +% \stopmarkdown +% \stoptext +% ````````` +% +% \end{markdown} +% \begin{macrocode} + \typefile[#2][]{#1}% + \fi}% +\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% +\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% +\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% +\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% +\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% +\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% +\def\markdownRendererHorizontalRulePrototype{% + \blackrule[height=1pt, width=\hsize]}% +\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% +\stopmodule\protect +% \end{macrocode} +% \par +% \begin{markdown} +% +% There is a basic implementation of tables. +% +% \end{markdown} +% \begin{macrocode} +\newcount\markdownConTeXtRowCounter +\newcount\markdownConTeXtRowTotal +\newcount\markdownConTeXtColumnCounter +\newcount\markdownConTeXtColumnTotal +\newtoks\markdownConTeXtTable +\newtoks\markdownConTeXtTableFloat +\def\markdownRendererTablePrototype#1#2#3{% + \markdownConTeXtTable={}% + \ifx\empty#1\empty + \markdownConTeXtTableFloat={% + \the\markdownConTeXtTable}% + \else + \markdownConTeXtTableFloat={% + \placetable{#1}{\the\markdownConTeXtTable}}% + \fi + \begingroup + \setupTABLE[r][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] + \setupTABLE[c][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] + \setupTABLE[r][1][topframe=on, bottomframe=on] + \setupTABLE[r][#1][bottomframe=on] + \markdownConTeXtRowCounter=0% + \markdownConTeXtRowTotal=#2% + \markdownConTeXtColumnTotal=#3% + \markdownConTeXtRenderTableRow} +\def\markdownConTeXtRenderTableRow#1{% + \markdownConTeXtColumnCounter=0% + \ifnum\markdownConTeXtRowCounter=0\relax + \markdownConTeXtReadAlignments#1% + \markdownConTeXtTable={\bTABLE}% + \else + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\bTR}% + \markdownConTeXtRenderTableCell#1% + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\eTR}% + \fi + \advance\markdownConTeXtRowCounter by 1\relax + \ifnum\markdownConTeXtRowCounter>\markdownConTeXtRowTotal\relax + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\eTABLE}% + \the\markdownConTeXtTableFloat + \endgroup + \expandafter\gobbleoneargument + \fi\markdownConTeXtRenderTableRow} +\def\markdownConTeXtReadAlignments#1{% + \advance\markdownConTeXtColumnCounter by 1\relax + \if#1d% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] + \fi\if#1l% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] + \fi\if#1c% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=middle] + \fi\if#1r% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=left] + \fi + \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else + \expandafter\gobbleoneargument + \fi\markdownConTeXtReadAlignments} +\def\markdownConTeXtRenderTableCell#1{% + \advance\markdownConTeXtColumnCounter by 1\relax + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\bTD#1\eTD}% + \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else + \expandafter\gobbleoneargument + \fi\markdownConTeXtRenderTableCell} +% \end{macrocode} +% \iffalse +%</context> +% \fi |