From f78056943ffe36621ca1cf595657f324cda9b13f Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 5 Jan 2017 22:56:40 +0000 Subject: markdown (5jan17) git-svn-id: svn://tug.org/texlive/trunk@42868 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/context/third/markdown/t-markdown.tex | 30 +- .../texmf-dist/tex/generic/markdown/markdown.tex | 137 +- Master/texmf-dist/tex/latex/markdown/markdown.sty | 42 +- Master/texmf-dist/tex/luatex/markdown/markdown.lua | 1685 +++++++++++++------- 4 files changed, 1165 insertions(+), 729 deletions(-) (limited to 'Master/texmf-dist/tex') 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 4f90f3b8f8f..91e89c1dc20 100644 --- a/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex +++ b/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex @@ -51,26 +51,14 @@ \let\stopmarkdown\relax \def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\_\do\%\do\~}% -\ifx\directlua\undefined - \input markdown -\else - \directlua{% - local function unescape(str) - return (str:gsub("|", string.char(92))) end - local old_callback = callback.find("process_input_buffer") - callback.register("process_input_buffer", function() end) - local new_callback = callback.find("process_input_buffer") - if new_callback == false then - tex.print(unescape([[|def|markdownMode{1}|input markdown]])) - else - callback.register("process_input_buffer", old_callback) - tex.print(unescape("|input markdown")) - end}% -\fi -\ifnum\markdownMode<2\relax - \def\markdownMakeOther{% - \catcode`|=12}% -\fi +\input markdown +\def\markdownMakeOther{% + \count0=128\relax + \loop + \catcode\count0=11\relax + \advance\count0 by 1\relax + \ifnum\count0<256\repeat + \catcode`|=12}% \def\markdownInfo#1{\writestatus{markdown}{#1.}}% \def\markdownWarning#1{\writestatus{markdown\space warn}{#1.}}% \begingroup @@ -132,7 +120,7 @@ \def\markdownRendererDlEndTightPrototype{% \stopMarkdownConTeXtDlTightPrototype}% \def\markdownRendererEmphasisPrototype#1{{\em#1}}% -\def\markdownRendererStrongEmphasisPrototype#1{{\bf\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% \def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% \def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% diff --git a/Master/texmf-dist/tex/generic/markdown/markdown.tex b/Master/texmf-dist/tex/generic/markdown/markdown.tex index c98168c110a..8de36017864 100644 --- a/Master/texmf-dist/tex/generic/markdown/markdown.tex +++ b/Master/texmf-dist/tex/generic/markdown/markdown.tex @@ -45,8 +45,8 @@ %% %% The names of the source files used are shown above. %% -\def\markdownLastModified{2016/12/09}% -\def\markdownVersion{2.2.2}% +\def\markdownLastModified{2017/01/05}% +\def\markdownVersion{2.3.0}% \let\markdownBegin\relax \let\markdownEnd\relax \let\markdownInput\relax @@ -57,12 +57,14 @@ \let\markdownOptionBlankBeforeBlockquote\undefined \let\markdownOptionBlankBeforeCodeFence\undefined \let\markdownOptionBlankBeforeHeading\undefined +\let\markdownOptionBreakableBlockquotes\undefined \let\markdownOptionCitations\undefined \let\markdownOptionCitationNbsps\undefined \let\markdownOptionDefinitionLists\undefined \let\markdownOptionFootnotes\undefined \let\markdownOptionFencedCode\undefined \let\markdownOptionHashEnumerators\undefined +\let\markdownOptionHtml\undefined \let\markdownOptionHybrid\undefined \let\markdownOptionInlineFootnotes\undefined \let\markdownOptionPreserveTabs\undefined @@ -237,11 +239,6 @@ \def\markdownInfo#1{}% \def\markdownWarning#1{}% \def\markdownError#1{}% -\def\markdownLuaRegisterIBCallback#1{% - local old_callback = callback.find("process_input_buffer") - callback.register("process_input_buffer", #1)}% -\def\markdownLuaUnregisterIBCallback{% - callback.register("process_input_buffer", old_callback)}% \let\markdownMakeOther\relax \let\markdownReadAndConvert\relax \begingroup @@ -257,6 +254,8 @@ \def\markdownMode{2}% \fi \fi +\def\markdownLuaRegisterIBCallback#1{\relax}% +\def\markdownLuaUnregisterIBCallback#1{\relax}% \def\markdownInfo#1{% \message{(l.\the\inputlineno) markdown.tex info: #1.}}% \def\markdownWarning#1{% @@ -304,7 +303,7 @@ \def\markdownRendererDlEndPrototype{}% \def\markdownRendererDlEndTightPrototype{}% \def\markdownRendererEmphasisPrototype#1{{\it#1}}% -\def\markdownRendererStrongEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% \def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% \def\markdownRendererInputVerbatimPrototype#1{% @@ -331,6 +330,9 @@ \ifx\markdownOptionBlankBeforeHeading\undefined\else blankBeforeHeading = \markdownOptionBlankBeforeHeading, \fi +\ifx\markdownOptionBreakableBlockquotes\undefined\else + breakableBlockquotes = \markdownOptionBreakableBlockquotes, +\fi \ifx\markdownOptionCacheDir\undefined\else cacheDir = "\markdownOptionCacheDir", \fi @@ -352,6 +354,9 @@ \ifx\markdownOptionHashEnumerators\undefined\else hashEnumerators = \markdownOptionHashEnumerators, \fi +\ifx\markdownOptionHtml\undefined\else + html = \markdownOptionHtml, +\fi \ifx\markdownOptionHybrid\undefined\else hybrid = \markdownOptionHybrid, \fi @@ -380,14 +385,53 @@ end local md = require("markdown") local convert = md.new(\markdownLuaOptions) }% - +\csname newwrite\endcsname\markdownLuaExecuteFileStream +\begingroup + \catcode`\^^I=12% + \gdef\markdownReadAndConvertTab{^^I}% +\endgroup +\begingroup + \catcode`\^^M=13% + \catcode`\^^I=13% + \catcode`|=0% + \catcode`\\=12% + |gdef|markdownReadAndConvert#1#2{% + |begingroup% + |immediate|openout|markdownLuaExecuteFileStream% + |markdownOptionInputTempFileName% + |markdownInfo{Buffering markdown input into the temporary % + input file "|markdownOptionInputTempFileName" and scanning % + for the closing token sequence "#1"}% + |def|do##1{|catcode`##1=12}|dospecials% + |catcode`| =12% + |markdownMakeOther% + |def|markdownReadAndConvertProcessLine##1#1##2#1##3|relax{% + |ifx|relax##3|relax% + |immediate|write|markdownLuaExecuteFileStream{##1}% + |else% + |def^^M{% + |markdownInfo{The ending token sequence was found}% + |immediate|closeout|markdownLuaExecuteFileStream% + |endgroup% + |markdownInput|markdownOptionInputTempFileName% + #2}% + |fi% + ^^M}% + |catcode`|^^I=13% + |def^^I{|markdownReadAndConvertTab}% + |catcode`|^^M=13% + |def^^M##1^^M{% + |def^^M####1^^M{% + |markdownReadAndConvertProcessLine####1#1#1|relax}% + ^^M}% + ^^M}% +|endgroup \ifnum\markdownMode<2\relax \ifnum\markdownMode=0\relax \markdownInfo{Using mode 0: Shell escape via write18}% \else \markdownInfo{Using mode 1: Shell escape via os.execute}% \fi -\csname newwrite\endcsname\markdownLuaExecuteFileStream \ifx\pdfshellescape\undefined \ifx\shellescape\undefined \ifnum\markdownMode=0\relax @@ -431,82 +475,9 @@ local convert = md.new(\markdownLuaOptions) \markdownExecute{texlua "\markdownOptionHelperScriptFileName" > "\markdownOptionOutputTempFileName"}% \input\markdownOptionOutputTempFileName\relax}% -\begingroup - \catcode`\^^I=12% - \gdef\markdownReadAndConvertTab{^^I}% -\endgroup -\begingroup - \catcode`\^^M=13% - \catcode`\^^I=13% - \catcode`|=0% - \catcode`\\=12% - |gdef|markdownReadAndConvert#1#2{% - |begingroup% - |immediate|openout|markdownLuaExecuteFileStream% - |markdownOptionInputTempFileName% - |markdownInfo{Buffering markdown input into the temporary % - input file "|markdownOptionInputTempFileName" and scanning % - for the closing token sequence "#1"}% - |def|do##1{|catcode`##1=12}|dospecials% - |catcode`| =12% - |markdownMakeOther% - |def|markdownReadAndConvertProcessLine##1#1##2#1##3|relax{% - |ifx|relax##3|relax% - |immediate|write|markdownLuaExecuteFileStream{##1}% - |else% - |def^^M{% - |markdownInfo{The ending token sequence was found}% - |immediate|closeout|markdownLuaExecuteFileStream% - |endgroup% - |markdownInput|markdownOptionInputTempFileName% - #2}% - |fi% - ^^M}% - |catcode`|^^I=13% - |def^^I{|markdownReadAndConvertTab}% - |catcode`|^^M=13% - |def^^M##1^^M{% - |def^^M####1^^M{% - |markdownReadAndConvertProcessLine####1#1#1|relax}% - ^^M}% - ^^M}% -|endgroup \else \markdownInfo{Using mode 2: Direct Lua access}% \def\markdownLuaExecute#1{\directlua{local print = tex.print #1}}% -\begingroup - \catcode`\_=12% - \catcode`\$=12% - \catcode`\^=12% - \catcode`\/=6% - \catcode`\#=12% - \catcode`\@=14% - \catcode`\%=12% - \catcode`|=0@ - \catcode`\\=12@ - |gdef|markdownReadAndConvert/1/2{@ - |def|markdownReadAndConvertAfter{/2}@ - |markdownInfo{Buffering markdown input and scanning for the - closing token sequence "/1"}@ - |directlua{@ - |markdownPrepare - local buffer = {} - local ending_sequence = "^.-" .. ([[/1]]):gsub( - "([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1") - |markdownLuaRegisterIBCallback{function(line) - if line:match(ending_sequence) then - |markdownLuaUnregisterIBCallback; - local input = table.concat(buffer, "\n") .. "\n" - local output = convert(input) - return [[\markdownInfo{The ending token sequence was found}]] .. - output .. [[\markdownReadAndConvertAfter]] - else - buffer[#buffer+1] = line - return [[\]] .. (#buffer == 1 and "fi" or "relax") - end - end}}@ - |iffalse}@ - |endgroup \fi \begingroup \catcode`|=0% diff --git a/Master/texmf-dist/tex/latex/markdown/markdown.sty b/Master/texmf-dist/tex/latex/markdown/markdown.sty index 97b42f5f766..94997e75fb8 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdown.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdown.sty @@ -63,6 +63,8 @@ \def\markdownOptionBlankBeforeCodeFence{#1}}% \define@key{markdownOptions}{blankBeforeHeading}[true]{% \def\markdownOptionBlankBeforeHeading{#1}}% +\define@key{markdownOptions}{breakableBlockquotes}[true]{% + \def\markdownOptionBreakableBlockquotes{#1}}% \define@key{markdownOptions}{citations}[true]{% \def\markdownOptionCitations{#1}}% \define@key{markdownOptions}{citationNbsps}[true]{% @@ -77,6 +79,8 @@ \def\markdownOptionFencedCode{#1}}% \define@key{markdownOptions}{hashEnumerators}[true]{% \def\markdownOptionHashEnumerators{#1}}% +\define@key{markdownOptions}{html}[true]{% + \def\markdownOptionHtml{#1}}% \define@key{markdownOptions}{hybrid}[true]{% \def\markdownOptionHybrid{#1}}% \define@key{markdownOptions}{inlineFootnotes}[true]{% @@ -403,12 +407,6 @@ dlItem = {\item[#1]}, dlEnd = {\end{description}}, emphasis = {\emph{#1}}, - strongEmphasis = {% - \ifx\alert\undefined - \textbf{\emph{#1}}% - \else % Beamer support - \alert{\emph{#1}}% - \fi}, blockQuoteBegin = {\begin{quotation}}, blockQuoteEnd = {\end{quotation}}, inputVerbatim = {\VerbatimInput{#1}}, @@ -428,7 +426,19 @@ \fi}, horizontalRule = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, footnote = {\footnote{#1}}}} - +\newif\ifmarkdownLATEXStrongEmphasisNested +\markdownLATEXStrongEmphasisNestedfalse +\markdownSetup{rendererPrototypes={ + strongEmphasis = {% + \ifmarkdownLATEXStrongEmphasisNested + \markdownLATEXStrongEmphasisNestedfalse + \textmd{#1}% + \markdownLATEXStrongEmphasisNestedtrue + \else + \markdownLATEXStrongEmphasisNestedtrue + \textbf{#1}% + \markdownLATEXStrongEmphasisNestedfalse + \fi}}} \ifx\chapter\undefined \markdownSetup{rendererPrototypes = { headingOne = {\section{#1}}, @@ -491,24 +501,6 @@ \markdownLaTeXBibLaTeXTextCitations \expandafter{\expandafter}% \fi}}} -\let\markdownLuaRegisterIBCallbackPrevious - \markdownLuaRegisterIBCallback -\let\markdownLuaUnregisterIBCallbackPrevious - \markdownLuaUnregisterIBCallback -\renewcommand\markdownLuaRegisterIBCallback[1]{% - 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{% - 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 06f2a2b6169..63e4effda43 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -58,10 +58,11 @@ -- those in the standard .ins files. -- local metadata = { - version = "2.2.2", + version = "2.3.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ý", + copyright = "2009-2017 John MacFarlane, Hans Hagen; " .. + "2016-2017 Vít Novotný", license = "LPPL 1.3" } if not modules then modules = { } end @@ -74,11 +75,13 @@ local defaultOptions = {} defaultOptions.blankBeforeBlockquote = false defaultOptions.blankBeforeCodeFence = false defaultOptions.blankBeforeHeading = false +defaultOptions.breakableBlockquotes = false defaultOptions.cacheDir = "." defaultOptions.citationNbsps = true defaultOptions.citations = false defaultOptions.definitionLists = false defaultOptions.hashEnumerators = false +defaultOptions.html = false defaultOptions.hybrid = false defaultOptions.fencedCode = false defaultOptions.footnotes = false @@ -221,6 +224,269 @@ function util.pathname(dir, file) return dir .. "/" .. file end end +local entities = {} + +local character_entities = { + ["quot"] = 0x0022, + ["amp"] = 0x0026, + ["apos"] = 0x0027, + ["lt"] = 0x003C, + ["gt"] = 0x003E, + ["nbsp"] = 160, + ["iexcl"] = 0x00A1, + ["cent"] = 0x00A2, + ["pound"] = 0x00A3, + ["curren"] = 0x00A4, + ["yen"] = 0x00A5, + ["brvbar"] = 0x00A6, + ["sect"] = 0x00A7, + ["uml"] = 0x00A8, + ["copy"] = 0x00A9, + ["ordf"] = 0x00AA, + ["laquo"] = 0x00AB, + ["not"] = 0x00AC, + ["shy"] = 173, + ["reg"] = 0x00AE, + ["macr"] = 0x00AF, + ["deg"] = 0x00B0, + ["plusmn"] = 0x00B1, + ["sup2"] = 0x00B2, + ["sup3"] = 0x00B3, + ["acute"] = 0x00B4, + ["micro"] = 0x00B5, + ["para"] = 0x00B6, + ["middot"] = 0x00B7, + ["cedil"] = 0x00B8, + ["sup1"] = 0x00B9, + ["ordm"] = 0x00BA, + ["raquo"] = 0x00BB, + ["frac14"] = 0x00BC, + ["frac12"] = 0x00BD, + ["frac34"] = 0x00BE, + ["iquest"] = 0x00BF, + ["Agrave"] = 0x00C0, + ["Aacute"] = 0x00C1, + ["Acirc"] = 0x00C2, + ["Atilde"] = 0x00C3, + ["Auml"] = 0x00C4, + ["Aring"] = 0x00C5, + ["AElig"] = 0x00C6, + ["Ccedil"] = 0x00C7, + ["Egrave"] = 0x00C8, + ["Eacute"] = 0x00C9, + ["Ecirc"] = 0x00CA, + ["Euml"] = 0x00CB, + ["Igrave"] = 0x00CC, + ["Iacute"] = 0x00CD, + ["Icirc"] = 0x00CE, + ["Iuml"] = 0x00CF, + ["ETH"] = 0x00D0, + ["Ntilde"] = 0x00D1, + ["Ograve"] = 0x00D2, + ["Oacute"] = 0x00D3, + ["Ocirc"] = 0x00D4, + ["Otilde"] = 0x00D5, + ["Ouml"] = 0x00D6, + ["times"] = 0x00D7, + ["Oslash"] = 0x00D8, + ["Ugrave"] = 0x00D9, + ["Uacute"] = 0x00DA, + ["Ucirc"] = 0x00DB, + ["Uuml"] = 0x00DC, + ["Yacute"] = 0x00DD, + ["THORN"] = 0x00DE, + ["szlig"] = 0x00DF, + ["agrave"] = 0x00E0, + ["aacute"] = 0x00E1, + ["acirc"] = 0x00E2, + ["atilde"] = 0x00E3, + ["auml"] = 0x00E4, + ["aring"] = 0x00E5, + ["aelig"] = 0x00E6, + ["ccedil"] = 0x00E7, + ["egrave"] = 0x00E8, + ["eacute"] = 0x00E9, + ["ecirc"] = 0x00EA, + ["euml"] = 0x00EB, + ["igrave"] = 0x00EC, + ["iacute"] = 0x00ED, + ["icirc"] = 0x00EE, + ["iuml"] = 0x00EF, + ["eth"] = 0x00F0, + ["ntilde"] = 0x00F1, + ["ograve"] = 0x00F2, + ["oacute"] = 0x00F3, + ["ocirc"] = 0x00F4, + ["otilde"] = 0x00F5, + ["ouml"] = 0x00F6, + ["divide"] = 0x00F7, + ["oslash"] = 0x00F8, + ["ugrave"] = 0x00F9, + ["uacute"] = 0x00FA, + ["ucirc"] = 0x00FB, + ["uuml"] = 0x00FC, + ["yacute"] = 0x00FD, + ["thorn"] = 0x00FE, + ["yuml"] = 0x00FF, + ["OElig"] = 0x0152, + ["oelig"] = 0x0153, + ["Scaron"] = 0x0160, + ["scaron"] = 0x0161, + ["Yuml"] = 0x0178, + ["fnof"] = 0x0192, + ["circ"] = 0x02C6, + ["tilde"] = 0x02DC, + ["Alpha"] = 0x0391, + ["Beta"] = 0x0392, + ["Gamma"] = 0x0393, + ["Delta"] = 0x0394, + ["Epsilon"] = 0x0395, + ["Zeta"] = 0x0396, + ["Eta"] = 0x0397, + ["Theta"] = 0x0398, + ["Iota"] = 0x0399, + ["Kappa"] = 0x039A, + ["Lambda"] = 0x039B, + ["Mu"] = 0x039C, + ["Nu"] = 0x039D, + ["Xi"] = 0x039E, + ["Omicron"] = 0x039F, + ["Pi"] = 0x03A0, + ["Rho"] = 0x03A1, + ["Sigma"] = 0x03A3, + ["Tau"] = 0x03A4, + ["Upsilon"] = 0x03A5, + ["Phi"] = 0x03A6, + ["Chi"] = 0x03A7, + ["Psi"] = 0x03A8, + ["Omega"] = 0x03A9, + ["alpha"] = 0x03B1, + ["beta"] = 0x03B2, + ["gamma"] = 0x03B3, + ["delta"] = 0x03B4, + ["epsilon"] = 0x03B5, + ["zeta"] = 0x03B6, + ["eta"] = 0x03B7, + ["theta"] = 0x03B8, + ["iota"] = 0x03B9, + ["kappa"] = 0x03BA, + ["lambda"] = 0x03BB, + ["mu"] = 0x03BC, + ["nu"] = 0x03BD, + ["xi"] = 0x03BE, + ["omicron"] = 0x03BF, + ["pi"] = 0x03C0, + ["rho"] = 0x03C1, + ["sigmaf"] = 0x03C2, + ["sigma"] = 0x03C3, + ["tau"] = 0x03C4, + ["upsilon"] = 0x03C5, + ["phi"] = 0x03C6, + ["chi"] = 0x03C7, + ["psi"] = 0x03C8, + ["omega"] = 0x03C9, + ["thetasym"] = 0x03D1, + ["upsih"] = 0x03D2, + ["piv"] = 0x03D6, + ["ensp"] = 0x2002, + ["emsp"] = 0x2003, + ["thinsp"] = 0x2009, + ["ndash"] = 0x2013, + ["mdash"] = 0x2014, + ["lsquo"] = 0x2018, + ["rsquo"] = 0x2019, + ["sbquo"] = 0x201A, + ["ldquo"] = 0x201C, + ["rdquo"] = 0x201D, + ["bdquo"] = 0x201E, + ["dagger"] = 0x2020, + ["Dagger"] = 0x2021, + ["bull"] = 0x2022, + ["hellip"] = 0x2026, + ["permil"] = 0x2030, + ["prime"] = 0x2032, + ["Prime"] = 0x2033, + ["lsaquo"] = 0x2039, + ["rsaquo"] = 0x203A, + ["oline"] = 0x203E, + ["frasl"] = 0x2044, + ["euro"] = 0x20AC, + ["image"] = 0x2111, + ["weierp"] = 0x2118, + ["real"] = 0x211C, + ["trade"] = 0x2122, + ["alefsym"] = 0x2135, + ["larr"] = 0x2190, + ["uarr"] = 0x2191, + ["rarr"] = 0x2192, + ["darr"] = 0x2193, + ["harr"] = 0x2194, + ["crarr"] = 0x21B5, + ["lArr"] = 0x21D0, + ["uArr"] = 0x21D1, + ["rArr"] = 0x21D2, + ["dArr"] = 0x21D3, + ["hArr"] = 0x21D4, + ["forall"] = 0x2200, + ["part"] = 0x2202, + ["exist"] = 0x2203, + ["empty"] = 0x2205, + ["nabla"] = 0x2207, + ["isin"] = 0x2208, + ["notin"] = 0x2209, + ["ni"] = 0x220B, + ["prod"] = 0x220F, + ["sum"] = 0x2211, + ["minus"] = 0x2212, + ["lowast"] = 0x2217, + ["radic"] = 0x221A, + ["prop"] = 0x221D, + ["infin"] = 0x221E, + ["ang"] = 0x2220, + ["and"] = 0x2227, + ["or"] = 0x2228, + ["cap"] = 0x2229, + ["cup"] = 0x222A, + ["int"] = 0x222B, + ["there4"] = 0x2234, + ["sim"] = 0x223C, + ["cong"] = 0x2245, + ["asymp"] = 0x2248, + ["ne"] = 0x2260, + ["equiv"] = 0x2261, + ["le"] = 0x2264, + ["ge"] = 0x2265, + ["sub"] = 0x2282, + ["sup"] = 0x2283, + ["nsub"] = 0x2284, + ["sube"] = 0x2286, + ["supe"] = 0x2287, + ["oplus"] = 0x2295, + ["otimes"] = 0x2297, + ["perp"] = 0x22A5, + ["sdot"] = 0x22C5, + ["lceil"] = 0x2308, + ["rceil"] = 0x2309, + ["lfloor"] = 0x230A, + ["rfloor"] = 0x230B, + ["lang"] = 0x27E8, + ["rang"] = 0x27E9, + ["loz"] = 0x25CA, + ["spades"] = 0x2660, + ["clubs"] = 0x2663, + ["hearts"] = 0x2665, + ["diams"] = 0x2666, +} +function entities.dec_entity(s) + return unicode.utf8.char(tonumber(s)) +end +function entities.hex_entity(s) + return unicode.utf8.char(tonumber("0x"..s)) +end +function entities.char_entity(s) + local n = character_entities[s] + return unicode.utf8.char(n) +end M.writer = {} function M.writer.new(options) local self = {} @@ -335,6 +601,8 @@ function M.writer.new(options) "\n\\markdownRendererOlEnd "} end end + function self.inline_html(html) return "" end + function self.display_html(html) return "" end local function dlitem(term, defs) local retVal = {"\\markdownRendererDlItem{",term,"}"} for _, def in ipairs(defs) do @@ -410,91 +678,432 @@ function M.writer.new(options) return self end -local percent = P("%") -local at = P("@") -local comma = P(",") -local asterisk = P("*") -local dash = P("-") -local plus = P("+") -local underscore = P("_") -local period = P(".") -local hash = P("#") -local ampersand = P("&") -local backtick = P("`") -local less = P("<") -local more = P(">") -local space = P(" ") -local squote = P("'") -local dquote = P('"') -local lparent = P("(") -local rparent = P(")") -local lbracket = P("[") -local rbracket = P("]") -local circumflex = P("^") -local slash = P("/") -local equal = P("=") -local colon = P(":") -local semicolon = P(";") -local exclamation = P("!") -local 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 internal_punctuation = S(":;,.#$%&-+?<>~/") - -local doubleasterisks = P("**") -local doubleunderscores = P("__") -local fourspaces = P(" ") - -local any = P(1) -local fail = any - 1 -local always = P("") - -local escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") - -local anyescaped = P("\\") / "" * escapable - + any - -local tab = P("\t") -local spacechar = S("\t ") -local spacing = S(" \n\r\t") -local newline = P("\n") -local nonspacechar = any - spacing -local tightblocksep = P("\001") - -local specialchar = S("*_`&[]") +parsers.space = P(" ") +parsers.squote = P("'") +parsers.dquote = P('"') +parsers.lparent = P("(") +parsers.rparent = P(")") +parsers.lbracket = P("[") +parsers.rbracket = P("]") +parsers.circumflex = P("^") +parsers.slash = P("/") +parsers.equal = P("=") +parsers.colon = P(":") +parsers.semicolon = P(";") +parsers.exclamation = P("!") +parsers.tilde = P("~") +parsers.tab = P("\t") +parsers.newline = P("\n") +parsers.tightblocksep = P("\001") + +parsers.digit = R("09") +parsers.hexdigit = R("09","af","AF") +parsers.letter = R("AZ","az") +parsers.alphanumeric = R("AZ","az","09") +parsers.keyword = parsers.letter + * parsers.alphanumeric^0 +parsers.internal_punctuation = S(":;,.#$%&-+?<>~/") + +parsers.doubleasterisks = P("**") +parsers.doubleunderscores = P("__") +parsers.fourspaces = P(" ") + +parsers.any = P(1) +parsers.fail = parsers.any - 1 + +parsers.escapable = S("\\`*_{}[]()+_.!<>#-~:^@;") +parsers.anyescaped = P("\\") / "" * parsers.escapable + + parsers.any + +parsers.spacechar = S("\t ") +parsers.spacing = S(" \n\r\t") +parsers.nonspacechar = parsers.any - parsers.spacing +parsers.optionalspace = parsers.spacechar^0 + +parsers.specialchar = S("*_`&[]= #b and i +end + +parsers.infostring = (parsers.linechar - (parsers.backtick + + parsers.space^1 * (parsers.newline + parsers.eof)))^0 + +local fenceindent +parsers.fencehead = function(char) + return C(parsers.nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * parsers.optionalspace * C(parsers.infostring) + * parsers.optionalspace * (parsers.newline + parsers.eof) +end + +parsers.fencetail = function(char) + return parsers.nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) + * parsers.optionalspace * (parsers.newline + parsers.eof) + + parsers.eof +end + +parsers.fencedline = function(char) + return C(parsers.line - parsers.fencetail(char)) + / function(s) + return s:gsub("^" .. string.rep(" ?", fenceindent), "") + end +end +parsers.leader = parsers.space^-3 + +-- in balanced brackets, parentheses, quotes: +parsers.bracketed = P{ parsers.lbracket + * ((parsers.anyescaped - (parsers.lbracket + + parsers.rbracket + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rbracket } + +parsers.inparens = P{ parsers.lparent + * ((parsers.anyescaped - (parsers.lparent + + parsers.rparent + + parsers.blankline^2) + ) + V(1))^0 + * parsers.rparent } + +parsers.squoted = P{ parsers.squote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.squote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.squote } + +parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric + * ((parsers.anyescaped - (parsers.dquote + + parsers.blankline^2) + ) + V(1))^0 + * parsers.dquote } + +-- bracketed 'tag' for markdown links, allowing nested brackets: +parsers.tag = parsers.lbracket + * Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped - (parsers.rbracket + + parsers.blankline^2)))^0) + * parsers.rbracket + +-- url for markdown links, allowing balanced parentheses: +parsers.url = parsers.less * Cs((parsers.anyescaped-parsers.more)^0) + * parsers.more + + Cs((parsers.inparens + (parsers.anyescaped + -parsers.spacing-parsers.rparent))^1) + +-- quoted text possibly with nested quotes: +parsers.title_s = parsers.squote * Cs(((parsers.anyescaped-parsers.squote) + + parsers.squoted)^0) + * parsers.squote + +parsers.title_d = parsers.dquote * Cs(((parsers.anyescaped-parsers.dquote) + + parsers.dquoted)^0) + * parsers.dquote + +parsers.title_p = parsers.lparent + * Cs((parsers.inparens + (parsers.anyescaped-parsers.rparent))^0) + * parsers.rparent + +parsers.title = parsers.title_d + parsers.title_s + parsers.title_p + +parsers.optionaltitle + = parsers.spnl * parsers.title * parsers.spacechar^0 + + Cc("") +parsers.citation_name = Cs(parsers.dash^-1) * parsers.at + * Cs(parsers.alphanumeric + * (parsers.alphanumeric + parsers.internal_punctuation + - parsers.comma - parsers.semicolon)^0) + +parsers.citation_body_prenote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.blankline^2)) + - (parsers.spnl * parsers.dash^-1 * parsers.at))^0) + +parsers.citation_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.semicolon + + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_body_chunk + = parsers.citation_body_prenote + * parsers.spnl * parsers.citation_name + * (parsers.comma * parsers.spnl)^-1 + * parsers.citation_body_postnote + +parsers.citation_body + = parsers.citation_body_chunk + * (parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 + +parsers.citation_headless_body_postnote + = Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + (parsers.anyescaped + - (parsers.rbracket + parsers.at + + parsers.semicolon + parsers.blankline^2)) + - (parsers.spnl * parsers.rbracket))^0) + +parsers.citation_headless_body + = parsers.citation_headless_body_postnote + * (parsers.sp * parsers.semicolon * parsers.spnl + * parsers.citation_body_chunk)^0 +local function strip_first_char(s) + return s:sub(2) +end + +parsers.RawNoteRef = #(parsers.lbracket * parsers.circumflex) + * parsers.tag / strip_first_char +-- case-insensitive match (we assume s is lowercase). must be single byte encoding +parsers.keyword_exact = function(s) + local parser = P(0) + for i=1,#s do + local c = s:sub(i,i) + local m = c .. upper(c) + parser = parser * S(m) + end + return parser +end + +parsers.block_keyword = + parsers.keyword_exact("address") + parsers.keyword_exact("blockquote") + + parsers.keyword_exact("center") + parsers.keyword_exact("del") + + parsers.keyword_exact("dir") + parsers.keyword_exact("div") + + parsers.keyword_exact("p") + parsers.keyword_exact("pre") + + parsers.keyword_exact("li") + parsers.keyword_exact("ol") + + parsers.keyword_exact("ul") + parsers.keyword_exact("dl") + + parsers.keyword_exact("dd") + parsers.keyword_exact("form") + + parsers.keyword_exact("fieldset") + parsers.keyword_exact("isindex") + + parsers.keyword_exact("ins") + parsers.keyword_exact("menu") + + parsers.keyword_exact("noframes") + parsers.keyword_exact("frameset") + + parsers.keyword_exact("h1") + parsers.keyword_exact("h2") + + parsers.keyword_exact("h3") + parsers.keyword_exact("h4") + + parsers.keyword_exact("h5") + parsers.keyword_exact("h6") + + parsers.keyword_exact("hr") + parsers.keyword_exact("script") + + parsers.keyword_exact("noscript") + parsers.keyword_exact("table") + + parsers.keyword_exact("tbody") + parsers.keyword_exact("tfoot") + + parsers.keyword_exact("thead") + parsers.keyword_exact("th") + + parsers.keyword_exact("td") + parsers.keyword_exact("tr") + +-- There is no reason to support bad html, so we expect quoted attributes +parsers.htmlattributevalue + = parsers.squote * (parsers.any - (parsers.blankline + + parsers.squote))^0 + * parsers.squote + + parsers.dquote * (parsers.any - (parsers.blankline + + parsers.dquote))^0 + * parsers.dquote + +parsers.htmlattribute = parsers.spacing^1 + * (parsers.alphanumeric + S("_-"))^1 + * parsers.sp * parsers.equal * parsers.sp + * parsers.htmlattributevalue + +parsers.htmlcomment = P(""))^0 * P("-->") + +parsers.htmlinstruction = P("" ))^0 * P("?>" ) + +parsers.openelt_any = parsers.less * parsers.keyword * parsers.htmlattribute^0 + * parsers.sp * parsers.more + +parsers.openelt_exact = function(s) + return parsers.less * parsers.sp * parsers.keyword_exact(s) + * parsers.htmlattribute^0 * parsers.sp * parsers.more +end + +parsers.openelt_block = parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.more + +parsers.closeelt_any = parsers.less * parsers.sp * parsers.slash + * parsers.keyword * parsers.sp * parsers.more + +parsers.closeelt_exact = function(s) + return parsers.less * parsers.sp * parsers.slash * parsers.keyword_exact(s) + * parsers.sp * parsers.more +end + +parsers.emptyelt_any = parsers.less * parsers.sp * parsers.keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.emptyelt_block = parsers.less * parsers.sp * parsers.block_keyword + * parsers.htmlattribute^0 * parsers.sp * parsers.slash + * parsers.more + +parsers.displaytext = (parsers.any - parsers.less)^1 + +-- return content between two matched HTML tags +parsers.in_matched = function(s) + return { parsers.openelt_exact(s) + * (V(1) + parsers.displaytext + + (parsers.less - parsers.closeelt_exact(s)))^0 + * parsers.closeelt_exact(s) } +end + +local function parse_matched_tags(s,pos) + local t = string.lower(lpeg.match(C(parsers.keyword),s,pos)) + return lpeg.match(parsers.in_matched(t),s,pos-1) +end + +parsers.in_matched_block_tags = parsers.less + * Cmt(#parsers.openelt_block, parse_matched_tags) + +parsers.displayhtml = parsers.htmlcomment + + parsers.emptyelt_block + + parsers.openelt_exact("hr") + + parsers.in_matched_block_tags + + parsers.htmlinstruction + +parsers.inlinehtml = parsers.emptyelt_any + + parsers.htmlcomment + + parsers.htmlinstruction + + parsers.openelt_any + + parsers.closeelt_any +parsers.hexentity = parsers.ampersand * parsers.hash * S("Xx") + * C(parsers.hexdigit^1) * parsers.semicolon +parsers.decentity = parsers.ampersand * parsers.hash + * C(parsers.digit^1) * parsers.semicolon +parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) + * parsers.semicolon +-- parse a reference definition: [foo]: /bar "title" +parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * parsers.blankline^1 +parsers.Inline = V("Inline") + +-- parse many p between starter and ender +parsers.between = function(p, starter, ender) + local ender2 = B(parsers.nonspacechar) * ender + return (starter * #parsers.nonspacechar * Ct(p * (p - ender2)^0) * ender2) +end + +parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more +parsers.Block = V("Block") + +parsers.TildeFencedCode + = parsers.fencehead(parsers.tilde) + * Cs(parsers.fencedline(parsers.tilde)^0) + * parsers.fencetail(parsers.tilde) + +parsers.BacktickFencedCode + = parsers.fencehead(parsers.backtick) + * Cs(parsers.fencedline(parsers.backtick)^0) + * parsers.fencetail(parsers.backtick) + +parsers.lineof = function(c) + return (parsers.leader * (P(c) * parsers.optionalspace)^3 + * (parsers.newline * parsers.blankline^1 + + parsers.newline^-1 * parsers.eof)) +end +parsers.defstartchar = S("~:") +parsers.defstart = ( parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-3) + + parsers.space * parsers.defstartchar * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * parsers.space * parsers.defstartchar + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * parsers.space + * parsers.defstartchar * #parsers.spacing + ) + +parsers.dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0) +-- parse Atx heading start and return level +parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6) + * -parsers.hash / length + +-- parse setext header ending and return level +parsers.HeadingLevel = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) + +local function strip_atx_end(s) + return s:gsub("[#%s]*\n$","") end M.reader = {} function M.reader.new(writer, options) @@ -518,14 +1127,7 @@ function M.reader.new(writer, options) end end end - local syntax - local blocks_toplevel - local blocks - local inlines - local inlines_no_link - local inlines_no_inline_note - local inlines_nbsp - + local larsers = {} local function create_parser(name, grammar) return function(str) local res = lpeg.match(grammar(), str) @@ -537,180 +1139,94 @@ function M.reader.new(writer, options) 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_no_inline_note = create_parser( - "parse_inlines_no_inline_note", - function() return inlines_no_inline_note end) - local parse_inlines_nbsp = create_parser("parse_inlines_nbsp", - function() return inlines_nbsp end) - local bulletchar = C(plus + asterisk + dash) - - local bullet = ( Cg(bulletchar, "bulletchar") * #spacing * (tab + space^-3) - + space * Cg(bulletchar, "bulletchar") * #spacing * (tab + space^-2) - + space * space * Cg(bulletchar, "bulletchar") * #spacing * (tab + space^-1) - + space * space * space * Cg(bulletchar, "bulletchar") * #spacing - ) - + local parse_blocks + = create_parser("parse_blocks", + function() + return larsers.blocks + end) + + local parse_blocks_toplevel + = create_parser("parse_blocks_toplevel", + function() + return larsers.blocks_toplevel + end) + + local parse_inlines + = create_parser("parse_inlines", + function() + return larsers.inlines + end) + + local parse_inlines_no_link + = create_parser("parse_inlines_no_link", + function() + return larsers.inlines_no_link + end) + + local parse_inlines_no_inline_note + = create_parser("parse_inlines_no_inline_note", + function() + return larsers.inlines_no_inline_note + end) + + local parse_inlines_nbsp + = create_parser("parse_inlines_nbsp", + function() + return larsers.inlines_nbsp + end) if options.hashEnumerators then - dig = digit + hash + larsers.dig = parsers.digit + parsers.hash else - dig = digit - end - - local enumerator = C(dig^3 * period) * #spacing - + C(dig^2 * period) * #spacing * (tab + space^1) - + C(dig * period) * #spacing * (tab + space^-2) - + space * C(dig^2 * period) * #spacing - + space * C(dig * period) * #spacing * (tab + space^-1) - + space * space * C(dig^1 * period) * #spacing - local openticks = Cg(backtick^1, "ticks") - - local function captures_equal_length(s,i,a,b) - return #a == #b and i - end - - local closeticks = space^-1 * - Cmt(C(backtick^1) * Cb("ticks"), captures_equal_length) - - local intickschar = (any - S(" \n\r`")) - + (newline * -blankline) - + (space - closeticks) - + (backtick^1 - closeticks) - - local inticks = openticks * space^-1 * C(intickschar^0) * closeticks - local function captures_geq_length(s,i,a,b) - return #a >= #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 + larsers.dig = parsers.digit + end + + larsers.enumerator = C(larsers.dig^3 * parsers.period) * #parsers.spacing + + C(larsers.dig^2 * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^1) + + C(larsers.dig * parsers.period) * #parsers.spacing + * (parsers.tab + parsers.space^-2) + + parsers.space * C(larsers.dig^2 * parsers.period) + * #parsers.spacing + + parsers.space * C(larsers.dig * parsers.period) + * #parsers.spacing + * (parsers.tab + parsers.space^-1) + + parsers.space * parsers.space * C(larsers.dig^1 + * parsers.period) * #parsers.spacing + -- strip off leading > and indents, and run through blocks + larsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/"" + * parsers.linechar^0 * parsers.newline)^1 + * (-(parsers.leader * parsers.more + + parsers.blankline) * parsers.linechar^1 + * parsers.newline)^0 - local function fencetail(char) - return nonindentspace - * Cmt(C(char^3) * Cb("fencelength"), - captures_geq_length) - * optionalspace * (newline + eof) - + eof + if not options.breakableBlockquotes then + larsers.blockquote_body = larsers.blockquote_body + * (parsers.blankline^0 / "") end + larsers.citations = function(text_cites, raw_cites) + local function normalize(str) + if str == "" then + str = nil + else + str = (options.citationNbsps and parse_inlines_nbsp or + parse_inlines)(str) + end + return str + end - local function fencedline(char) - return C(line - fencetail(char)) - / function(s) - return s:gsub("^" .. string.rep(" ?", - fenceindent), "") - 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 leader = space^-3 - - -- in balanced brackets, parentheses, quotes: - local bracketed = P{ lbracket - * ((anyescaped - (lbracket + rbracket - + blankline^2)) + V(1))^0 - * rbracket } - - local inparens = P{ lparent - * ((anyescaped - (lparent + rparent - + blankline^2)) + V(1))^0 - * rparent } - - local squoted = P{ squote * alphanumeric - * ((anyescaped - (squote + blankline^2)) - + V(1))^0 - * squote } - - local dquoted = P{ dquote * alphanumeric - * ((anyescaped - (dquote + blankline^2)) - + V(1))^0 - * dquote } - - -- bracketed 'tag' for markdown links, allowing nested brackets: - local tag = lbracket - * Cs((alphanumeric^1 - + bracketed - + inticks - + (anyescaped - (rbracket + blankline^2)))^0) - * rbracket - - -- url for markdown links, allowing balanced parentheses: - local url = less * Cs((anyescaped-more)^0) * more - + Cs((inparens + (anyescaped-spacing-rparent))^1) - - -- quoted text possibly with nested quotes: - local title_s = squote * Cs(((anyescaped-squote) + squoted)^0) * - squote - - local title_d = dquote * Cs(((anyescaped-dquote) + dquoted)^0) * - dquote - - local title_p = lparent - * Cs((inparens + (anyescaped-rparent))^0) - * rparent - - local title = title_d + title_s + title_p - - local optionaltitle = spnl * title * spacechar^0 - + Cc("") - local citation_name = Cs(dash^-1) * at - * Cs(alphanumeric - * (alphanumeric + internal_punctuation - - comma - semicolon)^0) - - local citation_body_prenote - = Cs((alphanumeric^1 - + bracketed - + inticks - + (anyescaped - - (rbracket + 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 - * (comma * spnl)^-1 - * citation_body_postnote - - local citation_body = citation_body_chunk - * (semicolon * spnl * citation_body_chunk)^0 - - local citation_headless_body_postnote - = Cs((alphanumeric^1 - + bracketed - + inticks - + (anyescaped - - (rbracket + at + semicolon + blankline^2)) - - (spnl * rbracket))^0) - - local citation_headless_body - = citation_headless_body_postnote - * (sp * semicolon * spnl * citation_body_chunk)^0 local rawnotes = {} - local function strip_first_char(s) - return s:sub(2) - end - -- like indirect_link local function lookup_note(ref) return function() @@ -728,16 +1244,15 @@ function M.reader.new(writer, options) return "" end - local RawNoteRef = #(lbracket * circumflex) * tag / strip_first_char + larsers.NoteRef = parsers.RawNoteRef / lookup_note - local NoteRef = RawNoteRef / lookup_note + larsers.NoteBlock = parsers.leader * parsers.RawNoteRef * parsers.colon + * parsers.spnl * parsers.indented_blocks(parsers.chunk) + / register_note - local NoteBlock = leader * RawNoteRef * colon * spnl - * indented_blocks(chunk) / register_note - - local InlineNote = circumflex -- no notes inside notes - * (tag / parse_inlines_no_inline_note) - / writer.note + larsers.InlineNote = parsers.circumflex + * (parsers.tag / parse_inlines_no_inline_note) -- no notes inside notes + / writer.note -- List of references defined in the document local references @@ -747,10 +1262,6 @@ function M.reader.new(writer, options) return "" end - -- parse a reference definition: [foo]: /bar "title" - local define_reference_parser = - leader * tag * colon * spacechar^0 * url * optionaltitle * blankline^1 - -- lookup link reference and return either -- the link or nil and fallback text. local function lookup_reference(label,sps,tag) @@ -800,232 +1311,239 @@ function M.reader.new(writer, options) end end end - local bqstart = more - local headerstart = hash - + (line * (equal^1 + dash^1) * optionalspace * newline) - local fencestart = fencehead(backtick) + fencehead(tilde) + larsers.Str = parsers.normalchar^1 / writer.string + + larsers.Symbol = (parsers.specialchar - parsers.tightblocksep) + / writer.string + + larsers.Ellipsis = P("...") / writer.ellipsis + + larsers.Smart = larsers.Ellipsis + + larsers.Code = parsers.inticks / writer.code if options.blankBeforeBlockquote then - bqstart = fail + larsers.bqstart = parsers.fail + else + larsers.bqstart = parsers.more end if options.blankBeforeHeading then - headerstart = fail + larsers.headerstart = parsers.fail + else + larsers.headerstart = parsers.hash + + (parsers.line * (parsers.equal^1 + parsers.dash^1) + * parsers.optionalspace * parsers.newline) end if not options.fencedCode or options.blankBeforeCodeFence then - 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 NonbreakingEndline - = newline * -( -- newline, but not before... - blankline -- paragraph break - + tightblocksep -- nested list - + eof -- end of document - + bqstart - + headerstart - + fencestart - ) * spacechar^0 / writer.nbsp - - 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 - - local Emph = ( between(Inline, asterisk, asterisk) - + between(Inline, underscore, underscore) - ) / writer.emphasis - local urlchar = anyescaped - newline - more - - local AutoLinkUrl = less - * C(alphanumeric^1 * P("://") * urlchar^1) - * more - / function(url) - return writer.link(writer.string(url), url) - end - - local AutoLinkEmail = less - * C((alphanumeric + S("-._+"))^1 * P("@") * urlchar^1) - * more - / function(email) - return writer.link(writer.string(email), - "mailto:"..email) - end - - local DirectLink = (tag / parse_inlines_no_link) -- no links inside links - * spnl - * lparent - * (url + Cc("")) -- link can be empty [foo]() - * optionaltitle - * rparent - / writer.link - - local IndirectLink = tag * (C(spnl) * tag)^-1 / indirect_link + larsers.fencestart = parsers.fail + else + larsers.fencestart = parsers.fencehead(parsers.backtick) + + parsers.fencehead(parsers.tilde) + end + + larsers.Endline = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.space + + larsers.Space = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.space + + larsers.NonbreakingEndline + = parsers.newline * -( -- newline, but not before... + parsers.blankline -- paragraph break + + parsers.tightblocksep -- nested list + + parsers.eof -- end of document + + larsers.bqstart + + larsers.headerstart + + larsers.fencestart + ) * parsers.spacechar^0 / writer.nbsp + + larsers.NonbreakingSpace + = parsers.spacechar^2 * larsers.Endline / writer.linebreak + + parsers.spacechar^1 * larsers.Endline^-1 * parsers.eof / "" + + parsers.spacechar^1 * larsers.Endline^-1 + * parsers.optionalspace / writer.nbsp + + larsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, + parsers.doubleasterisks) + + parsers.between(parsers.Inline, parsers.doubleunderscores, + parsers.doubleunderscores) + ) / writer.strong + + larsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, + parsers.asterisk) + + parsers.between(parsers.Inline, parsers.underscore, + parsers.underscore) + ) / writer.emphasis + + larsers.AutoLinkUrl = parsers.less + * C(parsers.alphanumeric^1 * P("://") * parsers.urlchar^1) + * parsers.more + / function(url) + return writer.link(writer.string(url), url) + end + + larsers.AutoLinkEmail = parsers.less + * C((parsers.alphanumeric + S("-._+"))^1 + * P("@") * parsers.urlchar^1) + * parsers.more + / function(email) + return writer.link(writer.string(email), + "mailto:"..email) + end + + larsers.DirectLink = (parsers.tag / parse_inlines_no_link) -- no links inside links + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.link + + larsers.IndirectLink = parsers.tag * (C(parsers.spnl) * parsers.tag)^-1 + / indirect_link -- parse a link or image (direct or indirect) - local Link = DirectLink + IndirectLink - local DirectImage = exclamation - * (tag / parse_inlines) - * spnl - * lparent - * (url + Cc("")) -- link can be empty [foo]() - * optionaltitle - * rparent - / writer.image - - local IndirectImage = exclamation * tag * (C(spnl) * tag)^-1 / - indirect_image - - local Image = DirectImage + IndirectImage - -- avoid parsing long strings of * or _ as emph/strong - local UlOrStarLine = asterisk^4 + underscore^4 / writer.string + larsers.Link = larsers.DirectLink + larsers.IndirectLink + + larsers.DirectImage = parsers.exclamation + * (parsers.tag / parse_inlines) + * parsers.spnl + * parsers.lparent + * (parsers.url + Cc("")) -- link can be empty [foo]() + * parsers.optionaltitle + * parsers.rparent + / writer.image + + larsers.IndirectImage = parsers.exclamation * parsers.tag + * (C(parsers.spnl) * parsers.tag)^-1 / indirect_image + + larsers.Image = larsers.DirectImage + larsers.IndirectImage + + larsers.TextCitations = Ct(Cc("") + * parsers.citation_name + * ((parsers.spnl + * parsers.lbracket + * parsers.citation_headless_body + * parsers.rbracket) + Cc(""))) + / function(raw_cites) + return larsers.citations(true, raw_cites) + end + + larsers.ParenthesizedCitations + = Ct(parsers.lbracket + * parsers.citation_body + * parsers.rbracket) + / function(raw_cites) + return larsers.citations(false, raw_cites) + end + + larsers.Citations = larsers.TextCitations + larsers.ParenthesizedCitations - 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 + -- avoid parsing long strings of * or _ as emph/strong + larsers.UlOrStarLine = parsers.asterisk^4 + parsers.underscore^4 + / writer.string - 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 + larsers.EscapedChar = S("\\") * C(parsers.escapable) / writer.string - 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 + larsers.InlineHtml = C(parsers.inlinehtml) / writer.inline_html - local TildeFencedCode - = fencehead(tilde) - * Cs(fencedline(tilde)^0) - * fencetail(tilde) + larsers.HtmlEntity = parsers.hexentity / entities.hex_entity / writer.string + + parsers.decentity / entities.dec_entity / writer.string + + parsers.tagentity / entities.char_entity / writer.string + larsers.DisplayHtml = C(parsers.displayhtml) + / expandtabs / writer.display_html - local BacktickFencedCode - = fencehead(backtick) - * Cs(fencedline(backtick)^0) - * fencetail(backtick) + larsers.Verbatim = Cs( (parsers.blanklines + * ((parsers.indentedline - parsers.blankline))^1)^1 + ) / expandtabs / writer.verbatim - local FencedCode = (TildeFencedCode + BacktickFencedCode) + larsers.FencedCode = (parsers.TildeFencedCode + + parsers.BacktickFencedCode) / function(infostring, code) - return writer.fencedCode( - writer.string(infostring), - expandtabs(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_toplevel / writer.blockquote - - local function lineof(c) - return (leader * (P(c) * optionalspace)^3 * (newline * blankline^1 - + newline^-1 * eof)) - end - local HorizontalRule = ( lineof(asterisk) - + lineof(dash) - + lineof(underscore) - ) / writer.hrule - local starter = bullet + enumerator + + larsers.Blockquote = Cs(larsers.blockquote_body^1) + / parse_blocks_toplevel / writer.blockquote + + larsers.HorizontalRule = ( parsers.lineof(parsers.asterisk) + + parsers.lineof(parsers.dash) + + parsers.lineof(parsers.underscore) + ) / writer.hrule + + larsers.Reference = parsers.define_reference_parser / register_link + + larsers.Paragraph = parsers.nonindentspace * Ct(parsers.Inline^1) + * parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + ) + / writer.paragraph + + larsers.ToplevelParagraph + = parsers.nonindentspace * Ct(parsers.Inline^1) + * ( parsers.newline + * ( parsers.blankline^1 + + #parsers.hash + + #(parsers.leader * parsers.more * parsers.space^-1) + + parsers.eof + ) + + parsers.eof ) + / writer.paragraph + + larsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) + / writer.plain + larsers.starter = parsers.bullet + larsers.enumerator -- we use \001 as a separator between a tight list item and a -- nested list under it. - local NestedList = Cs((optionallyindentedline - starter)^1) - / function(a) return "\001"..a end + larsers.NestedList = Cs((parsers.optionallyindentedline + - larsers.starter)^1) + / function(a) return "\001"..a end - local ListBlockLine = optionallyindentedline - - blankline - (indent^-1 * starter) + larsers.ListBlockLine = parsers.optionallyindentedline + - parsers.blankline - (parsers.indent^-1 + * larsers.starter) - local ListBlock = line * ListBlockLine^0 + larsers.ListBlock = parsers.line * larsers.ListBlockLine^0 - local ListContinuationBlock = blanklines * (indent / "") * ListBlock + larsers.ListContinuationBlock = parsers.blanklines * (parsers.indent / "") + * larsers.ListBlock - local function TightListItem(starter) - return -HorizontalRule - * (Cs(starter / "" * ListBlock * NestedList^-1) / - parse_blocks) - * -(blanklines * indent) + larsers.TightListItem = function(starter) + return -larsers.HorizontalRule + * (Cs(starter / "" * larsers.ListBlock * larsers.NestedList^-1) + / parse_blocks) + * -(parsers.blanklines * parsers.indent) end - local function LooseListItem(starter) - return -HorizontalRule - * Cs( starter / "" * ListBlock * Cc("\n") - * (NestedList + ListContinuationBlock^0) - * (blanklines / "\n\n") + larsers.LooseListItem = function(starter) + return -larsers.HorizontalRule + * Cs( starter / "" * larsers.ListBlock * Cc("\n") + * (larsers.NestedList + larsers.ListContinuationBlock^0) + * (parsers.blanklines / "\n\n") ) / parse_blocks end - local BulletList = ( Ct(TightListItem(bullet)^1) - * Cc(true) * skipblanklines * -bullet - + Ct(LooseListItem(bullet)^1) - * Cc(false) * skipblanklines ) / - writer.bulletlist + larsers.BulletList = ( Ct(larsers.TightListItem(parsers.bullet)^1) * Cc(true) + * parsers.skipblanklines * -parsers.bullet + + Ct(larsers.LooseListItem(parsers.bullet)^1) * Cc(false) + * parsers.skipblanklines ) + / writer.bulletlist - local function orderedlist(items,tight,startNumber) + local function ordered_list(items,tight,startNumber) if options.startNumber then startNumber = tonumber(startNumber) or 1 -- fallback for '#' else @@ -1034,107 +1552,65 @@ function M.reader.new(writer, options) return writer.orderedlist(items,tight,startNumber) end - local OrderedList = Cg(enumerator, "listtype") * - ( Ct(TightListItem(Cb("listtype")) * - TightListItem(enumerator)^0) - * Cc(true) * skipblanklines * -enumerator - + Ct(LooseListItem(Cb("listtype")) * - LooseListItem(enumerator)^0) - * Cc(false) * skipblanklines - ) * Cb("listtype") / orderedlist - - local defstartchar = S("~:") - local defstart = ( defstartchar * #spacing * (tab + space^-3) - + space * defstartchar * #spacing * (tab + space^-2) - + space * space * defstartchar * #spacing * - (tab + space^-1) - + space * space * space * defstartchar * #spacing - ) - - local dlchunk = Cs(line * (indentedline - blankline)^0) + larsers.OrderedList = Cg(larsers.enumerator, "listtype") * + ( Ct(larsers.TightListItem(Cb("listtype")) + * larsers.TightListItem(larsers.enumerator)^0) + * Cc(true) * parsers.skipblanklines * -larsers.enumerator + + Ct(larsers.LooseListItem(Cb("listtype")) + * larsers.LooseListItem(larsers.enumerator)^0) + * Cc(false) * parsers.skipblanklines + ) * Cb("listtype") / ordered_list local function definition_list_item(term, defs, tight) return { term = parse_inlines(term), definitions = defs } end - local DefinitionListItemLoose = C(line) * skipblanklines - * Ct((defstart * - indented_blocks(dlchunk) / - parse_blocks_toplevel)^1) - * Cc(false) - / definition_list_item - - local DefinitionListItemTight = C(line) - * Ct((defstart * dlchunk / - parse_blocks)^1) - * Cc(true) - / definition_list_item - - local DefinitionList = ( Ct(DefinitionListItemLoose^1) * Cc(false) - + Ct(DefinitionListItemTight^1) - * (skipblanklines * - -DefinitionListItemLoose * Cc(true)) - ) / writer.definitionlist - 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 - - -- parse setext header ending and return level - local HeadingLevel = equal^1 * Cc(1) + dash^1 * Cc(2) - - local function strip_atx_end(s) - return s:gsub("[#%s]*\n$","") - end - + larsers.DefinitionListItemLoose = C(parsers.line) * parsers.skipblanklines + * Ct((parsers.defstart + * parsers.indented_blocks(parsers.dlchunk) + / parse_blocks_toplevel)^1) + * Cc(false) / definition_list_item + + larsers.DefinitionListItemTight = C(parsers.line) + * Ct((parsers.defstart * parsers.dlchunk + / parse_blocks)^1) + * Cc(true) / definition_list_item + + larsers.DefinitionList = ( Ct(larsers.DefinitionListItemLoose^1) * Cc(false) + + Ct(larsers.DefinitionListItemTight^1) + * (parsers.skipblanklines + * -larsers.DefinitionListItemLoose * Cc(true)) + ) / writer.definitionlist + larsers.Blank = parsers.blankline / "" + + larsers.NoteBlock + + larsers.Reference + + (parsers.tightblocksep / "\n") -- parse atx header - local AtxHeading = Cg(HeadingStart,"level") - * optionalspace - * (C(line) / strip_atx_end / parse_inlines) + larsers.AtxHeading = Cg(parsers.HeadingStart,"level") + * parsers.optionalspace + * (C(parsers.line) / strip_atx_end / parse_inlines) * Cb("level") / writer.heading -- parse setext header - local SetextHeading = #(line * S("=-")) - * Ct(line / parse_inlines) - * HeadingLevel - * optionalspace * newline - / writer.heading - - local Heading = AtxHeading + SetextHeading - syntax = + larsers.SetextHeading = #(parsers.line * S("=-")) + * Ct(parsers.line / parse_inlines) + * parsers.HeadingLevel + * parsers.optionalspace * parsers.newline + / writer.heading + + larsers.Heading = larsers.AtxHeading + larsers.SetextHeading + local syntax = { "Blocks", - Blocks = Blank^0 * - Block^-1 * - (Blank^0 / function() - return writer.interblocksep - end * Block)^0 * - Blank^0 * - eof, + Blocks = larsers.Blank^0 * parsers.Block^-1 + * (larsers.Blank^0 / function() + return writer.interblocksep + end + * parsers.Block)^0 + * larsers.Blank^0 * parsers.eof, - Blank = Blank, + Blank = larsers.Blank, Block = V("Blockquote") + V("Verbatim") @@ -1144,20 +1620,21 @@ function M.reader.new(writer, options) + V("OrderedList") + V("Heading") + V("DefinitionList") + + V("DisplayHtml") + V("Paragraph") + V("Plain"), - Blockquote = Blockquote, - Verbatim = Verbatim, - FencedCode = FencedCode, - HorizontalRule = HorizontalRule, - BulletList = BulletList, - OrderedList = OrderedList, - Heading = Heading, - DefinitionList = DefinitionList, - DisplayHtml = DisplayHtml, - Paragraph = Paragraph, - Plain = Plain, + Blockquote = larsers.Blockquote, + Verbatim = larsers.Verbatim, + FencedCode = larsers.FencedCode, + HorizontalRule = larsers.HorizontalRule, + BulletList = larsers.BulletList, + OrderedList = larsers.OrderedList, + Heading = larsers.Heading, + DefinitionList = larsers.DefinitionList, + DisplayHtml = larsers.DisplayHtml, + Paragraph = larsers.Paragraph, + Plain = larsers.Plain, Inline = V("Str") + V("Space") @@ -1173,78 +1650,86 @@ function M.reader.new(writer, options) + V("Code") + V("AutoLinkUrl") + V("AutoLinkEmail") + + V("InlineHtml") + + V("HtmlEntity") + V("EscapedChar") + V("Smart") + V("Symbol"), - Str = Str, - Space = Space, - Endline = Endline, - UlOrStarLine = UlOrStarLine, - Strong = Strong, - Emph = Emph, - InlineNote = InlineNote, - NoteRef = NoteRef, - Citations = Citations, - Link = Link, - Image = Image, - Code = Code, - AutoLinkUrl = AutoLinkUrl, - AutoLinkEmail = AutoLinkEmail, - InlineHtml = InlineHtml, - HtmlEntity = HtmlEntity, - EscapedChar = EscapedChar, - Smart = Smart, - Symbol = Symbol, + Str = larsers.Str, + Space = larsers.Space, + Endline = larsers.Endline, + UlOrStarLine = larsers.UlOrStarLine, + Strong = larsers.Strong, + Emph = larsers.Emph, + InlineNote = larsers.InlineNote, + NoteRef = larsers.NoteRef, + Citations = larsers.Citations, + Link = larsers.Link, + Image = larsers.Image, + Code = larsers.Code, + AutoLinkUrl = larsers.AutoLinkUrl, + AutoLinkEmail = larsers.AutoLinkEmail, + InlineHtml = larsers.InlineHtml, + HtmlEntity = larsers.HtmlEntity, + EscapedChar = larsers.EscapedChar, + Smart = larsers.Smart, + Symbol = larsers.Symbol, } if not options.definitionLists then - syntax.DefinitionList = fail + syntax.DefinitionList = parsers.fail end if not options.fencedCode then - syntax.FencedCode = fail + syntax.FencedCode = parsers.fail end if not options.citations then - syntax.Citations = fail + syntax.Citations = parsers.fail end if not options.footnotes then - syntax.NoteRef = fail + syntax.NoteRef = parsers.fail end if not options.inlineFootnotes then - syntax.InlineNote = fail + syntax.InlineNote = parsers.fail end if not options.smartEllipses then - syntax.Smart = fail + syntax.Smart = parsers.fail + end + + if not options.html then + syntax.DisplayHtml = parsers.fail + syntax.InlineHtml = parsers.fail + syntax.HtmlEntity = parsers.fail end local blocks_toplevel_t = util.table_copy(syntax) - blocks_toplevel_t.Paragraph = ToplevelParagraph - blocks_toplevel = Ct(blocks_toplevel_t) + blocks_toplevel_t.Paragraph = larsers.ToplevelParagraph + larsers.blocks_toplevel = Ct(blocks_toplevel_t) - blocks = Ct(syntax) + larsers.blocks = Ct(syntax) local inlines_t = util.table_copy(syntax) inlines_t[1] = "Inlines" - inlines_t.Inlines = Inline^0 * (spacing^0 * eof / "") - inlines = Ct(inlines_t) + inlines_t.Inlines = parsers.Inline^0 * (parsers.spacing^0 * parsers.eof / "") + larsers.inlines = Ct(inlines_t) local inlines_no_link_t = util.table_copy(inlines_t) - inlines_no_link_t.Link = fail - inlines_no_link = Ct(inlines_no_link_t) + inlines_no_link_t.Link = parsers.fail + larsers.inlines_no_link = Ct(inlines_no_link_t) local inlines_no_inline_note_t = util.table_copy(inlines_t) - inlines_no_inline_note_t.InlineNote = fail - inlines_no_inline_note = Ct(inlines_no_inline_note_t) + inlines_no_inline_note_t.InlineNote = parsers.fail + larsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t) local inlines_nbsp_t = util.table_copy(inlines_t) - inlines_nbsp_t.Endline = NonbreakingEndline - inlines_nbsp_t.Space = NonbreakingSpace - inlines_nbsp = Ct(inlines_nbsp_t) + inlines_nbsp_t.Endline = larsers.NonbreakingEndline + inlines_nbsp_t.Space = larsers.NonbreakingSpace + larsers.inlines_nbsp = Ct(inlines_nbsp_t) function self.convert(input) references = {} local opt_string = {} -- cgit v1.2.3