diff options
Diffstat (limited to 'Master/texmf-dist/tex')
5 files changed, 522 insertions, 211 deletions
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 79ba3273a63..9c9e035629d 100644 --- a/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex +++ b/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex @@ -261,13 +261,36 @@ \def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% \def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% \def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% +\def\markdownRendererLineBlockBeginPrototype{% + \begingroup + \def\markdownRendererLineBreak{ + }% + \startlines +}% +\def\markdownRendererLineBlockEndPrototype{% + \stoplines + \endgroup +}% \def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% -\def\markdownRendererInputFencedCodePrototype#1#2{% - \ifx\relax#2\relax - \typefile{#1}% - \else - \typefile[#2][]{#1}% - \fi}% +\ExplSyntaxOn +\cs_gset:Npn + \markdownRendererInputFencedCodePrototype#1#2 + { + \tl_if_empty:nTF + { #2 } + { \markdownRendererInputVerbatim{#1} } + { + \regex_extract_once:nnN + { \w* } + { #2 } + \l_tmpa_seq + \seq_pop_left:NN + \l_tmpa_seq + \l_tmpa_tl + \typefile[\l_tmpa_tl][]{#1} + } + } +\ExplSyntaxOff \def\markdownRendererHeadingOnePrototype#1{\chapter{#1}}% \def\markdownRendererHeadingTwoPrototype#1{\section{#1}}% \def\markdownRendererHeadingThreePrototype#1{\subsection{#1}}% @@ -352,12 +375,39 @@ \cs_gset:Npn \markdownRendererInputRawInlinePrototype#1#2 { - \str_case:nn + \str_case:nnF { #2 } { - { tex } { \markdownEscape{#1} } - { context } { \markdownEscape{#1} } - { md } { \markdownInput{#1} } + { latex } + { + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { #1 } + { context } + } + } + { + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { #1 } + { #2 } + } + } +\cs_gset:Npn + \markdownRendererInputRawBlockPrototype#1#2 + { + \str_case:nnF + { #2 } + { + { context } + { + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { #1 } + { tex } + } + } + { + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { #1 } + { #2 } } } \cs_gset_eq:NN diff --git a/Master/texmf-dist/tex/generic/markdown/markdown.tex b/Master/texmf-dist/tex/generic/markdown/markdown.tex index bc769262a08..1158fcd4e17 100644 --- a/Master/texmf-dist/tex/generic/markdown/markdown.tex +++ b/Master/texmf-dist/tex/generic/markdown/markdown.tex @@ -404,6 +404,10 @@ { boolean } { false } \__markdown_add_lua_option:nnn + { fencedCodeAttributes } + { boolean } + { false } +\__markdown_add_lua_option:nnn { fencedDivs } { boolean } { false } @@ -448,6 +452,10 @@ { boolean } { false } \__markdown_add_lua_option:nnn + { lineBlocks } + { boolean } + { false } +\__markdown_add_lua_option:nnn { footnotes } { boolean } { false } @@ -524,8 +532,8 @@ { boolean } { true } \ExplSyntaxOff -\def\markdownLastModified{2022-12-23}% -\def\markdownVersion{2.19.0-0-g80fcf20}% +\def\markdownLastModified{2023-02-01}% +\def\markdownVersion{2.20.0-0-gf64ade1}% \let\markdownBegin\relax \let\markdownEnd\relax \let\markdownInput\relax @@ -1008,6 +1016,28 @@ { strongEmphasis } { 1 } \ExplSyntaxOff +\def\markdownRendererFencedCodeAttributeContextBegin{% + \markdownRendererFencedCodeAttributeContextBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { fencedCodeAttributeContextBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { fencedCodeAttributeContextBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererFencedCodeAttributeContextEnd{% + \markdownRendererFencedCodeAttributeContextEndPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { fencedCodeAttributeContextEnd } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { fencedCodeAttributeContextEnd } + { 0 } +\ExplSyntaxOff \def\markdownRendererFencedDivAttributeContextBegin{% \markdownRendererFencedDivAttributeContextBeginPrototype}% \ExplSyntaxOn @@ -1195,6 +1225,28 @@ { interblockSeparator } { 0 } \ExplSyntaxOff +\def\markdownRendererLineBlockBegin{% + \markdownRendererLineBlockBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { lineBlockBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { lineBlockBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererLineBlockEnd{% + \markdownRendererLineBlockEndPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { lineBlockEnd } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { lineBlockEnd } + { 0 } +\ExplSyntaxOff \def\markdownRendererLineBreak{% \markdownRendererLineBreakPrototype}% \ExplSyntaxOn @@ -1482,6 +1534,17 @@ { inputRawBlock } { 2 } \ExplSyntaxOff +\def\markdownRendererReplacementCharacter{% + \markdownRendererReplacementCharacterPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { replacementCharacter } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { replacementCharacter } + { 0 } +\ExplSyntaxOff \def\markdownRendererLeftBrace{% \markdownRendererLeftBracePrototype}% \ExplSyntaxOn @@ -2009,12 +2072,14 @@ \def\markdownRendererDlEndTightPrototype{}% \def\markdownRendererEmphasisPrototype#1{{\it#1}}% \def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% -\def\markdownRendererBlockQuoteBeginPrototype{\par\begingroup\it}% +\def\markdownRendererBlockQuoteBeginPrototype{\begingroup\it}% \def\markdownRendererBlockQuoteEndPrototype{\endgroup\par}% +\def\markdownRendererLineBlockBeginPrototype{\begingroup\parindent=0pt}% +\def\markdownRendererLineBlockEndPrototype{\endgroup}% \def\markdownRendererInputVerbatimPrototype#1{% \par{\tt\input#1\relax{}}\par}% \def\markdownRendererInputFencedCodePrototype#1#2{% - \markdownRendererInputVerbatimPrototype{#1}}% + \markdownRendererInputVerbatim{#1}}% \def\markdownRendererHeadingOnePrototype#1{#1}% \def\markdownRendererHeadingTwoPrototype#1{#1}% \def\markdownRendererHeadingThreePrototype#1{#1}% @@ -2033,18 +2098,79 @@ \def\markdownRendererSubscriptPrototype#1{#1}% \ExplSyntaxOn \cs_gset:Npn - \markdownRendererInputRawInlinePrototype#1#2 + \markdownRendererHeaderAttributeContextBeginPrototype + { + \group_begin: + \color_group_begin: + } +\cs_gset:Npn + \markdownRendererHeaderAttributeContextEndPrototype + { + \color_group_end: + \group_end: + } +\cs_gset_eq:NN + \markdownRendererBracketedSpanAttributeContextBeginPrototype + \markdownRendererHeaderAttributeContextBeginPrototype +\cs_gset_eq:NN + \markdownRendererBracketedSpanAttributeContextEndPrototype + \markdownRendererHeaderAttributeContextEndPrototype +\cs_gset_eq:NN + \markdownRendererFencedDivAttributeContextBeginPrototype + \markdownRendererHeaderAttributeContextBeginPrototype +\cs_gset_eq:NN + \markdownRendererFencedDivAttributeContextEndPrototype + \markdownRendererHeaderAttributeContextEndPrototype +\cs_gset_eq:NN + \markdownRendererFencedCodeAttributeContextBeginPrototype + \markdownRendererHeaderAttributeContextBeginPrototype +\cs_gset_eq:NN + \markdownRendererFencedCodeAttributeContextEndPrototype + \markdownRendererHeaderAttributeContextEndPrototype +\cs_gset:Npn + \markdownRendererReplacementCharacterPrototype + { + % TODO: Replace with `\codepoint_generate:nn` in TeX Live 2023 + \sys_if_engine_pdftex:TF + { ^^ef^^bf^^bd } + { ^^^^fffd } + } +\ExplSyntaxOff +\ExplSyntaxOn +\cs_new:Nn + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn { \str_case:nn { #2 } { - { tex } { \markdownEscape{#1} } { md } { \markdownInput{#1} } + { tex } { \markdownEscape{#1} \unskip } } } -\cs_gset_eq:NN - \markdownRendererInputRawBlockPrototype - \markdownRendererInputRawInlinePrototype +\cs_new:Nn + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { + \str_case:nn + { #2 } + { + { md } { \markdownInput{#1} } + { tex } { \markdownEscape{#1} } + } + } +\cs_gset:Npn + \markdownRendererInputRawInlinePrototype#1#2 + { + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { #1 } + { #2 } + } +\cs_gset:Npn + \markdownRendererInputRawBlockPrototype#1#2 + { + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { #1 } + { #2 } + } \ExplSyntaxOff \ExplSyntaxOn \seq_new:N \g__markdown_jekyll_data_datatypes_seq @@ -2490,7 +2616,7 @@ [[Could not open file "&1" for reading]]) local input = assert(file:read("*a")) assert(file:close()) - print(convert(input:gsub("\r\n?", "\n") .. "\n"))}% + print(convert(input))}% |global|advance|markdownOptionFrozenCacheCounter by 1|relax }% |endgroup diff --git a/Master/texmf-dist/tex/latex/markdown/markdown.sty b/Master/texmf-dist/tex/latex/markdown/markdown.sty index 47bdd40a0df..0dede25d9cc 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdown.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdown.sty @@ -521,9 +521,10 @@ { NnV } \ExplSyntaxOff \markdownIfOption{plain}{\iffalse}{\iftrue} -\markdownIfOption{tightLists}{ - \@ifclassloaded{beamer}{}{\RequirePackage{paralist}}% -}{} +\@ifclassloaded{beamer}{}{% + \markdownIfOption{tightLists}{\RequirePackage{paralist}}{}% + \markdownIfOption{fancyLists}{\RequirePackage{paralist}}{}% +} \ExplSyntaxOn \@ifpackageloaded{paralist}{ \tl_new:N @@ -735,7 +736,7 @@ emphasis = {\emph{#1}}, tickedBox = {$\boxtimes$}, halfTickedBox = {$\boxdot$}, - headerAttributeContextBegin = { + headerAttributeContextBegin = {% \markdownSetup{ rendererPrototypes = { attributeIdentifier = {% @@ -757,29 +758,49 @@ }, }% }, + headerAttributeContextEnd = {}, superscript = {\textsuperscript{#1}}, subscript = {\textsubscript{#1}}, blockQuoteBegin = {\begin{quotation}}, blockQuoteEnd = {\end{quotation}}, inputVerbatim = {\VerbatimInput{#1}}, - inputFencedCode = {% - \ifx\relax#2\relax - \VerbatimInput{#1}% - \else - \@ifundefined{minted@code}{% - \@ifundefined{lst@version}{% - \markdownRendererInputFencedCode{#1}{}% - }{% - \lstinputlisting[language=#2]{#1}% - }% - }{% - \catcode`\#=6\relax - \inputminted{#2}{#1}% - \catcode`\#=12\relax - }% - \fi}, thematicBreak = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, note = {\footnote{#1}}}} +\RequirePackage{ltxcmds} +\ExplSyntaxOn +\cs_gset:Npn + \markdownRendererInputFencedCodePrototype#1#2 + { + \tl_if_empty:nTF + { #2 } + { \markdownRendererInputVerbatim{#1} } + { + \regex_extract_once:nnN + { \w* } + { #2 } + \l_tmpa_seq + \seq_pop_left:NN + \l_tmpa_seq + \l_tmpa_tl + \ltx@ifpackageloaded + { minted } + { + \catcode`\#=6\relax + \exp_args:NV + \inputminted + \l_tmpa_tl + { #1 } + \catcode`\#=12\relax + } + { + \ltx@ifpackageloaded + { listings } + { \lstinputlisting[language=\l_tmpa_tl]{#1} } + { \markdownRendererInputFencedCode{#1}{} } + } + } + } +\ExplSyntaxOff \ExplSyntaxOn \def\markdownLATEXStrongEmphasis#1{% \str_if_in:NnTF @@ -1215,6 +1236,22 @@ \addto@hook\markdownLaTeXTable{#1\\}% \expandafter\@gobble \fi\markdownLaTeXRenderTableCell} + +\markdownIfOption{lineBlocks}{% + \RequirePackage{verse} + \markdownSetup{rendererPrototypes={ + lineBlockBegin = {% + \begingroup + \def\markdownRendererLineBreak{\\}% + \begin{verse}% + }, + lineBlockEnd = {% + \end{verse}% + \endgroup + }, + }} +}{} + \ExplSyntaxOn \keys_define:nn { markdown/jekyllData } @@ -1258,17 +1295,41 @@ \cs_gset:Npn \markdownRendererInputRawInlinePrototype#1#2 { - \str_case:nn + \str_case:nnF + { #2 } + { + { latex } + { + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { #1 } + { tex } + } + } + { + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { #1 } + { #2 } + } + } +\cs_gset:Npn + \markdownRendererInputRawBlockPrototype#1#2 + { + \str_case:nnF { #2 } { - { tex } { \markdownEscape{#1} } - { latex } { \markdownEscape{#1} } - { md } { \markdownInput{#1} } + { latex } + { + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { #1 } + { tex } + } + } + { + \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + { #1 } + { #2 } } } -\cs_gset_eq:NN - \markdownRendererInputRawBlockPrototype - \markdownRendererInputRawInlinePrototype \ExplSyntaxOff \fi % Closes `\markdownIfOption{Plain}{\iffalse}{iftrue}` \newcommand\markdownMakeOther{% diff --git a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty index c0e11e67e34..c788c950a86 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty @@ -47,7 +47,7 @@ \RequirePackage{ifthen,grffile} \let\markdown@witiko@dot@oldRendererInputFencedCodePrototype \markdownRendererInputFencedCodePrototype -\renewcommand\markdownRendererInputFencedCode[2]{% +\renewcommand\markdownRendererInputFencedCodePrototype[2]{% \def\next##1 ##2\relax{% \ifthenelse{\equal{##1}{dot}}{% \markdownIfOption{frozenCache}{}{% diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 8a5a6ce9f56..4d5a96e56cb 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -58,7 +58,7 @@ -- those in the standard .ins files. -- local metadata = { - version = "2.19.0-0-g80fcf20", + version = "2.20.0-0-gf64ade1", 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", @@ -135,6 +135,7 @@ metadata.grammar_version = 2 defaultOptions.extensions = {} defaultOptions.fancyLists = false defaultOptions.fencedCode = false +defaultOptions.fencedCodeAttributes = false defaultOptions.fencedDivs = false defaultOptions.finalizeCache = false defaultOptions.frozenCacheCounter = 0 @@ -146,6 +147,7 @@ defaultOptions.hybrid = false defaultOptions.inlineFootnotes = false defaultOptions.inlineNotes = false defaultOptions.jekyllData = false +defaultOptions.lineBlocks = false defaultOptions.footnotes = false defaultOptions.notes = false defaultOptions.pipeTables = false @@ -192,7 +194,6 @@ function util.cache(dir, string, salt, transform, suffix) return name end function util.cache_verbatim(dir, string) - string = string:gsub('[\r\n%s]*$', '') local name = util.cache(dir, string, nil, nil, ".verbatim") return name end @@ -2411,7 +2412,7 @@ function M.writer.new(options) return s end function self.pack(name) - return [[\input ]] .. name .. [[\relax]] + return [[\input{]] .. name .. [[}\relax]] end function self.interblocksep() if not self.is_writing then return "" end @@ -2423,31 +2424,35 @@ function M.writer.new(options) if not self.is_writing then return "" end return "\\markdownRendererThematicBreak{}" end - self.escaped_uri_chars = { - ["{"] = "\\markdownRendererLeftBrace{}", - ["}"] = "\\markdownRendererRightBrace{}", - ["\\"] = "\\markdownRendererBackslash{}", - } - self.escaped_minimal_strings = { - ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", - ["☒"] = "\\markdownRendererTickedBox{}", - ["⌛"] = "\\markdownRendererHalfTickedBox{}", - ["☐"] = "\\markdownRendererUntickedBox{}", - } + self.escaped_uri_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + self.escaped_minimal_strings = { + ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", + ["☒"] = "\\markdownRendererTickedBox{}", + ["⌛"] = "\\markdownRendererHalfTickedBox{}", + ["☐"] = "\\markdownRendererUntickedBox{}", + [entities.hex_entity('FFFD')] = "\\markdownRendererReplacementCharacter{}", + } + self.escaped_strings = util.table_copy(self.escaped_minimal_strings) + self.escaped_strings[entities.hex_entity('00A0')] = self.nbsp self.escaped_chars = { - ["{"] = "\\markdownRendererLeftBrace{}", - ["}"] = "\\markdownRendererRightBrace{}", - ["%"] = "\\markdownRendererPercentSign{}", - ["\\"] = "\\markdownRendererBackslash{}", - ["#"] = "\\markdownRendererHash{}", - ["$"] = "\\markdownRendererDollarSign{}", - ["&"] = "\\markdownRendererAmpersand{}", - ["_"] = "\\markdownRendererUnderscore{}", - ["^"] = "\\markdownRendererCircumflex{}", - ["~"] = "\\markdownRendererTilde{}", - ["|"] = "\\markdownRendererPipe{}", - } - self.escape = util.escaper(self.escaped_chars, self.escaped_minimal_strings) + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["\\"] = "\\markdownRendererBackslash{}", + ["#"] = "\\markdownRendererHash{}", + ["$"] = "\\markdownRendererDollarSign{}", + ["&"] = "\\markdownRendererAmpersand{}", + ["_"] = "\\markdownRendererUnderscore{}", + ["^"] = "\\markdownRendererCircumflex{}", + ["~"] = "\\markdownRendererTilde{}", + ["|"] = "\\markdownRendererPipe{}", + [entities.hex_entity('0000')] = "\\markdownRendererReplacementCharacter{}", + } + self.escape = util.escaper(self.escaped_chars, self.escaped_strings) self.escape_uri = util.escaper(self.escaped_uri_chars, self.escaped_minimal_strings) self.escape_minimal = util.escaper({}, self.escaped_minimal_strings) if options.hybrid then @@ -2557,6 +2562,7 @@ function M.writer.new(options) end function self.verbatim(s) if not self.is_writing then return "" end + s = s:gsub("\n$", "") local name = util.cache_verbatim(options.cacheDir, s) return {"\\markdownRendererInputVerbatim{",name,"}"} end @@ -2882,6 +2888,13 @@ parsers.attributes = parsers.lbrace * parsers.optionalspace * parsers.rbrace +parsers.raw_attribute = parsers.lbrace + * parsers.optionalspace + * parsers.equal + * C(parsers.attribute_key) + * parsers.optionalspace + * parsers.rbrace + -- block followed by 0 or more optionally -- indented blocks with first line indented. parsers.indented_blocks = function(bl) @@ -2928,65 +2941,6 @@ parsers.intickschar = (parsers.any - S(" \n\r`")) parsers.inticks = parsers.openticks * parsers.space^-1 * C(parsers.intickschar^0) * parsers.closeticks -local function captures_geq_length(_,i,a,b) - return #a >= #b and i -end - -parsers.tilde_infostring - = C((parsers.linechar - - (parsers.spacechar^1 * parsers.newline))^0) - * parsers.optionalspace - * (parsers.newline + parsers.eof) - -parsers.backtick_infostring - = C((parsers.linechar - - (parsers.backtick - + parsers.spacechar^1 * parsers.newline))^0) - * parsers.optionalspace - * (parsers.newline + parsers.eof) - -local fenceindent -parsers.fencehead = function(char, infostring) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end - * Cg(char^3, "fencelength") - * parsers.optionalspace * infostring -end - -parsers.fencehead_with_attributes - = function(char) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end - * Cg(char^3, "fencelength") - * parsers.optionalspace * Ct(parsers.attributes) - * 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) - local i = 1 - local remaining = fenceindent - while true do - local c = s:sub(i, i) - if c == " " and remaining > 0 then - remaining = remaining - 1 - i = i + 1 - elseif c == "\t" and remaining > 3 then - remaining = remaining - 4 - i = i + 1 - else - break - end - end - return s:sub(i) - end -end parsers.leader = parsers.space^-3 -- content in balanced brackets, parentheses, or quotes: @@ -3171,18 +3125,6 @@ parsers.between = function(p, starter, ender) end parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more -parsers.TildeFencedCode - = parsers.fencehead(parsers.tilde, - parsers.tilde_infostring) - * Cs(parsers.fencedline(parsers.tilde)^0) - * parsers.fencetail(parsers.tilde) - -parsers.BacktickFencedCode - = parsers.fencehead(parsers.backtick, - parsers.backtick_infostring) - * 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 @@ -3320,8 +3262,7 @@ function M.reader.new(writer, options) -- strip off leading > and indents, and run through blocks parsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/"" * parsers.linechar^0 * parsers.newline)^1 - * (-(parsers.leader * parsers.more - + parsers.blankline) * parsers.linechar^1 + * (-V("BlockquoteExceptions") * parsers.linechar^1 * parsers.newline)^0 if not options.breakableBlockquotes then @@ -3563,6 +3504,9 @@ function M.reader.new(writer, options) * ((parsers.indentedline - parsers.blankline))^1)^1 ) / self.expandtabs / writer.verbatim + parsers.BlockquoteExceptions = parsers.leader * parsers.more + + parsers.blankline + parsers.Blockquote = Cs(parsers.blockquote_body^1) / self.parser_functions.parse_blocks_nested / writer.blockquote @@ -3749,7 +3693,9 @@ function M.reader.new(writer, options) DisplayHtml = parsers.DisplayHtml, Paragraph = parsers.Paragraph, Plain = parsers.Plain, + EndlineExceptions = parsers.EndlineExceptions, + BlockquoteExceptions = parsers.BlockquoteExceptions, Str = parsers.Str, Space = parsers.Space, @@ -3798,7 +3744,6 @@ function M.reader.new(writer, options) end self.add_special_character("*") - self.add_special_character("`") self.add_special_character("[") self.add_special_character("]") self.add_special_character("<") @@ -3888,6 +3833,8 @@ function M.reader.new(writer, options) if not options.codeSpans then syntax.Code = parsers.fail + else + self.add_special_character("`") end if not options.html then @@ -3945,6 +3892,10 @@ function M.reader.new(writer, options) inlines_nbsp_t.Space = parsers.NonbreakingSpace parsers.inlines_nbsp = Ct(inlines_nbsp_t) return function(input) + input = input:gsub("\r\n?", "\n") + if input:sub(-1) ~= "\n" then + input = input .. "\n" + end references = {} local opt_string = {} for k, _ in pairs(defaultOptions) do @@ -4526,29 +4477,134 @@ M.extensions.fancy_lists = function() end } end -M.extensions.fenced_code = function(blank_before_code_fence) +M.extensions.fenced_code = function(blank_before_code_fence, + allow_attributes, + allow_raw_blocks) return { name = "built-in fenced_code syntax extension", extend_writer = function(self) local options = self.options - function self.fencedCode(s, i) + function self.fencedCode(s, i, attr) if not self.is_writing then return "" end + s = s:gsub("\n$", "") + local buf = {} + if attr ~= nil then + table.insert(buf, {"\\markdownRendererFencedCodeAttributeContextBegin", + self.attributes(attr)}) + end local name = util.cache_verbatim(options.cacheDir, s) - return {"\\markdownRendererInputFencedCode{", - name,"}{",self.string(i),"}"} + table.insert(buf, {"\\markdownRendererInputFencedCode{", + name,"}{",self.string(i),"}"}) + if attr ~= nil then + table.insert(buf, "\\markdownRendererFencedCodeAttributeContextEnd") + end + return buf + end + + if allow_raw_blocks then + function self.rawBlock(s, attr) + if not self.is_writing then return "" end + s = s:gsub("\n$", "") + local name = util.cache_verbatim(options.cacheDir, s) + return {"\\markdownRendererInputRawBlock{", + name,"}{", self.string(attr),"}"} + end end end, extend_reader = function(self) local parsers = self.parsers local writer = self.writer - local FencedCode = (parsers.TildeFencedCode - + parsers.BacktickFencedCode) - / function(infostring, code) - local expanded_code = self.expandtabs(code) - return writer.fencedCode(expanded_code, - infostring) - end + local function captures_geq_length(_,i,a,b) + return #a >= #b and i + end + + local tilde_infostring + = C((parsers.linechar + - (parsers.spacechar^1 * parsers.newline))^0) + + local backtick_infostring + = C((parsers.linechar + - (parsers.backtick + + parsers.spacechar^1 * parsers.newline))^0) + + local fenceindent + local fencehead = function(char, infostring) + return C(parsers.nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * parsers.optionalspace + * infostring + * (parsers.newline + parsers.eof) + end + + local fencetail = function(char) + return parsers.nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) + * parsers.optionalspace * (parsers.newline + parsers.eof) + + parsers.eof + end + + local fencedline = function(char) + return C(parsers.line - fencetail(char)) + / function(s) + local i = 1 + local remaining = fenceindent + while true do + local c = s:sub(i, i) + if c == " " and remaining > 0 then + remaining = remaining - 1 + i = i + 1 + elseif c == "\t" and remaining > 3 then + remaining = remaining - 4 + i = i + 1 + else + break + end + end + return s:sub(i) + end + end + + local TildeFencedCode + = fencehead(parsers.tilde, tilde_infostring) + * Cs(fencedline(parsers.tilde)^0) + * fencetail(parsers.tilde) + + local BacktickFencedCode + = fencehead(parsers.backtick, backtick_infostring) + * Cs(fencedline(parsers.backtick)^0) + * fencetail(parsers.backtick) + + local infostring_with_attributes + = Ct(C((parsers.linechar + - ( parsers.optionalspace + * parsers.attributes))^0) + * parsers.optionalspace + * Ct(parsers.attributes)) + + local FencedCode + = (TildeFencedCode + BacktickFencedCode) + / function(infostring, code) + local expanded_code = self.expandtabs(code) + + if allow_raw_blocks then + local raw_attr = lpeg.match(parsers.raw_attribute, + infostring) + if raw_attr then + return writer.rawBlock(expanded_code, raw_attr) + end + end + + local attr = nil + if allow_attributes then + local match = lpeg.match(infostring_with_attributes, + infostring) + if match then + infostring, attr = table.unpack(match) + end + end + return writer.fencedCode(expanded_code, infostring, attr) + end self.insert_pattern("Block after Verbatim", FencedCode, "FencedCode") @@ -4557,10 +4613,8 @@ M.extensions.fenced_code = function(blank_before_code_fence) if blank_before_code_fence then fencestart = parsers.fail else - fencestart = parsers.fencehead(parsers.backtick, - parsers.backtick_infostring) - + parsers.fencehead(parsers.tilde, - parsers.tilde_infostring) + fencestart = fencehead(parsers.backtick, backtick_infostring) + + fencehead(parsers.tilde, tilde_infostring) end self.update_rule("EndlineExceptions", function(previous_pattern) @@ -4570,6 +4624,7 @@ M.extensions.fenced_code = function(blank_before_code_fence) return previous_pattern + fencestart end) + self.add_special_character("`") self.add_special_character("~") end } @@ -4641,14 +4696,23 @@ M.extensions.fenced_divs = function(blank_before_div_fence) FencedDiv, "FencedDiv") self.add_special_character(":") - if not blank_before_div_fence then - local function check_div_level(s, i, current_level) -- luacheck: ignore s i - current_level = tonumber(current_level) - return current_level > 0 + + local function check_div_level(s, i, current_level) -- luacheck: ignore s i + current_level = tonumber(current_level) + return current_level > 0 + end + + local is_inside_div = Cmt(Cb("div_level"), check_div_level) + local fencestart = is_inside_div * fenced_div_end + + self.update_rule("BlockquoteExceptions", function(previous_pattern) + if previous_pattern == nil then + previous_pattern = parsers.BlockquoteExceptions end + return previous_pattern + fencestart + end) - local is_inside_div = Cmt(Cb("div_level"), check_div_level) - local fencestart = is_inside_div * fenced_div_end + if not blank_before_div_fence then self.update_rule("EndlineExceptions", function(previous_pattern) if previous_pattern == nil then previous_pattern = parsers.EndlineExceptions @@ -4714,6 +4778,44 @@ M.extensions.header_attributes = function() end } end +M.extensions.line_blocks = function() + return { + name = "built-in line_blocks syntax extension", + extend_writer = function(self) + function self.lineblock(lines) + if not self.is_writing then return "" end + local buffer = {} + for i = 1, #lines - 1 do + buffer[#buffer + 1] = { lines[i], self.linebreak } + end + buffer[#buffer + 1] = lines[#lines] + + return {"\\markdownRendererLineBlockBegin\n" + ,buffer, + "\n\\markdownRendererLineBlockEnd "} + end + end, extend_reader = function(self) + local parsers = self.parsers + local writer = self.writer + + local LineBlock = Ct( + (Cs( + ( (parsers.pipe * parsers.space)/"" + * ((parsers.space)/entities.char_entity("nbsp"))^0 + * parsers.linechar^0 * (parsers.newline/"")) + * (-parsers.pipe + * (parsers.space^1/" ") + * parsers.linechar^1 + * (parsers.newline/"") + )^0 + * (parsers.blankline/"")^0 + ) / self.parser_functions.parse_inlines)^1) / writer.lineblock + + self.insert_pattern("Block after Blockquote", + LineBlock, "LineBlock") + end + } +end M.extensions.notes = function(notes, inline_notes) assert(notes or inline_notes) return { @@ -4924,9 +5026,9 @@ M.extensions.pipe_tables = function(table_captions) end } end -M.extensions.raw_attribute = function() +M.extensions.raw_inline = function() return { - name = "built-in raw_attribute syntax extension", + name = "built-in raw_inline syntax extension", extend_writer = function(self) local options = self.options @@ -4936,50 +5038,15 @@ M.extensions.raw_attribute = function() return {"\\markdownRendererInputRawInline{", name,"}{", self.string(attr),"}"} end - - if options.fencedCode then - function self.rawBlock(s, attr) - if not self.is_writing then return "" end - local name = util.cache_verbatim(options.cacheDir, s) - return {"\\markdownRendererInputRawBlock{", - name,"}{", self.string(attr),"}"} - end - end end, extend_reader = function(self) - local options = self.options local writer = self.writer - local raw_attribute = parsers.lbrace - * parsers.optionalspace - * parsers.equal - * C(parsers.attribute_key) - * parsers.optionalspace - * parsers.rbrace - local RawInline = parsers.inticks - * raw_attribute + * parsers.raw_attribute / writer.rawInline self.insert_pattern("Inline before Code", RawInline, "RawInline") - - if options.fencedCode then - local RawBlock = (parsers.TildeFencedCode - + parsers.BacktickFencedCode) - / function(infostring, code) - local expanded_code = self.expandtabs(code) - local attr = lpeg.match(raw_attribute, infostring) - if attr then - return writer.rawBlock(expanded_code, attr) - else - return writer.fencedCode(expanded_code, - infostring) - end - end - - self.insert_pattern("Block after Verbatim", - RawBlock, "RawBlock") - end end } end @@ -5206,7 +5273,9 @@ function M.new(options) if options.fencedCode then local fenced_code_extension = M.extensions.fenced_code( - options.blankBeforeCodeFence) + options.blankBeforeCodeFence, + options.fencedCodeAttributes, + options.rawAttribute) table.insert(extensions, fenced_code_extension) end @@ -5234,8 +5303,8 @@ function M.new(options) end if options.rawAttribute then - local raw_attribute_extension = M.extensions.raw_attribute() - table.insert(extensions, raw_attribute_extension) + local raw_inline_extension = M.extensions.raw_inline() + table.insert(extensions, raw_inline_extension) end if options.strikeThrough then @@ -5253,6 +5322,11 @@ function M.new(options) table.insert(extensions, superscript_extension) end + if options.lineBlocks then + local line_block_extension = M.extensions.line_blocks() + table.insert(extensions, line_block_extension) + end + if options.footnotes or options.inlineFootnotes or options.notes or options.inlineNotes then local notes_extension = M.extensions.notes( |