From 835ae450df95b8a97500efebbe995d9950c4e2b2 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 29 Aug 2016 21:19:56 +0000 Subject: markdown (29aug16) git-svn-id: svn://tug.org/texlive/trunk@41950 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/doc/generic/markdown/markdown.pdf | Bin 299789 -> 318364 bytes .../source/generic/markdown/markdown.dtx | 995 ++++++++++++++++----- .../tex/context/third/markdown/t-markdown.tex | 42 +- .../texmf-dist/tex/generic/markdown/markdown.tex | 146 ++- Master/texmf-dist/tex/latex/markdown/markdown.sty | 150 +++- Master/texmf-dist/tex/luatex/markdown/markdown.lua | 344 +++++-- 6 files changed, 1292 insertions(+), 385 deletions(-) diff --git a/Master/texmf-dist/doc/generic/markdown/markdown.pdf b/Master/texmf-dist/doc/generic/markdown/markdown.pdf index 36777fbd15b..8ef9dee5525 100644 Binary files a/Master/texmf-dist/doc/generic/markdown/markdown.pdf and b/Master/texmf-dist/doc/generic/markdown/markdown.pdf differ diff --git a/Master/texmf-dist/source/generic/markdown/markdown.dtx b/Master/texmf-dist/source/generic/markdown/markdown.dtx index d657c7eeb20..e400439b93d 100644 --- a/Master/texmf-dist/source/generic/markdown/markdown.dtx +++ b/Master/texmf-dist/source/generic/markdown/markdown.dtx @@ -145,13 +145,15 @@ %<*lua> % \fi % \begin{macrocode} -if not modules then modules = { } end modules ['markdown'] = { - version = "1.0.2", +local metadata = { + version = "2.1.0", comment = "A module for the conversion from markdown to plain TeX", author = "John MacFarlane, Hans Hagen, Vít Novotný", copyright = "2009-2016 John MacFarlane, Hans Hagen; 2016 Vít Novotný", license = "LPPL 1.3" } +if not modules then modules = { } end +modules['markdown'] = metadata % \end{macrocode} % % \subsection{Feedback} @@ -293,10 +295,10 @@ local md5 = require("md5") %<*lua> % \fi % \subsection{Lua Interface}\label{sec:luainterface} -% The Lua interface provides the conversion from markdown to plain \TeX{}. -% This interface is used by the plain \TeX{} implementation (see Section -% \ref{sec:teximplementation}) and will be of interest to the developers of -% other packages and Lua modules. +% The Lua interface provides the conversion from \acro{utf}-\oldstylenums8 +% encoded markdown to plain \TeX{}. This interface is used by the plain \TeX{} +% implementation (see Section \ref{sec:teximplementation}) and will be of +% interest to the developers of other packages and Lua modules. % % The Lua interface is implemented by the \t`markdown` Lua module. % @@ -340,6 +342,17 @@ local defaultOptions = {} defaultOptions.blankBeforeBlockquote = false % \end{macrocode} % +% \Optitem[false]{blankBeforeCodeFence}{\opt{true}, \opt{false}} +% \begin{valuelist} +% \item[true] Require a blank line between a paragraph and the following +% fenced code block. +% \item[false] Do not require a blank line between a paragraph and the +% following fenced code block. +% \end{valuelist} +% \begin{macrocode} +defaultOptions.blankBeforeCodeFence = false +% \end{macrocode} +% % \Optitem[false]{blankBeforeHeading}{\opt{true}, \opt{false}} % \begin{valuelist} % \item[true] Require a blank line between a paragraph and the following @@ -363,6 +376,43 @@ defaultOptions.blankBeforeHeading = false defaultOptions.cacheDir = "." % \end{macrocode} % +% \Optitem[false]{citationNbsps}{\opt{true}, \opt{false}} +% \begin{valuelist} +% \item[true] Replace regular spaces with non-breakable spaces inside the +% prenotes and postnotes of citations produced via the pandoc citation +% syntax extension. +% \item[false] Do not replace regular spaces with non-breakable spaces +% inside the prenotes and postnotes of citations produced via the pandoc +% citation syntax extension. +% \end{valuelist} +% \begin{macrocode} +defaultOptions.citationNbsps = true +% \end{macrocode} +% +% \Optitem[false]{citations}{\opt{true}, \opt{false}} +% \begin{valuelist} +% \item[true] Enable the pandoc citation syntax extension: +% \begin{Verbatim} +% Here is a simple parenthetical citation [@doe99] and here +% is a string of several [see @doe99, pp. 33-35; also +% @smith04, chap. 1]. +% +% A parenthetical citation can have a [prenote @doe99] and +% a [@smith04 postnote]. The name of the author can be +% suppressed by inserting a dash before the name of an +% author as follows [-@smith04]. +% +% Here is a simple text citation @doe99 and here is +% a string of several @doe99 [pp. 33-35; also @smith04, +% chap. 1]. Here is one with the name of the author +% suppressed -@doe99. +% \end{Verbatim} +% \item[false] Disable the pandoc citation syntax extension. +% \end{valuelist} +% \begin{macrocode} +defaultOptions.citations = false +% \end{macrocode} +% % \Optitem[false]{definitionLists}{\opt{true}, \opt{false}} % \begin{valuelist} % \item[true] Enable the pandoc definition list syntax extension: @@ -414,6 +464,33 @@ defaultOptions.hashEnumerators = false defaultOptions.hybrid = false % \end{macrocode} % +% \Optitem[false]{fencedCode}{\opt{true}, \opt{false}} +% \begin{valuelist} +% \item[true] Enable the commonmark fenced code block extension: +% \begin{Verbatim} +% ~~~ js +% if (a > 3) { +% moveShip(5 * gravity, DOWN); +% } +% ~~~~~~ +% +% ``` html +%
+%     
+%       // Some comments
+%       line 1 of code
+%       line 2 of code
+%       line 3 of code
+%     
+%   
+% ``` +% \end{Verbatim} +% \item[true] Disable the commonmark fenced code block extension. +% \end{valuelist} +% \begin{macrocode} +defaultOptions.fencedCode = false +% \end{macrocode} +% % \Optitem[false]{footnotes}{\opt{true}, \opt{false}} % \begin{valuelist} % \item[true] Enable the pandoc footnote syntax extension: @@ -498,8 +575,8 @@ defaultOptions.tightLists = true % \ref{sec:luaoptions}) used during the conversion from markdown to plain % \TeX{}, and for changing the way markdown the tokens are rendered. % \begin{macrocode} -\def\markdownLastModified{2016/08/14}% -\def\markdownVersion{1.0.2}% +\def\markdownLastModified{2016/08/20}% +\def\markdownVersion{2.1.0}% % \end{macrocode} % % The plain \TeX{} interface is implemented by the \t`markdown.tex` file that @@ -620,12 +697,12 @@ defaultOptions.tightLists = true % % The \mdef{markdownOptionCacheDir} macro corresponds to the Lua interface % \Opt{cacheDir} option that sets the name of the directory that will contain -% the produced cache files. The option defaults to \t`_markdown-`\m{jobname}, +% the produced cache files. The option defaults to \t`_markdown_`\m{jobname}, % which is a similar naming scheme to the one used by the \pkg{minted} \LaTeX{} % package. The same limitations apply here as in the case of the % \m{markdownOptionHelperScriptFileName} macro. % \begin{macrocode} -\def\markdownOptionCacheDir{_markdown-\jobname}% +\def\markdownOptionCacheDir{_markdown_\jobname}% % \end{macrocode} % % \paragraph{Lua Interface Options} @@ -635,11 +712,15 @@ defaultOptions.tightLists = true % makes them fall back to the default values provided by the Lua interface. % \begin{macrocode} \let\markdownOptionBlankBeforeBlockquote\undefined +\let\markdownOptionBlankBeforeCodeFence\undefined \let\markdownOptionBlankBeforeHeading\undefined +\let\markdownOptionCitations\undefined +\let\markdownOptionCitationNbsps\undefined \let\markdownOptionDefinitionLists\undefined +\let\markdownOptionFootnotes\undefined +\let\markdownOptionFencedCode\undefined \let\markdownOptionHashEnumerators\undefined \let\markdownOptionHybrid\undefined -\let\markdownOptionFootnotes\undefined \let\markdownOptionPreserveTabs\undefined \let\markdownOptionSmartEllipses\undefined \let\markdownOptionStartNumber\undefined @@ -654,6 +735,14 @@ defaultOptions.tightLists = true % document. By default, they point to the corresponding prototypes (see Section % \ref{sec:texrendererprototypes}). % +% \paragraph{Interblock Separator Renderer} +% The \mdef{markdownRendererInterblockSeparator} macro represents a separator +% between two markdown block elements. The macro receives no arguments. +% \begin{macrocode} +\def\markdownRendererInterblockSeparator{% + \markdownRendererInterblockSeparatorPrototype}% +% \end{macrocode} +% % \paragraph{Line Break Renderer} % The \mdef{markdownRendererLineBreak} macro represents a forced line break. % The macro receives no arguments. @@ -671,6 +760,13 @@ defaultOptions.tightLists = true \markdownRendererEllipsisPrototype}% % \end{macrocode} % +% \paragraph{Non-breaking Space Renderer} +% The \mdef{markdownRendererNbsp} macro represents a non-breaking space. +% \begin{macrocode} +\def\markdownRendererNbsp{% + \markdownRendererNbspPrototype}% +% \end{macrocode} +% % \paragraph{Special Character Renderers} % The following macros replace any special plain \TeX{} characters (including % the active pipe character (\t`|`) of \Hologo{ConTeXt}) in the input text. @@ -749,13 +845,19 @@ defaultOptions.tightLists = true % \end{macrocode} % % The \mdef{markdownRendererUlItem} macro represents an item in a bulleted -% list. -% The macro receives no arguments. +% list. The macro receives no arguments. % \begin{macrocode} \def\markdownRendererUlItem{% \markdownRendererUlItemPrototype}% % \end{macrocode} % +% The \mdef{markdownRendererUlItemEnd} macro represents the end of an item in a +% bulleted list. The macro receives no arguments. +% \begin{macrocode} +\def\markdownRendererUlItemEnd{% + \markdownRendererUlItemEndPrototype}% +% \end{macrocode} +% % The \mdef{markdownRendererUlEnd} macro represents the end of a bulleted list % that contains an item with several paragraphs of text (the list is not % tight). The macro receives no arguments. @@ -799,6 +901,13 @@ defaultOptions.tightLists = true \markdownRendererOlItemPrototype}% % \end{macrocode} % +% The \mdef{markdownRendererOlItemEnd} macro represents the end of an item in +% an ordered list. The macro receives no arguments. +% \begin{macrocode} +\def\markdownRendererOlItemEnd{% + \markdownRendererOlItemEndPrototype}% +% \end{macrocode} +% % The \mdef{markdownRendererOlItemWithNumber} macro represents an item in an % ordered list. This macro will only be produced, when the \Opt{startNumber} % option is \t`true`. The macro receives no arguments. @@ -853,6 +962,13 @@ defaultOptions.tightLists = true \markdownRendererDlItemPrototype}% % \end{macrocode} % +% The \mdef{markdownRendererDlItemEnd} macro represents the end of a list of +% definitions for a single term. +% \begin{macrocode} +\def\markdownRendererDlItemEnd{% + \markdownRendererDlItemEndPrototype}% +% \end{macrocode} +% % The \mdef{markdownRendererDlDefinitionBegin} macro represents the beginning % of a definition in a definition list. There can be several definitions for % a single term. @@ -918,15 +1034,24 @@ defaultOptions.tightLists = true \markdownRendererBlockQuoteEndPrototype}% % \end{macrocode} % -% \paragraph{Code Block Renderer} +% \paragraph{Code Block Renderers} % The \mdef{markdownRendererInputVerbatim} macro represents a code % block. The macro receives a single argument that corresponds to the -% filename of a file contaning the code block to input. +% filename of a file contaning the code block contents. % \begin{macrocode} \def\markdownRendererInputVerbatim{% \markdownRendererInputVerbatimPrototype}% % \end{macrocode} % +% The \mdef{markdownRendererInputFencedCode} macro represents a fenced code +% block. This macro will only be produced, when the \Opt{fencedCode} option is +% \t`true`. The macro receives two arguments that correspond to the filename of +% a file contaning the code block contents and to the code fence infostring. +% \begin{macrocode} +\def\markdownRendererInputFencedCode{% + \markdownRendererInputFencedCodePrototype}% +% \end{macrocode} +% % \paragraph{Heading Renderers} % The \mdef{markdownRendererHeadingOne} macro represents a first level heading. % The macro receives a single argument that corresponds to the heading text. @@ -992,6 +1117,31 @@ defaultOptions.tightLists = true \markdownRendererFootnotePrototype}% % \end{macrocode} % +% \paragraph{Parenthesized Citations Renderer} +% The \mdef{markdownRendererCite} macro represents a string of one or more +% parenthetical citations. This macro will only be produced, when the +% \Opt{citations} option is \t`true`. The macro receives the parameter +% \t`\textbraceleft`\meta{number of citations}\t`\textbraceright` followed by +% \meta{suppress author}\t`\textbraceleft`\meta{prenote}\t`\textbraceright^^A +% \textbraceleft`\meta{postnote}\t`\textbraceright\textbraceleft`\meta{name}^^A +% \t`\textbraceright` repeated \meta{number of citations} times. The +% \meta{suppress author} parameter is either the token \t`-`, when the author's +% name is to be suppressed, or \t`+` otherwise. +% \begin{macrocode} +\def\markdownRendererCite{% + \markdownRendererCitePrototype}% +% \end{macrocode} +% +% \paragraph{Text Citations Renderer} +% The \mdef{markdownRendererTextCite} macro represents a string of one or more +% text citations. This macro will only be produced, when the +% \Opt{citations} option is \t`true`. The macro receives parameters in the same +% format as the \m{markdownRendererCite} macro. +% \begin{macrocode} +\def\markdownRendererTextCite{% + \markdownRendererTextCitePrototype}% +% \end{macrocode} +% % \subsubsection{Token Renderer Prototypes}\label{sec:texrendererprototypes} % The following \TeX{} macros provide definitions for the token renderers (see % Section \ref{sec:texrenderersuser}) that have not been redefined by the @@ -1000,8 +1150,10 @@ defaultOptions.tightLists = true % by the \LaTeX{} and \Hologo{ConTeXt} implementations (see sections % \ref{sec:lateximplementation} and \ref{sec:contextimplementation}). % \begin{macrocode} +\def\markdownRendererInterblockSeparatorPrototype{}% \def\markdownRendererLineBreakPrototype{}% \def\markdownRendererEllipsisPrototype{}% +\def\markdownRendererNbspPrototype{}% \def\markdownRendererLeftBracePrototype{}% \def\markdownRendererRightBracePrototype{}% \def\markdownRendererDollarSignPrototype{}% @@ -1013,40 +1165,46 @@ defaultOptions.tightLists = true \def\markdownRendererBackslashPrototype{}% \def\markdownRendererTildePrototype{}% \def\markdownRendererPipePrototype{}% -\long\def\markdownRendererCodeSpanPrototype#1{}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{}% -\long\def\markdownRendererImagePrototype#1#2#3#4{}% +\def\markdownRendererCodeSpanPrototype#1{}% +\def\markdownRendererLinkPrototype#1#2#3#4{}% +\def\markdownRendererImagePrototype#1#2#3#4{}% \def\markdownRendererUlBeginPrototype{}% \def\markdownRendererUlBeginTightPrototype{}% \def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% \def\markdownRendererUlEndPrototype{}% \def\markdownRendererUlEndTightPrototype{}% \def\markdownRendererOlBeginPrototype{}% \def\markdownRendererOlBeginTightPrototype{}% \def\markdownRendererOlItemPrototype{}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% \def\markdownRendererOlEndPrototype{}% \def\markdownRendererOlEndTightPrototype{}% \def\markdownRendererDlBeginPrototype{}% \def\markdownRendererDlBeginTightPrototype{}% -\long\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemEndPrototype{}% \def\markdownRendererDlDefinitionBeginPrototype{}% \def\markdownRendererDlDefinitionEndPrototype{}% \def\markdownRendererDlEndPrototype{}% \def\markdownRendererDlEndTightPrototype{}% -\long\def\markdownRendererEmphasisPrototype#1{}% -\long\def\markdownRendererStrongEmphasisPrototype#1{}% +\def\markdownRendererEmphasisPrototype#1{}% +\def\markdownRendererStrongEmphasisPrototype#1{}% \def\markdownRendererBlockQuoteBeginPrototype{}% \def\markdownRendererBlockQuoteEndPrototype{}% -\long\def\markdownRendererInputVerbatimPrototype#1{}% -\long\def\markdownRendererHeadingOnePrototype#1{}% -\long\def\markdownRendererHeadingTwoPrototype#1{}% -\long\def\markdownRendererHeadingThreePrototype#1{}% -\long\def\markdownRendererHeadingFourPrototype#1{}% -\long\def\markdownRendererHeadingFivePrototype#1{}% -\long\def\markdownRendererHeadingSixPrototype#1{}% +\def\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{}% -\long\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% % \end{macrocode} % % \subsubsection{Logging Facilities} @@ -1165,7 +1323,11 @@ defaultOptions.tightLists = true % \textbackslash{}usepackage[\textrm{\meta{options}}]\{markdown\} % \end{Verbatim} % where \meta{options} are the \LaTeX{} interface options (see Section -% \ref{sec:latexoptions}). +% \ref{sec:latexoptions}). Note that \meta{options} inside the \m{usepackage} +% macro may not set the \t`markdownRenderers` (see Section +% \ref{sec:latexrenderers}) and \t`markdownRendererPrototypes` (see Section +% \ref{sec:latexrendererprototypes}) keys. This limitation is due to the way +% \Hologo{LaTeX2e} parses package options. % % \subsubsection{Typesetting Markdown} % The interface exposes the \envmdef{markdown} and \envmdef{markdown*} @@ -1256,18 +1418,26 @@ defaultOptions.tightLists = true \def\markdownOptionOutputTempFileName{#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}{citations}[true]{% + \def\markdownOptionCitations{#1}}% +\define@key{markdownOptions}{citationNbsps}[true]{% + \def\markdownOptionCitationNbsps{#1}}% \define@key{markdownOptions}{cacheDir}{% \def\markdownOptionCacheDir{#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}{hybrid}[true]{% \def\markdownOptionHybrid{#1}}% -\define@key{markdownOptions}{footnotes}[true]{% - \def\markdownOptionFootnotes{#1}}% \define@key{markdownOptions}{preserveTabs}[true]{% \def\markdownOptionPreserveTabs{#1}}% \define@key{markdownOptions}{smartEllipses}[true]{% @@ -1278,7 +1448,7 @@ defaultOptions.tightLists = true % If the \t`tightLists=false` option is specified, when loading the package, % then the \pkg{paralist} package for typesetting tight lists will not be % automatically loaded. This precaution is meant to minimize the footprint of -% this package, since some documentclasses (\pkg{beamer}) do not play nice +% this package, since some documentclasses (\pkg{beamer}) experience clashes % with the \pkg{paralist} package. % \begin{macrocode} \define@key{markdownOptions}{tightLists}[true]{% @@ -1296,18 +1466,20 @@ defaultOptions.tightLists = true % } % \end{Verbatim} % -% \paragraph{Plain \TeX{} Markdown Token Renderers} +% \paragraph{Plain \TeX{} Markdown Token Renderers}\label{sec:latexrenderers} % The \LaTeX{} interface recognizes an option with the \t`renderers` key, % whose value must be a list of options that map directly to the markdown token % renderer macros exposed by the plain \TeX{} interface (see Section % \ref{sec:texrenderersuser}). % \begin{macrocode} -\define@key{markdownOptions}{renderers}{% - \setkeys{markdownRenderers}{#1}}% +\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}{% @@ -1342,6 +1514,8 @@ defaultOptions.tightLists = true \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}{% @@ -1354,6 +1528,8 @@ defaultOptions.tightLists = true \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}{% @@ -1364,6 +1540,8 @@ defaultOptions.tightLists = true \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}{% @@ -1382,6 +1560,8 @@ defaultOptions.tightLists = true \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}{% @@ -1398,6 +1578,10 @@ defaultOptions.tightLists = true \renewcommand\markdownRendererHorizontalRule{#1}}% \define@key{markdownRenderers}{footnote}{% \renewcommand\markdownRendererFootnote[1]{#1}}% +\define@key{markdownRenderers}{cite}{% + \renewcommand\markdownRendererCite[1]{#1}}% +\define@key{markdownRenderers}{textCite}{% + \renewcommand\markdownRendererTextCite[1]{#1}}% % \end{macrocode} % % The following example \LaTeX{} code showcases a possible configuration of the @@ -1413,17 +1597,20 @@ defaultOptions.tightLists = true % \end{Verbatim} % % \paragraph{Plain \TeX{} Markdown Token Renderer Prototypes} +% \label{sec:latexrendererprototypes} % The \LaTeX{} interface recognizes an option with the \t`rendererPrototypes` % key, whose value must be a list of options that map directly to the markdown % token renderer prototype macros exposed by the plain \TeX{} interface (see % Section \ref{sec:texrendererprototypes}). % \begin{macrocode} -\define@key{markdownOptions}{rendererPrototypes}{% - \setkeys{markdownRendererPrototypes}{#1}}% +\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}{% @@ -1445,19 +1632,21 @@ defaultOptions.tightLists = true \define@key{markdownRendererPrototypes}{tilde}{% \renewcommand\markdownRendererTildePrototype{#1}}% \define@key{markdownRendererPrototypes}{pipe}{% - \renewcommand\markdownRendererPipe{#1}}% + \renewcommand\markdownRendererPipePrototype{#1}}% \define@key{markdownRendererPrototypes}{codeSpan}{% \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}% \define@key{markdownRendererPrototypes}{link}{% - \renewcommand\markdownRendererLink[4]{#1}}% + \renewcommand\markdownRendererLinkPrototype[4]{#1}}% \define@key{markdownRendererPrototypes}{image}{% - \renewcommand\markdownRendererImage[4]{#1}}% + \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}{% @@ -1470,6 +1659,8 @@ defaultOptions.tightLists = true \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}{% @@ -1480,6 +1671,8 @@ defaultOptions.tightLists = true \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}{% @@ -1498,6 +1691,8 @@ defaultOptions.tightLists = true \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}{% @@ -1514,6 +1709,10 @@ defaultOptions.tightLists = true \renewcommand\markdownRendererHorizontalRulePrototype{#1}}% \define@key{markdownRendererPrototypes}{footnote}{% \renewcommand\markdownRendererFootnotePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{cite}{% + \renewcommand\markdownRendererCitePrototype[1]{#1}}% +\define@key{markdownRendererPrototypes}{textCite}{% + \renewcommand\markdownRendererTextCitePrototype[1]{#1}}% % \end{macrocode} % % The following example \LaTeX{} code showcases a possible configuration of the @@ -1521,7 +1720,7 @@ defaultOptions.tightLists = true % markdown token renderer prototypes. % \begin{Verbatim} % \markdownSetup{ -% renderers = { +% rendererPrototypes = { % image = {\includegraphics{#2}}, % codeSpan = {\texttt{#1}}, % Render inline code via `\texttt`. % } @@ -1885,6 +2084,12 @@ function M.writer.new(options) self.space = " " % \end{macrocode} % +% Define \luamdef{writer->nbsp} as the output format of a non-breaking space +% character. +% \begin{macrocode} + self.nbsp = "\\markdownRendererNbsp{}" +% \end{macrocode} +% % Define \luamdef{writer->plain} as a function that will transform an input % plain text block \t`s` to the output format. % \begin{macrocode} @@ -1913,13 +2118,7 @@ function M.writer.new(options) % Define \luamdef{writer->interblocksep} as the output format of a block % element separator. % \begin{macrocode} - self.interblocksep = "\n\n" -% \end{macrocode} -% -% Define \luamdef{writer->containersep} as the output format of a container -% separator. -% \begin{macrocode} - self.containersep = "\n\n" + self.interblocksep = "\\markdownRendererInterblockSeparator\n{}" % \end{macrocode} % % Define \luamdef{writer->eof} as the end of file marker in the output format. @@ -1929,7 +2128,7 @@ function M.writer.new(options) % % Define \luamdef{writer->linebreak} as the output format of a forced line break. % \begin{macrocode} - self.linebreak = "\\markdownRendererLineBreak " + self.linebreak = "\\markdownRendererLineBreak\n{}" % \end{macrocode} % % Define \luamdef{writer->ellipsis} as the output format of an ellipsis. @@ -1939,7 +2138,7 @@ function M.writer.new(options) % % Define \luamdef{writer->hrule} as the output format of a horizontal rule. % \begin{macrocode} - self.hrule = "\\markdownRendererHorizontalRule " + self.hrule = "\\markdownRendererHorizontalRule{}" % \end{macrocode} % % Define a table \luamdef{escaped_chars} containing the mapping from special @@ -2031,7 +2230,8 @@ function M.writer.new(options) % items and \t`tight` specifies, whether the list is tight or not. % \begin{macrocode} local function ulitem(s) - return {"\\markdownRendererUlItem ",s} + return {"\\markdownRendererUlItem ",s, + "\\markdownRendererUlItemEnd "} end function self.bulletlist(items,tight) @@ -2058,9 +2258,11 @@ function M.writer.new(options) % \begin{macrocode} local function olitem(s,num) if num ~= nil then - return {"\\markdownRendererOlItemWithNumber{",num,"}",s} + return {"\\markdownRendererOlItemWithNumber{",num,"}",s, + "\\markdownRendererOlItemEnd "} else - return {"\\markdownRendererOlItem ",s} + return {"\\markdownRendererOlItem ",s, + "\\markdownRendererOlItemEnd "} end end @@ -2096,6 +2298,7 @@ function M.writer.new(options) retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def, "\\markdownRendererDlDefinitionEnd "} end + retVal[#retVal+1] = "\\markdownRendererDlItemEnd " return retVal end @@ -2104,13 +2307,12 @@ function M.writer.new(options) for _,item in ipairs(items) do buffer[#buffer + 1] = dlitem(item.term, item.definitions) end - local contents = util.intersperse(buffer, self.containersep) if tight and options.tightLists then - return {"\\markdownRendererDlBeginTight\n\n", contents, - "\n\n\\markdownRendererDlEndTight\n"} + return {"\\markdownRendererDlBeginTight\n", buffer, + "\n\\markdownRendererDlEndTight"} else - return {"\\markdownRendererDlBegin\n\n", contents, - "\n\n\\markdownRendererDlEnd\n"} + return {"\\markdownRendererDlBegin\n", buffer, + "\n\\markdownRendererDlEnd"} end end % \end{macrocode} @@ -2149,6 +2351,16 @@ function M.writer.new(options) end % \end{macrocode} % +% Define \luamdef{writer->codeFence} as a function that will transform an +% input fenced code block \t`s` with the infostring \t`i` to the output +% format. +% \begin{macrocode} + function self.fencedCode(i, s) + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} + end +% \end{macrocode} +% % Define \luamdef{writer->heading} as a function that will transform an % input heading \t`s` at level \t`level` to the output format. % \begin{macrocode} @@ -2173,12 +2385,37 @@ function M.writer.new(options) end % \end{macrocode} % -% Define \luamdef{writer->footnote} as a function that will transform an +% Define \luamdef{writer->note} as a function that will transform an % input footnote \t`s` to the output format. % \begin{macrocode} function self.note(s) return {"\\markdownRendererFootnote{",s,"}"} end +% \end{macrocode} +% +% Define \luamdef{writer->citations} as a function that will transform an +% input array of citations \t`cites` to the output format. If \t`text_cites` +% is \t`true`, the citations should be rendered in-text, when applicable. +% The \t`cites` array contains tables with the following keys and values: +% \begin{itemize} +% \item\t`suppress_author` -- If the value of the key is true, then the +% author of the work should be omitted in the citation, when applicable. +% \item\t`prenote` -- The value of the key is either \t`nil` or a string +% that should be inserted before the citation. +% \item\t`postnote` -- The value of the key is either \t`nil` or a string +% that should be inserted after the citation. +% \item\t`name` -- The value of this key is the citation name. +% \end{itemize} +% \begin{macrocode} + function self.citations(text_cites, cites) + local buffer = {"\\markdownRenderer", text_cites and "TextCite" or "Cite", + "{", #cites, "}"} + for _,cite in ipairs(cites) do + buffer[#buffer+1] = {cite.suppress_author and "-" or "+", "{", + cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"} + end + return buffer + end return self end @@ -2249,44 +2486,36 @@ function M.reader.new(writer, options) % \paragraph{Top Level Parsing Functions} % \begin{macrocode} local syntax + local blocks_toplevel local blocks - local inlines - - local parse_blocks = - function(str) - local res = lpeg.match(blocks, str) - if res == nil then - error(format("parse_blocks failed on:\n%s", str:sub(1,20))) - else - return res - end - end + local inlines, inlines_no_link, inlines_nbsp - local parse_inlines = - function(str) - local res = lpeg.match(inlines, str) + local function create_parser(name, grammar) + return function(str) + local res = lpeg.match(grammar(), str) if res == nil then - error(format("parse_inlines failed on:\n%s", - str:sub(1,20))) - else - return res - end - end - - local parse_inlines_no_link = - function(str) - local res = lpeg.match(inlines_no_link, str) - if res == nil then - error(format("parse_inlines_no_link failed on:\n%s", - str:sub(1,20))) + 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 blocks end) + local parse_blocks_toplevel = create_parser("parse_blocks_toplevel", + function() return blocks_toplevel end) + local parse_inlines = create_parser("parse_inlines", + function() return inlines end) + local parse_inlines_no_link = create_parser("parse_inlines_no_link", + function() return inlines_no_link end) + local parse_inlines_nbsp = create_parser("parse_inlines_nbsp", + function() return inlines_nbsp end) % \end{macrocode} % \paragraph{Generic \acro{peg} Patterns} % \begin{macrocode} local percent = P("%") + local at = P("@") local asterisk = P("*") local dash = P("-") local plus = P("+") @@ -2310,12 +2539,14 @@ function M.reader.new(writer, options) local colon = P(":") local semicolon = P(";") local exclamation = P("!") + local tilde = P("~") local digit = R("09") local hexdigit = R("09","af","AF") local letter = R("AZ","az") local alphanumeric = R("AZ","az","09") local keyword = letter * alphanumeric^0 + local punctuation = S("!?,.:;") local doubleasterisks = P("**") local doubleunderscores = P("__") @@ -2325,7 +2556,8 @@ function M.reader.new(writer, options) local fail = any - 1 local always = P("") - local escapable = S("\\`*_{}[]()+_.!<>#-~:^") + local escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") + local anyescaped = P("\\") / "" * escapable + any @@ -2336,17 +2568,14 @@ function M.reader.new(writer, options) local nonspacechar = any - spacing local tightblocksep = P("\001") - local specialchar - if options.smartEllipses then - specialchar = S("*_`&[]= #b and i + end + + local infostring = (linechar - (backtick + space^1 * (newline + eof)))^0 + + local fenceindent + local function fencehead(char) + return C(nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * optionalspace * C(infostring) * optionalspace + * (newline + eof) + end + + local function fencetail(char) + return nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), + captures_geq_length) + * optionalspace * (newline + eof) + + eof + end + + local function fencedline(char) + return C(line - fencetail(char)) + / function(s) + return s:gsub("^" .. string.rep(" ?", + fenceindent), "") + end + end % \end{macrocode} % \paragraph{Tag \acro{peg} Patterns} % \begin{macrocode} @@ -2468,6 +2732,41 @@ function M.reader.new(writer, options) local optionaltitle = spnl * title * spacechar^0 + Cc("") % \end{macrocode} +% \paragraph{Citation \acro{peg} Patterns} +% \begin{macrocode} + local citation_name = (Cs(dash^-1) + * at * Cs((anyescaped + - (rbracket + spacing + punctuation + semicolon))^1)) + + local citation_body_prenote + = Cs((alphanumeric^1 + + bracketed + + inticks + + (anyescaped + - (rbracket + semicolon + blankline^2)) + - (spnl * dash^-1 * at))^0) + + local citation_body_postnote + = Cs((alphanumeric^1 + + bracketed + + inticks + + (anyescaped + - (rbracket + semicolon + blankline^2)) + - (spnl * rbracket))^0) + + local citation_body_chunk + = citation_body_prenote + * spnl * citation_name + * spnlor(punctuation - (semicolon + rbracket)) + * citation_body_postnote + + local citation_body = citation_body_chunk + * (semicolon * spnl * citation_body_chunk)^0 + + local citation_headless_body + = citation_body_postnote + * (sp * semicolon * spnl * citation_body_chunk)^0 +% \end{macrocode} % \paragraph{Footnote \acro{peg} Patterns} % \begin{macrocode} local rawnotes = {} @@ -2481,7 +2780,7 @@ function M.reader.new(writer, options) return function() local found = rawnotes[normalize_tag(ref)] if found then - return writer.note(parse_blocks(found)) + return writer.note(parse_blocks_toplevel(found)) else return {"[", parse_inlines("^" .. ref), "]"} end @@ -2571,23 +2870,12 @@ function M.reader.new(writer, options) end end % \end{macrocode} -% \paragraph{Inline Element \acro{peg} Patterns} +% \paragraph{Spacing \acro{peg} Patterns} % \begin{macrocode} - local Inline = V("Inline") - - local Str = normalchar^1 / writer.string - - local Ellipsis = P("...") / writer.ellipsis - - local Smart = Ellipsis - - local Symbol = (specialchar - tightblocksep) / writer.string - - local Code = inticks / writer.code - local bqstart = more local headerstart = hash + (line * (equal^1 + dash^1) * optionalspace * newline) + local fencestart = fencehead(backtick) + fencehead(tilde) if options.blankBeforeBlockquote then bqstart = fail @@ -2597,30 +2885,56 @@ function M.reader.new(writer, options) headerstart = fail end + if not options.fencedCode or options.blankBeforeCodeFence then + fencestart = fail + end +% \end{macrocode} +% \paragraph{String \acro{peg} Rules} +% \begin{macrocode} + local Inline = V("Inline") + + local Str = normalchar^1 / writer.string + + local Symbol = (specialchar - tightblocksep) / writer.string +% \end{macrocode} +% \paragraph{Ellipsis \acro{peg} Rules} +% \begin{macrocode} + local Ellipsis = P("...") / writer.ellipsis + + local Smart = Ellipsis +% \end{macrocode} +% \paragraph{Inline Code Block \acro{peg} Rules} +% \begin{macrocode} + local Code = inticks / writer.code +% \end{macrocode} +% \paragraph{Spacing \acro{peg} Rules} +% \begin{macrocode} local Endline = newline * -( -- newline, but not before... blankline -- paragraph break + tightblocksep -- nested list + eof -- end of document + bqstart + headerstart + + fencestart ) * spacechar^0 / writer.space -% \end{macrocode} -% Make two and more trailing spaces before a newline produce a forced line -% break, throw away one or more trailing spaces and an optional newline at the -% end of a file, and reduce one or more spaces and an optional newline into a -% single space. -% \begin{macrocode} local Space = spacechar^2 * Endline / writer.linebreak + spacechar^1 * Endline^-1 * eof / "" + spacechar^1 * Endline^-1 * optionalspace / writer.space + local NonbreakingSpace + = spacechar^2 * Endline / writer.linebreak + + spacechar^1 * Endline^-1 * eof / "" + + spacechar^1 * Endline^-1 * optionalspace / writer.nbsp + -- parse many p between starter and ender local function between(p, starter, ender) local ender2 = B(nonspacechar) * ender return (starter * #nonspacechar * Ct(p * (p - ender2)^0) * ender2) end - +% \end{macrocode} +% \paragraph{Emphasis \acro{peg} Rules} +% \begin{macrocode} local Strong = ( between(Inline, doubleasterisks, doubleasterisks) + between(Inline, doubleunderscores, doubleunderscores) ) / writer.strong @@ -2628,7 +2942,9 @@ function M.reader.new(writer, options) local Emph = ( between(Inline, asterisk, asterisk) + between(Inline, underscore, underscore) ) / writer.emphasis - +% \end{macrocode} +% \paragraph{Link \acro{peg} Rules} +% \begin{macrocode} local urlchar = anyescaped - newline - more local AutoLinkUrl = less @@ -2658,7 +2974,9 @@ function M.reader.new(writer, options) -- parse a link or image (direct or indirect) local Link = DirectLink + IndirectLink - +% \end{macrocode} +% \paragraph{Image \acro{peg} Rules} +% \begin{macrocode} local DirectImage = exclamation * (tag / parse_inlines) * spnl @@ -2672,48 +2990,106 @@ function M.reader.new(writer, options) indirect_image local Image = DirectImage + IndirectImage - +% \end{macrocode} +% \paragraph{Miscellaneous Inline \acro{peg} Rules} +% \begin{macrocode} -- avoid parsing long strings of * or _ as emph/strong local UlOrStarLine = asterisk^4 + underscore^4 / writer.string local EscapedChar = S("\\") * C(escapable) / writer.string % \end{macrocode} -% \paragraph{Block Element \acro{peg} Patterns} +% \paragraph{Citations \acro{peg} Rules} +% \begin{macrocode} + local function citations(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.string(raw_cites[i+2]), + postnote = normalize(raw_cites[i+3]), + } + end + return writer.citations(text_cites, cites) + end + + local TextCitations = Ct(Cc("") + * citation_name + * ((spnl + * lbracket + * citation_headless_body + * rbracket) + Cc(""))) / + function(raw_cites) + return citations(true, raw_cites) + end + + local ParenthesizedCitations + = Ct(lbracket + * citation_body + * rbracket) / + function(raw_cites) + return citations(false, raw_cites) + end + + local Citations = TextCitations + ParenthesizedCitations +% \end{macrocode} +% \paragraph{Code Block \acro{peg} Rules} % \begin{macrocode} local Block = V("Block") local Verbatim = Cs( (blanklines * ((indentedline - blankline))^1)^1 ) / expandtabs / writer.verbatim + + local TildeFencedCode + = fencehead(tilde) + * Cs(fencedline(tilde)^0) + * fencetail(tilde) + + local BacktickFencedCode + = fencehead(backtick) + * Cs(fencedline(backtick)^0) + * fencetail(backtick) + local FencedCode = (TildeFencedCode + BacktickFencedCode) + / function(infostring, code) + return writer.fencedCode( + writer.string(infostring), + expandtabs(code)) + end +% \end{macrocode} +% \paragraph{Blockquote \acro{peg} Patterns} +% \begin{macrocode} -- strip off leading > and indents, and run through blocks local Blockquote = Cs(( ((leader * more * space^-1)/"" * linechar^0 * newline)^1 * (-blankline * linechar^1 * newline)^0 - * blankline^0 - )^1) / parse_blocks / writer.blockquote + * (blankline^0 / "") + )^1) / parse_blocks_toplevel / writer.blockquote local function lineof(c) - return (leader * (P(c) * optionalspace)^3 * newline * blankline^1) + return (leader * (P(c) * optionalspace)^3 * (newline * blankline^1 + + newline^-1 * eof)) end - +% \end{macrocode} +% \paragraph{Horizontal Rule \acro{peg} Rules} +% \begin{macrocode} local HorizontalRule = ( lineof(asterisk) + lineof(dash) + lineof(underscore) ) / writer.hrule - - local Reference = define_reference_parser / register_link - - local Paragraph = nonindentspace * Ct(Inline^1) * newline - * ( blankline^1 - + #hash - + #(leader * more * space^-1) - ) - / writer.paragraph - - local Plain = nonindentspace * Ct(Inline^1) / writer.plain % \end{macrocode} -% \paragraph{List \acro{peg} Patterns} +% \paragraph{List \acro{peg} Rules} % \begin{macrocode} local starter = bullet + enumerator @@ -2785,7 +3161,7 @@ function M.reader.new(writer, options) local DefinitionListItemLoose = C(line) * skipblanklines * Ct((defstart * indented_blocks(dlchunk) / - parse_blocks)^1) + parse_blocks_toplevel)^1) * Cc(false) / definition_list_item @@ -2801,14 +3177,36 @@ function M.reader.new(writer, options) -DefinitionListItemLoose * Cc(true)) ) / writer.definitionlist % \end{macrocode} -% \paragraph{Blank \acro{peg} Patterns} +% \paragraph{Blank Line \acro{peg} Rules} % \begin{macrocode} + local Reference = define_reference_parser / register_link local Blank = blankline / "" + NoteBlock + Reference + (tightblocksep / "\n") % \end{macrocode} -% \paragraph{Heading \acro{peg} Patterns} +% \paragraph{Paragraph \acro{peg} Rules} +% \begin{macrocode} + local Paragraph = nonindentspace * Ct(Inline^1) * newline + * ( blankline^1 + + #hash + + #(leader * more * space^-1) + ) + / writer.paragraph + + local ToplevelParagraph + = nonindentspace * Ct(Inline^1) * (newline + * ( blankline^1 + + #hash + + #(leader * more * space^-1) + + eof + ) + + eof ) + / writer.paragraph + + local Plain = nonindentspace * Ct(Inline^1) / writer.plain +% \end{macrocode} +% \paragraph{Heading \acro{peg} Rules} % \begin{macrocode} -- parse Atx heading start and return level local HeadingStart = #hash * C(hash^-6) * -hash / length @@ -2833,6 +3231,8 @@ function M.reader.new(writer, options) * HeadingLevel * optionalspace * newline / writer.heading + + local Heading = AtxHeading + SetextHeading % \end{macrocode} % \paragraph{Top Level \acro{peg} Specification} % \begin{macrocode} @@ -2851,6 +3251,7 @@ function M.reader.new(writer, options) Block = V("Blockquote") + V("Verbatim") + + V("FencedCode") + V("HorizontalRule") + V("BulletList") + V("OrderedList") @@ -2861,10 +3262,11 @@ function M.reader.new(writer, options) Blockquote = Blockquote, Verbatim = Verbatim, + FencedCode = FencedCode, HorizontalRule = HorizontalRule, BulletList = BulletList, OrderedList = OrderedList, - Heading = AtxHeading + SetextHeading, + Heading = Heading, DefinitionList = DefinitionList, DisplayHtml = DisplayHtml, Paragraph = Paragraph, @@ -2877,6 +3279,7 @@ function M.reader.new(writer, options) + V("Strong") + V("Emph") + V("NoteRef") + + V("Citations") + V("Link") + V("Image") + V("Code") @@ -2893,6 +3296,7 @@ function M.reader.new(writer, options) Strong = Strong, Emph = Emph, NoteRef = NoteRef, + Citations = Citations, Link = Link, Image = Image, Code = Code, @@ -2909,6 +3313,14 @@ function M.reader.new(writer, options) syntax.DefinitionList = fail end + if not options.fencedCode then + syntax.FencedCode = fail + end + + if not options.citations then + syntax.Citations = fail + end + if not options.footnotes then syntax.NoteRef = fail end @@ -2917,6 +3329,10 @@ function M.reader.new(writer, options) syntax.Smart = fail end + local blocks_toplevel_t = util.table_copy(syntax) + blocks_toplevel_t.Paragraph = ToplevelParagraph + blocks_toplevel = Ct(blocks_toplevel_t) + blocks = Ct(syntax) local inlines_t = util.table_copy(syntax) @@ -2924,9 +3340,13 @@ function M.reader.new(writer, options) inlines_t.Inlines = Inline^0 * (spacing^0 * eof / "") inlines = Ct(inlines_t) - inlines_no_link_t = util.table_copy(inlines_t) + local inlines_no_link_t = util.table_copy(inlines_t) inlines_no_link_t.Link = fail inlines_no_link = Ct(inlines_no_link_t) + + local inlines_nbsp_t = util.table_copy(inlines_t) + inlines_nbsp_t.Space = NonbreakingSpace + inlines_nbsp = Ct(inlines_nbsp_t) % \end{macrocode} % % \paragraph{Exported Conversion Function} @@ -2938,8 +3358,9 @@ function M.reader.new(writer, options) references = {} % \end{macrocode} % When determining the name of the cache file, create salt for the hashing -% function out of the passed options recognized by the Lua interface (see -% Section \ref{sec:luaoptions}). The \Opt{cacheDir} option is disregarded. +% function out of the package version and the passed options recognized by the +% Lua interface (see Section \ref{sec:luaoptions}). The \Opt{cacheDir} option +% is disregarded. % \begin{macrocode} local opt_string = {} for k,_ in pairs(defaultOptions) do @@ -2949,13 +3370,13 @@ function M.reader.new(writer, options) end end table.sort(opt_string) - local salt = table.concat(opt_string, ",") + local salt = table.concat(opt_string, ",") .. "," .. metadata.version % \end{macrocode} % Produce the cache file, transform its filename via the \luam{writer->pack} % method, and return the result. % \begin{macrocode} local name = util.cache(options.cacheDir, input, salt, function(input) - return util.rope_to_string(parse_blocks(input)) .. writer.eof + return util.rope_to_string(parse_blocks_toplevel(input)) .. writer.eof end, ".md" .. writer.suffix) return writer.pack(name) end @@ -2997,11 +3418,13 @@ return M \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}% % \end{macrocode} % -% \subsubsection{Token Renderers} +% \subsubsection{Token Renderer Prototypes} % The following definitions should be considered placeholder. % \begin{macrocode} +\def\markdownRendererInterblockSeparatorPrototype{\par}% \def\markdownRendererLineBreakPrototype{\hfil\break}% \let\markdownRendererEllipsisPrototype\dots +\def\markdownRendererNbspPrototype{~}% \def\markdownRendererLeftBracePrototype{\char`{}% \def\markdownRendererRightBracePrototype{\char`}}% \def\markdownRendererDollarSignPrototype{\char`$}% @@ -3013,41 +3436,48 @@ return M \def\markdownRendererBackslashPrototype{\char`\\}% \def\markdownRendererTildePrototype{\char`~}% \def\markdownRendererPipePrototype{|}% -\long\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{#2}% -\long\def\markdownRendererImagePrototype#1#2#3#4{#2}% +\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% +\def\markdownRendererLinkPrototype#1#2#3#4{#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{}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% \def\markdownRendererOlEndPrototype{}% \def\markdownRendererOlEndTightPrototype{}% \def\markdownRendererDlBeginPrototype{}% \def\markdownRendererDlBeginTightPrototype{}% -\long\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemEndPrototype{}% \def\markdownRendererDlDefinitionBeginPrototype{}% \def\markdownRendererDlDefinitionEndPrototype{\par}% \def\markdownRendererDlEndPrototype{}% \def\markdownRendererDlEndTightPrototype{}% -\long\def\markdownRendererEmphasisPrototype#1{{\it#1}}% -\long\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% \def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% -\long\def\markdownRendererInputVerbatimPrototype#1{% -\par{\tt\input"#1"\relax}\par}% -\long\def\markdownRendererHeadingOnePrototype#1{#1}% -\long\def\markdownRendererHeadingTwoPrototype#1{#1}% -\long\def\markdownRendererHeadingThreePrototype#1{#1}% -\long\def\markdownRendererHeadingFourPrototype#1{#1}% -\long\def\markdownRendererHeadingFivePrototype#1{#1}% -\long\def\markdownRendererHeadingSixPrototype#1{#1}% +\def\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{}% -\long\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% % \end{macrocode} % % \subsubsection{Lua Snippets} @@ -3061,24 +3491,36 @@ return M \ifx\markdownOptionBlankBeforeBlockquote\undefined\else blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote, \fi +\ifx\markdownOptionBlankBeforeCodeFence\undefined\else + blankBeforeCodeFence = \markdownOptionBlankBeforeCodeFence, +\fi \ifx\markdownOptionBlankBeforeHeading\undefined\else blankBeforeHeading = \markdownOptionBlankBeforeHeading, \fi \ifx\markdownOptionCacheDir\undefined\else cacheDir = "\markdownOptionCacheDir", \fi +\ifx\markdownOptionCitations\undefined\else + citations = \markdownOptionCitations, +\fi +\ifx\markdownOptionCitationNbsps\undefined\else + citationNbsps = \markdownOptionCitationNbsps, +\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\markdownOptionHybrid\undefined\else hybrid = \markdownOptionHybrid, \fi -\ifx\markdownOptionFootnotes\undefined\else - footnotes = \markdownOptionFootnotes, -\fi \ifx\markdownOptionPreserveTabs\undefined\else preserveTabs = \markdownOptionPreserveTabs, \fi @@ -3154,28 +3596,26 @@ local convert = md.new(\markdownLuaOptions) % whether the shell access is enabled (\t`1`), disabled (\t`0`), or restricted % (\t`2`). % -% If Lua is unavailable, 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, act as if the shell access -% were enabled. +% Inherit the value of the the \m{pdfshellescape} (Lua\TeX{}, \Hologo{pdfTeX}) +% or the \m{shellescape} (\Hologo{XeTeX}) commands. If neither of these +% commands is defined and Lua is available, attempt to access the +% \luam{status.shell_escape} configuration item. +% +% If you cannot detect, whether the shell access is enabled, act as if it were. % \begin{macrocode} -\ifnum\markdownMode=0\relax - \ifx\pdfshellescape\undefined - \ifx\shellescape\undefined +\ifx\pdfshellescape\undefined + \ifx\shellescape\undefined + \ifnum\markdownMode=0\relax \def\markdownExecuteShellEscape{1}% \else - \let\markdownExecuteShellEscape\shellescape + \def\markdownExecuteShellEscape{% + \directlua{tex.sprint(status.shell_escape or "1")}}% \fi \else - \let\markdownExecuteShellEscape\pdfshellescape + \let\markdownExecuteShellEscape\shellescape \fi -% \end{macrocode} -% If Lua is available, inherit the value of the \t`status.shell_escape` -% configuration item. -% \begin{macrocode} \else - \def\markdownExecuteShellEscape{% - \directlua{tex.sprint(status.shell_escape)}}% + \let\markdownExecuteShellEscape\pdfshellescape \fi % \end{macrocode} % @@ -3304,7 +3744,6 @@ local convert = md.new(\markdownLuaOptions) % \begin{macrocode} |def^^M{% |markdownInfo{The ending token sequence was found}% - |immediate|write|markdownLuaExecuteFileStream{}% |immediate|closeout|markdownLuaExecuteFileStream% |endgroup% |markdownInput|markdownOptionInputTempFileName% @@ -3421,8 +3860,8 @@ local convert = md.new(\markdownLuaOptions) % the result into the input line buffer of \TeX{}. % \begin{macrocode} if line:match(ending_sequence) then - |markdownLuaUnregisterIBCallback - local input = table.concat(buffer, "\n") .. "\n\n" + |markdownLuaUnregisterIBCallback; + local input = table.concat(buffer, "\n") .. "\n" local output = convert(input) return [[\markdownInfo{The ending token sequence was found}]] .. output .. [[\markdownReadAndConvertAfter]] @@ -3465,7 +3904,7 @@ local convert = md.new(\markdownLuaOptions) |markdownInfo{Including markdown document "#1"}% |markdownLuaExecute{% |markdownPrepare - local input = assert(io.open("#1","r")):read("*a") .. "\n\n" + local input = assert(io.open("#1","r")):read("*a") % \end{macrocode} % Since the Lua converter expects \acro{unix} line endings, normalize the % input. @@ -3544,7 +3983,18 @@ local convert = md.new(\markdownLuaOptions) \expandafter\markdownSetup\expandafter{\CurrentOption}}% \ProcessOptions\relax % \end{macrocode} +% After processing the options, activate the \t`renderers` and +% \t`rendererPrototypes` keys. +% \begin{macrocode} +\define@key{markdownOptions}{renderers}{% + \setkeys{markdownRenderers}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +\define@key{markdownOptions}{rendererPrototypes}{% + \setkeys{markdownRendererPrototypes}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +% \end{macrocode} % +% \subsubsection{Token Renderer Prototypes} % The following configuration should be considered placeholder. % \begin{macrocode} \RequirePackage{url} @@ -3610,27 +4060,103 @@ local convert = md.new(\markdownLuaOptions) blockQuoteBegin = {\begin{quotation}}, blockQuoteEnd = {\end{quotation}}, inputVerbatim = {\VerbatimInput{#1}}, + inputFencedCode = {% + \ifx\relax#2\relax + \VerbatimInput{#1}% + \else + \ifx\minted@jobname\undefined + \ifx\lst@version\undefined + \markdownRendererInputFencedCode{#1}{}% +% \end{macrocode} +% When the \pkg{listings} package is loaded, use it for syntax highlighting. +% \begin{macrocode} + \else + \lstinputlisting[language=#2]{#1}% + \fi +% \end{macrocode} +% When the \pkg{minted} package is loaded, use it for syntax highlighting. +% The \pkg{minted} package is preferred over \pkg{listings}. +% \begin{macrocode} + \else + \inputminted{#2}{#1}% + \fi + \fi}, horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, - footnote = {\footnote{#1}}}}% + footnote = {\footnote{#1}}}} \ifx\chapter\undefined - \markdownSetup{rendererPrototypes={ + \markdownSetup{rendererPrototypes = { headingOne = {\section{#1}}, headingTwo = {\subsection{#1}}, headingThree = {\subsubsection{#1}}, headingFour = {\paragraph{#1}}, - headingFive = {\subparagraph{#1}}}}% + headingFive = {\subparagraph{#1}}}} \else - \markdownSetup{rendererPrototypes={ + \markdownSetup{rendererPrototypes = { headingOne = {\chapter{#1}}, headingTwo = {\section{#1}}, headingThree = {\subsection{#1}}, headingFour = {\subsubsection{#1}}, headingFive = {\paragraph{#1}}, - headingSix = {\subparagraph{#1}}}}% + headingSix = {\subparagraph{#1}}}} \fi % \end{macrocode} % +% There is a basic implementation for citations that uses the \LaTeX{} \m{cite} +% macro. There is also a more advanced implementation that uses the Bib\LaTeX{} +% \m{autocites} and \m{textcites} macros. This implementation will be used, when +% Bib\LaTeX{} is loaded. +% \begin{macrocode} +\newcount\markdownLaTeXCitationsCounter + +% Basic implementation +\def\markdownLaTeXBasicCitations#1#2#3#4{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#2\relax\else#2~\fi\cite[#3]{#4}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \expandafter\@gobble + \fi\markdownLaTeXBasicCitations} +\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations + +% BibLaTeX implementation +\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \autocites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} +\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \textcites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} + +\markdownSetup{rendererPrototypes = { + cite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\autocites\undefined + \expandafter + \markdownLaTeXBasicCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXCitations + \expandafter{\expandafter}% + \fi}, + textCite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\textcites\undefined + \expandafter + \markdownLaTeXBasicTextCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXTextCitations + \expandafter{\expandafter}% + \fi}}} +% \end{macrocode} +% % \subsubsection{Miscellanea} % Unlike base Lua\TeX{}, which only allows for a single registered function per % a callback (see \cite[Section~8.1]{luatex16}), the \Hologo{LaTeX2e} format @@ -3643,12 +4169,24 @@ local convert = md.new(\markdownLuaOptions) % redefine the \m{markdownLuaRegisterIBCallback} and % \m{markdownLuaUnregisterIBCallback} macros accordingly. % \begin{macrocode} +\let\markdownLuaRegisterIBCallbackPrevious + \markdownLuaRegisterIBCallback +\let\markdownLuaUnregisterIBCallbackPrevious + \markdownLuaUnregisterIBCallback \renewcommand\markdownLuaRegisterIBCallback[1]{% - luatexbase.add_to_callback("process_input_buffer", #1, % - "The markdown input processor")} + if luatexbase and luatexbase.add_to_callback then + luatexbase.add_to_callback("process_input_buffer", #1, % + "The markdown input processor") + else + \markdownLuaRegisterIBCallbackPrevious{#1} + end} \renewcommand\markdownLuaUnregisterIBCallback{% - luatexbase.remove_from_callback("process_input_buffer",% - "The markdown input processor")} + if luatexbase and luatexbase.add_to_callback then + luatexbase.remove_from_callback("process_input_buffer",% + "The markdown input processor") + else + \markdownLuaUnregisterIBCallbackPrevious; + end} % \end{macrocode} % % When buffering user input, we should disable the bytes with the high bit set, @@ -3722,7 +4260,7 @@ local convert = md.new(\markdownLuaOptions) % macro, so that the pipe character (\t`|`) is inactive during the scanning. % This is necessary, since the character is active in \Hologo{ConTeXt}. % \begin{macrocode} -\ifnum\markdownMode<2 +\ifnum\markdownMode<2\relax \def\markdownMakeOther{% \catcode`|=12}% \fi @@ -3756,7 +4294,7 @@ local convert = md.new(\markdownLuaOptions) |endgroup % \end{macrocode} % -% \subsubsection{Options} +% \subsubsection{Token Renderer Prototypes} % The following configuration should be considered placeholder. % \begin{macrocode} \def\markdownRendererLineBreakPrototype{\blank}% @@ -3769,10 +4307,10 @@ local convert = md.new(\markdownLuaOptions) \def\markdownRendererBackslashPrototype{\textbackslash}% \def\markdownRendererTildePrototype{\textasciitilde}% \def\markdownRendererPipePrototype{\char`|}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{% +\def\markdownRendererLinkPrototype#1#2#3#4{% \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: \fi\tt<\hyphenatedurl{#3}>}}% -\long\def\markdownRendererImagePrototype#1#2#3#4{% +\def\markdownRendererImagePrototype#1#2#3#4{% \placefigure[][fig:#1]{#4}{\externalfigure[#3]}}% \def\markdownRendererUlBeginPrototype{\startitemize}% \def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% @@ -3782,11 +4320,11 @@ local convert = md.new(\markdownLuaOptions) \def\markdownRendererOlBeginPrototype{\startitemize[n]}% \def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% \def\markdownRendererOlItemPrototype{\item}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% +\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% \def\markdownRendererOlEndPrototype{\stopitemize}% \def\markdownRendererOlEndTightPrototype{\stopitemize}% \definedescription - [markdownConTeXtDlItemPrototype] + [MarkdownConTeXtDlItemPrototype] [location=hanging, margin=standard, headstyle=bold]% @@ -3802,26 +4340,55 @@ local convert = md.new(\markdownLuaOptions) \startMarkdownConTeXtDlPrototype}% \def\markdownRendererDlBeginTightPrototype{% \startMarkdownConTeXtDlTightPrototype}% -\long\def\markdownRendererDlItemPrototype#1{% - \markdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemPrototype#1{% + \startMarkdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemEndPrototype{% + \stopMarkdownConTeXtDlItemPrototype}% \def\markdownRendererDlEndPrototype{% \stopMarkdownConTeXtDlPrototype}% \def\markdownRendererDlEndTightPrototype{% \stopMarkdownConTeXtDlTightPrototype}% -\long\def\markdownRendererEmphasisPrototype#1{{\em#1}}% -\long\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}% +\def\markdownRendererEmphasisPrototype#1{{\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% \def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% -\long\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% -\long\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% -\long\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% -\long\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% -\long\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% -\long\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% -\long\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% +\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \ifx\relax#2\relax + \typefile{#1}% + \else +% \end{macrocode} +% The code fence infostring is used as a name from the \Hologo{ConTeXt} +% \m{definetyping} command. This allows the user to set up code highlighting +% mapping as follows: +% \begin{Verbatim} +% % Map the `TEX` syntax highlighter to the `latex` infostring. +% \definetyping [latex] +% \setuptyping [latex] [option=TEX] +% +% \starttext +% \startmarkdown +% ~~~ latex +% \documentclass{article} +% \begin{document} +% Hello world! +% \end{document} +% ~~~ +% \stopmarkdown +% \stoptext +% \end{Verbatim} +% \begin{macrocode} + \typefile[#2][]{#1}% + \fi}% +\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% +\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% +\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% +\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% +\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% +\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% \def\markdownRendererHorizontalRulePrototype{% \blackrule[height=1pt, width=\hsize]}% -\long\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% +\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% \stopmodule\protect % \end{macrocode} % diff --git a/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex b/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex index bad0124577b..4f90f3b8f8f 100644 --- a/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex +++ b/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex @@ -67,7 +67,7 @@ tex.print(unescape("|input markdown")) end}% \fi -\ifnum\markdownMode<2 +\ifnum\markdownMode<2\relax \def\markdownMakeOther{% \catcode`|=12}% \fi @@ -90,10 +90,10 @@ \def\markdownRendererBackslashPrototype{\textbackslash}% \def\markdownRendererTildePrototype{\textasciitilde}% \def\markdownRendererPipePrototype{\char`|}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{% +\def\markdownRendererLinkPrototype#1#2#3#4{% \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: \fi\tt<\hyphenatedurl{#3}>}}% -\long\def\markdownRendererImagePrototype#1#2#3#4{% +\def\markdownRendererImagePrototype#1#2#3#4{% \placefigure[][fig:#1]{#4}{\externalfigure[#3]}}% \def\markdownRendererUlBeginPrototype{\startitemize}% \def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% @@ -103,11 +103,11 @@ \def\markdownRendererOlBeginPrototype{\startitemize[n]}% \def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% \def\markdownRendererOlItemPrototype{\item}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% +\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% \def\markdownRendererOlEndPrototype{\stopitemize}% \def\markdownRendererOlEndTightPrototype{\stopitemize}% \definedescription - [markdownConTeXtDlItemPrototype] + [MarkdownConTeXtDlItemPrototype] [location=hanging, margin=standard, headstyle=bold]% @@ -123,26 +123,34 @@ \startMarkdownConTeXtDlPrototype}% \def\markdownRendererDlBeginTightPrototype{% \startMarkdownConTeXtDlTightPrototype}% -\long\def\markdownRendererDlItemPrototype#1{% - \markdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemPrototype#1{% + \startMarkdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemEndPrototype{% + \stopMarkdownConTeXtDlItemPrototype}% \def\markdownRendererDlEndPrototype{% \stopMarkdownConTeXtDlPrototype}% \def\markdownRendererDlEndTightPrototype{% \stopMarkdownConTeXtDlTightPrototype}% -\long\def\markdownRendererEmphasisPrototype#1{{\em#1}}% -\long\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}% +\def\markdownRendererEmphasisPrototype#1{{\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% \def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% -\long\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% -\long\def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% -\long\def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% -\long\def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% -\long\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% -\long\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% -\long\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% +\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% +\def\markdownRendererInputFencedCodePrototype#1#2{% + \ifx\relax#2\relax + \typefile{#1}% + \else + \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]}% -\long\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% +\def\markdownRendererFootnotePrototype#1{\footnote{#1}}% \stopmodule\protect \endinput %% diff --git a/Master/texmf-dist/tex/generic/markdown/markdown.tex b/Master/texmf-dist/tex/generic/markdown/markdown.tex index 247290d0b3b..12fcc8df129 100644 --- a/Master/texmf-dist/tex/generic/markdown/markdown.tex +++ b/Master/texmf-dist/tex/generic/markdown/markdown.tex @@ -45,29 +45,37 @@ %% %% The names of the source files used are shown above. %% -\def\markdownLastModified{2016/08/14}% -\def\markdownVersion{1.0.2}% +\def\markdownLastModified{2016/08/20}% +\def\markdownVersion{2.1.0}% \let\markdownBegin\relax \let\markdownEnd\relax \let\markdownInput\relax \def\markdownOptionHelperScriptFileName{\jobname.markdown.lua}% \def\markdownOptionInputTempFileName{\jobname.markdown.in}% \def\markdownOptionOutputTempFileName{\jobname.markdown.out}% -\def\markdownOptionCacheDir{_markdown-\jobname}% +\def\markdownOptionCacheDir{_markdown_\jobname}% \let\markdownOptionBlankBeforeBlockquote\undefined +\let\markdownOptionBlankBeforeCodeFence\undefined \let\markdownOptionBlankBeforeHeading\undefined +\let\markdownOptionCitations\undefined +\let\markdownOptionCitationNbsps\undefined \let\markdownOptionDefinitionLists\undefined +\let\markdownOptionFootnotes\undefined +\let\markdownOptionFencedCode\undefined \let\markdownOptionHashEnumerators\undefined \let\markdownOptionHybrid\undefined -\let\markdownOptionFootnotes\undefined \let\markdownOptionPreserveTabs\undefined \let\markdownOptionSmartEllipses\undefined \let\markdownOptionStartNumber\undefined \let\markdownOptionTightLists\undefined +\def\markdownRendererInterblockSeparator{% + \markdownRendererInterblockSeparatorPrototype}% \def\markdownRendererLineBreak{% \markdownRendererLineBreakPrototype}% \def\markdownRendererEllipsis{% \markdownRendererEllipsisPrototype}% +\def\markdownRendererNbsp{% + \markdownRendererNbspPrototype}% \def\markdownRendererLeftBrace{% \markdownRendererLeftBracePrototype}% \def\markdownRendererRightBrace{% @@ -102,6 +110,8 @@ \markdownRendererUlBeginTightPrototype}% \def\markdownRendererUlItem{% \markdownRendererUlItemPrototype}% +\def\markdownRendererUlItemEnd{% + \markdownRendererUlItemEndPrototype}% \def\markdownRendererUlEnd{% \markdownRendererUlEndPrototype}% \def\markdownRendererUlEndTight{% @@ -112,6 +122,8 @@ \markdownRendererOlBeginTightPrototype}% \def\markdownRendererOlItem{% \markdownRendererOlItemPrototype}% +\def\markdownRendererOlItemEnd{% + \markdownRendererOlItemEndPrototype}% \def\markdownRendererOlItemWithNumber{% \markdownRendererOlItemWithNumberPrototype}% \def\markdownRendererOlEnd{% @@ -124,6 +136,8 @@ \markdownRendererDlBeginTightPrototype}% \def\markdownRendererDlItem{% \markdownRendererDlItemPrototype}% +\def\markdownRendererDlItemEnd{% + \markdownRendererDlItemEndPrototype}% \def\markdownRendererDlDefinitionBegin{% \markdownRendererDlDefinitionBeginPrototype}% \def\markdownRendererDlDefinitionEnd{% @@ -142,6 +156,8 @@ \markdownRendererBlockQuoteEndPrototype}% \def\markdownRendererInputVerbatim{% \markdownRendererInputVerbatimPrototype}% +\def\markdownRendererInputFencedCode{% + \markdownRendererInputFencedCodePrototype}% \def\markdownRendererHeadingOne{% \markdownRendererHeadingOnePrototype}% \def\markdownRendererHeadingTwo{% @@ -158,8 +174,14 @@ \markdownRendererHorizontalRulePrototype}% \def\markdownRendererFootnote{% \markdownRendererFootnotePrototype}% +\def\markdownRendererCite{% + \markdownRendererCitePrototype}% +\def\markdownRendererTextCite{% + \markdownRendererTextCitePrototype}% +\def\markdownRendererInterblockSeparatorPrototype{}% \def\markdownRendererLineBreakPrototype{}% \def\markdownRendererEllipsisPrototype{}% +\def\markdownRendererNbspPrototype{}% \def\markdownRendererLeftBracePrototype{}% \def\markdownRendererRightBracePrototype{}% \def\markdownRendererDollarSignPrototype{}% @@ -171,40 +193,46 @@ \def\markdownRendererBackslashPrototype{}% \def\markdownRendererTildePrototype{}% \def\markdownRendererPipePrototype{}% -\long\def\markdownRendererCodeSpanPrototype#1{}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{}% -\long\def\markdownRendererImagePrototype#1#2#3#4{}% +\def\markdownRendererCodeSpanPrototype#1{}% +\def\markdownRendererLinkPrototype#1#2#3#4{}% +\def\markdownRendererImagePrototype#1#2#3#4{}% \def\markdownRendererUlBeginPrototype{}% \def\markdownRendererUlBeginTightPrototype{}% \def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% \def\markdownRendererUlEndPrototype{}% \def\markdownRendererUlEndTightPrototype{}% \def\markdownRendererOlBeginPrototype{}% \def\markdownRendererOlBeginTightPrototype{}% \def\markdownRendererOlItemPrototype{}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% \def\markdownRendererOlEndPrototype{}% \def\markdownRendererOlEndTightPrototype{}% \def\markdownRendererDlBeginPrototype{}% \def\markdownRendererDlBeginTightPrototype{}% -\long\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemPrototype#1{}% +\def\markdownRendererDlItemEndPrototype{}% \def\markdownRendererDlDefinitionBeginPrototype{}% \def\markdownRendererDlDefinitionEndPrototype{}% \def\markdownRendererDlEndPrototype{}% \def\markdownRendererDlEndTightPrototype{}% -\long\def\markdownRendererEmphasisPrototype#1{}% -\long\def\markdownRendererStrongEmphasisPrototype#1{}% +\def\markdownRendererEmphasisPrototype#1{}% +\def\markdownRendererStrongEmphasisPrototype#1{}% \def\markdownRendererBlockQuoteBeginPrototype{}% \def\markdownRendererBlockQuoteEndPrototype{}% -\long\def\markdownRendererInputVerbatimPrototype#1{}% -\long\def\markdownRendererHeadingOnePrototype#1{}% -\long\def\markdownRendererHeadingTwoPrototype#1{}% -\long\def\markdownRendererHeadingThreePrototype#1{}% -\long\def\markdownRendererHeadingFourPrototype#1{}% -\long\def\markdownRendererHeadingFivePrototype#1{}% -\long\def\markdownRendererHeadingSixPrototype#1{}% +\def\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{}% -\long\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererFootnotePrototype#1{}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% \def\markdownInfo#1{}% \def\markdownWarning#1{}% \def\markdownError#1{}% @@ -235,8 +263,10 @@ \def\markdownError#1#2{% \errhelp{#2.}% \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}% +\def\markdownRendererInterblockSeparatorPrototype{\par}% \def\markdownRendererLineBreakPrototype{\hfil\break}% \let\markdownRendererEllipsisPrototype\dots +\def\markdownRendererNbspPrototype{~}% \def\markdownRendererLeftBracePrototype{\char`{}% \def\markdownRendererRightBracePrototype{\char`}}% \def\markdownRendererDollarSignPrototype{\char`$}% @@ -248,63 +278,82 @@ \def\markdownRendererBackslashPrototype{\char`\\}% \def\markdownRendererTildePrototype{\char`~}% \def\markdownRendererPipePrototype{|}% -\long\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% -\long\def\markdownRendererLinkPrototype#1#2#3#4{#2}% -\long\def\markdownRendererImagePrototype#1#2#3#4{#2}% +\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% +\def\markdownRendererLinkPrototype#1#2#3#4{#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{}% -\long\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% \def\markdownRendererOlEndPrototype{}% \def\markdownRendererOlEndTightPrototype{}% \def\markdownRendererDlBeginPrototype{}% \def\markdownRendererDlBeginTightPrototype{}% -\long\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemEndPrototype{}% \def\markdownRendererDlDefinitionBeginPrototype{}% \def\markdownRendererDlDefinitionEndPrototype{\par}% \def\markdownRendererDlEndPrototype{}% \def\markdownRendererDlEndTightPrototype{}% -\long\def\markdownRendererEmphasisPrototype#1{{\it#1}}% -\long\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% \def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% -\long\def\markdownRendererInputVerbatimPrototype#1{% -\par{\tt\input"#1"\relax}\par}% -\long\def\markdownRendererHeadingOnePrototype#1{#1}% -\long\def\markdownRendererHeadingTwoPrototype#1{#1}% -\long\def\markdownRendererHeadingThreePrototype#1{#1}% -\long\def\markdownRendererHeadingFourPrototype#1{#1}% -\long\def\markdownRendererHeadingFivePrototype#1{#1}% -\long\def\markdownRendererHeadingSixPrototype#1{#1}% +\def\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{}% -\long\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererFootnotePrototype#1{#1}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% \def\markdownLuaOptions{{% \ifx\markdownOptionBlankBeforeBlockquote\undefined\else blankBeforeBlockquote = \markdownOptionBlankBeforeBlockquote, \fi +\ifx\markdownOptionBlankBeforeCodeFence\undefined\else + blankBeforeCodeFence = \markdownOptionBlankBeforeCodeFence, +\fi \ifx\markdownOptionBlankBeforeHeading\undefined\else blankBeforeHeading = \markdownOptionBlankBeforeHeading, \fi \ifx\markdownOptionCacheDir\undefined\else cacheDir = "\markdownOptionCacheDir", \fi +\ifx\markdownOptionCitations\undefined\else + citations = \markdownOptionCitations, +\fi +\ifx\markdownOptionCitationNbsps\undefined\else + citationNbsps = \markdownOptionCitationNbsps, +\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\markdownOptionHybrid\undefined\else hybrid = \markdownOptionHybrid, \fi -\ifx\markdownOptionFootnotes\undefined\else - footnotes = \markdownOptionFootnotes, -\fi \ifx\markdownOptionPreserveTabs\undefined\else preserveTabs = \markdownOptionPreserveTabs, \fi @@ -335,19 +384,19 @@ local convert = md.new(\markdownLuaOptions) \markdownInfo{Using mode 1: Shell escape via os.execute}% \fi \csname newwrite\endcsname\markdownLuaExecuteFileStream -\ifnum\markdownMode=0\relax - \ifx\pdfshellescape\undefined - \ifx\shellescape\undefined +\ifx\pdfshellescape\undefined + \ifx\shellescape\undefined + \ifnum\markdownMode=0\relax \def\markdownExecuteShellEscape{1}% \else - \let\markdownExecuteShellEscape\shellescape + \def\markdownExecuteShellEscape{% + \directlua{tex.sprint(status.shell_escape or "1")}}% \fi \else - \let\markdownExecuteShellEscape\pdfshellescape + \let\markdownExecuteShellEscape\shellescape \fi \else - \def\markdownExecuteShellEscape{% - \directlua{tex.sprint(status.shell_escape)}}% + \let\markdownExecuteShellEscape\pdfshellescape \fi \ifnum\markdownMode=0\relax \def\markdownExecuteDirect#1{\immediate\write18{#1}}% @@ -403,7 +452,6 @@ local convert = md.new(\markdownLuaOptions) |else% |def^^M{% |markdownInfo{The ending token sequence was found}% - |immediate|write|markdownLuaExecuteFileStream{}% |immediate|closeout|markdownLuaExecuteFileStream% |endgroup% |markdownInput|markdownOptionInputTempFileName% @@ -443,8 +491,8 @@ local convert = md.new(\markdownLuaOptions) "([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1") |markdownLuaRegisterIBCallback{function(line) if line:match(ending_sequence) then - |markdownLuaUnregisterIBCallback - local input = table.concat(buffer, "\n") .. "\n\n" + |markdownLuaUnregisterIBCallback; + local input = table.concat(buffer, "\n") .. "\n" local output = convert(input) return [[\markdownInfo{The ending token sequence was found}]] .. output .. [[\markdownReadAndConvertAfter]] @@ -463,7 +511,7 @@ local convert = md.new(\markdownLuaOptions) |markdownInfo{Including markdown document "#1"}% |markdownLuaExecute{% |markdownPrepare - local input = assert(io.open("#1","r")):read("*a") .. "\n\n" + local input = assert(io.open("#1","r")):read("*a") print(convert(input:gsub("\r\n?", "\n")))}}% |endgroup \endinput diff --git a/Master/texmf-dist/tex/latex/markdown/markdown.sty b/Master/texmf-dist/tex/latex/markdown/markdown.sty index 08dc59ef1e8..34f443fef1b 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdown.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdown.sty @@ -59,18 +59,26 @@ \def\markdownOptionOutputTempFileName{#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}{citations}[true]{% + \def\markdownOptionCitations{#1}}% +\define@key{markdownOptions}{citationNbsps}[true]{% + \def\markdownOptionCitationNbsps{#1}}% \define@key{markdownOptions}{cacheDir}{% \def\markdownOptionCacheDir{#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}{hybrid}[true]{% \def\markdownOptionHybrid{#1}}% -\define@key{markdownOptions}{footnotes}[true]{% - \def\markdownOptionFootnotes{#1}}% \define@key{markdownOptions}{preserveTabs}[true]{% \def\markdownOptionPreserveTabs{#1}}% \define@key{markdownOptions}{smartEllipses}[true]{% @@ -79,12 +87,14 @@ \def\markdownOptionStartNumber{#1}}% \define@key{markdownOptions}{tightLists}[true]{% \def\markdownOptionTightLists{#1}}% -\define@key{markdownOptions}{renderers}{% - \setkeys{markdownRenderers}{#1}}% +\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}{% @@ -119,6 +129,8 @@ \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}{% @@ -131,6 +143,8 @@ \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}{% @@ -141,6 +155,8 @@ \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}{% @@ -159,6 +175,8 @@ \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}{% @@ -175,12 +193,18 @@ \renewcommand\markdownRendererHorizontalRule{#1}}% \define@key{markdownRenderers}{footnote}{% \renewcommand\markdownRendererFootnote[1]{#1}}% -\define@key{markdownOptions}{rendererPrototypes}{% - \setkeys{markdownRendererPrototypes}{#1}}% +\define@key{markdownRenderers}{cite}{% + \renewcommand\markdownRendererCite[1]{#1}}% +\define@key{markdownRenderers}{textCite}{% + \renewcommand\markdownRendererTextCite[1]{#1}}% +\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}{% @@ -202,19 +226,21 @@ \define@key{markdownRendererPrototypes}{tilde}{% \renewcommand\markdownRendererTildePrototype{#1}}% \define@key{markdownRendererPrototypes}{pipe}{% - \renewcommand\markdownRendererPipe{#1}}% + \renewcommand\markdownRendererPipePrototype{#1}}% \define@key{markdownRendererPrototypes}{codeSpan}{% \renewcommand\markdownRendererCodeSpanPrototype[1]{#1}}% \define@key{markdownRendererPrototypes}{link}{% - \renewcommand\markdownRendererLink[4]{#1}}% + \renewcommand\markdownRendererLinkPrototype[4]{#1}}% \define@key{markdownRendererPrototypes}{image}{% - \renewcommand\markdownRendererImage[4]{#1}}% + \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}{% @@ -227,6 +253,8 @@ \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}{% @@ -237,6 +265,8 @@ \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}{% @@ -255,6 +285,8 @@ \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}{% @@ -271,6 +303,10 @@ \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}}% \input markdown \def\markdownVersionSpace{ }% \ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v% @@ -299,6 +335,12 @@ \DeclareOption*{% \expandafter\markdownSetup\expandafter{\CurrentOption}}% \ProcessOptions\relax +\define@key{markdownOptions}{renderers}{% + \setkeys{markdownRenderers}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% +\define@key{markdownOptions}{rendererPrototypes}{% + \setkeys{markdownRendererPrototypes}{#1}% + \def\KV@prefix{KV@markdownOptions@}}% \RequirePackage{url} \RequirePackage{graphicx} \RequirePackage{ifthen} @@ -357,31 +399,103 @@ blockQuoteBegin = {\begin{quotation}}, blockQuoteEnd = {\end{quotation}}, inputVerbatim = {\VerbatimInput{#1}}, + inputFencedCode = {% + \ifx\relax#2\relax + \VerbatimInput{#1}% + \else + \ifx\minted@jobname\undefined + \ifx\lst@version\undefined + \markdownRendererInputFencedCode{#1}{}% + \else + \lstinputlisting[language=#2]{#1}% + \fi + \else + \inputminted{#2}{#1}% + \fi + \fi}, horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, - footnote = {\footnote{#1}}}}% + footnote = {\footnote{#1}}}} \ifx\chapter\undefined - \markdownSetup{rendererPrototypes={ + \markdownSetup{rendererPrototypes = { headingOne = {\section{#1}}, headingTwo = {\subsection{#1}}, headingThree = {\subsubsection{#1}}, headingFour = {\paragraph{#1}}, - headingFive = {\subparagraph{#1}}}}% + headingFive = {\subparagraph{#1}}}} \else - \markdownSetup{rendererPrototypes={ + \markdownSetup{rendererPrototypes = { headingOne = {\chapter{#1}}, headingTwo = {\section{#1}}, headingThree = {\subsection{#1}}, headingFour = {\subsubsection{#1}}, headingFive = {\paragraph{#1}}, - headingSix = {\subparagraph{#1}}}}% + headingSix = {\subparagraph{#1}}}} \fi +\newcount\markdownLaTeXCitationsCounter + +\def\markdownLaTeXBasicCitations#1#2#3#4{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#2\relax\else#2~\fi\cite[#3]{#4}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \expandafter\@gobble + \fi\markdownLaTeXBasicCitations} +\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations + +\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \autocites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} +\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \textcites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} + +\markdownSetup{rendererPrototypes = { + cite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\autocites\undefined + \expandafter + \markdownLaTeXBasicCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXCitations + \expandafter{\expandafter}% + \fi}, + textCite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \ifx\textcites\undefined + \expandafter + \markdownLaTeXBasicTextCitations + \else + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXTextCitations + \expandafter{\expandafter}% + \fi}}} +\let\markdownLuaRegisterIBCallbackPrevious + \markdownLuaRegisterIBCallback +\let\markdownLuaUnregisterIBCallbackPrevious + \markdownLuaUnregisterIBCallback \renewcommand\markdownLuaRegisterIBCallback[1]{% - luatexbase.add_to_callback("process_input_buffer", #1, % - "The markdown input processor")} + if luatexbase and luatexbase.add_to_callback then + luatexbase.add_to_callback("process_input_buffer", #1, % + "The markdown input processor") + else + \markdownLuaRegisterIBCallbackPrevious{#1} + end} \renewcommand\markdownLuaUnregisterIBCallback{% - luatexbase.remove_from_callback("process_input_buffer",% - "The markdown input processor")} + if luatexbase and luatexbase.add_to_callback then + luatexbase.remove_from_callback("process_input_buffer",% + "The markdown input processor") + else + \markdownLuaUnregisterIBCallbackPrevious; + end} \newcommand\markdownMakeOther{% \count0=128\relax \loop diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 8a0f237c1d7..6a194bbf7ea 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -57,24 +57,30 @@ -- should contain your own preambles for the files it generates, not -- those in the standard .ins files. -- -if not modules then modules = { } end modules ['markdown'] = { - version = "1.0.2", +local metadata = { + version = "2.1.0", comment = "A module for the conversion from markdown to plain TeX", author = "John MacFarlane, Hans Hagen, Vít Novotný", copyright = "2009-2016 John MacFarlane, Hans Hagen; 2016 Vít Novotný", license = "LPPL 1.3" } +if not modules then modules = { } end +modules['markdown'] = metadata local lpeg = require("lpeg") local unicode = require("unicode") local md5 = require("md5") local M = {} local defaultOptions = {} defaultOptions.blankBeforeBlockquote = false +defaultOptions.blankBeforeCodeFence = false defaultOptions.blankBeforeHeading = false defaultOptions.cacheDir = "." +defaultOptions.citationNbsps = true +defaultOptions.citations = false defaultOptions.definitionLists = false defaultOptions.hashEnumerators = false defaultOptions.hybrid = false +defaultOptions.fencedCode = false defaultOptions.footnotes = false defaultOptions.preserveTabs = false defaultOptions.smartEllipses = false @@ -222,6 +228,7 @@ function M.writer.new(options) return defaultOptions[key] end }) self.suffix = ".tex" self.space = " " + self.nbsp = "\\markdownRendererNbsp{}" function self.plain(s) return s end @@ -231,12 +238,11 @@ function M.writer.new(options) function self.pack(name) return [[\input"]] .. name .. [["\relax]] end - self.interblocksep = "\n\n" - self.containersep = "\n\n" + self.interblocksep = "\\markdownRendererInterblockSeparator\n{}" self.eof = [[\relax]] - self.linebreak = "\\markdownRendererLineBreak " + self.linebreak = "\\markdownRendererLineBreak\n{}" self.ellipsis = "\\markdownRendererEllipsis{}" - self.hrule = "\\markdownRendererHorizontalRule " + self.hrule = "\\markdownRendererHorizontalRule{}" local escaped_chars = { ["{"] = "\\markdownRendererLeftBrace{}", ["}"] = "\\markdownRendererRightBrace{}", @@ -282,7 +288,8 @@ function M.writer.new(options) "{",self.string(tit or ""),"}"} end local function ulitem(s) - return {"\\markdownRendererUlItem ",s} + return {"\\markdownRendererUlItem ",s, + "\\markdownRendererUlItemEnd "} end function self.bulletlist(items,tight) @@ -301,9 +308,11 @@ function M.writer.new(options) end local function olitem(s,num) if num ~= nil then - return {"\\markdownRendererOlItemWithNumber{",num,"}",s} + return {"\\markdownRendererOlItemWithNumber{",num,"}",s, + "\\markdownRendererOlItemEnd "} else - return {"\\markdownRendererOlItem ",s} + return {"\\markdownRendererOlItem ",s, + "\\markdownRendererOlItemEnd "} end end @@ -331,6 +340,7 @@ function M.writer.new(options) retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def, "\\markdownRendererDlDefinitionEnd "} end + retVal[#retVal+1] = "\\markdownRendererDlItemEnd " return retVal end @@ -339,13 +349,12 @@ function M.writer.new(options) for _,item in ipairs(items) do buffer[#buffer + 1] = dlitem(item.term, item.definitions) end - local contents = util.intersperse(buffer, self.containersep) if tight and options.tightLists then - return {"\\markdownRendererDlBeginTight\n\n", contents, - "\n\n\\markdownRendererDlEndTight\n"} + return {"\\markdownRendererDlBeginTight\n", buffer, + "\n\\markdownRendererDlEndTight"} else - return {"\\markdownRendererDlBegin\n\n", contents, - "\n\n\\markdownRendererDlEnd\n"} + return {"\\markdownRendererDlBegin\n", buffer, + "\n\\markdownRendererDlEnd"} end end function self.emphasis(s) @@ -362,6 +371,10 @@ function M.writer.new(options) local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") return {"\\markdownRendererInputVerbatim{",name,"}"} end + function self.fencedCode(i, s) + local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} + end function self.heading(s,level) local cmd if level == 1 then @@ -384,6 +397,15 @@ function M.writer.new(options) function self.note(s) return {"\\markdownRendererFootnote{",s,"}"} end + 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 @@ -410,41 +432,33 @@ function M.reader.new(writer, options) end end local syntax + local blocks_toplevel local blocks - local inlines + local inlines, inlines_no_link, inlines_nbsp - local parse_blocks = - function(str) - local res = lpeg.match(blocks, str) + local function create_parser(name, grammar) + return function(str) + local res = lpeg.match(grammar(), str) if res == nil then - error(format("parse_blocks failed on:\n%s", str:sub(1,20))) - else - return res - end - end - - local parse_inlines = - function(str) - local res = lpeg.match(inlines, str) - if res == nil then - error(format("parse_inlines failed on:\n%s", - str:sub(1,20))) + error(format("%s failed on:\n%s", name, str:sub(1,20))) else return res end end + end - local parse_inlines_no_link = - function(str) - local res = lpeg.match(inlines_no_link, str) - if res == nil then - error(format("parse_inlines_no_link failed on:\n%s", - str:sub(1,20))) - else - return res - end - end + local parse_blocks = create_parser("parse_blocks", + function() return blocks end) + local parse_blocks_toplevel = create_parser("parse_blocks_toplevel", + function() return blocks_toplevel end) + local parse_inlines = create_parser("parse_inlines", + function() return inlines end) + local parse_inlines_no_link = create_parser("parse_inlines_no_link", + function() return inlines_no_link end) + local parse_inlines_nbsp = create_parser("parse_inlines_nbsp", + function() return inlines_nbsp end) local percent = P("%") + local at = P("@") local asterisk = P("*") local dash = P("-") local plus = P("+") @@ -468,12 +482,14 @@ function M.reader.new(writer, options) local colon = P(":") local semicolon = P(";") local exclamation = P("!") + local tilde = P("~") local digit = R("09") local hexdigit = R("09","af","AF") local letter = R("AZ","az") local alphanumeric = R("AZ","az","09") local keyword = letter * alphanumeric^0 + local punctuation = S("!?,.:;") local doubleasterisks = P("**") local doubleunderscores = P("__") @@ -483,7 +499,8 @@ function M.reader.new(writer, options) local fail = any - 1 local always = P("") - local escapable = S("\\`*_{}[]()+_.!<>#-~:^") + local escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") + local anyescaped = P("\\") / "" * escapable + any @@ -494,17 +511,14 @@ function M.reader.new(writer, options) local nonspacechar = any - spacing local tightblocksep = P("\001") - local specialchar - if options.smartEllipses then - specialchar = S("*_`&[]= #b and i + end + + local infostring = (linechar - (backtick + space^1 * (newline + eof)))^0 + + local fenceindent + local function fencehead(char) + return C(nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * optionalspace * C(infostring) * optionalspace + * (newline + eof) + end + + local function fencetail(char) + return nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), + captures_geq_length) + * optionalspace * (newline + eof) + + eof + end + + local function fencedline(char) + return C(line - fencetail(char)) + / function(s) + return s:gsub("^" .. string.rep(" ?", + fenceindent), "") + end + end local leader = space^-3 -- in balanced brackets, parentheses, quotes: @@ -616,6 +663,38 @@ function M.reader.new(writer, options) local optionaltitle = spnl * title * spacechar^0 + Cc("") + local citation_name = (Cs(dash^-1) + * at * Cs((anyescaped + - (rbracket + spacing + punctuation + semicolon))^1)) + + local citation_body_prenote + = Cs((alphanumeric^1 + + bracketed + + inticks + + (anyescaped + - (rbracket + semicolon + blankline^2)) + - (spnl * dash^-1 * at))^0) + + local citation_body_postnote + = Cs((alphanumeric^1 + + bracketed + + inticks + + (anyescaped + - (rbracket + semicolon + blankline^2)) + - (spnl * rbracket))^0) + + local citation_body_chunk + = citation_body_prenote + * spnl * citation_name + * spnlor(punctuation - (semicolon + rbracket)) + * citation_body_postnote + + local citation_body = citation_body_chunk + * (semicolon * spnl * citation_body_chunk)^0 + + local citation_headless_body + = citation_body_postnote + * (sp * semicolon * spnl * citation_body_chunk)^0 local rawnotes = {} local function strip_first_char(s) @@ -627,7 +706,7 @@ function M.reader.new(writer, options) return function() local found = rawnotes[normalize_tag(ref)] if found then - return writer.note(parse_blocks(found)) + return writer.note(parse_blocks_toplevel(found)) else return {"[", parse_inlines("^" .. ref), "]"} end @@ -713,21 +792,10 @@ function M.reader.new(writer, options) end end end - local Inline = V("Inline") - - local Str = normalchar^1 / writer.string - - local Ellipsis = P("...") / writer.ellipsis - - local Smart = Ellipsis - - local Symbol = (specialchar - tightblocksep) / writer.string - - local Code = inticks / writer.code - local bqstart = more local headerstart = hash + (line * (equal^1 + dash^1) * optionalspace * newline) + local fencestart = fencehead(backtick) + fencehead(tilde) if options.blankBeforeBlockquote then bqstart = fail @@ -737,24 +805,41 @@ function M.reader.new(writer, options) headerstart = fail end + if not options.fencedCode or options.blankBeforeCodeFence then + fencestart = fail + end + local Inline = V("Inline") + + local Str = normalchar^1 / writer.string + + local Symbol = (specialchar - tightblocksep) / writer.string + local Ellipsis = P("...") / writer.ellipsis + + local Smart = Ellipsis + local Code = inticks / writer.code local Endline = newline * -( -- newline, but not before... blankline -- paragraph break + tightblocksep -- nested list + eof -- end of document + bqstart + headerstart + + fencestart ) * spacechar^0 / writer.space local Space = spacechar^2 * Endline / writer.linebreak + spacechar^1 * Endline^-1 * eof / "" + spacechar^1 * Endline^-1 * optionalspace / writer.space + local NonbreakingSpace + = spacechar^2 * Endline / writer.linebreak + + spacechar^1 * Endline^-1 * eof / "" + + spacechar^1 * Endline^-1 * optionalspace / writer.nbsp + -- parse many p between starter and ender local function between(p, starter, ender) local ender2 = B(nonspacechar) * ender return (starter * #nonspacechar * Ct(p * (p - ender2)^0) * ender2) end - local Strong = ( between(Inline, doubleasterisks, doubleasterisks) + between(Inline, doubleunderscores, doubleunderscores) ) / writer.strong @@ -762,7 +847,6 @@ function M.reader.new(writer, options) local Emph = ( between(Inline, asterisk, asterisk) + between(Inline, underscore, underscore) ) / writer.emphasis - local urlchar = anyescaped - newline - more local AutoLinkUrl = less @@ -792,7 +876,6 @@ function M.reader.new(writer, options) -- parse a link or image (direct or indirect) local Link = DirectLink + IndirectLink - local DirectImage = exclamation * (tag / parse_inlines) * spnl @@ -806,43 +889,89 @@ function M.reader.new(writer, options) indirect_image local Image = DirectImage + IndirectImage - -- avoid parsing long strings of * or _ as emph/strong local UlOrStarLine = asterisk^4 + underscore^4 / writer.string local EscapedChar = S("\\") * C(escapable) / writer.string + local function citations(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.string(raw_cites[i+2]), + postnote = normalize(raw_cites[i+3]), + } + end + return writer.citations(text_cites, cites) + end + + local TextCitations = Ct(Cc("") + * citation_name + * ((spnl + * lbracket + * citation_headless_body + * rbracket) + Cc(""))) / + function(raw_cites) + return citations(true, raw_cites) + end + + local ParenthesizedCitations + = Ct(lbracket + * citation_body + * rbracket) / + function(raw_cites) + return citations(false, raw_cites) + end + + local Citations = TextCitations + ParenthesizedCitations local Block = V("Block") local Verbatim = Cs( (blanklines * ((indentedline - blankline))^1)^1 ) / expandtabs / writer.verbatim + local TildeFencedCode + = fencehead(tilde) + * Cs(fencedline(tilde)^0) + * fencetail(tilde) + + local BacktickFencedCode + = fencehead(backtick) + * Cs(fencedline(backtick)^0) + * fencetail(backtick) + + local FencedCode = (TildeFencedCode + BacktickFencedCode) + / function(infostring, code) + return writer.fencedCode( + writer.string(infostring), + expandtabs(code)) + end -- strip off leading > and indents, and run through blocks local Blockquote = Cs(( ((leader * more * space^-1)/"" * linechar^0 * newline)^1 * (-blankline * linechar^1 * newline)^0 - * blankline^0 - )^1) / parse_blocks / writer.blockquote + * (blankline^0 / "") + )^1) / parse_blocks_toplevel / writer.blockquote local function lineof(c) - return (leader * (P(c) * optionalspace)^3 * newline * blankline^1) + return (leader * (P(c) * optionalspace)^3 * (newline * blankline^1 + + newline^-1 * eof)) end - local HorizontalRule = ( lineof(asterisk) + lineof(dash) + lineof(underscore) ) / writer.hrule - - local Reference = define_reference_parser / register_link - - local Paragraph = nonindentspace * Ct(Inline^1) * newline - * ( blankline^1 - + #hash - + #(leader * more * space^-1) - ) - / writer.paragraph - - local Plain = nonindentspace * Ct(Inline^1) / writer.plain local starter = bullet + enumerator -- we use \001 as a separator between a tight list item and a @@ -913,7 +1042,7 @@ function M.reader.new(writer, options) local DefinitionListItemLoose = C(line) * skipblanklines * Ct((defstart * indented_blocks(dlchunk) / - parse_blocks)^1) + parse_blocks_toplevel)^1) * Cc(false) / definition_list_item @@ -928,10 +1057,29 @@ function M.reader.new(writer, options) * (skipblanklines * -DefinitionListItemLoose * Cc(true)) ) / writer.definitionlist + local Reference = define_reference_parser / register_link local Blank = blankline / "" + NoteBlock + Reference + (tightblocksep / "\n") + local Paragraph = nonindentspace * Ct(Inline^1) * newline + * ( blankline^1 + + #hash + + #(leader * more * space^-1) + ) + / writer.paragraph + + local ToplevelParagraph + = nonindentspace * Ct(Inline^1) * (newline + * ( blankline^1 + + #hash + + #(leader * more * space^-1) + + eof + ) + + eof ) + / writer.paragraph + + local Plain = nonindentspace * Ct(Inline^1) / writer.plain -- parse Atx heading start and return level local HeadingStart = #hash * C(hash^-6) * -hash / length @@ -955,6 +1103,8 @@ function M.reader.new(writer, options) * HeadingLevel * optionalspace * newline / writer.heading + + local Heading = AtxHeading + SetextHeading syntax = { "Blocks", @@ -970,6 +1120,7 @@ function M.reader.new(writer, options) Block = V("Blockquote") + V("Verbatim") + + V("FencedCode") + V("HorizontalRule") + V("BulletList") + V("OrderedList") @@ -980,10 +1131,11 @@ function M.reader.new(writer, options) Blockquote = Blockquote, Verbatim = Verbatim, + FencedCode = FencedCode, HorizontalRule = HorizontalRule, BulletList = BulletList, OrderedList = OrderedList, - Heading = AtxHeading + SetextHeading, + Heading = Heading, DefinitionList = DefinitionList, DisplayHtml = DisplayHtml, Paragraph = Paragraph, @@ -996,6 +1148,7 @@ function M.reader.new(writer, options) + V("Strong") + V("Emph") + V("NoteRef") + + V("Citations") + V("Link") + V("Image") + V("Code") @@ -1012,6 +1165,7 @@ function M.reader.new(writer, options) Strong = Strong, Emph = Emph, NoteRef = NoteRef, + Citations = Citations, Link = Link, Image = Image, Code = Code, @@ -1028,6 +1182,14 @@ function M.reader.new(writer, options) syntax.DefinitionList = fail end + if not options.fencedCode then + syntax.FencedCode = fail + end + + if not options.citations then + syntax.Citations = fail + end + if not options.footnotes then syntax.NoteRef = fail end @@ -1036,6 +1198,10 @@ function M.reader.new(writer, options) syntax.Smart = fail end + local blocks_toplevel_t = util.table_copy(syntax) + blocks_toplevel_t.Paragraph = ToplevelParagraph + blocks_toplevel = Ct(blocks_toplevel_t) + blocks = Ct(syntax) local inlines_t = util.table_copy(syntax) @@ -1043,9 +1209,13 @@ function M.reader.new(writer, options) inlines_t.Inlines = Inline^0 * (spacing^0 * eof / "") inlines = Ct(inlines_t) - inlines_no_link_t = util.table_copy(inlines_t) + local inlines_no_link_t = util.table_copy(inlines_t) inlines_no_link_t.Link = fail inlines_no_link = Ct(inlines_no_link_t) + + local inlines_nbsp_t = util.table_copy(inlines_t) + inlines_nbsp_t.Space = NonbreakingSpace + inlines_nbsp = Ct(inlines_nbsp_t) function self.convert(input) references = {} local opt_string = {} @@ -1056,9 +1226,9 @@ function M.reader.new(writer, options) end end table.sort(opt_string) - local salt = table.concat(opt_string, ",") + local salt = table.concat(opt_string, ",") .. "," .. metadata.version local name = util.cache(options.cacheDir, input, salt, function(input) - return util.rope_to_string(parse_blocks(input)) .. writer.eof + return util.rope_to_string(parse_blocks_toplevel(input)) .. writer.eof end, ".md" .. writer.suffix) return writer.pack(name) end -- cgit v1.2.3