From 45d62c355885e905db2a729761eb384ec447e931 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Sun, 18 Feb 2024 21:05:58 +0000 Subject: markdown (18feb24) git-svn-id: svn://tug.org/texlive/trunk@69962 c570f23f-e606-0410-a88d-b1316a301751 --- .../tex/context/third/markdown/t-markdown.tex | 391 +- .../t-markdownthemewitiko_markdown_defaults.tex | 279 ++ .../texmf-dist/tex/generic/markdown/markdown.tex | 2063 ++++---- .../markdownthemewitiko_markdown_defaults.tex | 321 ++ .../generic/markdown/markdownthemewitiko_tilde.tex | 52 + Master/texmf-dist/tex/latex/markdown/markdown.sty | 1713 +------ .../tex/latex/markdown/markdownthemewitiko_dot.sty | 10 +- .../markdown/markdownthemewitiko_graphicx_http.sty | 6 +- .../markdownthemewitiko_markdown_defaults.sty | 933 ++++ .../latex/markdown/markdownthemewitiko_tilde.sty | 49 - .../tex/luatex/markdown/markdown-tinyyaml.lua | 4 +- Master/texmf-dist/tex/luatex/markdown/markdown.lua | 5002 ++++++++++++++------ 12 files changed, 6709 insertions(+), 4114 deletions(-) create mode 100644 Master/texmf-dist/tex/context/third/markdown/t-markdownthemewitiko_markdown_defaults.tex create mode 100644 Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_markdown_defaults.tex create mode 100644 Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_tilde.tex create mode 100644 Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_markdown_defaults.sty delete mode 100644 Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_tilde.sty (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 7185b66c2c5..642d0bcd2da 100644 --- a/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex +++ b/Master/texmf-dist/tex/context/third/markdown/t-markdown.tex @@ -6,7 +6,7 @@ %% %% markdown.dtx (with options: `context') %% -%% Copyright (C) 2016-2023 Vít Novotný +%% Copyright (C) 2016-2024 Vít Starý Novotný %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c @@ -16,7 +16,7 @@ %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. +%% The Current Maintainer of this work is Vít Starý Novotný. %% %% Send bug reports, requests for additions and questions %% either to the GitHub issue tracker at @@ -42,11 +42,25 @@ %% %% The names of the source files used are shown above. %% +\unprotect +\ifx\ExplSyntaxOn\undefined + \input expl3-generic +\fi +\ExplSyntaxOn +\tl_const:Nn \c__markdown_option_layer_context_tl { context } +\cs_generate_variant:Nn + \tl_const:Nn + { NV } +\tl_if_exist:NF + \c__markdown_top_layer_tl + { + \tl_const:NV + \c__markdown_top_layer_tl + \c__markdown_option_layer_context_tl + } +\ExplSyntaxOff \writestatus{loading}{ConTeXt User Module / markdown}% \startmodule[markdown] -\unprotect -\def\markdownInfo#1{\writestatus{markdown}{#1.}}% -\def\markdownWarning#1{\writestatus{markdown\space warn}{#1.}}% \def\dospecials{\do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\_\do\%\do\~}% \input markdown/markdown @@ -54,39 +68,13 @@ \let\stopmarkdown\relax \let\inputmarkdown\relax \ExplSyntaxOn -\cs_new:Nn - \__markdown_setup:n - { - \keys_set:nn - { markdown/context-options } - { #1 } - } -\long\def\setupmarkdown[#1] +\cs_new:Npn + \setupmarkdown + [ #1 ] { \__markdown_setup:n { #1 } } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Nn \__markdown_context_define_option_commands_and_keyvals: - { - \seq_map_inline:Nn - \g__markdown_option_layers_seq - { - \seq_map_inline:cn - { g__markdown_ ##1 _options_seq } - { - \__markdown_with_various_cases:nn - { ####1 } - { - \__markdown_context_define_option_keyval:nnn - { ##1 } - { ####1 } - { ########1 } - } - } - } - } \cs_new:Nn \__markdown_caseless:N { \regex_replace_all:nnN @@ -98,47 +86,14 @@ { #1 } } \seq_gput_right:Nn \g__markdown_cases_seq { __markdown_caseless:N } -\cs_new:Nn \__markdown_context_define_option_keyval:nnn +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_context_tl { - \prop_get:cnN - { g__markdown_ #1 _option_types_prop } - { #2 } - \l_tmpa_tl - \keys_define:nn - { markdown/context-options } - { - #3 .code:n = { - \tl_set:Nx - \l_tmpa_tl - { - \str_case:nnF - { ##1 } - { - { yes } { true } - { no } { false } - } - { ##1 } - } - \__markdown_set_option_value:nV - { #2 } - \l_tmpa_tl - }, - } - \str_if_eq:VVT - \l_tmpa_tl - \c__markdown_option_type_boolean_tl - { - \keys_define:nn - { markdown/context-options } - { - #3 .default:n = { true }, - } - } + \__markdown_define_option_commands_and_keyvals: + \__markdown_define_renderers: + \__markdown_define_renderer_prototypes: } -\cs_generate_variant:Nn - \__markdown_set_option_value:nn - { nV } -\__markdown_context_define_option_commands_and_keyvals: \ExplSyntaxOff \def\markdownMakeOther{% \count0=128\relax @@ -153,270 +108,62 @@ \long\def\doinputmarkdown[#1]#2{% \begingroup \iffirstargument - \setupmarkdown{#1}% + \setupmarkdown[#1]% \fi \markdownInput{#2}% \endgroup}% -\ifx\startluacode\undefined % MkII - \begingroup - \catcode`\|=0% - \catcode`\\=12% - |gdef|startmarkdown{% - |markdownReadAndConvert{\stopmarkdown}% - {|stopmarkdown}}% - |gdef|stopmarkdown{% - |markdownEnd}% - |endgroup -\else % MkIV - \startluacode - document.markdown_buffering = false - local function preserve_trailing_spaces(line) - if document.markdown_buffering then - line = line:gsub("[ \t][ \t]$", "\t\t") - end - return line +\startluacode + document.markdown_buffering = false + local function preserve_trailing_spaces(line) + if document.markdown_buffering then + line = line:gsub("[ \t][ \t]$", "\t\t") end - resolvers.installinputlinehandler(preserve_trailing_spaces) - \stopluacode - \begingroup - \catcode`\|=0% - \catcode`\\=12% - |gdef|startmarkdown{% - |ctxlua{document.markdown_buffering = true}% - |markdownReadAndConvert{\stopmarkdown}% - {|stopmarkdown}}% - |gdef|stopmarkdown{% - |ctxlua{document.markdown_buffering = false}% - |markdownEnd}% - |endgroup -\fi -\def\markdownRendererHardLineBreakPrototype{\blank}% -\def\markdownRendererLeftBracePrototype{\textbraceleft}% -\def\markdownRendererRightBracePrototype{\textbraceright}% -\def\markdownRendererDollarSignPrototype{\textdollar}% -\def\markdownRendererPercentSignPrototype{\percent}% -\def\markdownRendererUnderscorePrototype{\textunderscore}% -\def\markdownRendererCircumflexPrototype{\textcircumflex}% -\def\markdownRendererBackslashPrototype{\textbackslash}% -\def\markdownRendererTildePrototype{\textasciitilde}% -\def\markdownRendererPipePrototype{\char`|}% -\def\markdownRendererLinkPrototype#1#2#3#4{% - \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: - \fi\tt<\hyphenatedurl{#3}>}}% -\usemodule[database] -\defineseparatedlist - [MarkdownConTeXtCSV] - [separator={,}, - before=\bTABLE,after=\eTABLE, - first=\bTR,last=\eTR, - left=\bTD,right=\eTD] -\def\markdownConTeXtCSV{csv} -\def\markdownRendererContentBlockPrototype#1#2#3#4{% - \def\markdownConTeXtCSV@arg{#1}% - \ifx\markdownConTeXtCSV@arg\markdownConTeXtCSV - \placetable[][tab:#1]{#4}{% - \processseparatedfile[MarkdownConTeXtCSV][#3]}% - \else - \markdownInput{#3}% - \fi}% -\def\markdownRendererImagePrototype#1#2#3#4{% - \placefigure[][]{#4}{\externalfigure[#3]}}% -\def\markdownRendererUlBeginPrototype{\startitemize}% -\def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% -\def\markdownRendererUlItemPrototype{\item}% -\def\markdownRendererUlEndPrototype{\stopitemize}% -\def\markdownRendererUlEndTightPrototype{\stopitemize}% -\def\markdownRendererOlBeginPrototype{\startitemize[n]}% -\def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% -\def\markdownRendererOlItemPrototype{\item}% -\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% -\def\markdownRendererOlEndPrototype{\stopitemize}% -\def\markdownRendererOlEndTightPrototype{\stopitemize}% -\definedescription - [MarkdownConTeXtDlItemPrototype] - [location=hanging, - margin=standard, - headstyle=bold]% -\definestartstop - [MarkdownConTeXtDlPrototype] - [before=\blank, - after=\blank]% -\definestartstop - [MarkdownConTeXtDlTightPrototype] - [before=\blank\startpacked, - after=\stoppacked\blank]% -\def\markdownRendererDlBeginPrototype{% - \startMarkdownConTeXtDlPrototype}% -\def\markdownRendererDlBeginTightPrototype{% - \startMarkdownConTeXtDlTightPrototype}% -\def\markdownRendererDlItemPrototype#1{% - \startMarkdownConTeXtDlItemPrototype{#1}}% -\def\markdownRendererDlItemEndPrototype{% - \stopMarkdownConTeXtDlItemPrototype}% -\def\markdownRendererDlEndPrototype{% - \stopMarkdownConTeXtDlPrototype}% -\def\markdownRendererDlEndTightPrototype{% - \stopMarkdownConTeXtDlTightPrototype}% -\def\markdownRendererEmphasisPrototype#1{{\em#1}}% -\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% -\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% -\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% -\def\markdownRendererLineBlockBeginPrototype{% - \begingroup - \def\markdownRendererHardLineBreak{ - }% - \startlines -}% -\def\markdownRendererLineBlockEndPrototype{% - \stoplines - \endgroup -}% -\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% -\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}}% -\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% -\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% -\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% -\def\markdownRendererThematicBreakPrototype{% - \blackrule[height=1pt, width=\hsize]}% -\def\markdownRendererNotePrototype#1{\footnote{#1}}% -\def\markdownRendererTickedBoxPrototype{$\boxtimes$} -\def\markdownRendererHalfTickedBoxPrototype{$\boxdot$} -\def\markdownRendererUntickedBoxPrototype{$\square$} -\def\markdownRendererStrikeThroughPrototype#1{\overstrikes{#1}} -\def\markdownRendererSuperscriptPrototype#1{\high{#1}} -\def\markdownRendererSubscriptPrototype#1{\low{#1}} -\def\markdownRendererDisplayMathPrototype#1{\startformula#1\stopformula}% -\def\markdownRendererInlineMathPrototype#1{$#1$}% -\newcount\markdownConTeXtRowCounter -\newcount\markdownConTeXtRowTotal -\newcount\markdownConTeXtColumnCounter -\newcount\markdownConTeXtColumnTotal -\newtoks\markdownConTeXtTable -\newtoks\markdownConTeXtTableFloat -\def\markdownRendererTablePrototype#1#2#3{% - \markdownConTeXtTable={}% - \ifx\empty#1\empty - \markdownConTeXtTableFloat={% - \the\markdownConTeXtTable}% - \else - \markdownConTeXtTableFloat={% - \placetable{#1}{\the\markdownConTeXtTable}}% - \fi - \begingroup - \setupTABLE[r][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] - \setupTABLE[c][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] - \setupTABLE[r][1][topframe=on, bottomframe=on] - \setupTABLE[r][#1][bottomframe=on] - \markdownConTeXtRowCounter=0% - \markdownConTeXtRowTotal=#2% - \markdownConTeXtColumnTotal=#3% - \markdownConTeXtRenderTableRow} -\def\markdownConTeXtRenderTableRow#1{% - \markdownConTeXtColumnCounter=0% - \ifnum\markdownConTeXtRowCounter=0\relax - \markdownConTeXtReadAlignments#1% - \markdownConTeXtTable={\bTABLE}% - \else - \markdownConTeXtTable=\expandafter{% - \the\markdownConTeXtTable\bTR}% - \markdownConTeXtRenderTableCell#1% - \markdownConTeXtTable=\expandafter{% - \the\markdownConTeXtTable\eTR}% - \fi - \advance\markdownConTeXtRowCounter by 1\relax - \ifnum\markdownConTeXtRowCounter>\markdownConTeXtRowTotal\relax - \markdownConTeXtTable=\expandafter{% - \the\markdownConTeXtTable\eTABLE}% - \the\markdownConTeXtTableFloat - \endgroup - \expandafter\gobbleoneargument - \fi\markdownConTeXtRenderTableRow} -\def\markdownConTeXtReadAlignments#1{% - \advance\markdownConTeXtColumnCounter by 1\relax - \if#1d% - \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] - \fi\if#1l% - \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] - \fi\if#1c% - \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=middle] - \fi\if#1r% - \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=left] - \fi - \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else - \expandafter\gobbleoneargument - \fi\markdownConTeXtReadAlignments} -\def\markdownConTeXtRenderTableCell#1{% - \advance\markdownConTeXtColumnCounter by 1\relax - \markdownConTeXtTable=\expandafter{% - \the\markdownConTeXtTable\bTD#1\eTD}% - \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else - \expandafter\gobbleoneargument - \fi\markdownConTeXtRenderTableCell} + return line + end + resolvers.installinputlinehandler(preserve_trailing_spaces) +\stopluacode +\begingroup + \catcode`\|=0% + \catcode`\\=12% + |gdef|startmarkdown{% + |ctxlua{document.markdown_buffering = true}% + |markdownReadAndConvert{\stopmarkdown}% + {|stopmarkdown}}% + |gdef|stopmarkdown{% + |ctxlua{document.markdown_buffering = false}% + |markdownEnd}% +|endgroup \ExplSyntaxOn -\cs_gset:Npn - \markdownRendererInputRawInlinePrototype#1#2 +\cs_gset:Nn + \__markdown_load_theme:nn { - \str_case:nnF - { #2 } - { - { latex } - { - \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn - { #1 } - { context } - } - } + \file_if_exist:nTF + { t - markdown theme #2.tex } { - \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + \msg_info:nnn + { markdown } + { loading-context-theme } { #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 } - } + \usemodule + [ t ] + [ markdown theme #2 ] } { - \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + \__markdown_plain_tex_load_theme:nn { #1 } { #2 } } } -\cs_gset_eq:NN - \markdownRendererInputRawBlockPrototype - \markdownRendererInputRawInlinePrototype +\msg_new:nnn + { markdown } + { loading-context-theme } + { Loading~ConTeXt~Markdown~theme~#1 } \ExplSyntaxOff -\stopmodule\protect +\markdownIfOption{noDefaults}{}{ + \setupmarkdown[theme=witiko/markdown/defaults] +} +\stopmodule +\protect \endinput %% %% End of file `t-markdown.tex'. diff --git a/Master/texmf-dist/tex/context/third/markdown/t-markdownthemewitiko_markdown_defaults.tex b/Master/texmf-dist/tex/context/third/markdown/t-markdownthemewitiko_markdown_defaults.tex new file mode 100644 index 00000000000..35fd80f89cd --- /dev/null +++ b/Master/texmf-dist/tex/context/third/markdown/t-markdownthemewitiko_markdown_defaults.tex @@ -0,0 +1,279 @@ +%% +%% This is file `t-markdownthemewitiko_markdown_defaults.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `themes-witiko-markdown-defaults-context') +%% +%% Copyright (C) 2016-2024 Vít Starý Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Starý Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\startmodule[markdownthemewitiko_markdown_defaults] +\unprotect +\markdownLoadPlainTeXTheme +\markdownIfOption{plain}{\iffalse}{\iftrue} +\def\markdownRendererHardLineBreakPrototype{\blank}% +\def\markdownRendererLeftBracePrototype{\textbraceleft}% +\def\markdownRendererRightBracePrototype{\textbraceright}% +\def\markdownRendererDollarSignPrototype{\textdollar}% +\def\markdownRendererPercentSignPrototype{\percent}% +\def\markdownRendererUnderscorePrototype{\textunderscore}% +\def\markdownRendererCircumflexPrototype{\textcircumflex}% +\def\markdownRendererBackslashPrototype{\textbackslash}% +\def\markdownRendererTildePrototype{\textasciitilde}% +\def\markdownRendererPipePrototype{\char`|}% +\def\markdownRendererLinkPrototype#1#2#3#4{% + \useURL[#1][#3][][#4]#1\footnote[#1]{\ifx\empty#4\empty\else#4: + \fi\tt<\hyphenatedurl{#3}>}}% +\usemodule[database] +\defineseparatedlist + [MarkdownConTeXtCSV] + [separator={,}, + before=\bTABLE,after=\eTABLE, + first=\bTR,last=\eTR, + left=\bTD,right=\eTD] +\def\markdownConTeXtCSV{csv} +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \def\markdownConTeXtCSV@arg{#1}% + \ifx\markdownConTeXtCSV@arg\markdownConTeXtCSV + \placetable[][tab:#1]{#4}{% + \processseparatedfile[MarkdownConTeXtCSV][#3]}% + \else + \markdownInput{#3}% + \fi}% +\def\markdownRendererImagePrototype#1#2#3#4{% + \placefigure[][]{#4}{\externalfigure[#3]}}% +\def\markdownRendererUlBeginPrototype{\startitemize}% +\def\markdownRendererUlBeginTightPrototype{\startitemize[packed]}% +\def\markdownRendererUlItemPrototype{\item}% +\def\markdownRendererUlEndPrototype{\stopitemize}% +\def\markdownRendererUlEndTightPrototype{\stopitemize}% +\def\markdownRendererOlBeginPrototype{\startitemize[n]}% +\def\markdownRendererOlBeginTightPrototype{\startitemize[packed,n]}% +\def\markdownRendererOlItemPrototype{\item}% +\def\markdownRendererOlItemWithNumberPrototype#1{\sym{#1.}}% +\def\markdownRendererOlEndPrototype{\stopitemize}% +\def\markdownRendererOlEndTightPrototype{\stopitemize}% +\definedescription + [MarkdownConTeXtDlItemPrototype] + [location=hanging, + margin=standard, + headstyle=bold]% +\definestartstop + [MarkdownConTeXtDlPrototype] + [before=\blank, + after=\blank]% +\definestartstop + [MarkdownConTeXtDlTightPrototype] + [before=\blank\startpacked, + after=\stoppacked\blank]% +\def\markdownRendererDlBeginPrototype{% + \startMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlBeginTightPrototype{% + \startMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererDlItemPrototype#1{% + \startMarkdownConTeXtDlItemPrototype{#1}}% +\def\markdownRendererDlItemEndPrototype{% + \stopMarkdownConTeXtDlItemPrototype}% +\def\markdownRendererDlEndPrototype{% + \stopMarkdownConTeXtDlPrototype}% +\def\markdownRendererDlEndTightPrototype{% + \stopMarkdownConTeXtDlTightPrototype}% +\def\markdownRendererEmphasisPrototype#1{{\em#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\startquotation}% +\def\markdownRendererBlockQuoteEndPrototype{\stopquotation}% +\def\markdownRendererLineBlockBeginPrototype{% + \begingroup + \def\markdownRendererHardLineBreak{ + }% + \startlines +}% +\def\markdownRendererLineBlockEndPrototype{% + \stoplines + \endgroup +}% +\def\markdownRendererInputVerbatimPrototype#1{\typefile{#1}}% +\ExplSyntaxOn +\cs_gset:Npn + \markdownRendererInputFencedCodePrototype#1#2#3 + { + \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}}% +\def\markdownRendererHeadingFourPrototype#1{\subsubsection{#1}}% +\def\markdownRendererHeadingFivePrototype#1{\subsubsubsection{#1}}% +\def\markdownRendererHeadingSixPrototype#1{\subsubsubsubsection{#1}}% +\def\markdownRendererThematicBreakPrototype{% + \blackrule[height=1pt, width=\hsize]}% +\def\markdownRendererNotePrototype#1{\footnote{#1}}% +\def\markdownRendererTickedBoxPrototype{$\boxtimes$} +\def\markdownRendererHalfTickedBoxPrototype{$\boxdot$} +\def\markdownRendererUntickedBoxPrototype{$\square$} +\def\markdownRendererStrikeThroughPrototype#1{\overstrikes{#1}} +\def\markdownRendererSuperscriptPrototype#1{\high{#1}} +\def\markdownRendererSubscriptPrototype#1{\low{#1}} +\def\markdownRendererDisplayMathPrototype#1{\startformula#1\stopformula}% +\newcount\markdownConTeXtRowCounter +\newcount\markdownConTeXtRowTotal +\newcount\markdownConTeXtColumnCounter +\newcount\markdownConTeXtColumnTotal +\newtoks\markdownConTeXtTable +\newtoks\markdownConTeXtTableFloat +\def\markdownRendererTablePrototype#1#2#3{% + \markdownConTeXtTable={}% + \ifx\empty#1\empty + \markdownConTeXtTableFloat={% + \the\markdownConTeXtTable}% + \else + \markdownConTeXtTableFloat={% + \placetable{#1}{\the\markdownConTeXtTable}}% + \fi + \begingroup + \setupTABLE[r][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] + \setupTABLE[c][each][topframe=off, bottomframe=off, leftframe=off, rightframe=off] + \setupTABLE[r][1][topframe=on, bottomframe=on] + \setupTABLE[r][#1][bottomframe=on] + \markdownConTeXtRowCounter=0% + \markdownConTeXtRowTotal=#2% + \markdownConTeXtColumnTotal=#3% + \markdownConTeXtRenderTableRow} +\def\markdownConTeXtRenderTableRow#1{% + \markdownConTeXtColumnCounter=0% + \ifnum\markdownConTeXtRowCounter=0\relax + \markdownConTeXtReadAlignments#1% + \markdownConTeXtTable={\bTABLE}% + \else + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\bTR}% + \markdownConTeXtRenderTableCell#1% + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\eTR}% + \fi + \advance\markdownConTeXtRowCounter by 1\relax + \ifnum\markdownConTeXtRowCounter>\markdownConTeXtRowTotal\relax + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\eTABLE}% + \the\markdownConTeXtTableFloat + \endgroup + \expandafter\gobbleoneargument + \fi\markdownConTeXtRenderTableRow} +\def\markdownConTeXtReadAlignments#1{% + \advance\markdownConTeXtColumnCounter by 1\relax + \if#1d% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] + \fi\if#1l% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=right] + \fi\if#1c% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=middle] + \fi\if#1r% + \setupTABLE[c][\the\markdownConTeXtColumnCounter][align=left] + \fi + \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else + \expandafter\gobbleoneargument + \fi\markdownConTeXtReadAlignments} +\def\markdownConTeXtRenderTableCell#1{% + \advance\markdownConTeXtColumnCounter by 1\relax + \markdownConTeXtTable=\expandafter{% + \the\markdownConTeXtTable\bTD#1\eTD}% + \ifnum\markdownConTeXtColumnCounter<\markdownConTeXtColumnTotal\relax\else + \expandafter\gobbleoneargument + \fi\markdownConTeXtRenderTableCell} +\ExplSyntaxOn +\cs_gset:Npn + \markdownRendererInputRawInlinePrototype#1#2 + { + \str_case:nnF + { #2 } + { + { 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 + \markdownRendererInputRawBlockPrototype + \markdownRendererInputRawInlinePrototype +\fi % Closes `\markdownIfOption{plain}{\iffalse}{\iftrue}` +\ExplSyntaxOff +\stopmodule +\protect +\endinput +%% +%% End of file `t-markdownthemewitiko_markdown_defaults.tex'. diff --git a/Master/texmf-dist/tex/generic/markdown/markdown.tex b/Master/texmf-dist/tex/generic/markdown/markdown.tex index 8ad545ea609..3f692d579e8 100644 --- a/Master/texmf-dist/tex/generic/markdown/markdown.tex +++ b/Master/texmf-dist/tex/generic/markdown/markdown.tex @@ -6,7 +6,7 @@ %% %% markdown.dtx (with options: `tex') %% -%% Copyright (C) 2016-2023 Vít Novotný +%% Copyright (C) 2016-2024 Vít Starý Novotný %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c @@ -16,7 +16,7 @@ %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. +%% The Current Maintainer of this work is Vít Starý Novotný. %% %% Send bug reports, requests for additions and questions %% either to the GitHub issue tracker at @@ -43,7 +43,7 @@ %% The names of the source files used are shown above. %% \ifx\ExplSyntaxOn\undefined - \input expl3-generic\relax + \input expl3-generic \fi \ExplSyntaxOn \seq_new:N \g__markdown_lua_options_seq @@ -320,6 +320,14 @@ { #1 } } \seq_gput_right:Nn \g__markdown_cases_seq { __markdown_snake_case:N } +\__markdown_add_lua_option:nnn + { eagerCache } + { boolean } + { false } +\__markdown_add_lua_option:nnn + { singletonCache } + { boolean } + { true } \__markdown_add_lua_option:nnn { cacheDir } { path } @@ -336,6 +344,10 @@ { frozenCacheFileName } { path } { \markdownOptionCacheDir / frozenCache.tex } +\__markdown_add_lua_option:nnn + { autoIdentifiers } + { boolean } + { false } \__markdown_add_lua_option:nnn { blankBeforeBlockquote } { boolean } @@ -352,6 +364,10 @@ { blankBeforeHeading } { boolean } { false } +\__markdown_add_lua_option:nnn + { blankBeforeList } + { boolean } + { false } \__markdown_add_lua_option:nnn { bracketedSpans } { boolean } @@ -359,7 +375,7 @@ \__markdown_add_lua_option:nnn { breakableBlockquotes } { boolean } - { false } + { true } \__markdown_add_lua_option:nnn { citationNbsps } { boolean } @@ -376,6 +392,10 @@ { contentBlocks } { boolean } { false } +\__markdown_add_lua_option:nnn + { contentLevel } + { string } + { block } \__markdown_add_lua_option:nnn { debugExtensions } { boolean } @@ -384,10 +404,6 @@ { definitionLists } { boolean } { false } -\__markdown_add_lua_option:nnn - { eagerCache } - { boolean } - { true } \__markdown_add_lua_option:nnn { expectJekyllData } { boolean } @@ -406,7 +422,7 @@ \__markdown_add_lua_option:nnn { fencedCode } { boolean } - { false } + { true } \__markdown_add_lua_option:nnn { fencedCodeAttributes } { boolean } @@ -424,7 +440,7 @@ { counter } { 0 } \__markdown_add_lua_option:nnn - { hardLineBreaks } + { gfmAutoIdentifiers } { boolean } { false } \__markdown_add_lua_option:nnn @@ -438,7 +454,7 @@ \__markdown_add_lua_option:nnn { html } { boolean } - { false } + { true } \__markdown_add_lua_option:nnn { hybrid } { boolean } @@ -447,10 +463,6 @@ { inlineCodeAttributes } { boolean } { false } -\__markdown_add_lua_option:nnn - { inlineFootnotes } - { boolean } - { false } \__markdown_add_lua_option:nnn { inlineNotes } { boolean } @@ -468,7 +480,7 @@ { boolean } { false } \__markdown_add_lua_option:nnn - { footnotes } + { mark } { boolean } { false } \__markdown_add_lua_option:nnn @@ -482,7 +494,7 @@ \__markdown_add_lua_option:nnn { preserveTabs } { boolean } - { false } + { true } \__markdown_add_lua_option:nnn { rawAttribute } { boolean } @@ -523,6 +535,10 @@ { superscripts } { boolean } { false } +\__markdown_add_lua_option:nnn + { tableAttributes } + { boolean } + { false } \__markdown_add_lua_option:nnn { tableCaptions } { boolean } @@ -556,17 +572,27 @@ { boolean } { true } \ExplSyntaxOff -\def\markdownLastModified{2023-04-27}% -\def\markdownVersion{2.23.0-0-g0b22f91}% +\def\markdownLastModified{2024-02-16}% +\def\markdownVersion{3.4.1-0-g457226ae}% \let\markdownBegin\relax \let\markdownEnd\relax \let\markdownInput\relax \let\markdownEscape\relax \ExplSyntaxOn +\tl_const:Nn \c__markdown_option_layer_plain_tex_tl { plain_tex } +\cs_generate_variant:Nn + \tl_const:Nn + { NV } +\tl_if_exist:NF + \c__markdown_top_layer_tl + { + \tl_const:NV + \c__markdown_top_layer_tl + \c__markdown_option_layer_plain_tex_tl + } \seq_new:N \g__markdown_plain_tex_options_seq \prop_new:N \g__markdown_plain_tex_option_types_prop \prop_new:N \g__markdown_default_plain_tex_options_prop -\tl_const:Nn \c__markdown_option_layer_plain_tex_tl { plain_tex } \seq_gput_right:NV \g__markdown_option_layers_seq \c__markdown_option_layer_plain_tex_tl \cs_new:Nn \__markdown_add_plain_tex_option:nnn @@ -577,46 +603,111 @@ { #2 } { #3 } } +\cs_new:Nn + \__markdown_setup:n + { + \keys_set:nn + { markdown/options } + { #1 } + } +\cs_gset_eq:NN + \markdownSetup + \__markdown_setup:n +\prg_new_conditional:Nnn + \__markdown_if_option:n + { TF, T, F } + { + \__markdown_get_option_type:nN + { #1 } + \l_tmpa_tl + \str_if_eq:NNF + \l_tmpa_tl + \c__markdown_option_type_boolean_tl + { + \msg_error:nnxx + { markdown } + { expected-boolean-option } + { #1 } + { \l_tmpa_tl } + } + \__markdown_get_option_value:nN + { #1 } + \l_tmpa_tl + \str_if_eq:NNTF + \l_tmpa_tl + \c__markdown_option_value_true_tl + { \prg_return_true: } + { \prg_return_false: } + } +\msg_new:nnn + { markdown } + { expected-boolean-option } + { + Option~#1~has~type~#2,~ + but~a~boolean~was~expected. + } +\let\markdownIfOption=\__markdown_if_option:nTF \__markdown_add_plain_tex_option:nnn { frozenCache } { boolean } { false } -\__markdown_add_plain_tex_option:nnn - { helperScriptFileName } - { path } - { \jobname.markdown.lua } -\str_new:N - \g_luabridge_helper_script_filename_str -\tl_gset:Nn - \g_luabridge_helper_script_filename_str - { \markdownOptionHelperScriptFileName } \__markdown_add_plain_tex_option:nnn { inputTempFileName } { path } { \jobname.markdown.in } -\__markdown_add_plain_tex_option:nnn - { outputTempFileName } +\cs_generate_variant:Nn + \__markdown_add_plain_tex_option:nnn + { nnV } +\ExplSyntaxOff +\input lt3luabridge.tex +\ExplSyntaxOn +\bool_if:nTF + { + \cs_if_exist_p:N + \luabridge_tl_set:Nn && + ( + \int_compare_p:nNn + { \g_luabridge_method_int } + = + { \c_luabridge_method_directlua_int } || + \sys_if_shell_unrestricted_p: + ) + } + { + \luabridge_tl_set:Nn + \l_tmpa_tl + { print(os.getenv("TEXMF_OUTPUT_DIRECTORY") or ".") } + } + { + \tl_set:Nn + \l_tmpa_tl + { . } + } +\__markdown_add_plain_tex_option:nnV + { outputDir } { path } - { \jobname.markdown.out } -\str_new:N - \g_luabridge_standard_output_filename_str -\tl_gset:Nn - \g_luabridge_standard_output_filename_str - { \markdownOptionOutputTempFileName } + \l_tmpa_tl \__markdown_add_plain_tex_option:nnn - { errorTempFileName } - { path } - { \jobname.markdown.err } -\str_new:N - \g_luabridge_error_output_filename_str -\tl_gset:Nn - \g_luabridge_error_output_filename_str - { \markdownOptionErrorTempFileName } + { plain } + { boolean } + { false } \__markdown_add_plain_tex_option:nnn - { outputDir } - { path } - { . } -\cs_new:Nn \__markdown_plain_tex_define_option_commands: + { noDefaults } + { boolean } + { false } +\seq_gput_right:Nn + \g__markdown_plain_tex_options_seq + { stripPercentSigns } +\prop_gput:Nnn + \g__markdown_plain_tex_option_types_prop + { stripPercentSigns } + { boolean } +\prop_gput:Nnx + \g__markdown_default_plain_tex_options_prop + { stripPercentSigns } + { false } +\cs_new:Nn + \__markdown_define_option_commands_and_keyvals: { \seq_map_inline:Nn \g__markdown_option_layers_seq @@ -624,19 +715,35 @@ \seq_map_inline:cn { g__markdown_ ##1 _options_seq } { - \__markdown_plain_tex_define_option_command:n + \__markdown_define_option_command:n + { ####1 } + \__markdown_with_various_cases:nn { ####1 } + { + \__markdown_define_option_keyval:nnn + { ##1 } + { ####1 } + { ########1 } + } } } } -\cs_new:Nn \__markdown_plain_tex_define_option_command:n +\cs_new:Nn + \__markdown_define_option_command:n { - \__markdown_get_default_option_value:nN - { #1 } - \l_tmpa_tl - \__markdown_set_option_value:nV + \__markdown_option_tl_to_csname:nN { #1 } \l_tmpa_tl + \cs_if_exist:cF + { \l_tmpa_tl } + { + \__markdown_get_default_option_value:nN + { #1 } + \l_tmpa_tl + \__markdown_set_option_value:nV + { #1 } + \l_tmpa_tl + } } \cs_new:Nn \__markdown_set_option_value:nn @@ -693,133 +800,490 @@ } } } -\__markdown_plain_tex_define_option_commands: -\seq_gput_right:Nn - \g__markdown_plain_tex_options_seq - { stripPercentSigns } -\prop_gput:Nnn - \g__markdown_plain_tex_option_types_prop - { stripPercentSigns } - { boolean } -\prop_gput:Nnx - \g__markdown_default_plain_tex_options_prop - { stripPercentSigns } - { false } -\ExplSyntaxOff -\ExplSyntaxOn -\seq_new:N \g__markdown_renderers_seq -\prop_new:N \g__markdown_renderer_arities_prop -\ExplSyntaxOff -\def\markdownRendererAttributeIdentifier{% - \markdownRendererAttributeIdentifierPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { attributeIdentifier } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { attributeIdentifier } - { 1 } -\ExplSyntaxOff -\def\markdownRendererAttributeClassName{% - \markdownRendererAttributeClassNamePrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { attributeClassName } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { attributeClassName } - { 1 } -\ExplSyntaxOff -\def\markdownRendererAttributeKeyValue{% - \markdownRendererAttributeKeyValuePrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { attributeKeyValue } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { attributeKeyValue } - { 2 } -\ExplSyntaxOff -\def\markdownRendererBlockQuoteBegin{% - \markdownRendererBlockQuoteBeginPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { blockQuoteBegin } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { blockQuoteBegin } - { 0 } -\ExplSyntaxOff -\def\markdownRendererBlockQuoteEnd{% - \markdownRendererBlockQuoteEndPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { blockQuoteEnd } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { blockQuoteEnd } - { 0 } -\ExplSyntaxOff -\def\markdownRendererBracketedSpanAttributeContextBegin{% - \markdownRendererBracketedSpanAttributeContextBeginPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { bracketedSpanAttributeContextBegin } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { bracketedSpanAttributeContextBegin } - { 0 } -\ExplSyntaxOff -\def\markdownRendererBracketedSpanAttributeContextEnd{% - \markdownRendererBracketedSpanAttributeContextEndPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { bracketedSpanAttributeContextEnd } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { bracketedSpanAttributeContextEnd } - { 0 } -\ExplSyntaxOff -\def\markdownRendererUlBegin{% - \markdownRendererUlBeginPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { ulBegin } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { ulBegin } - { 0 } -\ExplSyntaxOff -\def\markdownRendererUlBeginTight{% - \markdownRendererUlBeginTightPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { ulBeginTight } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { ulBeginTight } - { 0 } -\ExplSyntaxOff -\def\markdownRendererUlItem{% - \markdownRendererUlItemPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { ulItem } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { ulItem } - { 0 } -\ExplSyntaxOff +\cs_new:Nn + \__markdown_define_option_keyval:nnn + { + \prop_get:cnN + { g__markdown_ #1 _option_types_prop } + { #2 } + \l_tmpa_tl + \str_if_eq:VVTF + \l_tmpa_tl + \c__markdown_option_type_boolean_tl + { + \keys_define:nn + { markdown/options } + { + #3 .code:n = { + \tl_set:Nx + \l_tmpa_tl + { + \str_case:nnF + { ##1 } + { + { yes } { true } + { no } { false } + } + { ##1 } + } + \__markdown_set_option_value:nV + { #2 } + \l_tmpa_tl + }, + #3 .default:n = { true }, + } + } + { + \keys_define:nn + { markdown/options } + { + #3 .code:n = { + \__markdown_set_option_value:nn + { #2 } + { ##1 } + }, + } + } + \str_if_eq:VVT + \l_tmpa_tl + \c__markdown_option_type_clist_tl + { + \tl_set:Nn + \l_tmpa_tl + { #3 } + \tl_reverse:N + \l_tmpa_tl + \str_if_eq:enF + { + \tl_head:V + \l_tmpa_tl + } + { s } + { + \msg_error:nnn + { markdown } + { malformed-name-for-clist-option } + { #3 } + } + \tl_set:Nx + \l_tmpa_tl + { + \tl_tail:V + \l_tmpa_tl + } + \tl_reverse:N + \l_tmpa_tl + \tl_put_right:Nn + \l_tmpa_tl + { + .code:n = { + \__markdown_get_option_value:nN + { #2 } + \l_tmpa_tl + \clist_set:NV + \l_tmpa_clist + { \l_tmpa_tl, { ##1 } } + \__markdown_set_option_value:nV + { #2 } + \l_tmpa_clist + } + } + \keys_define:nV + { markdown/options } + \l_tmpa_tl + } + } +\cs_generate_variant:Nn + \clist_set:Nn + { NV } +\cs_generate_variant:Nn + \keys_define:nn + { nV } +\cs_generate_variant:Nn + \__markdown_set_option_value:nn + { nV } +\prg_generate_conditional_variant:Nnn + \str_if_eq:nn + { en } + { F } +\msg_new:nnn + { markdown } + { malformed-name-for-clist-option } + { + Clist~option~name~#1~does~not~end~with~-s. + } +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_plain_tex_tl + { + \__markdown_define_option_commands_and_keyvals: + } +\keys_define:nn + { markdown/options } + { + theme .code:n = { + \__markdown_set_theme:n + { #1 } + }, + import .code:n = { + \tl_set:Nn + \l_tmpa_tl + { #1 } + \tl_replace_all:NnV + \l_tmpa_tl + { / } + \c_backslash_str + \keys_set:nV + { markdown/options/import } + \l_tmpa_tl + }, + } +\seq_new:N + \g__markdown_themes_seq +\tl_new:N + \g__markdown_current_theme_tl +\tl_gset:Nn + \g__markdown_current_theme_tl + { } +\seq_gput_right:NV + \g__markdown_themes_seq + \g__markdown_current_theme_tl +\cs_new:Nn + \__markdown_set_theme:n + { + \str_if_in:nnF + { #1 } + { / } + { + \msg_error:nnn + { markdown } + { unqualified-theme-name } + { #1 } + } + \str_if_in:nnT + { #1 } + { _ } + { + \msg_error:nnn + { markdown } + { underscores-in-theme-name } + { #1 } + } + \str_set:Nn + \l_tmpa_str + { #1 } + \str_replace_all:Nnn + \l_tmpa_str + { / } + { _ } + \tl_gset:Nn + \g__markdown_current_theme_tl + { #1 / } + \seq_gput_right:NV + \g__markdown_themes_seq + \g__markdown_current_theme_tl + \__markdown_load_theme:nV + { #1 } + \l_tmpa_str + \seq_gpop_right:NN + \g__markdown_themes_seq + \l_tmpa_tl + \seq_get_right:NN + \g__markdown_themes_seq + \l_tmpa_tl + \tl_gset:NV + \g__markdown_current_theme_tl + \l_tmpa_tl + } +\msg_new:nnnn + { markdown } + { unqualified-theme-name } + { Won't~load~theme~with~unqualified~name~#1 } + { Theme~names~must~contain~at~least~one~forward~slash } +\msg_new:nnnn + { markdown } + { underscores-in-theme-name } + { Won't~load~theme~with~an~underscore~in~its~name~#1 } + { Theme~names~must~not~contain~underscores~in~their~names } +\cs_generate_variant:Nn + \tl_replace_all:Nnn + { NnV } +\prop_new:N + \g__markdown_snippets_prop +\cs_new:Nn + \__markdown_setup_snippet:nn + { + \tl_if_empty:nT + { #1 } + { + \msg_error:nnn + { markdown } + { empty-snippet-name } + { #1 } + } + \tl_set:NV + \l_tmpa_tl + \g__markdown_current_theme_tl + \tl_put_right:Nn + \l_tmpa_tl + { #1 } + \__markdown_if_snippet_exists:nT + { #1 } + { + \msg_warning:nnV + { markdown } + { redefined-snippet } + \l_tmpa_tl + } + \prop_gput:NVn + \g__markdown_snippets_prop + \l_tmpa_tl + { #2 } + } +\cs_gset_eq:NN + \markdownSetupSnippet + \__markdown_setup_snippet:nn +\msg_new:nnnn + { markdown } + { empty-snippet-name } + { Empty~snippet~name~#1 } + { Pick~a~non-empty~name~for~your~snippet } +\msg_new:nnn + { markdown } + { redefined-snippet } + { Redefined~snippet~#1 } +\prg_new_conditional:Nnn + \__markdown_if_snippet_exists:n + { TF, T, F } + { + \tl_set:NV + \l_tmpa_tl + \g__markdown_current_theme_tl + \tl_put_right:Nn + \l_tmpa_tl + { #1 } + \prop_get:NVNTF + \g__markdown_snippets_prop + \l_tmpa_tl + \l_tmpb_tl + { \prg_return_true: } + { \prg_return_false: } + } +\cs_gset_eq:NN + \markdownIfSnippetExists + \__markdown_if_snippet_exists:nTF +\keys_define:nn + { markdown/options } + { + snippet .code:n = { + \tl_set:NV + \l_tmpa_tl + \g__markdown_current_theme_tl + \tl_put_right:Nn + \l_tmpa_tl + { #1 } + \__markdown_if_snippet_exists:nTF + { #1 } + { + \prop_get:NVN + \g__markdown_snippets_prop + \l_tmpa_tl + \l_tmpb_tl + \__markdown_setup:V + \l_tmpb_tl + } + { + \msg_error:nnV + { markdown } + { undefined-snippet } + \l_tmpa_tl + } + } + } +\msg_new:nnn + { markdown } + { undefined-snippet } + { Can't~invoke~undefined~snippet~#1 } +\cs_generate_variant:Nn + \__markdown_setup:n + { V } +\tl_new:N + \l__markdown_import_current_theme_tl +\keys_define:nn + { markdown/options/import } + { + unknown .default:n = {}, + unknown .code:n = { + \tl_set_eq:NN + \l__markdown_import_current_theme_tl + \l_keys_key_str + \tl_replace_all:NVn + \l__markdown_import_current_theme_tl + \c_backslash_str + { / } + \clist_map_inline:nn + { #1 } + { + \regex_extract_once:nnNTF + { ^(.*?)\s+as\s+(.*?)$ } + { ##1 } + \l_tmpa_seq + { + \seq_pop:NN + \l_tmpa_seq + \l_tmpa_tl + \seq_pop:NN + \l_tmpa_seq + \l_tmpa_tl + \seq_pop:NN + \l_tmpa_seq + \l_tmpb_tl + } + { + \tl_set:Nn + \l_tmpa_tl + { ##1 } + \tl_set:Nn + \l_tmpb_tl + { ##1 } + } + \tl_put_left:Nn + \l_tmpa_tl + { / } + \tl_put_left:NV + \l_tmpa_tl + \l__markdown_import_current_theme_tl + \__markdown_setup_snippet:Vx + \l_tmpb_tl + { snippet = { \l_tmpa_tl } } + } + \__markdown_set_theme:V + \l__markdown_import_current_theme_tl + }, + } +\cs_generate_variant:Nn + \tl_replace_all:Nnn + { NVn } +\cs_generate_variant:Nn + \__markdown_set_theme:n + { V } +\cs_generate_variant:Nn + \__markdown_setup_snippet:nn + { Vx } +\ExplSyntaxOn +\seq_new:N \g__markdown_renderers_seq +\prop_new:N \g__markdown_renderer_arities_prop +\ExplSyntaxOff +\def\markdownRendererAttributeIdentifier{% + \markdownRendererAttributeIdentifierPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { attributeIdentifier } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { attributeIdentifier } + { 1 } +\ExplSyntaxOff +\def\markdownRendererAttributeClassName{% + \markdownRendererAttributeClassNamePrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { attributeClassName } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { attributeClassName } + { 1 } +\ExplSyntaxOff +\def\markdownRendererAttributeKeyValue{% + \markdownRendererAttributeKeyValuePrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { attributeKeyValue } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { attributeKeyValue } + { 2 } +\ExplSyntaxOff +\def\markdownRendererBlockQuoteBegin{% + \markdownRendererBlockQuoteBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { blockQuoteBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { blockQuoteBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererBlockQuoteEnd{% + \markdownRendererBlockQuoteEndPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { blockQuoteEnd } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { blockQuoteEnd } + { 0 } +\ExplSyntaxOff +\def\markdownRendererBracketedSpanAttributeContextBegin{% + \markdownRendererBracketedSpanAttributeContextBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { bracketedSpanAttributeContextBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { bracketedSpanAttributeContextBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererBracketedSpanAttributeContextEnd{% + \markdownRendererBracketedSpanAttributeContextEndPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { bracketedSpanAttributeContextEnd } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { bracketedSpanAttributeContextEnd } + { 0 } +\ExplSyntaxOff +\def\markdownRendererUlBegin{% + \markdownRendererUlBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { ulBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { ulBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererUlBeginTight{% + \markdownRendererUlBeginTightPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { ulBeginTight } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { ulBeginTight } + { 0 } +\ExplSyntaxOff +\def\markdownRendererUlItem{% + \markdownRendererUlItemPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { ulItem } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { ulItem } + { 0 } +\ExplSyntaxOff \def\markdownRendererUlItemEnd{% \markdownRendererUlItemEndPrototype}% \ExplSyntaxOn @@ -853,6 +1317,28 @@ { ulEndTight } { 0 } \ExplSyntaxOff +\def\markdownRendererCite{% + \markdownRendererCitePrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { cite } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { cite } + { 1 } +\ExplSyntaxOff +\def\markdownRendererTextCite{% + \markdownRendererTextCitePrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { textCite } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { textCite } + { 1 } +\ExplSyntaxOff \def\markdownRendererInputVerbatim{% \markdownRendererInputVerbatimPrototype}% \ExplSyntaxOn @@ -873,7 +1359,7 @@ \prop_gput:Nnn \g__markdown_renderer_arities_prop { inputFencedCode } - { 2 } + { 3 } \ExplSyntaxOff \def\markdownRendererCodeSpan{% \markdownRendererCodeSpanPrototype}% @@ -1205,28 +1691,6 @@ { inlineHtmlComment } { 1 } \ExplSyntaxOff -\def\markdownRendererBlockHtmlCommentBegin{% - \markdownRendererBlockHtmlCommentBeginPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { blockHtmlCommentBegin } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { blockHtmlCommentBegin } - { 0 } -\ExplSyntaxOff -\def\markdownRendererBlockHtmlCommentEnd{% - \markdownRendererBlockHtmlCommentEndPrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { blockHtmlCommentEnd } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { blockHtmlCommentEnd } - { 0 } -\ExplSyntaxOff \def\markdownRendererInlineHtmlTag{% \markdownRendererInlineHtmlTagPrototype}% \ExplSyntaxOn @@ -1293,6 +1757,17 @@ { interblockSeparator } { 0 } \ExplSyntaxOff +\def\markdownRendererParagraphSeparator{% + \markdownRendererParagraphSeparatorPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { paragraphSeparator } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { paragraphSeparator } + { 0 } +\ExplSyntaxOff \def\markdownRendererLineBlockBegin{% \markdownRendererLineBlockBeginPrototype}% \ExplSyntaxOn @@ -1315,43 +1790,20 @@ { lineBlockEnd } { 0 } \ExplSyntaxOff +\def\markdownRendererSoftLineBreak{% + \markdownRendererSoftLineBreakPrototype}% \ExplSyntaxOn -\cs_new:Npn - \markdownRendererHardLineBreak - { - \cs_if_exist:NTF - \markdownRendererLineBreak - { - \markdownWarning - { - Line~break~renderer~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererLineBreak - } - { - \cs_if_exist:NTF - \markdownRendererLineBreakPrototype - { - \markdownWarning - { - Line~break~renderer~prototype~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererLineBreakPrototype - } - { - \markdownRendererHardLineBreakPrototype - } - } - } \seq_gput_right:Nn \g__markdown_renderers_seq - { lineBreak } + { softLineBreak } \prop_gput:Nnn \g__markdown_renderer_arities_prop - { lineBreak } + { softLineBreak } { 0 } +\ExplSyntaxOff +\def\markdownRendererHardLineBreak{% + \markdownRendererHardLineBreakPrototype}% +\ExplSyntaxOn \seq_gput_right:Nn \g__markdown_renderers_seq { hardLineBreak } @@ -1393,6 +1845,17 @@ { linkAttributeContextEnd } { 0 } \ExplSyntaxOff +\def\markdownRendererMark{% + \markdownRendererMarkPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { mark } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { mark } + { 1 } +\ExplSyntaxOff \def\markdownRendererDocumentBegin{% \markdownRendererDocumentBeginPrototype}% \ExplSyntaxOn @@ -1426,43 +1889,9 @@ { nbsp } { 0 } \ExplSyntaxOff +\def\markdownRendererNote{% + \markdownRendererNotePrototype}% \ExplSyntaxOn -\cs_new:Npn - \markdownRendererNote - { - \cs_if_exist:NTF - \markdownRendererFootnote - { - \markdownWarning - { - Footnote~renderer~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererFootnote - } - { - \cs_if_exist:NTF - \markdownRendererFootnotePrototype - { - \markdownWarning - { - Footnote~renderer~prototype~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererFootnotePrototype - } - { - \markdownRendererNotePrototype - } - } - } -\seq_gput_right:Nn - \g__markdown_renderers_seq - { footnote } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { footnote } - { 1 } \seq_gput_right:Nn \g__markdown_renderers_seq { note } @@ -1625,17 +2054,6 @@ { fancyOlEndTight } { 0 } \ExplSyntaxOff -\def\markdownRendererCite{% - \markdownRendererCitePrototype}% -\ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { cite } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { cite } - { 1 } -\ExplSyntaxOff \def\markdownRendererInputRawInline{% \markdownRendererInputRawInlinePrototype}% \ExplSyntaxOn @@ -1844,6 +2262,28 @@ { superscript } { 1 } \ExplSyntaxOff +\def\markdownRendererTableAttributeContextBegin{% + \markdownRendererTableAttributeContextBeginPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { tableAttributeContextBegin } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { tableAttributeContextBegin } + { 0 } +\ExplSyntaxOff +\def\markdownRendererTableAttributeContextEnd{% + \markdownRendererTableAttributeContextEndPrototype}% +\ExplSyntaxOn +\seq_gput_right:Nn + \g__markdown_renderers_seq + { tableAttributeContextEnd } +\prop_gput:Nnn + \g__markdown_renderer_arities_prop + { tableAttributeContextEnd } + { 0 } +\ExplSyntaxOff \def\markdownRendererTable{% \markdownRendererTablePrototype}% \ExplSyntaxOn @@ -1877,54 +2317,9 @@ { displayMath } { 1 } \ExplSyntaxOff -\def\markdownRendererTextCite{% - \markdownRendererTextCitePrototype}% +\def\markdownRendererThematicBreak{% + \markdownRendererThematicBreakPrototype}% \ExplSyntaxOn -\seq_gput_right:Nn - \g__markdown_renderers_seq - { textCite } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { textCite } - { 1 } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Npn - \markdownRendererThematicBreak - { - \cs_if_exist:NTF - \markdownRendererHorizontalRule - { - \markdownWarning - { - Horizontal~rule~renderer~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererHorizontalRule - } - { - \cs_if_exist:NTF - \markdownRendererHorizontalRulePrototype - { - \markdownWarning - { - Horizontal~rule~renderer~prototype~has~been~deprecated,~ - to~be~removed~in~Markdown~3.0.0 - } - \markdownRendererHorizontalRulePrototype - } - { - \markdownRendererThematicBreakPrototype - } - } - } -\seq_gput_right:Nn - \g__markdown_renderers_seq - { horizontalRule } -\prop_gput:Nnn - \g__markdown_renderer_arities_prop - { horizontalRule } - { 0 } \seq_gput_right:Nn \g__markdown_renderers_seq { thematicBreak } @@ -2075,28 +2470,263 @@ \g__markdown_renderer_arities_prop { jekyllDataEmpty } { 1 } -\ExplSyntaxOff -\ExplSyntaxOn +\cs_new:Nn \__markdown_define_renderers: + { + \seq_map_function:NN + \g__markdown_renderers_seq + \__markdown_define_renderer:n + } +\cs_new:Nn \__markdown_define_renderer:n + { + \__markdown_renderer_tl_to_csname:nN + { #1 } + \l_tmpa_tl + \prop_get:NnN + \g__markdown_renderer_arities_prop + { #1 } + \l_tmpb_tl + \__markdown_define_renderer:ncV + { #1 } + { \l_tmpa_tl } + \l_tmpb_tl + } +\cs_new:Nn \__markdown_renderer_tl_to_csname:nN + { + \tl_set:Nn + \l_tmpa_tl + { \str_uppercase:n { #1 } } + \tl_set:Nx + #2 + { + markdownRenderer + \tl_head:f { \l_tmpa_tl } + \tl_tail:n { #1 } + } + } +\tl_new:N + \l__markdown_renderer_definition_tl +\cs_new:Nn \__markdown_define_renderer:nNn + { + \keys_define:nn + { markdown/options/renderers } + { + #1 .code:n = { + \tl_set:Nn + \l__markdown_renderer_definition_tl + { ##1 } + \regex_replace_all:nnN + { \cP\#0 } + { #1 } + \l__markdown_renderer_definition_tl + \cs_generate_from_arg_count:NNnV + #2 + \cs_set:Npn + { #3 } + \l__markdown_renderer_definition_tl + }, + } + } +\cs_generate_variant:Nn + \__markdown_define_renderer:nNn + { ncV } +\cs_generate_variant:Nn + \cs_generate_from_arg_count:NNnn + { NNnV } +\keys_define:nn + { markdown/options } + { + renderers .code:n = { + \keys_set:nn + { markdown/options/renderers } + { #1 } + }, + } +\prop_new:N + \g__markdown_glob_cache_prop +\tl_new:N + \l__markdown_current_glob_tl +\cs_new:Nn + \__markdown_glob_seq:nnN + { + \tl_set:Nn + \l__markdown_current_glob_tl + { ^ #1 $ } + \prop_get:NeNTF + \g__markdown_glob_cache_prop + { #2 / \l__markdown_current_glob_tl } + \l_tmpa_clist + { + \seq_set_from_clist:NN + #3 + \l_tmpa_clist + } + { + \seq_clear:N + #3 + \regex_replace_all:nnN + { \* } + { .* } + \l__markdown_current_glob_tl + \regex_set:NV + \l_tmpa_regex + \l__markdown_current_glob_tl + \seq_map_inline:cn + { #2 } + { + \regex_match:NnT + \l_tmpa_regex + { ##1 } + { + \seq_put_right:Nn + #3 + { ##1 } + } + } + \clist_set_from_seq:NN + \l_tmpa_clist + #3 + \prop_gput:NeV + \g__markdown_glob_cache_prop + { #2 / \l__markdown_current_glob_tl } + \l_tmpa_clist + } + } +\prg_generate_conditional_variant:Nnn + \prop_get:NnN + { NeN } + { TF } +\cs_generate_variant:Nn + \regex_set:Nn + { NV } +\cs_generate_variant:Nn + \prop_gput:Nnn + { NeV } +\seq_new:N + \l__markdown_renderer_glob_results_seq +\keys_define:nn + { markdown/options/renderers } + { + unknown .code:n = { + \__markdown_glob_seq:VnN + \l_keys_key_str + { g__markdown_renderers_seq } + \l__markdown_renderer_glob_results_seq + \seq_if_empty:NTF + \l__markdown_renderer_glob_results_seq + { + \msg_error:nnV + { markdown } + { undefined-renderer } + \l_keys_key_str + } + { + \tl_set:Nn + \l__markdown_renderer_definition_tl + { #1 } + \seq_map_inline:Nn + \l__markdown_renderer_glob_results_seq + { + \__markdown_renderer_tl_to_csname:nN + { ##1 } + \l_tmpa_tl + \prop_get:NnN + \g__markdown_renderer_arities_prop + { ##1 } + \l_tmpb_tl + \int_set:Nn + \l_tmpa_int + \l_tmpb_tl + \tl_set:NV + \l_tmpb_tl + \l__markdown_renderer_definition_tl + \regex_replace_all:nnN + { \cP\#0 } + { ##1 } + \l_tmpb_tl + \cs_generate_from_arg_count:cNVV + { \l_tmpa_tl } + \cs_set:Npn + \l_tmpa_int + \l_tmpb_tl + } + } + }, + } +\msg_new:nnn + { markdown } + { undefined-renderer } + { + Renderer~#1~is~undefined. + } +\cs_generate_variant:Nn + \__markdown_glob_seq:nnN + { VnN } +\cs_generate_variant:Nn + \cs_generate_from_arg_count:NNnn + { cNVV } +\cs_generate_variant:Nn + \msg_error:nnn + { nnV } +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_plain_tex_tl + { + \__markdown_define_renderers: + } \keys_define:nn { markdown/jekyllData } { } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Nn \__markdown_plaintex_define_renderer_prototypes: +\__markdown_with_various_cases:nn + { jekyllDataRenderers } + { + \keys_define:nn + { markdown/options } + { + #1 .code:n = { + \tl_set:Nn + \l_tmpa_tl + { ##1 } + \tl_replace_all:NnV + \l_tmpa_tl + { / } + \c_backslash_str + \keys_set:nV + { markdown/options/jekyll-data-renderers } + \l_tmpa_tl + }, + } + } +\keys_define:nn + { markdown/options/jekyll-data-renderers } + { + unknown .code:n = { + \tl_set_eq:NN + \l_tmpa_tl + \l_keys_key_str + \tl_replace_all:NVn + \l_tmpa_tl + \c_backslash_str + { / } + \tl_put_right:Nn + \l_tmpa_tl + { + .code:n = { #1 } + } + \keys_define:nV + { markdown/jekyllData } + \l_tmpa_tl + } + } +\cs_generate_variant:Nn + \keys_define:nn + { nV } +\cs_new:Nn \__markdown_define_renderer_prototypes: { \seq_map_function:NN \g__markdown_renderers_seq - \__markdown_plaintex_define_renderer_prototype:n - \let\markdownRendererBlockHtmlCommentBeginPrototype=\iffalse - \let\markdownRendererBlockHtmlCommentBegin=\iffalse - \let\markdownRendererBlockHtmlCommentEndPrototype=\fi - \let\markdownRendererBlockHtmlCommentEnd=\fi - \cs_undefine:N \markdownRendererFootnote - \cs_undefine:N \markdownRendererFootnotePrototype - \cs_undefine:N \markdownRendererHorizontalRule - \cs_undefine:N \markdownRendererHorizontalRulePrototype - } -\cs_new:Nn \__markdown_plaintex_define_renderer_prototype:n + \__markdown_define_renderer_prototype:n + } +\cs_new:Nn \__markdown_define_renderer_prototype:n { \__markdown_renderer_prototype_tl_to_csname:nN { #1 } @@ -2105,7 +2735,8 @@ \g__markdown_renderer_arities_prop { #1 } \l_tmpb_tl - \__markdown_plaintex_define_renderer_prototype:cV + \__markdown_define_renderer_prototype:ncV + { #1 } { \l_tmpa_tl } \l_tmpb_tl } @@ -2123,18 +2754,117 @@ Prototype } } -\cs_new:Nn \__markdown_plaintex_define_renderer_prototype:Nn +\tl_new:N + \l__markdown_renderer_prototype_definition_tl +\cs_new:Nn \__markdown_define_renderer_prototype:nNn { - \cs_generate_from_arg_count:NNnn - #1 - \cs_set:Npn - { #2 } - { } + \keys_define:nn + { markdown/options/renderer-prototypes } + { + #1 .code:n = { + \tl_set:Nn + \l__markdown_renderer_prototype_definition_tl + { ##1 } + \regex_replace_all:nnN + { \cP\#0 } + { #1 } + \l__markdown_renderer_prototype_definition_tl + \cs_generate_from_arg_count:NNnV + #2 + \cs_set:Npn + { #3 } + \l__markdown_renderer_prototype_definition_tl + }, + } + \cs_if_free:NT + #2 + { + \cs_generate_from_arg_count:NNnn + #2 + \cs_set:Npn + { #3 } + { } + } } \cs_generate_variant:Nn - \__markdown_plaintex_define_renderer_prototype:Nn - { cV } -\__markdown_plaintex_define_renderer_prototypes: + \__markdown_define_renderer_prototype:nNn + { ncV } +\seq_new:N + \l__markdown_renderer_prototype_glob_results_seq +\keys_define:nn + { markdown/options/renderer-prototypes } + { + unknown .code:n = { + \__markdown_glob_seq:VnN + \l_keys_key_str + { g__markdown_renderers_seq } + \l__markdown_renderer_prototype_glob_results_seq + \seq_if_empty:NTF + \l__markdown_renderer_prototype_glob_results_seq + { + \msg_error:nnV + { markdown } + { undefined-renderer-prototype } + \l_keys_key_str + } + { + \tl_set:Nn + \l__markdown_renderer_prototype_definition_tl + { #1 } + \seq_map_inline:Nn + \l__markdown_renderer_prototype_glob_results_seq + { + \__markdown_renderer_prototype_tl_to_csname:nN + { ##1 } + \l_tmpa_tl + \prop_get:NnN + \g__markdown_renderer_arities_prop + { ##1 } + \l_tmpb_tl + \int_set:Nn + \l_tmpa_int + \l_tmpb_tl + \tl_set:NV + \l_tmpb_tl + \l__markdown_renderer_prototype_definition_tl + \regex_replace_all:nnN + { \cP\#0 } + { ##1 } + \l_tmpb_tl + \cs_generate_from_arg_count:cNVV + { \l_tmpa_tl } + \cs_set:Npn + \l_tmpa_int + \l_tmpb_tl + } + } + }, + } +\msg_new:nnn + { markdown } + { undefined-renderer-prototype } + { + Renderer~prototype~#1~is~undefined. + } +\__markdown_with_various_cases:nn + { rendererPrototypes } + { + \keys_define:nn + { markdown/options } + { + #1 .code:n = { + \keys_set:nn + { markdown/options/renderer-prototypes } + { ##1 } + }, + } + } +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_plain_tex_tl + { + \__markdown_define_renderer_prototypes: + } \ExplSyntaxOff \let\markdownMakeOther\relax \let\markdownReadAndConvert\relax @@ -2145,326 +2875,160 @@ {|markdownEnd}}% |endgroup \ExplSyntaxOn -\cs_if_exist:NF - \markdownMode - { - \file_if_exist:nTF - { lt3luabridge.tex } - { - \cs_new:Npn - \markdownMode - { 3 } - } - { - \cs_if_exist:NTF - \directlua - { - \cs_new:Npn - \markdownMode - { 2 } - } - { - \cs_new:Npn - \markdownMode - { 0 } - } - } - } -\ExplSyntaxOff -\def\markdownLuaRegisterIBCallback#1{\relax}% -\def\markdownLuaUnregisterIBCallback#1{\relax}% -\ifx\markdownInfo\undefined - \def\markdownInfo#1{% - \immediate\write-1{(l.\the\inputlineno) markdown.tex info: #1.}}% -\fi -\ifx\markdownWarning\undefined - \def\markdownWarning#1{% - \immediate\write16{(l.\the\inputlineno) markdown.tex warning: #1}}% -\fi -\ifx\markdownError\undefined - \def\markdownError#1#2{% - \errhelp{#2.}% - \errmessage{(l.\the\inputlineno) markdown.tex error: #1}}% -\fi -\def\markdownRendererInterblockSeparatorPrototype{\par}% -\def\markdownRendererHardLineBreakPrototype{\hfil\break}% -\let\markdownRendererEllipsisPrototype\dots -\def\markdownRendererNbspPrototype{~}% -\def\markdownRendererLeftBracePrototype{\char`\{}% -\def\markdownRendererRightBracePrototype{\char`\}}% -\def\markdownRendererDollarSignPrototype{\char`$}% -\def\markdownRendererPercentSignPrototype{\char`\%}% -\def\markdownRendererAmpersandPrototype{\&}% -\def\markdownRendererUnderscorePrototype{\char`_}% -\def\markdownRendererHashPrototype{\char`\#}% -\def\markdownRendererCircumflexPrototype{\char`^}% -\def\markdownRendererBackslashPrototype{\char`\\}% -\def\markdownRendererTildePrototype{\char`~}% -\def\markdownRendererPipePrototype{|}% -\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% -\def\markdownRendererLinkPrototype#1#2#3#4{#2}% -\def\markdownRendererContentBlockPrototype#1#2#3#4{% - \markdownInput{#3}}% -\def\markdownRendererContentBlockOnlineImagePrototype{% - \markdownRendererImage}% -\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{% - \markdownRendererInputFencedCode{#3}{#2}}% -\def\markdownRendererImagePrototype#1#2#3#4{#2}% -\def\markdownRendererUlBeginPrototype{}% -\def\markdownRendererUlBeginTightPrototype{}% -\def\markdownRendererUlItemPrototype{}% -\def\markdownRendererUlItemEndPrototype{}% -\def\markdownRendererUlEndPrototype{}% -\def\markdownRendererUlEndTightPrototype{}% -\def\markdownRendererOlBeginPrototype{}% -\def\markdownRendererOlBeginTightPrototype{}% -\def\markdownRendererFancyOlBeginPrototype#1#2{\markdownRendererOlBegin}% -\def\markdownRendererFancyOlBeginTightPrototype#1#2{\markdownRendererOlBeginTight}% -\def\markdownRendererOlItemPrototype{}% -\def\markdownRendererOlItemWithNumberPrototype#1{}% -\def\markdownRendererOlItemEndPrototype{}% -\def\markdownRendererFancyOlItemPrototype{\markdownRendererOlItem}% -\def\markdownRendererFancyOlItemWithNumberPrototype{\markdownRendererOlItemWithNumber}% -\def\markdownRendererFancyOlItemEndPrototype{}% -\def\markdownRendererOlEndPrototype{}% -\def\markdownRendererOlEndTightPrototype{}% -\def\markdownRendererFancyOlEndPrototype{\markdownRendererOlEnd}% -\def\markdownRendererFancyOlEndTightPrototype{\markdownRendererOlEndTight}% -\def\markdownRendererDlBeginPrototype{}% -\def\markdownRendererDlBeginTightPrototype{}% -\def\markdownRendererDlItemPrototype#1{#1}% -\def\markdownRendererDlItemEndPrototype{}% -\def\markdownRendererDlDefinitionBeginPrototype{}% -\def\markdownRendererDlDefinitionEndPrototype{\par}% -\def\markdownRendererDlEndPrototype{}% -\def\markdownRendererDlEndTightPrototype{}% -\def\markdownRendererEmphasisPrototype#1{{\it#1}}% -\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% -\def\markdownRendererBlockQuoteBeginPrototype{\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{% - \markdownRendererInputVerbatim{#1}}% -\def\markdownRendererHeadingOnePrototype#1{#1}% -\def\markdownRendererHeadingTwoPrototype#1{#1}% -\def\markdownRendererHeadingThreePrototype#1{#1}% -\def\markdownRendererHeadingFourPrototype#1{#1}% -\def\markdownRendererHeadingFivePrototype#1{#1}% -\def\markdownRendererHeadingSixPrototype#1{#1}% -\def\markdownRendererThematicBreakPrototype{}% -\def\markdownRendererNotePrototype#1{#1}% -\def\markdownRendererCitePrototype#1{}% -\def\markdownRendererTextCitePrototype#1{}% -\def\markdownRendererTickedBoxPrototype{[X]}% -\def\markdownRendererHalfTickedBoxPrototype{[/]}% -\def\markdownRendererUntickedBoxPrototype{[ ]}% -\def\markdownRendererStrikeThroughPrototype#1{#1}% -\def\markdownRendererSuperscriptPrototype#1{#1}% -\def\markdownRendererSubscriptPrototype#1{#1}% -\def\markdownRendererDisplayMathPrototype#1{$$#1$$}% -\def\markdownRendererInlineMathPrototype#1{$#1$}% -\ExplSyntaxOn -\cs_gset:Npn - \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 +\keys_define:nn + { markdown/options } { - % TODO: Replace with `\codepoint_generate:nn` in TeX Live 2023 - \sys_if_engine_pdftex:TF - { ^^ef^^bf^^bd } - { ^^^^fffd } + code .code:n = { #1 }, } -\ExplSyntaxOff -\def\markdownRendererSectionBeginPrototype{}% -\def\markdownRendererSectionEndPrototype{}% -\ExplSyntaxOn -\cs_new:Nn - \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn +\cs_if_free:NT + \markdownInfo { - \str_case:nn - { #2 } + \cs_new:Npn + \markdownInfo #1 { - { md } { \markdownInput{#1} } - { tex } { \markdownEscape{#1} \unskip } + \msg_info:nne + { markdown } + { generic-message } + { #1 } } } -\cs_new:Nn - \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn +\cs_if_free:NT + \markdownWarning { - \str_case:nn - { #2 } + \cs_new:Npn + \markdownWarning #1 { - { md } { \markdownInput{#1} } - { tex } { \markdownEscape{#1} } + \msg_warning:nne + { markdown } + { generic-message } + { #1 } } } -\cs_gset:Npn - \markdownRendererInputRawInlinePrototype#1#2 +\cs_if_free:NT + \markdownError { - \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn - { #1 } - { #2 } + \cs_new:Npn + \markdownError #1 #2 + { + \msg_error:nnee + { markdown } + { generic-message-with-help-text } + { #1 } + { #2 } + } } -\cs_gset:Npn - \markdownRendererInputRawBlockPrototype#1#2 +\msg_new:nnn + { markdown } + { generic-message } + { #1 } +\msg_new:nnnn + { markdown } + { generic-message-with-help-text } + { #1 } + { #2 } +\cs_generate_variant:Nn + \msg_info:nnn + { nne } +\cs_generate_variant:Nn + \msg_warning:nnn + { nne } +\cs_generate_variant:Nn + \msg_error:nnnn + { nnee } +\prop_new:N \g__markdown_plain_tex_loaded_themes_linenos_prop +\cs_new:Nn + \__markdown_plain_tex_load_theme:nn { - \__markdown_plain_tex_default_input_raw_block_renderer_prototype:nn + \prop_get:NnNTF + \g__markdown_plain_tex_loaded_themes_linenos_prop { #1 } - { #2 } - } -\ExplSyntaxOff -\ExplSyntaxOn -\seq_new:N \g__markdown_jekyll_data_datatypes_seq -\tl_const:Nn \c__markdown_jekyll_data_sequence_tl { sequence } -\tl_const:Nn \c__markdown_jekyll_data_mapping_tl { mapping } -\tl_const:Nn \c__markdown_jekyll_data_scalar_tl { scalar } -\seq_new:N \g__markdown_jekyll_data_wildcard_absolute_address_seq -\cs_new:Nn \markdown_jekyll_data_push_address_segment:n - { - \seq_if_empty:NF - \g__markdown_jekyll_data_datatypes_seq + \l_tmpa_tl { - \seq_get_right:NN - \g__markdown_jekyll_data_datatypes_seq + \msg_warning:nnnV + { markdown } + { repeatedly-loaded-plain-tex-theme } + { #1 } \l_tmpa_tl - \str_if_eq:NNTF - \l_tmpa_tl - \c__markdown_jekyll_data_sequence_tl - { - \seq_put_right:Nn - \g__markdown_jekyll_data_wildcard_absolute_address_seq - { * } - } - { - \seq_put_right:Nn - \g__markdown_jekyll_data_wildcard_absolute_address_seq - { #1 } - } + } + { + \msg_info:nnn + { markdown } + { loading-plain-tex-theme } + { #1 } + \prop_gput:Nnx + \g__markdown_plain_tex_loaded_themes_linenos_prop + { #1 } + { \tex_the:D \tex_inputlineno:D } + \file_input:n + { markdown theme #2 } } } -\tl_new:N \g__markdown_jekyll_data_wildcard_absolute_address_tl -\tl_new:N \g__markdown_jekyll_data_wildcard_relative_address_tl -\cs_new:Nn \markdown_jekyll_data_concatenate_address:NN - { - \seq_pop_left:NN #1 \l_tmpa_tl - \tl_set:Nx #2 { / \seq_use:Nn #1 { / } } - \seq_put_left:NV #1 \l_tmpa_tl - } -\cs_new:Nn \markdown_jekyll_data_update_address_tls: - { - \markdown_jekyll_data_concatenate_address:NN - \g__markdown_jekyll_data_wildcard_absolute_address_seq - \g__markdown_jekyll_data_wildcard_absolute_address_tl - \seq_get_right:NN - \g__markdown_jekyll_data_wildcard_absolute_address_seq - \g__markdown_jekyll_data_wildcard_relative_address_tl - } -\cs_new:Nn \markdown_jekyll_data_push:nN +\msg_new:nnn + { markdown } + { loading-plain-tex-theme } + { Loading~plain~TeX~Markdown~theme~#1 } +\msg_new:nnn + { markdown } + { repeatedly-loaded-plain-tex-theme } { - \markdown_jekyll_data_push_address_segment:n - { #1 } - \seq_put_right:NV - \g__markdown_jekyll_data_datatypes_seq - #2 - \markdown_jekyll_data_update_address_tls: + Plain~TeX~Markdown~theme~#1~was~previously~ + loaded~on~line~#2,~not~loading~it~again } -\cs_new:Nn \markdown_jekyll_data_pop: +\cs_generate_variant:Nn + \prop_gput:Nnn + { Nnx } +\cs_gset_eq:NN + \__markdown_load_theme:nn + \__markdown_plain_tex_load_theme:nn +\cs_generate_variant:Nn + \__markdown_load_theme:nn + { nV } +\cs_new:Npn + \markdownLoadPlainTeXTheme { - \seq_pop_right:NN - \g__markdown_jekyll_data_wildcard_absolute_address_seq + \tl_set:NV \l_tmpa_tl - \seq_pop_right:NN - \g__markdown_jekyll_data_datatypes_seq + \g__markdown_current_theme_tl + \tl_reverse:N \l_tmpa_tl - \markdown_jekyll_data_update_address_tls: - } -\cs_new:Nn \markdown_jekyll_data_set_keyval:nn - { - \keys_set_known:nn - { markdown/jekyllData } - { { #1 } = { #2 } } + \tl_set:Ne + \l_tmpb_tl + { + \tl_tail:V + \l_tmpa_tl + } + \tl_reverse:N + \l_tmpb_tl + \str_set:NV + \l_tmpa_str + \l_tmpb_tl + \str_replace_all:Nnn + \l_tmpa_str + { / } + { _ } + \__markdown_plain_tex_load_theme:VV + \l_tmpb_tl + \l_tmpa_str } \cs_generate_variant:Nn - \markdown_jekyll_data_set_keyval:nn - { Vn } -\cs_new:Nn \markdown_jekyll_data_set_keyvals:nn + \tl_set:Nn + { Ne } +\cs_generate_variant:Nn + \__markdown_plain_tex_load_theme:nn + { VV } +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_plain_tex_tl { - \markdown_jekyll_data_push:nN - { #1 } - \c__markdown_jekyll_data_scalar_tl - \markdown_jekyll_data_set_keyval:Vn - \g__markdown_jekyll_data_wildcard_absolute_address_tl - { #2 } - \markdown_jekyll_data_set_keyval:Vn - \g__markdown_jekyll_data_wildcard_relative_address_tl - { #2 } - \markdown_jekyll_data_pop: - } -\def\markdownRendererJekyllDataSequenceBeginPrototype#1#2{ - \markdown_jekyll_data_push:nN - { #1 } - \c__markdown_jekyll_data_sequence_tl -} -\def\markdownRendererJekyllDataMappingBeginPrototype#1#2{ - \markdown_jekyll_data_push:nN - { #1 } - \c__markdown_jekyll_data_mapping_tl -} -\def\markdownRendererJekyllDataSequenceEndPrototype{ - \markdown_jekyll_data_pop: -} -\def\markdownRendererJekyllDataMappingEndPrototype{ - \markdown_jekyll_data_pop: -} -\def\markdownRendererJekyllDataBooleanPrototype#1#2{ - \markdown_jekyll_data_set_keyvals:nn - { #1 } - { #2 } -} -\def\markdownRendererJekyllDataEmptyPrototype#1{} -\def\markdownRendererJekyllDataNumberPrototype#1#2{ - \markdown_jekyll_data_set_keyvals:nn - { #1 } - { #2 } -} -\def\markdownRendererJekyllDataStringPrototype#1#2{ - \markdown_jekyll_data_set_keyvals:nn - { #1 } - { #2 } -} -\ExplSyntaxOff -\ExplSyntaxOn + \ExplSyntaxOff + \__markdown_if_option:nF + { noDefaults } + { + \__markdown_setup:n + {theme = witiko/markdown/defaults} + } + \ExplSyntaxOn + } \tl_new:N \g__markdown_formatted_lua_options_tl \cs_new:Nn \__markdown_format_lua_options: { @@ -2550,42 +3114,9 @@ local md = require("markdown") local convert = md.new(\markdownLuaOptions) }% -\ExplSyntaxOn -\prg_new_conditional:Nnn - \__markdown_if_option:n - { TF, T, F } - { - \__markdown_get_option_type:nN - { #1 } - \l_tmpa_tl - \str_if_eq:NNF - \l_tmpa_tl - \c__markdown_option_type_boolean_tl - { - \msg_error:nnxx - { markdown } - { expected-boolean-option } - { #1 } - { \l_tmpa_tl } - } - \__markdown_get_option_value:nN - { #1 } - \l_tmpa_tl - \str_if_eq:NNTF - \l_tmpa_tl - \c__markdown_option_value_true_tl - { \prg_return_true: } - { \prg_return_false: } - } -\msg_new:nnn - { markdown } - { expected-boolean-option } - { - Option~#1~has~type~#2,~ - but~a~boolean~was~expected. - } -\let\markdownIfOption=\__markdown_if_option:nTF -\ExplSyntaxOff +\def\markdownCleanup{% + lfs.rmdir(cacheDir) +}% \csname newread\endcsname\markdownInputFileStream \csname newwrite\endcsname\markdownOutputFileStream \begingroup @@ -2656,118 +3187,54 @@ ^^M}@ |endgroup \ExplSyntaxOn -\int_compare:nT - { \markdownMode = 3 } +\cs_new:Npn + \markdownLuaExecute + #1 { - \markdownInfo{Using~mode~3:~The~lt3luabridge~package} - \file_input:n { lt3luabridge.tex } - \cs_new:Npn - \markdownLuaExecute - { \luabridgeExecute } + \int_compare:nNnT + { \g_luabridge_method_int } + = + { \c_luabridge_method_shell_int } + { + \sys_if_shell_unrestricted:F + { + \sys_if_shell:TF + { + \msg_error:nn + { markdown } + { restricted-shell-access } + } + { + \msg_error:nn + { markdown } + { disabled-shell-access } + } + } + } + \luabridge_now:e + { #1 } + } +\cs_generate_variant:Nn + \msg_new:nnnn + { nnnV } +\tl_set:Nn + \l_tmpa_tl + { + You~may~need~to~run~TeX~with~the~--shell-escape~or~the~ + --enable-write18~flag,~or~write~shell_escape=t~in~the~ + texmf.cnf~file. } +\msg_new:nnnV + { markdown } + { restricted-shell-access } + { Shell~escape~is~restricted } + \l_tmpa_tl +\msg_new:nnnV + { markdown } + { disabled-shell-access } + { Shell~escape~is~disabled } + \l_tmpa_tl \ExplSyntaxOff -\ifnum\markdownMode<2\relax -\ifnum\markdownMode=0\relax - \markdownWarning{Using mode 0: Shell escape via write18 - (deprecated, to be removed in Markdown 3.0.0)}% -\else - \markdownWarning{Using mode 1: Shell escape via os.execute - (deprecated, to be removed in Markdown 3.0.0)}% -\fi -\ifx\pdfshellescape\undefined - \ifx\shellescape\undefined - \ifnum\markdownMode=0\relax - \def\markdownExecuteShellEscape{1}% - \else - \def\markdownExecuteShellEscape{% - \directlua{tex.sprint(status.shell_escape or "1")}}% - \fi - \else - \let\markdownExecuteShellEscape\shellescape - \fi -\else - \let\markdownExecuteShellEscape\pdfshellescape -\fi -\ifnum\markdownMode=0\relax - \def\markdownExecuteDirect#1{\immediate\write18{#1}}% -\else - \def\markdownExecuteDirect#1{% - \directlua{os.execute("\luaescapestring{#1}")}}% -\fi -\def\markdownExecute#1{% - \ifnum\markdownExecuteShellEscape=1\relax - \markdownExecuteDirect{#1}% - \else - \markdownError{I can not access the shell}{Either run the TeX - compiler with the --shell-escape or the --enable-write18 flag, - or set shell_escape=t in the texmf.cnf file}% - \fi}% -\begingroup - \catcode`|=0% - \catcode`\\=12% - |gdef|markdownLuaExecute#1{% - |immediate|openout|markdownOutputFileStream=% - |markdownOptionHelperScriptFileName - |markdownInfo{Writing a helper Lua script to the file - "|markdownOptionHelperScriptFileName"}% - |immediate|write|markdownOutputFileStream{% - local ran_ok, error = pcall(function() - local kpse - (function() - local should_initialize = package.loaded.kpse == nil - or tex.initialize - local ran_ok - ran_ok, kpse = pcall(require, "kpse") - if ran_ok and should_initialize then - kpse.set_program_name("luatex") - end - end)() - #1 - end) - if not ran_ok then - local file = io.open("% - |markdownOptionOutputDir - /|markdownOptionErrorTempFileName", "w") - if file then - file:write(error .. "\n") - file:close() - end - print('\\markdownError{An error was encountered while executing - Lua code}{For further clues, examine the file - "|markdownOptionOutputDir - /|markdownOptionErrorTempFileName"}') - end}% - |immediate|closeout|markdownOutputFileStream - |markdownInfo{Executing a helper Lua script from the file - "|markdownOptionHelperScriptFileName" and storing the result in the - file "|markdownOptionOutputTempFileName"}% - |markdownExecute{texlua "|markdownOptionOutputDir - /|markdownOptionHelperScriptFileName" > % - "|markdownOptionOutputDir - /|markdownOptionOutputTempFileName"}% - |input|markdownOptionOutputTempFileName|relax}% -|endgroup -\fi -\ifnum\markdownMode=2\relax - \markdownWarning{Using mode 2: Direct Lua access - (deprecated, to be removed in Markdown 3.0.0)}% -\begingroup - \catcode`|=0% - \catcode`\\=12% - |gdef|markdownLuaExecute#1{% - |directlua{% - local function print(input) - local output = {} - for line in input:gmatch("[^\r\n]+") do - table.insert(output, line) - end - tex.print(output) - end - #1 - }% - }% -|endgroup -\fi \begingroup \catcode`|=0% \catcode`\\=12% @@ -2797,8 +3264,10 @@ [[Could not open file "&1" for reading]]) local input = assert(file:read("*a")) assert(file:close()) - print(convert(input))}% - |global|advance|markdownOptionFrozenCacheCounter by 1|relax + print(convert(input)) + |markdownCleanup}% + |markdownIfOption{finalizeCache}{% + |global|advance|markdownOptionFrozenCacheCounter by 1|relax}{}% }% |endgroup }% diff --git a/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_markdown_defaults.tex b/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_markdown_defaults.tex new file mode 100644 index 00000000000..dc8a90917f6 --- /dev/null +++ b/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_markdown_defaults.tex @@ -0,0 +1,321 @@ +%% +%% This is file `markdownthemewitiko_markdown_defaults.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `themes-witiko-markdown-defaults-tex') +%% +%% Copyright (C) 2016-2024 Vít Starý Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Starý Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\def\markdownRendererInterblockSeparatorPrototype{\par}% +\def\markdownRendererParagraphSeparatorPrototype{% + \markdownRendererInterblockSeparator}% +\def\markdownRendererHardLineBreakPrototype{\hfil\break}% +\def\markdownRendererSoftLineBreakPrototype{ }% +\let\markdownRendererEllipsisPrototype\dots +\def\markdownRendererNbspPrototype{~}% +\def\markdownRendererLeftBracePrototype{\char`\{}% +\def\markdownRendererRightBracePrototype{\char`\}}% +\def\markdownRendererDollarSignPrototype{\char`$}% +\def\markdownRendererPercentSignPrototype{\char`\%}% +\def\markdownRendererAmpersandPrototype{\&}% +\def\markdownRendererUnderscorePrototype{\char`_}% +\def\markdownRendererHashPrototype{\char`\#}% +\def\markdownRendererCircumflexPrototype{\char`^}% +\def\markdownRendererBackslashPrototype{\char`\\}% +\def\markdownRendererTildePrototype{\char`~}% +\def\markdownRendererPipePrototype{|}% +\def\markdownRendererCodeSpanPrototype#1{{\tt#1}}% +\def\markdownRendererLinkPrototype#1#2#3#4{#2}% +\def\markdownRendererContentBlockPrototype#1#2#3#4{% + \markdownInput{#3}}% +\def\markdownRendererContentBlockOnlineImagePrototype{% + \markdownRendererImage}% +\def\markdownRendererContentBlockCodePrototype#1#2#3#4#5{% + \markdownRendererInputFencedCode{#3}{#2}{#2}}% +\def\markdownRendererImagePrototype#1#2#3#4{#2}% +\def\markdownRendererUlBeginPrototype{}% +\def\markdownRendererUlBeginTightPrototype{}% +\def\markdownRendererUlItemPrototype{}% +\def\markdownRendererUlItemEndPrototype{}% +\def\markdownRendererUlEndPrototype{}% +\def\markdownRendererUlEndTightPrototype{}% +\def\markdownRendererOlBeginPrototype{}% +\def\markdownRendererOlBeginTightPrototype{}% +\def\markdownRendererFancyOlBeginPrototype#1#2{\markdownRendererOlBegin}% +\def\markdownRendererFancyOlBeginTightPrototype#1#2{\markdownRendererOlBeginTight}% +\def\markdownRendererOlItemPrototype{}% +\def\markdownRendererOlItemWithNumberPrototype#1{}% +\def\markdownRendererOlItemEndPrototype{}% +\def\markdownRendererFancyOlItemPrototype{\markdownRendererOlItem}% +\def\markdownRendererFancyOlItemWithNumberPrototype{\markdownRendererOlItemWithNumber}% +\def\markdownRendererFancyOlItemEndPrototype{}% +\def\markdownRendererOlEndPrototype{}% +\def\markdownRendererOlEndTightPrototype{}% +\def\markdownRendererFancyOlEndPrototype{\markdownRendererOlEnd}% +\def\markdownRendererFancyOlEndTightPrototype{\markdownRendererOlEndTight}% +\def\markdownRendererDlBeginPrototype{}% +\def\markdownRendererDlBeginTightPrototype{}% +\def\markdownRendererDlItemPrototype#1{#1}% +\def\markdownRendererDlItemEndPrototype{}% +\def\markdownRendererDlDefinitionBeginPrototype{}% +\def\markdownRendererDlDefinitionEndPrototype{\par}% +\def\markdownRendererDlEndPrototype{}% +\def\markdownRendererDlEndTightPrototype{}% +\def\markdownRendererEmphasisPrototype#1{{\it#1}}% +\def\markdownRendererStrongEmphasisPrototype#1{{\bf#1}}% +\def\markdownRendererBlockQuoteBeginPrototype{\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#3{% + \markdownRendererInputVerbatim{#1}}% +\def\markdownRendererHeadingOnePrototype#1{#1}% +\def\markdownRendererHeadingTwoPrototype#1{#1}% +\def\markdownRendererHeadingThreePrototype#1{#1}% +\def\markdownRendererHeadingFourPrototype#1{#1}% +\def\markdownRendererHeadingFivePrototype#1{#1}% +\def\markdownRendererHeadingSixPrototype#1{#1}% +\def\markdownRendererThematicBreakPrototype{}% +\def\markdownRendererNotePrototype#1{#1}% +\def\markdownRendererCitePrototype#1{}% +\def\markdownRendererTextCitePrototype#1{}% +\def\markdownRendererTickedBoxPrototype{[X]}% +\def\markdownRendererHalfTickedBoxPrototype{[/]}% +\def\markdownRendererUntickedBoxPrototype{[ ]}% +\def\markdownRendererStrikeThroughPrototype#1{#1}% +\def\markdownRendererSuperscriptPrototype#1{#1}% +\def\markdownRendererSubscriptPrototype#1{#1}% +\def\markdownRendererDisplayMathPrototype#1{$$#1$$}% +\def\markdownRendererInlineMathPrototype#1{$#1$}% +\ExplSyntaxOn +\cs_gset:Npn + \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 + { \codepoint_str_generate:n { fffd } } +\ExplSyntaxOff +\def\markdownRendererSectionBeginPrototype{}% +\def\markdownRendererSectionEndPrototype{}% +\ExplSyntaxOn +\cs_new:Nn + \__markdown_plain_tex_default_input_raw_inline_renderer_prototype:nn + { + \str_case:nn + { #2 } + { + { md } { \markdownInput{#1} } + { tex } { \markdownEscape{#1} \unskip } + } + } +\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 } + } +\seq_new:N \g__markdown_jekyll_data_datatypes_seq +\tl_const:Nn \c__markdown_jekyll_data_sequence_tl { sequence } +\tl_const:Nn \c__markdown_jekyll_data_mapping_tl { mapping } +\tl_const:Nn \c__markdown_jekyll_data_scalar_tl { scalar } +\seq_new:N \g__markdown_jekyll_data_wildcard_absolute_address_seq +\cs_new:Nn \markdown_jekyll_data_push_address_segment:n + { + \seq_if_empty:NF + \g__markdown_jekyll_data_datatypes_seq + { + \seq_get_right:NN + \g__markdown_jekyll_data_datatypes_seq + \l_tmpa_tl + \str_if_eq:NNTF + \l_tmpa_tl + \c__markdown_jekyll_data_sequence_tl + { + \seq_put_right:Nn + \g__markdown_jekyll_data_wildcard_absolute_address_seq + { * } + } + { + \seq_put_right:Nn + \g__markdown_jekyll_data_wildcard_absolute_address_seq + { #1 } + } + } + } +\tl_new:N \g__markdown_jekyll_data_wildcard_absolute_address_tl +\tl_new:N \g__markdown_jekyll_data_wildcard_relative_address_tl +\cs_new:Nn \markdown_jekyll_data_concatenate_address:NN + { + \seq_pop_left:NN #1 \l_tmpa_tl + \tl_set:Nx #2 { / \seq_use:Nn #1 { / } } + \seq_put_left:NV #1 \l_tmpa_tl + } +\cs_new:Nn \markdown_jekyll_data_update_address_tls: + { + \markdown_jekyll_data_concatenate_address:NN + \g__markdown_jekyll_data_wildcard_absolute_address_seq + \g__markdown_jekyll_data_wildcard_absolute_address_tl + \seq_get_right:NN + \g__markdown_jekyll_data_wildcard_absolute_address_seq + \g__markdown_jekyll_data_wildcard_relative_address_tl + } +\cs_new:Nn \markdown_jekyll_data_push:nN + { + \markdown_jekyll_data_push_address_segment:n + { #1 } + \seq_put_right:NV + \g__markdown_jekyll_data_datatypes_seq + #2 + \markdown_jekyll_data_update_address_tls: + } +\cs_new:Nn \markdown_jekyll_data_pop: + { + \seq_pop_right:NN + \g__markdown_jekyll_data_wildcard_absolute_address_seq + \l_tmpa_tl + \seq_pop_right:NN + \g__markdown_jekyll_data_datatypes_seq + \l_tmpa_tl + \markdown_jekyll_data_update_address_tls: + } +\cs_new:Nn \markdown_jekyll_data_set_keyval:nn + { + \keys_set_known:nn + { markdown/jekyllData } + { { #1 } = { #2 } } + } +\cs_generate_variant:Nn + \markdown_jekyll_data_set_keyval:nn + { Vn } +\cs_new:Nn \markdown_jekyll_data_set_keyvals:nn + { + \markdown_jekyll_data_push:nN + { #1 } + \c__markdown_jekyll_data_scalar_tl + \markdown_jekyll_data_set_keyval:Vn + \g__markdown_jekyll_data_wildcard_absolute_address_tl + { #2 } + \markdown_jekyll_data_set_keyval:Vn + \g__markdown_jekyll_data_wildcard_relative_address_tl + { #2 } + \markdown_jekyll_data_pop: + } +\def\markdownRendererJekyllDataSequenceBeginPrototype#1#2{ + \markdown_jekyll_data_push:nN + { #1 } + \c__markdown_jekyll_data_sequence_tl +} +\def\markdownRendererJekyllDataMappingBeginPrototype#1#2{ + \markdown_jekyll_data_push:nN + { #1 } + \c__markdown_jekyll_data_mapping_tl +} +\def\markdownRendererJekyllDataSequenceEndPrototype{ + \markdown_jekyll_data_pop: +} +\def\markdownRendererJekyllDataMappingEndPrototype{ + \markdown_jekyll_data_pop: +} +\def\markdownRendererJekyllDataBooleanPrototype#1#2{ + \markdown_jekyll_data_set_keyvals:nn + { #1 } + { #2 } +} +\def\markdownRendererJekyllDataEmptyPrototype#1{} +\def\markdownRendererJekyllDataNumberPrototype#1#2{ + \markdown_jekyll_data_set_keyvals:nn + { #1 } + { #2 } +} +\def\markdownRendererJekyllDataStringPrototype#1#2{ + \markdown_jekyll_data_set_keyvals:nn + { #1 } + { #2 } +} +\ExplSyntaxOff +\endinput +%% +%% End of file `markdownthemewitiko_markdown_defaults.tex'. diff --git a/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_tilde.tex b/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_tilde.tex new file mode 100644 index 00000000000..90d34446f00 --- /dev/null +++ b/Master/texmf-dist/tex/generic/markdown/markdownthemewitiko_tilde.tex @@ -0,0 +1,52 @@ +%% +%% This is file `markdownthemewitiko_tilde.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `themes-witiko-tilde') +%% +%% Copyright (C) 2016-2024 Vít Starý Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Starý Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\markdownSetup { + rendererPrototypes = { + tilde = {~}, + }, +} +\endinput +%% +%% End of file `markdownthemewitiko_tilde.tex'. diff --git a/Master/texmf-dist/tex/latex/markdown/markdown.sty b/Master/texmf-dist/tex/latex/markdown/markdown.sty index 661ea377553..4f2bcd4bdba 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdown.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdown.sty @@ -6,7 +6,7 @@ %% %% markdown.dtx (with options: `latex') %% -%% Copyright (C) 2016-2023 Vít Novotný +%% Copyright (C) 2016-2024 Vít Starý Novotný %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c @@ -16,7 +16,7 @@ %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. +%% The Current Maintainer of this work is Vít Starý Novotný. %% %% Send bug reports, requests for additions and questions %% either to the GitHub issue tracker at @@ -43,649 +43,93 @@ %% The names of the source files used are shown above. %% \RequirePackage{expl3} -\newcommand\markdownInfo[1]{\PackageInfo{markdown}{#1}}% -\newcommand\markdownWarning[1]{\PackageWarning{markdown}{#1}}% -\newcommand\markdownError[2]{\PackageError{markdown}{#1}{#2.}}% -\input markdown/markdown -\newenvironment{markdown}\relax\relax -\newenvironment{markdown*}[1]\relax\relax \ExplSyntaxOn -\cs_new:Nn - \__markdown_setup:n - { - \keys_set:nn - { markdown/latex-options } - { #1 } - } -\let\markdownSetup=\__markdown_setup:n -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Nn - \__markdown_latex_setup_snippet:nn - { - \markdownIfSnippetExists - { #1 } - { - \markdownWarning - {Redefined~snippet~\markdownLaTeXThemeName#1} - \csname markdownLaTeXSetupSnippet% - \markdownLaTeXThemeName#1\endcsname={#2} - } - { - \newtoks\next - \next={#2} - \expandafter\let\csname markdownLaTeXSetupSnippet% - \markdownLaTeXThemeName#1\endcsname=\next - } - } -\let\markdownSetupSnippet=\__markdown_latex_setup_snippet:nn -\ExplSyntaxOff -\newcommand\markdownIfSnippetExists[3]{% - \@ifundefined - {markdownLaTeXSetupSnippet\markdownLaTeXThemeName#1}% - {#3}{#2}}% -\ExplSyntaxOn -\seq_new:N \g__markdown_latex_options_seq -\prop_new:N \g__markdown_latex_option_types_prop -\prop_new:N \g__markdown_default_latex_options_prop \tl_const:Nn \c__markdown_option_layer_latex_tl { latex } -\seq_gput_right:NV \g__markdown_option_layers_seq \c__markdown_option_layer_latex_tl -\cs_new:Nn - \__markdown_add_latex_option:nnn - { - \__markdown_add_option:Vnnn - \c__markdown_option_layer_latex_tl - { #1 } - { #2 } - { #3 } - } -\__markdown_add_latex_option:nnn - { plain } - { boolean } - { false } -\ExplSyntaxOff -\newif\ifmarkdownLaTeXLoaded - \markdownLaTeXLoadedfalse -\AtEndOfPackage{\markdownLaTeXLoadedtrue} -\ExplSyntaxOn -\tl_new:N \markdownLaTeXThemePackageName -\cs_new:Nn - \__markdown_set_latex_theme:n - { - \str_if_in:nnF - { #1 } - { / } - { - \markdownError - { Won't~load~theme~with~unqualified~name~#1 } - { Theme~names~must~contain~at~least~one~forward~slash } - } - \str_if_in:nnT - { #1 } - { _ } - { - \markdownError - { Won't~load~theme~with~an~underscore~in~its~name~#1 } - { Theme~names~must~not~contain~underscores~in~their~names } - } - \tl_set:Nn \markdownLaTeXThemePackageName { #1 } - \str_replace_all:Nnn - \markdownLaTeXThemePackageName - { / } - { _ } - \edef\markdownLaTeXThemePackageName{ - markdowntheme\markdownLaTeXThemePackageName} - \expandafter\markdownLaTeXThemeLoad\expandafter{ - \markdownLaTeXThemePackageName}{#1/} - } -\keys_define:nn - { markdown/latex-options } - { - import .code:n = { - \tl_set:Nn - \l_tmpa_tl - { #1 } - \tl_replace_all:NnV - \l_tmpa_tl - { / } - \c_backslash_str - \keys_set:nV - { markdown/latex-options/import } - \l_tmpa_tl - }, - } -\cs_generate_variant:Nn - \tl_replace_all:Nnn - { NnV } -\keys_define:nn - { markdown/latex-options } - { - theme .code:n = { \__markdown_set_latex_theme:n { #1 } }, - } -\ExplSyntaxOff -\ExplSyntaxOn -\@onlypreamble - \__markdown_set_latex_theme:n -\ExplSyntaxOff -\ExplSyntaxOn -\keys_define:nn - { markdown/latex-options } - { - snippet .code:n = { - \markdownIfSnippetExists{#1} - { - \expandafter\markdownSetup\expandafter{ - \the\csname markdownLaTeXSetupSnippet - \markdownLaTeXThemeName#1\endcsname} - }{ - \markdownError - {Can't~invoke~setup~snippet~#1} - {The~setup~snippet~is~undefined} - } - } - } -\ExplSyntaxOff -\ExplSyntaxOn -\tl_new:N - \l__markdown_latex_import_current_theme_tl -\keys_define:nn - { markdown/latex-options/import } - { - unknown .default:n = {}, - unknown .code:n = { - \tl_set_eq:NN - \l__markdown_latex_import_current_theme_tl - \l_keys_key_str - \tl_replace_all:NVn - \l__markdown_latex_import_current_theme_tl - \c_backslash_str - { / } - \__markdown_set_latex_theme:V - \l__markdown_latex_import_current_theme_tl - \clist_map_inline:nn - { #1 } - { - \regex_extract_once:nnNTF - { ^(.*?)\s+as\s+(.*?)$ } - { ##1 } - \l_tmpa_seq - { - \seq_pop:NN - \l_tmpa_seq - \l_tmpa_tl - \seq_pop:NN - \l_tmpa_seq - \l_tmpa_tl - \seq_pop:NN - \l_tmpa_seq - \l_tmpb_tl - } - { - \tl_set:Nn - \l_tmpa_tl - { ##1 } - \tl_set:Nn - \l_tmpb_tl - { ##1 } - } - \tl_put_left:Nn - \l_tmpa_tl - { / } - \tl_put_left:NV - \l_tmpa_tl - \l__markdown_latex_import_current_theme_tl - \__markdown_latex_setup_snippet:Vx - \l_tmpb_tl - { snippet = { \l_tmpa_tl } } - } - }, - } -\cs_generate_variant:Nn - \tl_replace_all:Nnn - { NVn } -\cs_generate_variant:Nn - \__markdown_set_latex_theme:n - { V } -\cs_generate_variant:Nn - \__markdown_latex_setup_snippet:nn - { Vx } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Nn \__markdown_latex_define_option_commands_and_keyvals: - { - \seq_map_inline:Nn - \g__markdown_latex_options_seq - { - \__markdown_plain_tex_define_option_command:n - { ##1 } - } - \seq_map_inline:Nn - \g__markdown_option_layers_seq - { - \seq_map_inline:cn - { g__markdown_ ##1 _options_seq } - { - \__markdown_with_various_cases:nn - { ####1 } - { - \__markdown_latex_define_option_keyval:nnn - { ##1 } - { ####1 } - { ########1 } - } - } - } - } -\cs_new:Nn \__markdown_latex_define_option_keyval:nnn - { - \prop_get:cnN - { g__markdown_ #1 _option_types_prop } - { #2 } - \l_tmpa_tl - \keys_define:nn - { markdown/latex-options } - { - #3 .code:n = { - \__markdown_set_option_value:nn - { #2 } - { ##1 } - }, - } - \str_if_eq:VVT - \l_tmpa_tl - \c__markdown_option_type_boolean_tl - { - \keys_define:nn - { markdown/latex-options } - { - #3 .default:n = { true }, - } - } - \str_if_eq:VVT - \l_tmpa_tl - \c__markdown_option_type_clist_tl - { - \tl_set:Nn - \l_tmpa_tl - { #3 } - \tl_reverse:N - \l_tmpa_tl - \str_if_eq:enF - { - \tl_head:V - \l_tmpa_tl - } - { s } - { - \msg_error:nnn - { markdown } - { malformed-name-for-clist-option } - { #3 } - } - \tl_set:Nx - \l_tmpa_tl - { - \tl_tail:V - \l_tmpa_tl - } - \tl_reverse:N - \l_tmpa_tl - \tl_put_right:Nn - \l_tmpa_tl - { - .code:n = { - \__markdown_get_option_value:nN - { #2 } - \l_tmpa_tl - \clist_set:NV - \l_tmpa_clist - { \l_tmpa_tl, { ##1 } } - \__markdown_set_option_value:nV - { #2 } - \l_tmpa_clist - } - } - \keys_define:nV - { markdown/latex-options } - \l_tmpa_tl - } - } \cs_generate_variant:Nn - \clist_set:Nn + \tl_const:Nn { NV } -\cs_generate_variant:Nn - \keys_define:nn - { nV } -\cs_generate_variant:Nn - \__markdown_set_option_value:nn - { nV } -\prg_generate_conditional_variant:Nnn - \str_if_eq:nn - { en } - { F } -\msg_new:nnn - { markdown } - { malformed-name-for-clist-option } +\tl_if_exist:NF + \c__markdown_top_layer_tl { - Clist~option~name~#1~does~not~end~with~-s. + \tl_const:NV + \c__markdown_top_layer_tl + \c__markdown_option_layer_latex_tl } -\__markdown_latex_define_option_commands_and_keyvals: \ExplSyntaxOff +\input markdown/markdown +\newenvironment{markdown}\relax\relax +\newenvironment{markdown*}[1]\relax\relax \DeclareOption{finalizecache}{\markdownSetup{finalizeCache}} \DeclareOption{frozencache}{\markdownSetup{frozenCache}} \ExplSyntaxOn -\cs_new:Nn \__markdown_latex_define_renderers: +\str_if_eq:VVT + \c__markdown_top_layer_tl + \c__markdown_option_layer_latex_tl { - \seq_map_function:NN - \g__markdown_renderers_seq - \__markdown_latex_define_renderer:n + \__markdown_define_option_commands_and_keyvals: + \__markdown_define_renderers: + \__markdown_define_renderer_prototypes: } -\cs_new:Nn \__markdown_latex_define_renderer:n - { - \__markdown_renderer_tl_to_csname:nN - { #1 } - \l_tmpa_tl - \prop_get:NnN - \g__markdown_renderer_arities_prop - { #1 } - \l_tmpb_tl - \__markdown_latex_define_renderer:ncV - { #1 } - { \l_tmpa_tl } - \l_tmpb_tl +\ExplSyntaxOff +\newif\ifmarkdownLaTeXLoaded + \markdownLaTeXLoadedfalse +\AtEndOfPackage{ + \markdownLaTeXLoadedtrue + \markdownIfOption{noDefaults}{}{ + \markdownSetup{theme=witiko/markdown/defaults} } -\cs_new:Nn \__markdown_renderer_tl_to_csname:nN +} +\def\markdownVersionSpace{ }% +\ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v% + \markdownVersion\markdownVersionSpace markdown renderer]% +\let\markdownInputPlainTeX\markdownInput +\renewcommand\markdownInput[2][]{% + \begingroup + \markdownSetup{#1}% + \markdownInputPlainTeX{#2}% + \endgroup}% +\ExplSyntaxOn +\renewenvironment + { markdown } { - \tl_set:Nn - \l_tmpa_tl - { \str_uppercase:n { #1 } } - \tl_set:Nx - #2 + \group_begin: + \char_set_catcode_active:n { 13 } + \char_set_catcode_letter:n { 35 } + \peek_regex_replace_once:nnF + { \ *\[([^]]*)\][^\r]* } { - markdownRenderer - \tl_head:f { \l_tmpa_tl } - \tl_tail:n { #1 } + \c { group_end: } + \c { tl_set_rescan:Nnn } \c { l_tmpa_tl } { } { \1 } + \c { __markdown_setup:V } \c { l_tmpa_tl } + \c { markdownReadAndConvert@markdown } { } } - } -\cs_new:Nn \__markdown_latex_define_renderer:nNn - { - \__markdown_with_various_cases:nn - { #1 } { - \keys_define:nn - { markdown/latex-options/renderers } - { - ##1 .code:n = { - \cs_generate_from_arg_count:NNnn - #2 - \cs_set:Npn - { #3 } - { ####1 } - }, - } + \group_end: + \markdownReadAndConvert@markdown { } } } -\cs_generate_variant:Nn - \__markdown_latex_define_renderer:nNn - { ncV } -\ExplSyntaxOff -\ExplSyntaxOn -\tl_new:N - \l__markdown_renderer_definition_tl -\keys_define:nn - { markdown/latex-options/renderers } + { \markdownEnd } +\renewenvironment + { markdown* } + [ 1 ] { - unknown .code:n = { - \regex_match:nVTF - { \* } - \l_keys_key_str - { - \tl_set:Nn - \l__markdown_renderer_definition_tl - { #1 } - \tl_set:NV - \l_tmpa_tl - \l_keys_key_str - \regex_replace_all:nnN - { \* } - { .* } - \l_tmpa_tl - \regex_set:NV - \l_tmpa_regex - \l_tmpa_tl - \int_zero:N - \l_tmpa_int - \seq_map_inline:Nn - \g__markdown_renderers_seq - { - \__markdown_with_various_cases:nn - { ##1 } - { - \regex_match:NnT - \l_tmpa_regex - { ####1 } - { - \__markdown_renderer_tl_to_csname:nN - { ##1 } - \l_tmpa_tl - \prop_get:NnN - \g__markdown_renderer_arities_prop - { ##1 } - \l_tmpb_tl - \cs_generate_from_arg_count:cNVV - { \l_tmpa_tl } - \cs_set:Npn - \l_tmpb_tl - \l__markdown_renderer_definition_tl - \int_incr:N - \l_tmpa_int - \__markdown_with_various_cases_break: - } - } - } - \int_compare:nNnT - { \l_tmpa_int } = { 0 } - { - \msg_error:nnV - { markdown } - { nonmatched-renderer-wildcard } - \l_keys_key_str - } - } - { - \msg_error:nnV - { markdown } - { undefined-renderer } - \l_keys_key_str - } - }, - } -\msg_new:nnn - { markdown } - { undefined-renderer } - { - Renderer~#1~is~undefined. - } -\msg_new:nnn - { markdown } - { nonmatched-renderer-wildcard } - { - Wildcard~#1~matches~no~renderers. - } -\cs_generate_variant:Nn - \regex_set:Nn - { NV } -\cs_generate_variant:Nn - \cs_generate_from_arg_count:NNnn - { cNVV } -\cs_generate_variant:Nn - \msg_error:nnn - { nnV } -\prg_generate_conditional_variant:Nnn - \regex_match:nn - { nV } - { TF } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_new:Nn \__markdown_latex_define_renderer_prototypes: - { - \seq_map_function:NN - \g__markdown_renderers_seq - \__markdown_latex_define_renderer_prototype:n - } -\cs_new:Nn \__markdown_latex_define_renderer_prototype:n - { - \__markdown_renderer_prototype_tl_to_csname:nN - { #1 } - \l_tmpa_tl - \prop_get:NnN - \g__markdown_renderer_arities_prop + \msg_warning:nnn + { markdown } + { latex-markdown-star-deprecated } { #1 } - \l_tmpb_tl - \__markdown_latex_define_renderer_prototype:ncV - { #1 } - { \l_tmpa_tl } - \l_tmpb_tl - } -\cs_new:Nn \__markdown_latex_define_renderer_prototype:nNn - { - \__markdown_with_various_cases:nn + \__markdown_setup:n { #1 } - { - \keys_define:nn - { markdown/latex-options/renderer-prototypes } - { - ##1 .code:n = { - \cs_generate_from_arg_count:NNnn - #2 - \cs_set:Npn - { #3 } - { ####1 } - }, - } - } - } -\cs_generate_variant:Nn - \__markdown_latex_define_renderer_prototype:nNn - { ncV } -\ExplSyntaxOff -\ExplSyntaxOn -\tl_new:N - \l__markdown_renderer_prototype_definition_tl -\keys_define:nn - { markdown/latex-options/renderer-prototypes } - { - unknown .code:n = { - \regex_match:nVTF - { \* } - \l_keys_key_str - { - \tl_set:Nn - \l__markdown_renderer_prototype_definition_tl - { #1 } - \tl_set:NV - \l_tmpa_tl - \l_keys_key_str - \regex_replace_all:nnN - { \* } - { .* } - \l_tmpa_tl - \regex_set:NV - \l_tmpa_regex - \l_tmpa_tl - \int_zero:N - \l_tmpa_int - \seq_map_inline:Nn - \g__markdown_renderers_seq - { - \__markdown_with_various_cases:nn - { ##1 } - { - \regex_match:NnT - \l_tmpa_regex - { ####1 } - { - \__markdown_renderer_prototype_tl_to_csname:nN - { ##1 } - \l_tmpa_tl - \prop_get:NnN - \g__markdown_renderer_arities_prop - { ##1 } - \l_tmpb_tl - \cs_generate_from_arg_count:cNVV - { \l_tmpa_tl } - \cs_set:Npn - \l_tmpb_tl - \l__markdown_renderer_prototype_definition_tl - \int_incr:N - \l_tmpa_int - \__markdown_with_various_cases_break: - } - } - } - \int_compare:nNnT - { \l_tmpa_int } = { 0 } - { - \msg_error:nnV - { markdown } - { nonmatched-renderer-prototype-wildcard } - \l_keys_key_str - } - } - { - \msg_error:nnV - { markdown } - { undefined-renderer-prototype } - \l_keys_key_str - } - }, + \markdownReadAndConvert@markdown * } + { \markdownEnd } \msg_new:nnn { markdown } - { undefined-renderer-prototype } + { latex-markdown-star-deprecated } { - Renderer~prototype~#1~is~undefined. + The~markdown*~LaTeX~environment~has~been~deprecated~and~will~ + be~removed~in~the~next~major~version~of~the~Markdown~package. } -\msg_new:nnn - { markdown } - { nonmatched-renderer-prototype-wildcard } - { - Wildcard~#1~matches~no~renderer~prototypes. - } -\cs_generate_variant:Nn - \regex_set:Nn - { NV } -\cs_generate_variant:Nn - \cs_generate_from_arg_count:NNnn - { cNVV } -\cs_generate_variant:Nn - \msg_error:nnn - { nnV } -\prg_generate_conditional_variant:Nnn - \regex_match:nn - { nV } - { TF } \ExplSyntaxOff -\def\markdownVersionSpace{ }% -\ProvidesPackage{markdown}[\markdownLastModified\markdownVersionSpace v% - \markdownVersion\markdownVersionSpace markdown renderer]% -\ExplSyntaxOn -\__markdown_latex_define_renderers: -\__markdown_latex_define_renderer_prototypes: -\ExplSyntaxOff -\let\markdownInputPlainTeX\markdownInput -\renewcommand\markdownInput[2][]{% - \begingroup - \markdownSetup{#1}% - \markdownInputPlainTeX{#2}% - \endgroup}% -\renewenvironment{markdown}{% - \markdownReadAndConvert@markdown{}}{% - \markdownEnd}% -\renewenvironment{markdown*}[1]{% - \markdownSetup{#1}% - \markdownReadAndConvert@markdown*}{% - \markdownEnd}% \begingroup \catcode`\|=0\catcode`\<=1\catcode`\>=2% \catcode`\\=12|catcode`|{=12|catcode`|}=12% @@ -693,991 +137,96 @@ |markdownReadAndConvert<\end{markdown#1}>% <|end>>% |endgroup -\ExplSyntaxOn -\newcommand\markdownLaTeXThemeName{} -\seq_new:N \g__markdown_latex_themes_seq -\seq_gput_right:NV - \g__markdown_latex_themes_seq - \markdownLaTeXThemeName -\newcommand\markdownLaTeXThemeLoad[2]{ - \def\@tempa{% - \def\markdownLaTeXThemeName{#2} - \seq_gput_right:NV - \g__markdown_latex_themes_seq - \markdownLaTeXThemeName - \RequirePackage{#1} - \seq_pop_right:NN - \g__markdown_latex_themes_seq - \l_tmpa_tl - \seq_get_right:NN - \g__markdown_latex_themes_seq - \l_tmpa_tl - \exp_args:NNV - \def - \markdownLaTeXThemeName - \l_tmpa_tl} - \ifmarkdownLaTeXLoaded - \@tempa - \else - \exp_args:No - \AtEndOfPackage - { \@tempa } - \fi} -\ExplSyntaxOff \DeclareOption*{% \expandafter\markdownSetup\expandafter{\CurrentOption}}% \ProcessOptions\relax \ExplSyntaxOn -\keys_define:nn - { markdown/latex-options } - { - renderers .code:n = { - \keys_set:nn - { markdown/latex-options/renderers } - { #1 } - }, - } -\__markdown_with_various_cases:nn - { rendererPrototypes } - { - \keys_define:nn - { markdown/latex-options } - { - #1 .code:n = { - \keys_set:nn - { markdown/latex-options/renderer-prototypes } - { ##1 } - }, - } - } -\keys_define:nn - { markdown/latex-options } - { - code .code:n = { #1 }, - } -\__markdown_with_various_cases:nn - { jekyllDataRenderers } +\cs_gset:Nn + \__markdown_load_theme:nn { - \keys_define:nn - { markdown/latex-options } - { - #1 .code:n = { - \tl_set:Nn - \l_tmpa_tl - { ##1 } - \tl_replace_all:NnV - \l_tmpa_tl - { / } - \c_backslash_str - \keys_set:nV - { markdown/latex-options/jekyll-data-renderers } - \l_tmpa_tl - }, - } - } -\keys_define:nn - { markdown/latex-options/jekyll-data-renderers } - { - unknown .code:n = { - \tl_set_eq:NN - \l_tmpa_tl - \l_keys_key_str - \tl_replace_all:NVn - \l_tmpa_tl - \c_backslash_str - { / } - \tl_put_right:Nn - \l_tmpa_tl - { - .code:n = { #1 } - } - \keys_define:nV - { markdown/jekyllData } - \l_tmpa_tl - } - } -\cs_generate_variant:Nn - \keys_define:nn - { nV } -\ExplSyntaxOff -\markdownIfOption{plain}{\iffalse}{\iftrue} -\@ifclassloaded{beamer}{}{% - \markdownIfOption{tightLists}{\RequirePackage{paralist}}{}% - \markdownIfOption{fancyLists}{\RequirePackage{paralist}}{}% -} -\ExplSyntaxOn -\@ifpackageloaded{paralist}{ - \tl_new:N - \l__markdown_latex_fancy_list_item_label_number_style_tl - \tl_new:N - \l__markdown_latex_fancy_list_item_label_delimiter_style_tl - \cs_new:Nn - \__markdown_latex_fancy_list_item_label_number:nn - { - \str_case:nn - { #1 } - { - { Decimal } { #2 } - { LowerRoman } { \int_to_roman:n { #2 } } - { UpperRoman } { \int_to_Roman:n { #2 } } - { LowerAlpha } { \int_to_alph:n { #2 } } - { UpperAlpha } { \int_to_alph:n { #2 } } - } - } - \cs_new:Nn - \__markdown_latex_fancy_list_item_label_delimiter:n - { - \str_case:nn - { #1 } - { - { Default } { . } - { OneParen } { ) } - { Period } { . } - } - } - \cs_new:Nn - \__markdown_latex_fancy_list_item_label:nnn - { - \__markdown_latex_fancy_list_item_label_number:nn - { #1 } - { #3 } - \__markdown_latex_fancy_list_item_label_delimiter:n - { #2 } - } - \cs_new:Nn - \__markdown_latex_paralist_style:nn - { - \str_case:nn - { #1 } - { - { Decimal } { 1 } - { LowerRoman } { i } - { UpperRoman } { I } - { LowerAlpha } { a } - { UpperAlpha } { A } - } - \__markdown_latex_fancy_list_item_label_delimiter:n - { #2 } - } - \markdownSetup{rendererPrototypes={ - ulBeginTight = {% - \group_begin: - \pltopsep=\topsep - \plpartopsep=\partopsep - \begin{compactitem} - }, - ulEndTight = { - \end{compactitem} - \group_end: - }, - fancyOlBegin = { - \group_begin: - \tl_set:Nn - \l__markdown_latex_fancy_list_item_label_number_style_tl - { #1 } - \tl_set:Nn - \l__markdown_latex_fancy_list_item_label_delimiter_style_tl - { #2 } - \tl_set:Nn - \l_tmpa_tl - { \begin{enumerate}[ } - \tl_put_right:Nx - \l_tmpa_tl - { \__markdown_latex_paralist_style:nn { #1 } { #2 } } - \tl_put_right:Nn - \l_tmpa_tl - { ] } - \l_tmpa_tl - }, - fancyOlEnd = { - \end{enumerate} - \group_end: - }, - olBeginTight = {% - \group_begin: - \plpartopsep=\partopsep - \pltopsep=\topsep - \begin{compactenum} - }, - olEndTight = { - \end{compactenum} - \group_end: - }, - fancyOlBeginTight = { - \group_begin: - \tl_set:Nn - \l__markdown_latex_fancy_list_item_label_number_style_tl - { #1 } - \tl_set:Nn - \l__markdown_latex_fancy_list_item_label_delimiter_style_tl - { #2 } - \tl_set:Nn - \l_tmpa_tl - { - \plpartopsep=\partopsep - \pltopsep=\topsep - \begin{compactenum}[ - } - \tl_put_right:Nx - \l_tmpa_tl - { \__markdown_latex_paralist_style:nn { #1 } { #2 } } - \tl_put_right:Nn - \l_tmpa_tl - { ] } - \l_tmpa_tl - }, - fancyOlEndTight = { - \end{compactenum} - \group_end: - }, - fancyOlItemWithNumber = { - \item - [ - \__markdown_latex_fancy_list_item_label:VVn - \l__markdown_latex_fancy_list_item_label_number_style_tl - \l__markdown_latex_fancy_list_item_label_delimiter_style_tl - { #1 } - ] - }, - dlBeginTight = { - \group_begin: - \plpartopsep=\partopsep - \pltopsep=\topsep - \begin{compactdesc} - }, - dlEndTight = { - \end{compactdesc} - \group_end: - }}} - \cs_generate_variant:Nn - \__markdown_latex_fancy_list_item_label:nnn - { VVn } -}{ - \markdownSetup{rendererPrototypes={ - ulBeginTight = {\markdownRendererUlBegin}, - ulEndTight = {\markdownRendererUlEnd}, - fancyOlBegin = {\markdownRendererOlBegin}, - fancyOlEnd = {\markdownRendererOlEnd}, - olBeginTight = {\markdownRendererOlBegin}, - olEndTight = {\markdownRendererOlEnd}, - fancyOlBeginTight = {\markdownRendererOlBegin}, - fancyOlEndTight = {\markdownRendererOlEnd}, - dlBeginTight = {\markdownRendererDlBegin}, - dlEndTight = {\markdownRendererDlEnd}}} -} -\ExplSyntaxOff -\RequirePackage{amsmath} -\@ifpackageloaded{unicode-math}{ - \markdownSetup{rendererPrototypes={ - untickedBox = {$\mdlgwhtsquare$}, - }} -}{ - \RequirePackage{amssymb} - \markdownSetup{rendererPrototypes={ - untickedBox = {$\square$}, - }} -} -\RequirePackage{csvsimple} -\RequirePackage{fancyvrb} -\RequirePackage{graphicx} -\markdownSetup{rendererPrototypes={ - hardLineBreak = {\\}, - leftBrace = {\textbraceleft}, - rightBrace = {\textbraceright}, - dollarSign = {\textdollar}, - underscore = {\textunderscore}, - circumflex = {\textasciicircum}, - backslash = {\textbackslash}, - tilde = {\textasciitilde}, - pipe = {\textbar}, - codeSpan = {% - \ifmmode - \text{#1}% - \else - \texttt{#1}% - \fi - }}} -\ExplSyntaxOn -\markdownSetup{ - rendererPrototypes = { - contentBlock = { - \str_case:nnF - { #1 } - { - { csv } - { - \begin{table} - \begin{center} - \csvautotabular{#3} - \end{center} - \tl_if_empty:nF - { #4 } - { \caption{#4} } - \end{table} - } - { tex } { \markdownEscape{#3} } - } - { \markdownInput{#3} } - }, - }, -} -\ExplSyntaxOff -\markdownSetup{rendererPrototypes={ - image = {% - \begin{figure}% - \begin{center}% - \includegraphics{#3}% - \end{center}% - \ifx\empty#4\empty\else - \caption{#4}% - \fi - \end{figure}}, - ulBegin = {\begin{itemize}}, - ulEnd = {\end{itemize}}, - olBegin = {\begin{enumerate}}, - olItem = {\item{}}, - olItemWithNumber = {\item[#1.]}, - olEnd = {\end{enumerate}}, - dlBegin = {\begin{description}}, - dlItem = {\item[#1]}, - dlEnd = {\end{description}}, - emphasis = {\emph{#1}}, - tickedBox = {$\boxtimes$}, - halfTickedBox = {$\boxdot$}, - headerAttributeContextBegin = {% - \markdownSetup{ - rendererPrototypes = { - attributeIdentifier = {% - \begingroup - \def\next####1{% - \def####1########1{% - \endgroup - ####1{########1}% - \label{##1}% - }% - }% - \next\markdownRendererHeadingOne - \next\markdownRendererHeadingTwo - \next\markdownRendererHeadingThree - \next\markdownRendererHeadingFour - \next\markdownRendererHeadingFive - \next\markdownRendererHeadingSix - }, - }, - }% - }, - headerAttributeContextEnd = {}, - superscript = {\textsuperscript{#1}}, - subscript = {\textsubscript{#1}}, - displayMath = {\begin{displaymath}#1\end{displaymath}}, - inlineMath = {\begin{math}#1\end{math}}, - blockQuoteBegin = {\begin{quotation}}, - blockQuoteEnd = {\end{quotation}}, - inputVerbatim = {\VerbatimInput{#1}}, - 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 } + \ifmarkdownLaTeXLoaded + \ifx\@onlypreamble\@notprerr + \file_if_exist:nTF + { markdown theme #2.sty } { - \catcode`\#=6\relax - \exp_args:NV - \inputminted - \l_tmpa_tl + \msg_error:nnn + { markdown } + { latex-theme-after-preamble } { #1 } - \catcode`\#=12\relax } { - \ltx@ifpackageloaded - { listings } - { \lstinputlisting[language=\l_tmpa_tl]{#1} } - { \markdownRendererInputFencedCode{#1}{} } + \__markdown_plain_tex_load_theme:nn + { #1 } + { #2 } } - } - } -\ExplSyntaxOff -\ExplSyntaxOn -\def\markdownLATEXStrongEmphasis#1{% - \str_if_in:NnTF - \f@series - { b } - { \textnormal{#1} } - { \textbf{#1} } -} -\ExplSyntaxOff -\markdownSetup{rendererPrototypes={strongEmphasis={% - \protect\markdownLATEXStrongEmphasis{#1}}}} -\@ifundefined{chapter}{% - \markdownSetup{rendererPrototypes = { - headingOne = {\section{#1}}, - headingTwo = {\subsection{#1}}, - headingThree = {\subsubsection{#1}}, - headingFour = {\paragraph{#1}\leavevmode}, - headingFive = {\subparagraph{#1}\leavevmode}}} -}{% - \markdownSetup{rendererPrototypes = { - headingOne = {\chapter{#1}}, - headingTwo = {\section{#1}}, - headingThree = {\subsection{#1}}, - headingFour = {\subsubsection{#1}}, - headingFive = {\paragraph{#1}\leavevmode}, - headingSix = {\subparagraph{#1}\leavevmode}}} -}% -\markdownSetup{ - rendererPrototypes = { - ulItem = {% - \futurelet\markdownLaTeXCheckbox\markdownLaTeXUlItem - }, - }, -} -\def\markdownLaTeXUlItem{% - \ifx\markdownLaTeXCheckbox\markdownRendererTickedBox - \item[\markdownLaTeXCheckbox]% - \expandafter\@gobble - \else - \ifx\markdownLaTeXCheckbox\markdownRendererHalfTickedBox - \item[\markdownLaTeXCheckbox]% - \expandafter\expandafter\expandafter\@gobble - \else - \ifx\markdownLaTeXCheckbox\markdownRendererUntickedBox - \item[\markdownLaTeXCheckbox]% - \expandafter\expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\@gobble \else - \item{}% - \fi - \fi - \fi -} -\@ifundefined{HCode}{}{ - \markdownSetup{ - rendererPrototypes = { - inlineHtmlTag = {% - \ifvmode - \IgnorePar - \EndP - \fi - \HCode{#1}% - }, - inputBlockHtmlElement = {% - \ifvmode - \IgnorePar - \fi - \EndP - \special{t4ht*<#1}% - \par - \ShowPar - }, - }, - } -} -\newcount\markdownLaTeXCitationsCounter - -\RequirePackage{gobble} -\def\markdownLaTeXBasicCitations#1#2#3#4#5#6{% - \advance\markdownLaTeXCitationsCounter by 1\relax - \ifx\relax#4\relax - \ifx\relax#5\relax - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \cite{#1#2#6}% Without prenotes and postnotes, just accumulate cites - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \@gobblethree - \fi - \else% Before a postnote (#5), dump the accumulator - \ifx\relax#1\relax\else - \cite{#1}% - \fi - \cite[#5]{#6}% - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \else - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \markdownLaTeXBasicCitations - \fi - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter - \@gobblethree - \fi - \else% Before a prenote (#4), dump the accumulator - \ifx\relax#1\relax\else - \cite{#1}% - \fi - \ifnum\markdownLaTeXCitationsCounter>1\relax - \space % Insert a space before the prenote in later citations - \fi - #4~\expandafter\cite\ifx\relax#5\relax{#6}\else[#5]{#6}\fi - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \else - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \markdownLaTeXBasicCitations - \fi - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter - \@gobblethree - \fi\markdownLaTeXBasicCitations{#1#2#6},} -\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations - -\def\markdownLaTeXNatbibCitations#1#2#3#4#5{% - \advance\markdownLaTeXCitationsCounter by 1\relax - \ifx\relax#3\relax - \ifx\relax#4\relax - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \citep{#1,#5}% Without prenotes and postnotes, just accumulate cites - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \@gobbletwo - \fi - \else% Before a postnote (#4), dump the accumulator - \ifx\relax#1\relax\else - \citep{#1}% - \fi - \citep[][#4]{#5}% - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \else - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \markdownLaTeXNatbibCitations - \fi - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter - \@gobbletwo - \fi - \else% Before a prenote (#3), dump the accumulator - \ifx\relax#1\relax\relax\else - \citep{#1}% - \fi - \citep[#3][#4]{#5}% - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \else - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \markdownLaTeXNatbibCitations - \fi - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter - \@gobbletwo - \fi\markdownLaTeXNatbibCitations{#1,#5}} -\def\markdownLaTeXNatbibTextCitations#1#2#3#4#5{% - \advance\markdownLaTeXCitationsCounter by 1\relax - \ifx\relax#3\relax - \ifx\relax#4\relax - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \citet{#1,#5}% Without prenotes and postnotes, just accumulate cites - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \@gobbletwo - \fi - \else% After a prenote or a postnote, dump the accumulator - \ifx\relax#1\relax\else - \citet{#1}% - \fi - , \citet[#3][#4]{#5}% - \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax - , - \else - \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax - , - \fi + \file_if_exist:nTF + { markdown theme #2.sty } + { + \msg_info:nnn + { markdown } + { loading-latex-theme } + { #1 } + \RequirePackage + { markdown theme #2 } + } + { + \__markdown_plain_tex_load_theme:nn + { #1 } + { #2 } + } \fi - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter - \markdownLaTeXNatbibTextCitations - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter - \@gobbletwo - \fi - \else% After a prenote or a postnote, dump the accumulator - \ifx\relax#1\relax\relax\else - \citet{#1}% - \fi - , \citet[#3][#4]{#5}% - \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax - , \else - \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax - , - \fi - \fi - \expandafter\expandafter\expandafter - \markdownLaTeXNatbibTextCitations - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter - \@gobbletwo - \fi\markdownLaTeXNatbibTextCitations{#1,#5}} - -\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% - \advance\markdownLaTeXCitationsCounter by 1\relax - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \autocites#1[#3][#4]{#5}% - \expandafter\@gobbletwo - \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} -\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% - \advance\markdownLaTeXCitationsCounter by 1\relax - \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax - \textcites#1[#3][#4]{#5}% - \expandafter\@gobbletwo - \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} - -\markdownSetup{rendererPrototypes = { - cite = {% - \markdownLaTeXCitationsCounter=1% - \def\markdownLaTeXCitationsTotal{#1}% - \@ifundefined{autocites}{% - \@ifundefined{citep}{% - \expandafter\expandafter\expandafter - \markdownLaTeXBasicCitations - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - }{% - \expandafter\expandafter\expandafter - \markdownLaTeXNatbibCitations - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - }% - }{% - \expandafter\expandafter\expandafter - \markdownLaTeXBibLaTeXCitations - \expandafter{\expandafter}% - }}, - textCite = {% - \markdownLaTeXCitationsCounter=1% - \def\markdownLaTeXCitationsTotal{#1}% - \@ifundefined{autocites}{% - \@ifundefined{citep}{% - \expandafter\expandafter\expandafter - \markdownLaTeXBasicTextCitations - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - }{% - \expandafter\expandafter\expandafter - \markdownLaTeXNatbibTextCitations - \expandafter\expandafter\expandafter{% - \expandafter\expandafter\expandafter}% - }% - }{% - \expandafter\expandafter\expandafter - \markdownLaTeXBibLaTeXTextCitations - \expandafter{\expandafter}% - }}}} -\RequirePackage{url} -\RequirePackage{expl3} -\ExplSyntaxOn -\def\markdownRendererLinkPrototype#1#2#3#4{ - \tl_set:Nn \l_tmpa_tl { #1 } - \tl_set:Nn \l_tmpb_tl { #2 } - \bool_set:Nn - \l_tmpa_bool - { - \tl_if_eq_p:NN - \l_tmpa_tl - \l_tmpb_tl - } - \tl_set:Nn \l_tmpa_tl { #4 } - \bool_set:Nn - \l_tmpb_bool - { - \tl_if_empty_p:N - \l_tmpa_tl - } - \bool_if:nTF - { - \l_tmpa_bool && \l_tmpb_bool - } - { - \markdownLaTeXRendererAutolink { #2 } { #3 } - }{ - \markdownLaTeXRendererDirectOrIndirectLink { #1 } { #2 } { #3 } { #4 } - } -} -\def\markdownLaTeXRendererAutolink#1#2{% - \tl_set:Nn - \l_tmpa_tl - { #2 } - \tl_trim_spaces:N - \l_tmpa_tl - \tl_set:Nx - \l_tmpb_tl - { - \tl_range:Nnn - \l_tmpa_tl - { 1 } - { 1 } - } - \str_if_eq:NNTF - \l_tmpb_tl - \c_hash_str - { - \tl_set:Nx - \l_tmpb_tl + \msg_info:nnn + { markdown } + { theme-loading-postponed } + { #1 } + \AtEndOfPackage { - \tl_range:Nnn - \l_tmpa_tl - { 2 } - { -1 } + \__markdown_load_theme:nn + { #1 } + { #2 } } - \exp_args:NV - \ref - \l_tmpb_tl - }{ - \url { #2 } - } -} -\ExplSyntaxOff -\def\markdownLaTeXRendererDirectOrIndirectLink#1#2#3#4{% - #1\footnote{\ifx\empty#4\empty\else#4: \fi\url{#3}}} -\newcount\markdownLaTeXRowCounter -\newcount\markdownLaTeXRowTotal -\newcount\markdownLaTeXColumnCounter -\newcount\markdownLaTeXColumnTotal -\newtoks\markdownLaTeXTable -\newtoks\markdownLaTeXTableAlignment -\newtoks\markdownLaTeXTableEnd -\AtBeginDocument{% - \@ifpackageloaded{booktabs}{% - \def\markdownLaTeXTopRule{\toprule}% - \def\markdownLaTeXMidRule{\midrule}% - \def\markdownLaTeXBottomRule{\bottomrule}% - }{% - \def\markdownLaTeXTopRule{\hline}% - \def\markdownLaTeXMidRule{\hline}% - \def\markdownLaTeXBottomRule{\hline}% - }% -} -\markdownSetup{rendererPrototypes={ - table = {% - \markdownLaTeXTable={}% - \markdownLaTeXTableAlignment={}% - \markdownLaTeXTableEnd={% - \markdownLaTeXBottomRule - \end{tabular}}% - \ifx\empty#1\empty\else - \addto@hook\markdownLaTeXTable{% - \begin{table} - \centering}% - \addto@hook\markdownLaTeXTableEnd{% - \caption{#1} - \end{table}}% \fi - \addto@hook\markdownLaTeXTable{\begin{tabular}}% - \markdownLaTeXRowCounter=0% - \markdownLaTeXRowTotal=#2% - \markdownLaTeXColumnTotal=#3% - \markdownLaTeXRenderTableRow - } -}} -\def\markdownLaTeXRenderTableRow#1{% - \markdownLaTeXColumnCounter=0% - \ifnum\markdownLaTeXRowCounter=0\relax - \markdownLaTeXReadAlignments#1% - \markdownLaTeXTable=\expandafter\expandafter\expandafter{% - \expandafter\the\expandafter\markdownLaTeXTable\expandafter{% - \the\markdownLaTeXTableAlignment}}% - \addto@hook\markdownLaTeXTable{\markdownLaTeXTopRule}% - \else - \markdownLaTeXRenderTableCell#1% - \fi - \ifnum\markdownLaTeXRowCounter=1\relax - \addto@hook\markdownLaTeXTable\markdownLaTeXMidRule - \fi - \advance\markdownLaTeXRowCounter by 1\relax - \ifnum\markdownLaTeXRowCounter>\markdownLaTeXRowTotal\relax - \the\markdownLaTeXTable - \the\markdownLaTeXTableEnd - \expandafter\@gobble - \fi\markdownLaTeXRenderTableRow} -\def\markdownLaTeXReadAlignments#1{% - \advance\markdownLaTeXColumnCounter by 1\relax - \if#1d% - \addto@hook\markdownLaTeXTableAlignment{l}% - \else - \addto@hook\markdownLaTeXTableAlignment{#1}% - \fi - \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax\else - \expandafter\@gobble - \fi\markdownLaTeXReadAlignments} -\def\markdownLaTeXRenderTableCell#1{% - \advance\markdownLaTeXColumnCounter by 1\relax - \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax - \addto@hook\markdownLaTeXTable{#1&}% - \else - \addto@hook\markdownLaTeXTable{#1\\}% - \expandafter\@gobble - \fi\markdownLaTeXRenderTableCell} - -\markdownIfOption{lineBlocks}{% - \RequirePackage{verse} - \markdownSetup{rendererPrototypes={ - lineBlockBegin = {% - \begingroup - \def\markdownRendererHardLineBreak{\\}% - \begin{verse}% - }, - lineBlockEnd = {% - \end{verse}% - \endgroup - }, - }} -}{} - -\ExplSyntaxOn -\keys_define:nn - { markdown/jekyllData } - { - author .code:n = { \author{#1} }, - date .code:n = { \date{#1} }, - title .code:n = { \title{#1} }, - } -\providecommand\IfFormatAtLeastTF{\@ifl@t@r\fmtversion} -\markdownSetup{ - rendererPrototypes = { - jekyllDataEnd = { - \IfFormatAtLeastTF - { 2020-10-01 } - { \AddToHook{begindocument/end}{\maketitle} } - { - \ifx\@onlypreamble\@notprerr - % We are in the document - \maketitle - \else - % We are in the preamble - \RequirePackage{etoolbox} - \AfterEndPreamble{\maketitle} - \fi - } - }, - }, -} -\ExplSyntaxOff -\markdownIfOption{strikeThrough}{% - \RequirePackage{soulutf8}% - \markdownSetup{ - rendererPrototypes = { - strikeThrough = {% - \st{#1}% - }, - } - } -}{} -\markdownIfOption{strikeThrough}{% - \RequirePackage{soulutf8}% - \markdownSetup{ - rendererPrototypes = { - strikeThrough = {% - \st{#1}% - }, - } - } -}{} -\ExplSyntaxOn -\__markdown_if_option:nT - { linkAttributes } - { - \RequirePackage{graphicx} - \markdownSetup{ - rendererPrototypes = { - imageAttributeContextBegin = { - \group_begin: - \markdownSetup{ - rendererPrototypes = { - attributeKeyValue = { - \setkeys - { Gin } - { { ##1 } = { ##2 } } - }, - }, - } - }, - imageAttributeContextEnd = { - \group_end: - }, - }, - } - } -\ExplSyntaxOff -\ExplSyntaxOn -\cs_gset:Npn - \markdownRendererInputRawInlinePrototype#1#2 - { - \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 +\msg_new:nnn + { markdown } + { theme-loading-postponed } { - \str_case:nnF - { #2 } - { - { 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 } - } + Postponing~loading~Markdown~theme~#1~until~ + Markdown~package~has~finished~loading } +\msg_new:nnn + { markdown } + { loading-latex-theme } + { Loading~LaTeX~Markdown~theme~#1 } +\cs_generate_variant:Nn + \msg_new:nnnn + { nnVV } +\tl_set:Nn + \l_tmpa_tl + { Cannot~load~LaTeX~Markdown~theme~#1~after~ } +\tl_put_right:NV + \l_tmpa_tl + \c_backslash_str +\tl_put_right:Nn + \l_tmpa_tl + { begin{document} } +\tl_set:Nn + \l_tmpb_tl + { Load~Markdown~theme~#1~before~ } +\tl_put_right:NV + \l_tmpb_tl + \c_backslash_str +\tl_put_right:Nn + \l_tmpb_tl + { begin{document} } +\msg_new:nnVV + { markdown } + { latex-theme-after-preamble } + \l_tmpa_tl + \l_tmpb_tl \ExplSyntaxOff -\fi % Closes `\markdownIfOption{Plain}{\iffalse}{iftrue}` \newcommand\markdownMakeOther{% \count0=128\relax \loop diff --git a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty index 54aa163371a..a6ebbd6f1d9 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_dot.sty @@ -4,9 +4,9 @@ %% %% The original source files were: %% -%% markdown.dtx (with options: `latex-themes-witiko-dot') +%% markdown.dtx (with options: `themes-witiko-dot') %% -%% Copyright (C) 2016-2023 Vít Novotný +%% Copyright (C) 2016-2024 Vít Starý Novotný %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c @@ -16,7 +16,7 @@ %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. +%% The Current Maintainer of this work is Vít Starý Novotný. %% %% Send bug reports, requests for additions and questions %% either to the GitHub issue tracker at @@ -47,7 +47,7 @@ \RequirePackage{ifthen,grffile} \let\markdown@witiko@dot@oldRendererInputFencedCodePrototype \markdownRendererInputFencedCodePrototype -\renewcommand\markdownRendererInputFencedCodePrototype[2]{% +\renewcommand\markdownRendererInputFencedCodePrototype[3]{% \def\next##1 ##2\relax{% \ifthenelse{\equal{##1}{dot}}{% \markdownIfOption{frozenCache}{}{% @@ -59,7 +59,7 @@ fi}}% \markdownRendererImage{Graphviz image}{#1.pdf}{#1.pdf}{##2}% }{% - \markdown@witiko@dot@oldRendererInputFencedCodePrototype{#1}{#2}% + \markdown@witiko@dot@oldRendererInputFencedCodePrototype{#1}{#2}{#3}% }% }% \next#2 \relax}% diff --git a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_graphicx_http.sty b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_graphicx_http.sty index 57d27069ab0..a962d1d8cd0 100644 --- a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_graphicx_http.sty +++ b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_graphicx_http.sty @@ -4,9 +4,9 @@ %% %% The original source files were: %% -%% markdown.dtx (with options: `latex-themes-witiko-graphicx-http') +%% markdown.dtx (with options: `themes-witiko-graphicx-http') %% -%% Copyright (C) 2016-2023 Vít Novotný +%% Copyright (C) 2016-2024 Vít Starý Novotný %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3c @@ -16,7 +16,7 @@ %% http://www.latex-project.org/lppl.txt %% %% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. +%% The Current Maintainer of this work is Vít Starý Novotný. %% %% Send bug reports, requests for additions and questions %% either to the GitHub issue tracker at diff --git a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_markdown_defaults.sty b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_markdown_defaults.sty new file mode 100644 index 00000000000..99de31845a7 --- /dev/null +++ b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_markdown_defaults.sty @@ -0,0 +1,933 @@ +%% +%% This is file `markdownthemewitiko_markdown_defaults.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% markdown.dtx (with options: `themes-witiko-markdown-defaults-latex') +%% +%% Copyright (C) 2016-2024 Vít Starý Novotný +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This work has the LPPL maintenance status `maintained'. +%% The Current Maintainer of this work is Vít Starý Novotný. +%% +%% Send bug reports, requests for additions and questions +%% either to the GitHub issue tracker at +%% +%% https://github.com/Witiko/markdown/issues +%% +%% or to the e-mail address . +%% +%% MODIFICATION ADVICE: +%% +%% If you want to customize this file, it is best to make a copy of +%% the source file(s) from which it was produced. Use a different +%% name for your copy(ies) and modify the copy(ies); this will ensure +%% that your modifications do not get overwritten when you install a +%% new release of the standard system. You should also ensure that +%% your modified source file does not generate any modified file with +%% the same name as a standard file. +%% +%% You will also need to produce your own, suitably named, .ins file to +%% control the generation of files from your source file; this file +%% should contain your own preambles for the files it generates, not +%% those in the standard .ins files. +%% +%% The names of the source files used are shown above. +%% +\ProvidesPackage{markdownthemewitiko_markdown_defaults}[2024/01/03]% +\markdownLoadPlainTeXTheme +\markdownIfOption{plain}{\iffalse}{\iftrue} +\@ifclassloaded{beamer}{}{% + \markdownIfOption{tightLists}{\RequirePackage{paralist}}{}% + \markdownIfOption{fancyLists}{\RequirePackage{paralist}}{}% +} +\ExplSyntaxOn +\@ifpackageloaded{paralist}{ + \tl_new:N + \l__markdown_latex_fancy_list_item_label_number_style_tl + \tl_new:N + \l__markdown_latex_fancy_list_item_label_delimiter_style_tl + \cs_new:Nn + \__markdown_latex_fancy_list_item_label_number:nn + { + \str_case:nn + { #1 } + { + { Decimal } { #2 } + { LowerRoman } { \int_to_roman:n { #2 } } + { UpperRoman } { \int_to_Roman:n { #2 } } + { LowerAlpha } { \int_to_alph:n { #2 } } + { UpperAlpha } { \int_to_Alph:n { #2 } } + } + } + \cs_new:Nn + \__markdown_latex_fancy_list_item_label_delimiter:n + { + \str_case:nn + { #1 } + { + { Default } { . } + { OneParen } { ) } + { Period } { . } + } + } + \cs_new:Nn + \__markdown_latex_fancy_list_item_label:nnn + { + \__markdown_latex_fancy_list_item_label_number:nn + { #1 } + { #3 } + \__markdown_latex_fancy_list_item_label_delimiter:n + { #2 } + } + \cs_new:Nn + \__markdown_latex_paralist_style:nn + { + \str_case:nn + { #1 } + { + { Decimal } { 1 } + { LowerRoman } { i } + { UpperRoman } { I } + { LowerAlpha } { a } + { UpperAlpha } { A } + } + \__markdown_latex_fancy_list_item_label_delimiter:n + { #2 } + } + \markdownSetup{rendererPrototypes={ + ulBeginTight = {% + \group_begin: + \pltopsep=\topsep + \plpartopsep=\partopsep + \begin{compactitem} + }, + ulEndTight = { + \end{compactitem} + \group_end: + }, + fancyOlBegin = { + \group_begin: + \tl_set:Nn + \l__markdown_latex_fancy_list_item_label_number_style_tl + { #1 } + \tl_set:Nn + \l__markdown_latex_fancy_list_item_label_delimiter_style_tl + { #2 } + \__markdown_if_option:nTF + { startNumber } + { + \tl_set:Nn + \l_tmpa_tl + { \begin{enumerate} } + } + { + \tl_set:Nn + \l_tmpa_tl + { \begin{enumerate}[ } + \tl_put_right:Nx + \l_tmpa_tl + { \__markdown_latex_paralist_style:nn { #1 } { #2 } } + \tl_put_right:Nn + \l_tmpa_tl + { ] } + } + \tl_use:N + \l_tmpa_tl + }, + fancyOlEnd = { + \end{enumerate} + \group_end: + }, + olBeginTight = {% + \group_begin: + \plpartopsep=\partopsep + \pltopsep=\topsep + \begin{compactenum} + }, + olEndTight = { + \end{compactenum} + \group_end: + }, + fancyOlBeginTight = { + \group_begin: + \tl_set:Nn + \l__markdown_latex_fancy_list_item_label_number_style_tl + { #1 } + \tl_set:Nn + \l__markdown_latex_fancy_list_item_label_delimiter_style_tl + { #2 } + \tl_set:Nn + \l_tmpa_tl + { + \plpartopsep=\partopsep + \pltopsep=\topsep + } + \__markdown_if_option:nTF + { startNumber } + { + \tl_put_right:Nn + \l_tmpa_tl + { \begin{compactenum} } + } + { + \tl_put_right:Nn + \l_tmpa_tl + { \begin{compactenum}[ } + \tl_put_right:Nx + \l_tmpa_tl + { \__markdown_latex_paralist_style:nn { #1 } { #2 } } + \tl_put_right:Nn + \l_tmpa_tl + { ] } + } + \tl_use:N + \l_tmpa_tl + }, + fancyOlEndTight = { + \end{compactenum} + \group_end: + }, + fancyOlItemWithNumber = { + \item + [ + \__markdown_latex_fancy_list_item_label:VVn + \l__markdown_latex_fancy_list_item_label_number_style_tl + \l__markdown_latex_fancy_list_item_label_delimiter_style_tl + { #1 } + ] + }, + dlBeginTight = { + \group_begin: + \plpartopsep=\partopsep + \pltopsep=\topsep + \begin{compactdesc} + }, + dlEndTight = { + \end{compactdesc} + \group_end: + }}} + \cs_generate_variant:Nn + \__markdown_latex_fancy_list_item_label:nnn + { VVn } +}{ + \markdownSetup{rendererPrototypes={ + ulBeginTight = {\markdownRendererUlBegin}, + ulEndTight = {\markdownRendererUlEnd}, + fancyOlBegin = {\markdownRendererOlBegin}, + fancyOlEnd = {\markdownRendererOlEnd}, + olBeginTight = {\markdownRendererOlBegin}, + olEndTight = {\markdownRendererOlEnd}, + fancyOlBeginTight = {\markdownRendererOlBegin}, + fancyOlEndTight = {\markdownRendererOlEnd}, + dlBeginTight = {\markdownRendererDlBegin}, + dlEndTight = {\markdownRendererDlEnd}}} +} +\ExplSyntaxOff +\RequirePackage{amsmath} +\@ifpackageloaded{unicode-math}{ + \markdownSetup{rendererPrototypes={ + untickedBox = {$\mdlgwhtsquare$}, + }} +}{ + \RequirePackage{amssymb} + \markdownSetup{rendererPrototypes={ + untickedBox = {$\square$}, + }} +} +\RequirePackage{csvsimple} +\RequirePackage{fancyvrb} +\RequirePackage{graphicx} +\markdownSetup{rendererPrototypes={ + hardLineBreak = {\\}, + leftBrace = {\textbraceleft}, + rightBrace = {\textbraceright}, + dollarSign = {\textdollar}, + underscore = {\textunderscore}, + circumflex = {\textasciicircum}, + backslash = {\textbackslash}, + tilde = {\textasciitilde}, + pipe = {\textbar}, + codeSpan = {% + \ifmmode + \text{#1}% + \else + \texttt{#1}% + \fi + }}} +\ExplSyntaxOn +\markdownSetup{ + rendererPrototypes = { + contentBlock = { + \str_case:nnF + { #1 } + { + { csv } + { + \begin{table} + \begin{center} + \csvautotabular{#3} + \end{center} + \tl_if_empty:nF + { #4 } + { \caption{#4} } + \end{table} + } + { tex } { \markdownEscape{#3} } + } + { \markdownInput{#3} } + }, + }, +} +\ExplSyntaxOff +\markdownSetup{rendererPrototypes={ + image = {% + \begin{figure}% + \begin{center}% + \includegraphics[alt={#1}]{#3}% + \end{center}% + \ifx\empty#4\empty\else + \caption{#4}% + \fi + \end{figure}}, + ulBegin = {\begin{itemize}}, + ulEnd = {\end{itemize}}, + olBegin = {\begin{enumerate}}, + olItem = {\item{}}, + olItemWithNumber = {\item[#1.]}, + olEnd = {\end{enumerate}}, + dlBegin = {\begin{description}}, + dlItem = {\item[#1]}, + dlEnd = {\end{description}}, + emphasis = {\emph{#1}}, + tickedBox = {$\boxtimes$}, + halfTickedBox = {$\boxdot$}}} +\ExplSyntaxOn +\seq_new:N \l__markdown_header_identifiers_seq +\markdownSetup{ + rendererPrototypes = { + headerAttributeContextBegin = { + \seq_clear:N \l__markdown_header_identifiers_seq + \markdownSetup + { + renderers = { + attributeIdentifier = { + \seq_put_right:Nn + \l__markdown_header_identifiers_seq + { ##1 } + }, + }, + } + }, + headerAttributeContextEnd = { + \seq_map_inline:Nn + \l__markdown_header_identifiers_seq + { \label { ##1 } } + }, + }, +} +\ExplSyntaxOff +\markdownSetup{rendererPrototypes={ + superscript = {\textsuperscript{#1}}, + subscript = {\textsubscript{#1}}, + blockQuoteBegin = {\begin{quotation}}, + blockQuoteEnd = {\end{quotation}}, + inputVerbatim = {\VerbatimInput{#1}}, + thematicBreak = {\noindent\rule[0.5ex]{\linewidth}{1pt}}, + note = {\footnote{#1}}}} +\RequirePackage{ltxcmds} +\ExplSyntaxOn +\cs_gset:Npn + \markdownRendererInputFencedCodePrototype#1#2#3 + { + \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}{}{} } + } + } + } +\def\markdownLATEXStrongEmphasis#1{% + \str_if_in:NnTF + \f@series + { b } + { \textnormal{#1} } + { \textbf{#1} } +} +\ExplSyntaxOff +\markdownSetup{rendererPrototypes={strongEmphasis={% + \protect\markdownLATEXStrongEmphasis{#1}}}} +\@ifundefined{chapter}{% + \markdownSetup{rendererPrototypes = { + headingOne = {\section{#1}}, + headingTwo = {\subsection{#1}}, + headingThree = {\subsubsection{#1}}, + headingFour = {\paragraph{#1}}, + headingFive = {\subparagraph{#1}}}} +}{% + \markdownSetup{rendererPrototypes = { + headingOne = {\chapter{#1}}, + headingTwo = {\section{#1}}, + headingThree = {\subsection{#1}}, + headingFour = {\subsubsection{#1}}, + headingFive = {\paragraph{#1}}, + headingSix = {\subparagraph{#1}}}} +}% +\markdownSetup{ + rendererPrototypes = { + ulItem = {% + \futurelet\markdownLaTeXCheckbox\markdownLaTeXUlItem + }, + }, +} +\def\markdownLaTeXUlItem{% + \ifx\markdownLaTeXCheckbox\markdownRendererTickedBox + \item[\markdownLaTeXCheckbox]% + \expandafter\@gobble + \else + \ifx\markdownLaTeXCheckbox\markdownRendererHalfTickedBox + \item[\markdownLaTeXCheckbox]% + \expandafter\expandafter\expandafter\@gobble + \else + \ifx\markdownLaTeXCheckbox\markdownRendererUntickedBox + \item[\markdownLaTeXCheckbox]% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\@gobble + \else + \item{}% + \fi + \fi + \fi +} +\@ifundefined{HCode}{}{ + \markdownSetup{ + rendererPrototypes = { + inlineHtmlTag = {% + \ifvmode + \IgnorePar + \EndP + \fi + \HCode{#1}% + }, + inputBlockHtmlElement = {% + \ifvmode + \IgnorePar + \fi + \EndP + \special{t4ht*<#1}% + \par + \ShowPar + }, + }, + } +} +\newcount\markdownLaTeXCitationsCounter + +\RequirePackage{gobble} +\def\markdownLaTeXBasicCitations#1#2#3#4#5#6{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#4\relax + \ifx\relax#5\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \cite{#1#2#6}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobblethree + \fi + \else% Before a postnote (#5), dump the accumulator + \ifx\relax#1\relax\else + \cite{#1}% + \fi + \cite[#5]{#6}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobblethree + \fi + \else% Before a prenote (#4), dump the accumulator + \ifx\relax#1\relax\else + \cite{#1}% + \fi + \ifnum\markdownLaTeXCitationsCounter>1\relax + \space % Insert a space before the prenote in later citations + \fi + #4~\expandafter\cite\ifx\relax#5\relax{#6}\else[#5]{#6}\fi + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \fi + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobblethree + \fi\markdownLaTeXBasicCitations{#1#2#6},} +\let\markdownLaTeXBasicTextCitations\markdownLaTeXBasicCitations + +\def\markdownLaTeXNatbibCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#3\relax + \ifx\relax#4\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \citep{#1,#5}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% Before a postnote (#4), dump the accumulator + \ifx\relax#1\relax\else + \citep{#1}% + \fi + \citep[][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% Before a prenote (#3), dump the accumulator + \ifx\relax#1\relax\relax\else + \citep{#1}% + \fi + \citep[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \else + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \fi + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobbletwo + \fi\markdownLaTeXNatbibCitations{#1,#5}} +\def\markdownLaTeXNatbibTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifx\relax#3\relax + \ifx\relax#4\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \citet{#1,#5}% Without prenotes and postnotes, just accumulate cites + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% After a prenote or a postnote, dump the accumulator + \ifx\relax#1\relax\else + \citet{#1}% + \fi + , \citet[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax + , + \else + \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax + , + \fi + \fi + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter + \@gobbletwo + \fi + \else% After a prenote or a postnote, dump the accumulator + \ifx\relax#1\relax\relax\else + \citet{#1}% + \fi + , \citet[#3][#4]{#5}% + \ifnum\markdownLaTeXCitationsCounter<\markdownLaTeXCitationsTotal\relax + , + \else + \ifnum\markdownLaTeXCitationsCounter=\markdownLaTeXCitationsTotal\relax + , + \fi + \fi + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter + \@gobbletwo + \fi\markdownLaTeXNatbibTextCitations{#1,#5}} + +\def\markdownLaTeXBibLaTeXCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \autocites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXCitations{#1[#3][#4]{#5}}} +\def\markdownLaTeXBibLaTeXTextCitations#1#2#3#4#5{% + \advance\markdownLaTeXCitationsCounter by 1\relax + \ifnum\markdownLaTeXCitationsCounter>\markdownLaTeXCitationsTotal\relax + \textcites#1[#3][#4]{#5}% + \expandafter\@gobbletwo + \fi\markdownLaTeXBibLaTeXTextCitations{#1[#3][#4]{#5}}} + +\markdownSetup{rendererPrototypes = { + cite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \@ifundefined{autocites}{% + \@ifundefined{citep}{% + \expandafter\expandafter\expandafter + \markdownLaTeXBasicCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + }{% + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + }% + }{% + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXCitations + \expandafter{\expandafter}% + }}, + textCite = {% + \markdownLaTeXCitationsCounter=1% + \def\markdownLaTeXCitationsTotal{#1}% + \@ifundefined{autocites}{% + \@ifundefined{citep}{% + \expandafter\expandafter\expandafter + \markdownLaTeXBasicTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + }{% + \expandafter\expandafter\expandafter + \markdownLaTeXNatbibTextCitations + \expandafter\expandafter\expandafter{% + \expandafter\expandafter\expandafter}% + }% + }{% + \expandafter\expandafter\expandafter + \markdownLaTeXBibLaTeXTextCitations + \expandafter{\expandafter}% + }}}} +\RequirePackage{url} +\RequirePackage{expl3} +\ExplSyntaxOn +\def\markdownRendererLinkPrototype#1#2#3#4{ + \tl_set:Nn \l_tmpa_tl { #1 } + \tl_set:Nn \l_tmpb_tl { #2 } + \bool_set:Nn + \l_tmpa_bool + { + \tl_if_eq_p:NN + \l_tmpa_tl + \l_tmpb_tl + } + \tl_set:Nn \l_tmpa_tl { #4 } + \bool_set:Nn + \l_tmpb_bool + { + \tl_if_empty_p:N + \l_tmpa_tl + } + \bool_if:nTF + { + \l_tmpa_bool && \l_tmpb_bool + } + { + \markdownLaTeXRendererAutolink { #2 } { #3 } + }{ + \markdownLaTeXRendererDirectOrIndirectLink { #1 } { #2 } { #3 } { #4 } + } +} +\def\markdownLaTeXRendererAutolink#1#2{% + \tl_set:Nn + \l_tmpa_tl + { #2 } + \tl_trim_spaces:N + \l_tmpa_tl + \tl_set:Nx + \l_tmpb_tl + { + \tl_range:Nnn + \l_tmpa_tl + { 1 } + { 1 } + } + \str_if_eq:NNTF + \l_tmpb_tl + \c_hash_str + { + \tl_set:Nx + \l_tmpb_tl + { + \tl_range:Nnn + \l_tmpa_tl + { 2 } + { -1 } + } + \exp_args:NV + \ref + \l_tmpb_tl + }{ + \url { #2 } + } +} +\ExplSyntaxOff +\def\markdownLaTeXRendererDirectOrIndirectLink#1#2#3#4{% + #1\footnote{\ifx\empty#4\empty\else#4: \fi\url{#3}}} +\newcount\markdownLaTeXRowCounter +\newcount\markdownLaTeXRowTotal +\newcount\markdownLaTeXColumnCounter +\newcount\markdownLaTeXColumnTotal +\newtoks\markdownLaTeXTable +\newtoks\markdownLaTeXTableAlignment +\newtoks\markdownLaTeXTableEnd +\AtBeginDocument{% + \@ifpackageloaded{booktabs}{% + \def\markdownLaTeXTopRule{\toprule}% + \def\markdownLaTeXMidRule{\midrule}% + \def\markdownLaTeXBottomRule{\bottomrule}% + }{% + \def\markdownLaTeXTopRule{\hline}% + \def\markdownLaTeXMidRule{\hline}% + \def\markdownLaTeXBottomRule{\hline}% + }% +} +\markdownSetup{rendererPrototypes={ + table = {% + \markdownLaTeXTable={}% + \markdownLaTeXTableAlignment={}% + \markdownLaTeXTableEnd={% + \markdownLaTeXBottomRule + \end{tabular}}% + \ifx\empty#1\empty\else + \addto@hook\markdownLaTeXTable{% + \begin{table} + \centering}% + \addto@hook\markdownLaTeXTableEnd{% + \caption{#1} + \end{table}}% + \fi + \addto@hook\markdownLaTeXTable{\begin{tabular}}% + \markdownLaTeXRowCounter=0% + \markdownLaTeXRowTotal=#2% + \markdownLaTeXColumnTotal=#3% + \markdownLaTeXRenderTableRow + } +}} +\def\markdownLaTeXRenderTableRow#1{% + \markdownLaTeXColumnCounter=0% + \ifnum\markdownLaTeXRowCounter=0\relax + \markdownLaTeXReadAlignments#1% + \markdownLaTeXTable=\expandafter\expandafter\expandafter{% + \expandafter\the\expandafter\markdownLaTeXTable\expandafter{% + \the\markdownLaTeXTableAlignment}}% + \addto@hook\markdownLaTeXTable{\markdownLaTeXTopRule}% + \else + \markdownLaTeXRenderTableCell#1% + \fi + \ifnum\markdownLaTeXRowCounter=1\relax + \addto@hook\markdownLaTeXTable\markdownLaTeXMidRule + \fi + \advance\markdownLaTeXRowCounter by 1\relax + \ifnum\markdownLaTeXRowCounter>\markdownLaTeXRowTotal\relax + \the\markdownLaTeXTable + \the\markdownLaTeXTableEnd + \expandafter\@gobble + \fi\markdownLaTeXRenderTableRow} +\def\markdownLaTeXReadAlignments#1{% + \advance\markdownLaTeXColumnCounter by 1\relax + \if#1d% + \addto@hook\markdownLaTeXTableAlignment{l}% + \else + \addto@hook\markdownLaTeXTableAlignment{#1}% + \fi + \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax\else + \expandafter\@gobble + \fi\markdownLaTeXReadAlignments} +\def\markdownLaTeXRenderTableCell#1{% + \advance\markdownLaTeXColumnCounter by 1\relax + \ifnum\markdownLaTeXColumnCounter<\markdownLaTeXColumnTotal\relax + \addto@hook\markdownLaTeXTable{#1&}% + \else + \addto@hook\markdownLaTeXTable{#1\\}% + \expandafter\@gobble + \fi\markdownLaTeXRenderTableCell} + +\markdownIfOption{lineBlocks}{% + \RequirePackage{verse} + \markdownSetup{rendererPrototypes={ + lineBlockBegin = {% + \begingroup + \def\markdownRendererHardLineBreak{\\}% + \begin{verse}% + }, + lineBlockEnd = {% + \end{verse}% + \endgroup + }, + }} +}{} + +\ExplSyntaxOn +\keys_define:nn + { markdown/jekyllData } + { + author .code:n = { \author{#1} }, + date .code:n = { \date{#1} }, + title .code:n = { \title{#1} }, + } +\markdownSetup{ + rendererPrototypes = { + jekyllDataEnd = { + \AddToHook{begindocument/end}{\maketitle} + }, + }, +} +\ExplSyntaxOff +\markdownIfOption{strikeThrough}{% + \RequirePackage{soulutf8}% + \markdownSetup{ + rendererPrototypes = { + strikeThrough = {% + \st{#1}% + }, + } + } +}{} +\markdownIfOption{mark}{% + \RequirePackage{soulutf8}% + \markdownSetup{ + rendererPrototypes = { + mark = {% + \hl{#1}% + }, + } + } +}{} +\ExplSyntaxOn +\__markdown_if_option:nT + { linkAttributes } + { + \RequirePackage{graphicx} + \markdownSetup{ + rendererPrototypes = { + imageAttributeContextBegin = { + \group_begin: + \markdownSetup{ + rendererPrototypes = { + attributeKeyValue = { + \setkeys + { Gin } + { { ##1 } = { ##2 } } + }, + }, + } + }, + imageAttributeContextEnd = { + \group_end: + }, + }, + } + } +\cs_gset:Npn + \markdownRendererInputRawInlinePrototype#1#2 + { + \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 } + { + { 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 } + } + } +\ExplSyntaxOff +\fi % Closes `\markdownIfOption{plain}{\iffalse}{\iftrue}` +\endinput +%% +%% End of file `markdownthemewitiko_markdown_defaults.sty'. diff --git a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_tilde.sty b/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_tilde.sty deleted file mode 100644 index 83dcd4015bf..00000000000 --- a/Master/texmf-dist/tex/latex/markdown/markdownthemewitiko_tilde.sty +++ /dev/null @@ -1,49 +0,0 @@ -%% -%% This is file `markdownthemewitiko_tilde.sty', -%% generated with the docstrip utility. -%% -%% The original source files were: -%% -%% markdown.dtx (with options: `latex-themes-witiko-tilde') -%% -%% Copyright (C) 2016-2023 Vít Novotný -%% -%% This work may be distributed and/or modified under the -%% conditions of the LaTeX Project Public License, either version 1.3c -%% of this license or (at your option) any later version. -%% The latest version of this license is in -%% -%% http://www.latex-project.org/lppl.txt -%% -%% This work has the LPPL maintenance status `maintained'. -%% The Current Maintainer of this work is Vít Novotný. -%% -%% Send bug reports, requests for additions and questions -%% either to the GitHub issue tracker at -%% -%% https://github.com/Witiko/markdown/issues -%% -%% or to the e-mail address . -%% -%% MODIFICATION ADVICE: -%% -%% If you want to customize this file, it is best to make a copy of -%% the source file(s) from which it was produced. Use a different -%% name for your copy(ies) and modify the copy(ies); this will ensure -%% that your modifications do not get overwritten when you install a -%% new release of the standard system. You should also ensure that -%% your modified source file does not generate any modified file with -%% the same name as a standard file. -%% -%% You will also need to produce your own, suitably named, .ins file to -%% control the generation of files from your source file; this file -%% should contain your own preambles for the files it generates, not -%% those in the standard .ins files. -%% -%% The names of the source files used are shown above. -%% -\ProvidesPackage{markdownthemewitiko_tilde}[2021/03/22]% -\renewcommand\markdownRendererTildePrototype{~}% -\endinput -%% -%% End of file `markdownthemewitiko_tilde.sty'. diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua b/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua index 074ad79446e..36cef293ed9 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua @@ -633,8 +633,10 @@ function Parser:parseseq(line, lines, indent) error("did not find expected alphabetic or numeric character") elseif rest then -- Array entry with a value + local nextline = lines[1] + local indent2 = countindent(nextline) tremove(lines, 1) - tinsert(seq, self:parsescalar(rest, lines)) + tinsert(seq, self:parsescalar(rest, lines, indent2)) end end return seq diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 225428abe03..fce3c1fe827 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -20,7 +20,7 @@ -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -- --- Copyright (C) 2016-2023 Vít Novotný +-- Copyright (C) 2016-2024 Vít Starý Novotný -- -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3 @@ -33,7 +33,7 @@ -- version 2005/12/01 or later. -- -- This work has the LPPL maintenance status `maintained'. --- The Current Maintainer of this work is Vít Novotný. +-- The Current Maintainer of this work is Vít Starý Novotný. -- -- Send bug reports, requests for additions and questions -- either to the GitHub issue tracker at @@ -58,50 +58,28 @@ -- those in the standard .ins files. -- local metadata = { - version = "2.23.0-0-g0b22f91", + version = "3.4.1-0-g457226ae", comment = "A module for the conversion from markdown to plain TeX", - author = "John MacFarlane, Hans Hagen, Vít Novotný", + author = "John MacFarlane, Hans Hagen, Vít Starý Novotný", copyright = {"2009-2016 John MacFarlane, Hans Hagen", - "2016-2023 Vít Novotný"}, + "2016-2023 Vít Starý Novotný"}, license = "LPPL 1.3c" } if not modules then modules = { } end modules['markdown'] = metadata local lpeg = require("lpeg") -local unicode -(function() - local ran_ok - ran_ok, unicode = pcall(require, "unicode") - if not ran_ok then - unicode = {utf8 = {char=utf8.char}} - end -end)() +local unicode = require("unicode") local md5 = require("md5"); (function() local should_initialize = package.loaded.kpse == nil or tex.initialize ~= nil - local ran_ok - ran_ok, kpse = pcall(require, "kpse") - if ran_ok and should_initialize then + kpse = require("kpse") + if should_initialize then kpse.set_program_name("luatex") end - if not ran_ok then - kpse = {lookup = function(f, _) return f end} - end -end)() -local uni_case -(function() - local ran_ok - ran_ok, uni_case = pcall(require, "lua-uni-case") - if not ran_ok then - if unicode.utf8.lower then - uni_case = {casefold = unicode.utf8.lower} - else - uni_case = {casefold = string.lower} - end - end end)() +local uni_algos = require("lua-uni-algos") local M = {metadata = metadata} local walkable_syntax = { Block = { @@ -110,8 +88,11 @@ local walkable_syntax = { "ThematicBreak", "BulletList", "OrderedList", - "Heading", "DisplayHtml", + "Heading", + }, + BlockOrParagraph = { + "Block", "Paragraph", "Plain", }, @@ -119,11 +100,8 @@ local walkable_syntax = { "Str", "Space", "Endline", - "UlOrStarLine", - "Strong", - "Emph", - "Link", - "Image", + "EndlineBreak", + "LinkAndEmph", "Code", "AutoLinkUrl", "AutoLinkEmail", @@ -136,49 +114,56 @@ local walkable_syntax = { }, } local defaultOptions = {} +defaultOptions.eagerCache = false +defaultOptions.singletonCache = true +local singletonCache = { + convert = nil, + options = nil, +} defaultOptions.cacheDir = "." defaultOptions.contentBlocksLanguageMap = "markdown-languages.json" defaultOptions.debugExtensionsFileName = "debug-extensions.json" defaultOptions.frozenCacheFileName = "frozenCache.tex" +defaultOptions.autoIdentifiers = false defaultOptions.blankBeforeBlockquote = false defaultOptions.blankBeforeCodeFence = false defaultOptions.blankBeforeDivFence = false defaultOptions.blankBeforeHeading = false +defaultOptions.blankBeforeList = false defaultOptions.bracketedSpans = false -defaultOptions.breakableBlockquotes = false +defaultOptions.breakableBlockquotes = true defaultOptions.citationNbsps = true defaultOptions.citations = false defaultOptions.codeSpans = true defaultOptions.contentBlocks = false +defaultOptions.contentLevel = "block" defaultOptions.debugExtensions = false defaultOptions.definitionLists = false -defaultOptions.eagerCache = true defaultOptions.expectJekyllData = false metadata.user_extension_api_version = 2 -metadata.grammar_version = 2 +metadata.grammar_version = 4 defaultOptions.extensions = {} defaultOptions.fancyLists = false -defaultOptions.fencedCode = false +defaultOptions.fencedCode = true defaultOptions.fencedCodeAttributes = false defaultOptions.fencedDivs = false defaultOptions.finalizeCache = false defaultOptions.frozenCacheCounter = 0 -defaultOptions.hardLineBreaks = false +defaultOptions.gfmAutoIdentifiers = false defaultOptions.hashEnumerators = false defaultOptions.headerAttributes = false -defaultOptions.html = false +defaultOptions.html = true defaultOptions.hybrid = false defaultOptions.inlineCodeAttributes = false -defaultOptions.inlineFootnotes = false defaultOptions.inlineNotes = false defaultOptions.jekyllData = false defaultOptions.linkAttributes = false defaultOptions.lineBlocks = false -defaultOptions.footnotes = false +defaultOptions.mark = false defaultOptions.notes = false defaultOptions.pipeTables = false -defaultOptions.preserveTabs = false -defaultOptions.rawAttribute = true +defaultOptions.preserveTabs = true +defaultOptions.rawAttribute = false defaultOptions.relativeReferences = false defaultOptions.shiftHeadings = 0 defaultOptions.slice = "^ $" @@ -188,6 +173,7 @@ defaultOptions.strikeThrough = false defaultOptions.stripIndent = false defaultOptions.subscripts = false defaultOptions.superscripts = false +defaultOptions.tableAttributes = false defaultOptions.tableCaptions = false defaultOptions.taskLists = false defaultOptions.texComments = false @@ -198,9 +184,9 @@ defaultOptions.tightLists = true defaultOptions.underscores = true local upper, format, length = string.upper, string.format, string.len -local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, any = +local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, Cp, any = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cg, lpeg.Cb, - lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.P(1) + lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.Cp, lpeg.P(1) local util = {} function util.err(msg, exit_code) io.stderr:write("markdown.lua: " .. msg .. "\n") @@ -348,13 +334,13 @@ local character_entities = { ["Tab"] = 9, ["NewLine"] = 10, ["excl"] = 33, - ["quot"] = 34, ["QUOT"] = 34, + ["quot"] = 34, ["num"] = 35, ["dollar"] = 36, ["percnt"] = 37, - ["amp"] = 38, ["AMP"] = 38, + ["amp"] = 38, ["apos"] = 39, ["lpar"] = 40, ["rpar"] = 41, @@ -366,31 +352,36 @@ local character_entities = { ["sol"] = 47, ["colon"] = 58, ["semi"] = 59, - ["lt"] = 60, ["LT"] = 60, + ["lt"] = 60, + ["nvlt"] = {60, 8402}, + ["bne"] = {61, 8421}, ["equals"] = 61, - ["gt"] = 62, ["GT"] = 62, + ["gt"] = 62, + ["nvgt"] = {62, 8402}, ["quest"] = 63, ["commat"] = 64, - ["lsqb"] = 91, ["lbrack"] = 91, + ["lsqb"] = 91, ["bsol"] = 92, - ["rsqb"] = 93, ["rbrack"] = 93, + ["rsqb"] = 93, ["Hat"] = 94, + ["UnderBar"] = 95, ["lowbar"] = 95, - ["grave"] = 96, ["DiacriticalGrave"] = 96, - ["lcub"] = 123, + ["grave"] = 96, + ["fjlig"] = {102, 106}, ["lbrace"] = 123, + ["lcub"] = 123, + ["VerticalLine"] = 124, ["verbar"] = 124, ["vert"] = 124, - ["VerticalLine"] = 124, - ["rcub"] = 125, ["rbrace"] = 125, - ["nbsp"] = 160, + ["rcub"] = 125, ["NonBreakingSpace"] = 160, + ["nbsp"] = 160, ["iexcl"] = 161, ["cent"] = 162, ["pound"] = 163, @@ -399,36 +390,35 @@ local character_entities = { ["brvbar"] = 166, ["sect"] = 167, ["Dot"] = 168, - ["die"] = 168, ["DoubleDot"] = 168, + ["die"] = 168, ["uml"] = 168, - ["copy"] = 169, ["COPY"] = 169, + ["copy"] = 169, ["ordf"] = 170, ["laquo"] = 171, ["not"] = 172, ["shy"] = 173, - ["reg"] = 174, - ["circledR"] = 174, ["REG"] = 174, + ["circledR"] = 174, + ["reg"] = 174, ["macr"] = 175, - ["OverBar"] = 175, ["strns"] = 175, ["deg"] = 176, + ["PlusMinus"] = 177, ["plusmn"] = 177, ["pm"] = 177, - ["PlusMinus"] = 177, ["sup2"] = 178, ["sup3"] = 179, - ["acute"] = 180, ["DiacriticalAcute"] = 180, + ["acute"] = 180, ["micro"] = 181, ["para"] = 182, - ["middot"] = 183, - ["centerdot"] = 183, ["CenterDot"] = 183, - ["cedil"] = 184, + ["centerdot"] = 183, + ["middot"] = 183, ["Cedilla"] = 184, + ["cedil"] = 184, ["sup1"] = 185, ["ordm"] = 186, ["raquo"] = 187, @@ -443,6 +433,7 @@ local character_entities = { ["Atilde"] = 195, ["Auml"] = 196, ["Aring"] = 197, + ["angst"] = 197, ["AElig"] = 198, ["Ccedil"] = 199, ["Egrave"] = 200, @@ -492,8 +483,8 @@ local character_entities = { ["ocirc"] = 244, ["otilde"] = 245, ["ouml"] = 246, - ["divide"] = 247, ["div"] = 247, + ["divide"] = 247, ["oslash"] = 248, ["ugrave"] = 249, ["uacute"] = 250, @@ -628,20 +619,19 @@ local character_entities = { ["gacute"] = 501, ["jmath"] = 567, ["circ"] = 710, - ["caron"] = 711, ["Hacek"] = 711, - ["breve"] = 728, + ["caron"] = 711, ["Breve"] = 728, - ["dot"] = 729, + ["breve"] = 728, ["DiacriticalDot"] = 729, + ["dot"] = 729, ["ring"] = 730, ["ogon"] = 731, - ["tilde"] = 732, ["DiacriticalTilde"] = 732, - ["dblac"] = 733, + ["tilde"] = 732, ["DiacriticalDoubleAcute"] = 733, + ["dblac"] = 733, ["DownBreve"] = 785, - ["UnderBar"] = 818, ["Alpha"] = 913, ["Beta"] = 914, ["Gamma"] = 915, @@ -666,12 +656,12 @@ local character_entities = { ["Chi"] = 935, ["Psi"] = 936, ["Omega"] = 937, + ["ohm"] = 937, ["alpha"] = 945, ["beta"] = 946, ["gamma"] = 947, ["delta"] = 948, - ["epsiv"] = 949, - ["varepsilon"] = 949, + ["epsi"] = 949, ["epsilon"] = 949, ["zeta"] = 950, ["eta"] = 951, @@ -685,38 +675,39 @@ local character_entities = { ["omicron"] = 959, ["pi"] = 960, ["rho"] = 961, + ["sigmaf"] = 962, ["sigmav"] = 962, ["varsigma"] = 962, - ["sigmaf"] = 962, ["sigma"] = 963, ["tau"] = 964, ["upsi"] = 965, ["upsilon"] = 965, ["phi"] = 966, - ["phiv"] = 966, - ["varphi"] = 966, ["chi"] = 967, ["psi"] = 968, ["omega"] = 969, + ["thetasym"] = 977, ["thetav"] = 977, ["vartheta"] = 977, - ["thetasym"] = 977, ["Upsi"] = 978, ["upsih"] = 978, + ["phiv"] = 981, ["straightphi"] = 981, + ["varphi"] = 981, ["piv"] = 982, ["varpi"] = 982, ["Gammad"] = 988, - ["gammad"] = 989, ["digamma"] = 989, + ["gammad"] = 989, ["kappav"] = 1008, ["varkappa"] = 1008, ["rhov"] = 1009, ["varrho"] = 1009, - ["epsi"] = 1013, + ["epsiv"] = 1013, ["straightepsilon"] = 1013, - ["bepsi"] = 1014, + ["varepsilon"] = 1013, ["backepsilon"] = 1014, + ["bepsi"] = 1014, ["IOcy"] = 1025, ["DJcy"] = 1026, ["GJcy"] = 1027, @@ -815,40 +806,40 @@ local character_entities = { ["emsp14"] = 8197, ["numsp"] = 8199, ["puncsp"] = 8200, - ["thinsp"] = 8201, ["ThinSpace"] = 8201, - ["hairsp"] = 8202, + ["thinsp"] = 8201, ["VeryThinSpace"] = 8202, - ["ZeroWidthSpace"] = 8203, - ["NegativeVeryThinSpace"] = 8203, - ["NegativeThinSpace"] = 8203, + ["hairsp"] = 8202, ["NegativeMediumSpace"] = 8203, ["NegativeThickSpace"] = 8203, + ["NegativeThinSpace"] = 8203, + ["NegativeVeryThinSpace"] = 8203, + ["ZeroWidthSpace"] = 8203, ["zwnj"] = 8204, ["zwj"] = 8205, ["lrm"] = 8206, ["rlm"] = 8207, - ["hyphen"] = 8208, ["dash"] = 8208, + ["hyphen"] = 8208, ["ndash"] = 8211, ["mdash"] = 8212, ["horbar"] = 8213, ["Verbar"] = 8214, ["Vert"] = 8214, - ["lsquo"] = 8216, ["OpenCurlyQuote"] = 8216, + ["lsquo"] = 8216, + ["CloseCurlyQuote"] = 8217, ["rsquo"] = 8217, ["rsquor"] = 8217, - ["CloseCurlyQuote"] = 8217, ["lsquor"] = 8218, ["sbquo"] = 8218, - ["ldquo"] = 8220, ["OpenCurlyDoubleQuote"] = 8220, + ["ldquo"] = 8220, + ["CloseCurlyDoubleQuote"] = 8221, ["rdquo"] = 8221, ["rdquor"] = 8221, - ["CloseCurlyDoubleQuote"] = 8221, - ["ldquor"] = 8222, ["bdquo"] = 8222, + ["ldquor"] = 8222, ["dagger"] = 8224, ["Dagger"] = 8225, ["ddagger"] = 8225, @@ -862,10 +853,11 @@ local character_entities = { ["prime"] = 8242, ["Prime"] = 8243, ["tprime"] = 8244, - ["bprime"] = 8245, ["backprime"] = 8245, + ["bprime"] = 8245, ["lsaquo"] = 8249, ["rsaquo"] = 8250, + ["OverBar"] = 8254, ["oline"] = 8254, ["caret"] = 8257, ["hybull"] = 8259, @@ -873,6 +865,7 @@ local character_entities = { ["bsemi"] = 8271, ["qprime"] = 8279, ["MediumSpace"] = 8287, + ["ThickSpace"] = {8287, 8202}, ["NoBreak"] = 8288, ["ApplyFunction"] = 8289, ["af"] = 8289, @@ -881,34 +874,34 @@ local character_entities = { ["InvisibleComma"] = 8291, ["ic"] = 8291, ["euro"] = 8364, - ["tdot"] = 8411, ["TripleDot"] = 8411, + ["tdot"] = 8411, ["DotDot"] = 8412, ["Copf"] = 8450, ["complexes"] = 8450, ["incare"] = 8453, ["gscr"] = 8458, - ["hamilt"] = 8459, ["HilbertSpace"] = 8459, ["Hscr"] = 8459, + ["hamilt"] = 8459, ["Hfr"] = 8460, ["Poincareplane"] = 8460, - ["quaternions"] = 8461, ["Hopf"] = 8461, + ["quaternions"] = 8461, ["planckh"] = 8462, - ["planck"] = 8463, ["hbar"] = 8463, - ["plankv"] = 8463, ["hslash"] = 8463, + ["planck"] = 8463, + ["plankv"] = 8463, ["Iscr"] = 8464, ["imagline"] = 8464, - ["image"] = 8465, + ["Ifr"] = 8465, ["Im"] = 8465, + ["image"] = 8465, ["imagpart"] = 8465, - ["Ifr"] = 8465, + ["Laplacetrf"] = 8466, ["Lscr"] = 8466, ["lagran"] = 8466, - ["Laplacetrf"] = 8466, ["ell"] = 8467, ["Nopf"] = 8469, ["naturals"] = 8469, @@ -918,40 +911,38 @@ local character_entities = { ["wp"] = 8472, ["Popf"] = 8473, ["primes"] = 8473, - ["rationals"] = 8474, ["Qopf"] = 8474, + ["rationals"] = 8474, ["Rscr"] = 8475, ["realine"] = 8475, - ["real"] = 8476, ["Re"] = 8476, - ["realpart"] = 8476, ["Rfr"] = 8476, - ["reals"] = 8477, + ["real"] = 8476, + ["realpart"] = 8476, ["Ropf"] = 8477, + ["reals"] = 8477, ["rx"] = 8478, - ["trade"] = 8482, ["TRADE"] = 8482, - ["integers"] = 8484, + ["trade"] = 8482, ["Zopf"] = 8484, - ["ohm"] = 8486, + ["integers"] = 8484, ["mho"] = 8487, ["Zfr"] = 8488, ["zeetrf"] = 8488, ["iiota"] = 8489, - ["angst"] = 8491, - ["bernou"] = 8492, ["Bernoullis"] = 8492, ["Bscr"] = 8492, - ["Cfr"] = 8493, + ["bernou"] = 8492, ["Cayleys"] = 8493, + ["Cfr"] = 8493, ["escr"] = 8495, ["Escr"] = 8496, ["expectation"] = 8496, - ["Fscr"] = 8497, ["Fouriertrf"] = 8497, - ["phmmat"] = 8499, + ["Fscr"] = 8497, ["Mellintrf"] = 8499, ["Mscr"] = 8499, + ["phmmat"] = 8499, ["order"] = 8500, ["orderof"] = 8500, ["oscr"] = 8500, @@ -965,8 +956,8 @@ local character_entities = { ["DifferentialD"] = 8518, ["dd"] = 8518, ["ExponentialE"] = 8519, - ["exponentiale"] = 8519, ["ee"] = 8519, + ["exponentiale"] = 8519, ["ImaginaryI"] = 8520, ["ii"] = 8520, ["frac13"] = 8531, @@ -981,46 +972,47 @@ local character_entities = { ["frac38"] = 8540, ["frac58"] = 8541, ["frac78"] = 8542, + ["LeftArrow"] = 8592, + ["ShortLeftArrow"] = 8592, ["larr"] = 8592, ["leftarrow"] = 8592, - ["LeftArrow"] = 8592, ["slarr"] = 8592, - ["ShortLeftArrow"] = 8592, + ["ShortUpArrow"] = 8593, + ["UpArrow"] = 8593, ["uarr"] = 8593, ["uparrow"] = 8593, - ["UpArrow"] = 8593, - ["ShortUpArrow"] = 8593, + ["RightArrow"] = 8594, + ["ShortRightArrow"] = 8594, ["rarr"] = 8594, ["rightarrow"] = 8594, - ["RightArrow"] = 8594, ["srarr"] = 8594, - ["ShortRightArrow"] = 8594, - ["darr"] = 8595, - ["downarrow"] = 8595, ["DownArrow"] = 8595, ["ShortDownArrow"] = 8595, + ["darr"] = 8595, + ["downarrow"] = 8595, + ["LeftRightArrow"] = 8596, ["harr"] = 8596, ["leftrightarrow"] = 8596, - ["LeftRightArrow"] = 8596, - ["varr"] = 8597, - ["updownarrow"] = 8597, ["UpDownArrow"] = 8597, - ["nwarr"] = 8598, + ["updownarrow"] = 8597, + ["varr"] = 8597, ["UpperLeftArrow"] = 8598, + ["nwarr"] = 8598, ["nwarrow"] = 8598, - ["nearr"] = 8599, ["UpperRightArrow"] = 8599, + ["nearr"] = 8599, ["nearrow"] = 8599, + ["LowerRightArrow"] = 8600, ["searr"] = 8600, ["searrow"] = 8600, - ["LowerRightArrow"] = 8600, + ["LowerLeftArrow"] = 8601, ["swarr"] = 8601, ["swarrow"] = 8601, - ["LowerLeftArrow"] = 8601, ["nlarr"] = 8602, ["nleftarrow"] = 8602, ["nrarr"] = 8603, ["nrightarrow"] = 8603, + ["nrarrw"] = {8605, 824}, ["rarrw"] = 8605, ["rightsquigarrow"] = 8605, ["Larr"] = 8606, @@ -1037,27 +1029,27 @@ local character_entities = { ["mapstoleft"] = 8612, ["UpTeeArrow"] = 8613, ["mapstoup"] = 8613, - ["map"] = 8614, ["RightTeeArrow"] = 8614, + ["map"] = 8614, ["mapsto"] = 8614, ["DownTeeArrow"] = 8615, ["mapstodown"] = 8615, - ["larrhk"] = 8617, ["hookleftarrow"] = 8617, - ["rarrhk"] = 8618, + ["larrhk"] = 8617, ["hookrightarrow"] = 8618, + ["rarrhk"] = 8618, ["larrlp"] = 8619, ["looparrowleft"] = 8619, - ["rarrlp"] = 8620, ["looparrowright"] = 8620, + ["rarrlp"] = 8620, ["harrw"] = 8621, ["leftrightsquigarrow"] = 8621, ["nharr"] = 8622, ["nleftrightarrow"] = 8622, - ["lsh"] = 8624, ["Lsh"] = 8624, - ["rsh"] = 8625, + ["lsh"] = 8624, ["Rsh"] = 8625, + ["rsh"] = 8625, ["ldsh"] = 8626, ["rdsh"] = 8627, ["crarr"] = 8629, @@ -1065,456 +1057,505 @@ local character_entities = { ["curvearrowleft"] = 8630, ["curarr"] = 8631, ["curvearrowright"] = 8631, - ["olarr"] = 8634, ["circlearrowleft"] = 8634, - ["orarr"] = 8635, + ["olarr"] = 8634, ["circlearrowright"] = 8635, - ["lharu"] = 8636, + ["orarr"] = 8635, ["LeftVector"] = 8636, ["leftharpoonup"] = 8636, - ["lhard"] = 8637, - ["leftharpoondown"] = 8637, + ["lharu"] = 8636, ["DownLeftVector"] = 8637, + ["leftharpoondown"] = 8637, + ["lhard"] = 8637, + ["RightUpVector"] = 8638, ["uharr"] = 8638, ["upharpoonright"] = 8638, - ["RightUpVector"] = 8638, + ["LeftUpVector"] = 8639, ["uharl"] = 8639, ["upharpoonleft"] = 8639, - ["LeftUpVector"] = 8639, - ["rharu"] = 8640, ["RightVector"] = 8640, + ["rharu"] = 8640, ["rightharpoonup"] = 8640, + ["DownRightVector"] = 8641, ["rhard"] = 8641, ["rightharpoondown"] = 8641, - ["DownRightVector"] = 8641, - ["dharr"] = 8642, ["RightDownVector"] = 8642, + ["dharr"] = 8642, ["downharpoonright"] = 8642, - ["dharl"] = 8643, ["LeftDownVector"] = 8643, + ["dharl"] = 8643, ["downharpoonleft"] = 8643, - ["rlarr"] = 8644, - ["rightleftarrows"] = 8644, ["RightArrowLeftArrow"] = 8644, - ["udarr"] = 8645, + ["rightleftarrows"] = 8644, + ["rlarr"] = 8644, ["UpArrowDownArrow"] = 8645, - ["lrarr"] = 8646, - ["leftrightarrows"] = 8646, + ["udarr"] = 8645, ["LeftArrowRightArrow"] = 8646, - ["llarr"] = 8647, + ["leftrightarrows"] = 8646, + ["lrarr"] = 8646, ["leftleftarrows"] = 8647, - ["uuarr"] = 8648, + ["llarr"] = 8647, ["upuparrows"] = 8648, - ["rrarr"] = 8649, + ["uuarr"] = 8648, ["rightrightarrows"] = 8649, + ["rrarr"] = 8649, ["ddarr"] = 8650, ["downdownarrows"] = 8650, - ["lrhar"] = 8651, ["ReverseEquilibrium"] = 8651, ["leftrightharpoons"] = 8651, - ["rlhar"] = 8652, - ["rightleftharpoons"] = 8652, + ["lrhar"] = 8651, ["Equilibrium"] = 8652, - ["nlArr"] = 8653, + ["rightleftharpoons"] = 8652, + ["rlhar"] = 8652, ["nLeftarrow"] = 8653, - ["nhArr"] = 8654, + ["nlArr"] = 8653, ["nLeftrightarrow"] = 8654, - ["nrArr"] = 8655, + ["nhArr"] = 8654, ["nRightarrow"] = 8655, - ["lArr"] = 8656, - ["Leftarrow"] = 8656, + ["nrArr"] = 8655, ["DoubleLeftArrow"] = 8656, - ["uArr"] = 8657, - ["Uparrow"] = 8657, + ["Leftarrow"] = 8656, + ["lArr"] = 8656, ["DoubleUpArrow"] = 8657, - ["rArr"] = 8658, - ["Rightarrow"] = 8658, - ["Implies"] = 8658, + ["Uparrow"] = 8657, + ["uArr"] = 8657, ["DoubleRightArrow"] = 8658, - ["dArr"] = 8659, - ["Downarrow"] = 8659, + ["Implies"] = 8658, + ["Rightarrow"] = 8658, + ["rArr"] = 8658, ["DoubleDownArrow"] = 8659, - ["hArr"] = 8660, - ["Leftrightarrow"] = 8660, + ["Downarrow"] = 8659, + ["dArr"] = 8659, ["DoubleLeftRightArrow"] = 8660, + ["Leftrightarrow"] = 8660, + ["hArr"] = 8660, ["iff"] = 8660, - ["vArr"] = 8661, - ["Updownarrow"] = 8661, ["DoubleUpDownArrow"] = 8661, + ["Updownarrow"] = 8661, + ["vArr"] = 8661, ["nwArr"] = 8662, ["neArr"] = 8663, ["seArr"] = 8664, ["swArr"] = 8665, - ["lAarr"] = 8666, ["Lleftarrow"] = 8666, - ["rAarr"] = 8667, + ["lAarr"] = 8666, ["Rrightarrow"] = 8667, + ["rAarr"] = 8667, ["zigrarr"] = 8669, - ["larrb"] = 8676, ["LeftArrowBar"] = 8676, - ["rarrb"] = 8677, + ["larrb"] = 8676, ["RightArrowBar"] = 8677, - ["duarr"] = 8693, + ["rarrb"] = 8677, ["DownArrowUpArrow"] = 8693, + ["duarr"] = 8693, ["loarr"] = 8701, ["roarr"] = 8702, ["hoarr"] = 8703, - ["forall"] = 8704, ["ForAll"] = 8704, + ["forall"] = 8704, ["comp"] = 8705, ["complement"] = 8705, - ["part"] = 8706, ["PartialD"] = 8706, - ["exist"] = 8707, + ["npart"] = {8706, 824}, + ["part"] = 8706, ["Exists"] = 8707, - ["nexist"] = 8708, + ["exist"] = 8707, ["NotExists"] = 8708, + ["nexist"] = 8708, ["nexists"] = 8708, ["empty"] = 8709, ["emptyset"] = 8709, ["emptyv"] = 8709, ["varnothing"] = 8709, - ["nabla"] = 8711, ["Del"] = 8711, - ["isin"] = 8712, - ["isinv"] = 8712, + ["nabla"] = 8711, ["Element"] = 8712, ["in"] = 8712, - ["notin"] = 8713, + ["isin"] = 8712, + ["isinv"] = 8712, ["NotElement"] = 8713, + ["notin"] = 8713, ["notinva"] = 8713, - ["niv"] = 8715, ["ReverseElement"] = 8715, - ["ni"] = 8715, ["SuchThat"] = 8715, + ["ni"] = 8715, + ["niv"] = 8715, + ["NotReverseElement"] = 8716, ["notni"] = 8716, ["notniva"] = 8716, - ["NotReverseElement"] = 8716, - ["prod"] = 8719, ["Product"] = 8719, - ["coprod"] = 8720, + ["prod"] = 8719, ["Coproduct"] = 8720, - ["sum"] = 8721, + ["coprod"] = 8720, ["Sum"] = 8721, + ["sum"] = 8721, ["minus"] = 8722, + ["MinusPlus"] = 8723, ["mnplus"] = 8723, ["mp"] = 8723, - ["MinusPlus"] = 8723, - ["plusdo"] = 8724, ["dotplus"] = 8724, - ["setmn"] = 8726, - ["setminus"] = 8726, + ["plusdo"] = 8724, ["Backslash"] = 8726, - ["ssetmn"] = 8726, + ["setminus"] = 8726, + ["setmn"] = 8726, ["smallsetminus"] = 8726, + ["ssetmn"] = 8726, ["lowast"] = 8727, - ["compfn"] = 8728, ["SmallCircle"] = 8728, - ["radic"] = 8730, + ["compfn"] = 8728, ["Sqrt"] = 8730, + ["radic"] = 8730, + ["Proportional"] = 8733, ["prop"] = 8733, ["propto"] = 8733, - ["Proportional"] = 8733, - ["vprop"] = 8733, ["varpropto"] = 8733, + ["vprop"] = 8733, ["infin"] = 8734, ["angrt"] = 8735, ["ang"] = 8736, ["angle"] = 8736, + ["nang"] = {8736, 8402}, ["angmsd"] = 8737, ["measuredangle"] = 8737, ["angsph"] = 8738, - ["mid"] = 8739, ["VerticalBar"] = 8739, - ["smid"] = 8739, + ["mid"] = 8739, ["shortmid"] = 8739, - ["nmid"] = 8740, + ["smid"] = 8739, ["NotVerticalBar"] = 8740, - ["nsmid"] = 8740, + ["nmid"] = 8740, ["nshortmid"] = 8740, + ["nsmid"] = 8740, + ["DoubleVerticalBar"] = 8741, ["par"] = 8741, ["parallel"] = 8741, - ["DoubleVerticalBar"] = 8741, - ["spar"] = 8741, ["shortparallel"] = 8741, + ["spar"] = 8741, + ["NotDoubleVerticalBar"] = 8742, ["npar"] = 8742, ["nparallel"] = 8742, - ["NotDoubleVerticalBar"] = 8742, - ["nspar"] = 8742, ["nshortparallel"] = 8742, + ["nspar"] = 8742, ["and"] = 8743, ["wedge"] = 8743, ["or"] = 8744, ["vee"] = 8744, ["cap"] = 8745, + ["caps"] = {8745, 65024}, ["cup"] = 8746, - ["int"] = 8747, + ["cups"] = {8746, 65024}, ["Integral"] = 8747, + ["int"] = 8747, ["Int"] = 8748, - ["tint"] = 8749, ["iiint"] = 8749, + ["tint"] = 8749, + ["ContourIntegral"] = 8750, ["conint"] = 8750, ["oint"] = 8750, - ["ContourIntegral"] = 8750, ["Conint"] = 8751, ["DoubleContourIntegral"] = 8751, ["Cconint"] = 8752, ["cwint"] = 8753, - ["cwconint"] = 8754, ["ClockwiseContourIntegral"] = 8754, - ["awconint"] = 8755, + ["cwconint"] = 8754, ["CounterClockwiseContourIntegral"] = 8755, + ["awconint"] = 8755, + ["Therefore"] = 8756, ["there4"] = 8756, ["therefore"] = 8756, - ["Therefore"] = 8756, + ["Because"] = 8757, ["becaus"] = 8757, ["because"] = 8757, - ["Because"] = 8757, ["ratio"] = 8758, ["Colon"] = 8759, ["Proportion"] = 8759, - ["minusd"] = 8760, ["dotminus"] = 8760, + ["minusd"] = 8760, ["mDDot"] = 8762, ["homtht"] = 8763, - ["sim"] = 8764, ["Tilde"] = 8764, - ["thksim"] = 8764, + ["nvsim"] = {8764, 8402}, + ["sim"] = 8764, ["thicksim"] = 8764, - ["bsim"] = 8765, + ["thksim"] = 8764, ["backsim"] = 8765, + ["bsim"] = 8765, + ["race"] = {8765, 817}, ["ac"] = 8766, + ["acE"] = {8766, 819}, ["mstpos"] = 8766, ["acd"] = 8767, - ["wreath"] = 8768, ["VerticalTilde"] = 8768, ["wr"] = 8768, - ["nsim"] = 8769, + ["wreath"] = 8768, ["NotTilde"] = 8769, - ["esim"] = 8770, + ["nsim"] = 8769, ["EqualTilde"] = 8770, + ["NotEqualTilde"] = {8770, 824}, ["eqsim"] = 8770, - ["sime"] = 8771, + ["esim"] = 8770, + ["nesim"] = {8770, 824}, ["TildeEqual"] = 8771, + ["sime"] = 8771, ["simeq"] = 8771, + ["NotTildeEqual"] = 8772, ["nsime"] = 8772, ["nsimeq"] = 8772, - ["NotTildeEqual"] = 8772, - ["cong"] = 8773, ["TildeFullEqual"] = 8773, + ["cong"] = 8773, ["simne"] = 8774, - ["ncong"] = 8775, ["NotTildeFullEqual"] = 8775, - ["asymp"] = 8776, - ["ap"] = 8776, + ["ncong"] = 8775, ["TildeTilde"] = 8776, + ["ap"] = 8776, ["approx"] = 8776, - ["thkap"] = 8776, + ["asymp"] = 8776, ["thickapprox"] = 8776, - ["nap"] = 8777, + ["thkap"] = 8776, ["NotTildeTilde"] = 8777, + ["nap"] = 8777, ["napprox"] = 8777, ["ape"] = 8778, ["approxeq"] = 8778, ["apid"] = 8779, - ["bcong"] = 8780, + ["napid"] = {8779, 824}, ["backcong"] = 8780, - ["asympeq"] = 8781, + ["bcong"] = 8780, ["CupCap"] = 8781, - ["bump"] = 8782, - ["HumpDownHump"] = 8782, + ["asympeq"] = 8781, + ["nvap"] = {8781, 8402}, ["Bumpeq"] = 8782, - ["bumpe"] = 8783, + ["HumpDownHump"] = 8782, + ["NotHumpDownHump"] = {8782, 824}, + ["bump"] = 8782, + ["nbump"] = {8782, 824}, ["HumpEqual"] = 8783, + ["NotHumpEqual"] = {8783, 824}, + ["bumpe"] = 8783, ["bumpeq"] = 8783, - ["esdot"] = 8784, + ["nbumpe"] = {8783, 824}, ["DotEqual"] = 8784, ["doteq"] = 8784, - ["eDot"] = 8785, + ["esdot"] = 8784, + ["nedot"] = {8784, 824}, ["doteqdot"] = 8785, + ["eDot"] = 8785, ["efDot"] = 8786, ["fallingdotseq"] = 8786, ["erDot"] = 8787, ["risingdotseq"] = 8787, + ["Assign"] = 8788, ["colone"] = 8788, ["coloneq"] = 8788, - ["Assign"] = 8788, ["ecolon"] = 8789, ["eqcolon"] = 8789, ["ecir"] = 8790, ["eqcirc"] = 8790, - ["cire"] = 8791, ["circeq"] = 8791, + ["cire"] = 8791, ["wedgeq"] = 8793, ["veeeq"] = 8794, - ["trie"] = 8796, ["triangleq"] = 8796, + ["trie"] = 8796, ["equest"] = 8799, ["questeq"] = 8799, - ["ne"] = 8800, ["NotEqual"] = 8800, - ["equiv"] = 8801, + ["ne"] = 8800, ["Congruent"] = 8801, - ["nequiv"] = 8802, + ["bnequiv"] = {8801, 8421}, + ["equiv"] = 8801, ["NotCongruent"] = 8802, + ["nequiv"] = 8802, ["le"] = 8804, ["leq"] = 8804, - ["ge"] = 8805, + ["nvle"] = {8804, 8402}, ["GreaterEqual"] = 8805, + ["ge"] = 8805, ["geq"] = 8805, - ["lE"] = 8806, + ["nvge"] = {8805, 8402}, ["LessFullEqual"] = 8806, + ["lE"] = 8806, ["leqq"] = 8806, - ["gE"] = 8807, + ["nlE"] = {8806, 824}, + ["nleqq"] = {8806, 824}, ["GreaterFullEqual"] = 8807, + ["NotGreaterFullEqual"] = {8807, 824}, + ["gE"] = 8807, ["geqq"] = 8807, + ["ngE"] = {8807, 824}, + ["ngeqq"] = {8807, 824}, ["lnE"] = 8808, ["lneqq"] = 8808, + ["lvertneqq"] = {8808, 65024}, + ["lvnE"] = {8808, 65024}, ["gnE"] = 8809, ["gneqq"] = 8809, + ["gvertneqq"] = {8809, 65024}, + ["gvnE"] = {8809, 65024}, ["Lt"] = 8810, ["NestedLessLess"] = 8810, + ["NotLessLess"] = {8810, 824}, ["ll"] = 8810, + ["nLt"] = {8810, 8402}, + ["nLtv"] = {8810, 824}, ["Gt"] = 8811, ["NestedGreaterGreater"] = 8811, + ["NotGreaterGreater"] = {8811, 824}, ["gg"] = 8811, - ["twixt"] = 8812, + ["nGt"] = {8811, 8402}, + ["nGtv"] = {8811, 824}, ["between"] = 8812, + ["twixt"] = 8812, ["NotCupCap"] = 8813, - ["nlt"] = 8814, ["NotLess"] = 8814, ["nless"] = 8814, - ["ngt"] = 8815, + ["nlt"] = 8814, ["NotGreater"] = 8815, + ["ngt"] = 8815, ["ngtr"] = 8815, - ["nle"] = 8816, ["NotLessEqual"] = 8816, + ["nle"] = 8816, ["nleq"] = 8816, - ["nge"] = 8817, ["NotGreaterEqual"] = 8817, + ["nge"] = 8817, ["ngeq"] = 8817, - ["lsim"] = 8818, ["LessTilde"] = 8818, ["lesssim"] = 8818, + ["lsim"] = 8818, + ["GreaterTilde"] = 8819, ["gsim"] = 8819, ["gtrsim"] = 8819, - ["GreaterTilde"] = 8819, - ["nlsim"] = 8820, ["NotLessTilde"] = 8820, - ["ngsim"] = 8821, + ["nlsim"] = 8820, ["NotGreaterTilde"] = 8821, - ["lg"] = 8822, - ["lessgtr"] = 8822, + ["ngsim"] = 8821, ["LessGreater"] = 8822, + ["lessgtr"] = 8822, + ["lg"] = 8822, + ["GreaterLess"] = 8823, ["gl"] = 8823, ["gtrless"] = 8823, - ["GreaterLess"] = 8823, - ["ntlg"] = 8824, ["NotLessGreater"] = 8824, - ["ntgl"] = 8825, + ["ntlg"] = 8824, ["NotGreaterLess"] = 8825, - ["pr"] = 8826, + ["ntgl"] = 8825, ["Precedes"] = 8826, + ["pr"] = 8826, ["prec"] = 8826, - ["sc"] = 8827, ["Succeeds"] = 8827, + ["sc"] = 8827, ["succ"] = 8827, - ["prcue"] = 8828, ["PrecedesSlantEqual"] = 8828, + ["prcue"] = 8828, ["preccurlyeq"] = 8828, - ["sccue"] = 8829, ["SucceedsSlantEqual"] = 8829, + ["sccue"] = 8829, ["succcurlyeq"] = 8829, - ["prsim"] = 8830, - ["precsim"] = 8830, ["PrecedesTilde"] = 8830, + ["precsim"] = 8830, + ["prsim"] = 8830, + ["NotSucceedsTilde"] = {8831, 824}, + ["SucceedsTilde"] = 8831, ["scsim"] = 8831, ["succsim"] = 8831, - ["SucceedsTilde"] = 8831, + ["NotPrecedes"] = 8832, ["npr"] = 8832, ["nprec"] = 8832, - ["NotPrecedes"] = 8832, + ["NotSucceeds"] = 8833, ["nsc"] = 8833, ["nsucc"] = 8833, - ["NotSucceeds"] = 8833, + ["NotSubset"] = {8834, 8402}, + ["nsubset"] = {8834, 8402}, ["sub"] = 8834, ["subset"] = 8834, + ["vnsub"] = {8834, 8402}, + ["NotSuperset"] = {8835, 8402}, + ["Superset"] = 8835, + ["nsupset"] = {8835, 8402}, ["sup"] = 8835, ["supset"] = 8835, - ["Superset"] = 8835, + ["vnsup"] = {8835, 8402}, ["nsub"] = 8836, ["nsup"] = 8837, - ["sube"] = 8838, ["SubsetEqual"] = 8838, + ["sube"] = 8838, ["subseteq"] = 8838, + ["SupersetEqual"] = 8839, ["supe"] = 8839, ["supseteq"] = 8839, - ["SupersetEqual"] = 8839, + ["NotSubsetEqual"] = 8840, ["nsube"] = 8840, ["nsubseteq"] = 8840, - ["NotSubsetEqual"] = 8840, + ["NotSupersetEqual"] = 8841, ["nsupe"] = 8841, ["nsupseteq"] = 8841, - ["NotSupersetEqual"] = 8841, ["subne"] = 8842, ["subsetneq"] = 8842, + ["varsubsetneq"] = {8842, 65024}, + ["vsubne"] = {8842, 65024}, ["supne"] = 8843, ["supsetneq"] = 8843, + ["varsupsetneq"] = {8843, 65024}, + ["vsupne"] = {8843, 65024}, ["cupdot"] = 8845, - ["uplus"] = 8846, ["UnionPlus"] = 8846, - ["sqsub"] = 8847, + ["uplus"] = 8846, + ["NotSquareSubset"] = {8847, 824}, ["SquareSubset"] = 8847, + ["sqsub"] = 8847, ["sqsubset"] = 8847, - ["sqsup"] = 8848, + ["NotSquareSuperset"] = {8848, 824}, ["SquareSuperset"] = 8848, + ["sqsup"] = 8848, ["sqsupset"] = 8848, - ["sqsube"] = 8849, ["SquareSubsetEqual"] = 8849, + ["sqsube"] = 8849, ["sqsubseteq"] = 8849, - ["sqsupe"] = 8850, ["SquareSupersetEqual"] = 8850, + ["sqsupe"] = 8850, ["sqsupseteq"] = 8850, - ["sqcap"] = 8851, ["SquareIntersection"] = 8851, - ["sqcup"] = 8852, + ["sqcap"] = 8851, + ["sqcaps"] = {8851, 65024}, ["SquareUnion"] = 8852, - ["oplus"] = 8853, + ["sqcup"] = 8852, + ["sqcups"] = {8852, 65024}, ["CirclePlus"] = 8853, - ["ominus"] = 8854, + ["oplus"] = 8853, ["CircleMinus"] = 8854, - ["otimes"] = 8855, + ["ominus"] = 8854, ["CircleTimes"] = 8855, + ["otimes"] = 8855, ["osol"] = 8856, - ["odot"] = 8857, ["CircleDot"] = 8857, - ["ocir"] = 8858, + ["odot"] = 8857, ["circledcirc"] = 8858, - ["oast"] = 8859, + ["ocir"] = 8858, ["circledast"] = 8859, - ["odash"] = 8861, + ["oast"] = 8859, ["circleddash"] = 8861, - ["plusb"] = 8862, + ["odash"] = 8861, ["boxplus"] = 8862, - ["minusb"] = 8863, + ["plusb"] = 8862, ["boxminus"] = 8863, - ["timesb"] = 8864, + ["minusb"] = 8863, ["boxtimes"] = 8864, - ["sdotb"] = 8865, + ["timesb"] = 8864, ["dotsquare"] = 8865, - ["vdash"] = 8866, + ["sdotb"] = 8865, ["RightTee"] = 8866, - ["dashv"] = 8867, + ["vdash"] = 8866, ["LeftTee"] = 8867, - ["top"] = 8868, + ["dashv"] = 8867, ["DownTee"] = 8868, - ["bottom"] = 8869, + ["top"] = 8868, + ["UpTee"] = 8869, ["bot"] = 8869, + ["bottom"] = 8869, ["perp"] = 8869, - ["UpTee"] = 8869, ["models"] = 8871, - ["vDash"] = 8872, ["DoubleRightTee"] = 8872, + ["vDash"] = 8872, ["Vdash"] = 8873, ["Vvdash"] = 8874, ["VDash"] = 8875, @@ -1523,22 +1564,24 @@ local character_entities = { ["nVdash"] = 8878, ["nVDash"] = 8879, ["prurel"] = 8880, - ["vltri"] = 8882, - ["vartriangleleft"] = 8882, ["LeftTriangle"] = 8882, - ["vrtri"] = 8883, - ["vartriangleright"] = 8883, + ["vartriangleleft"] = 8882, + ["vltri"] = 8882, ["RightTriangle"] = 8883, - ["ltrie"] = 8884, - ["trianglelefteq"] = 8884, + ["vartriangleright"] = 8883, + ["vrtri"] = 8883, ["LeftTriangleEqual"] = 8884, + ["ltrie"] = 8884, + ["nvltrie"] = {8884, 8402}, + ["trianglelefteq"] = 8884, + ["RightTriangleEqual"] = 8885, + ["nvrtrie"] = {8885, 8402}, ["rtrie"] = 8885, ["trianglerighteq"] = 8885, - ["RightTriangleEqual"] = 8885, ["origof"] = 8886, ["imof"] = 8887, - ["mumap"] = 8888, ["multimap"] = 8888, + ["mumap"] = 8888, ["hercon"] = 8889, ["intcal"] = 8890, ["intercal"] = 8890, @@ -1546,39 +1589,39 @@ local character_entities = { ["barvee"] = 8893, ["angrtvb"] = 8894, ["lrtri"] = 8895, - ["xwedge"] = 8896, ["Wedge"] = 8896, ["bigwedge"] = 8896, - ["xvee"] = 8897, + ["xwedge"] = 8896, ["Vee"] = 8897, ["bigvee"] = 8897, - ["xcap"] = 8898, + ["xvee"] = 8897, ["Intersection"] = 8898, ["bigcap"] = 8898, - ["xcup"] = 8899, + ["xcap"] = 8898, ["Union"] = 8899, ["bigcup"] = 8899, + ["xcup"] = 8899, + ["Diamond"] = 8900, ["diam"] = 8900, ["diamond"] = 8900, - ["Diamond"] = 8900, ["sdot"] = 8901, - ["sstarf"] = 8902, ["Star"] = 8902, - ["divonx"] = 8903, + ["sstarf"] = 8902, ["divideontimes"] = 8903, + ["divonx"] = 8903, ["bowtie"] = 8904, ["ltimes"] = 8905, ["rtimes"] = 8906, - ["lthree"] = 8907, ["leftthreetimes"] = 8907, - ["rthree"] = 8908, + ["lthree"] = 8907, ["rightthreetimes"] = 8908, - ["bsime"] = 8909, + ["rthree"] = 8908, ["backsimeq"] = 8909, - ["cuvee"] = 8910, + ["bsime"] = 8909, ["curlyvee"] = 8910, - ["cuwed"] = 8911, + ["cuvee"] = 8910, ["curlywedge"] = 8911, + ["cuwed"] = 8911, ["Sub"] = 8912, ["Subset"] = 8912, ["Sup"] = 8913, @@ -1588,49 +1631,53 @@ local character_entities = { ["fork"] = 8916, ["pitchfork"] = 8916, ["epar"] = 8917, - ["ltdot"] = 8918, ["lessdot"] = 8918, + ["ltdot"] = 8918, ["gtdot"] = 8919, ["gtrdot"] = 8919, ["Ll"] = 8920, + ["nLl"] = {8920, 824}, ["Gg"] = 8921, ["ggg"] = 8921, - ["leg"] = 8922, + ["nGg"] = {8921, 824}, ["LessEqualGreater"] = 8922, + ["leg"] = 8922, + ["lesg"] = {8922, 65024}, ["lesseqgtr"] = 8922, + ["GreaterEqualLess"] = 8923, ["gel"] = 8923, + ["gesl"] = {8923, 65024}, ["gtreqless"] = 8923, - ["GreaterEqualLess"] = 8923, ["cuepr"] = 8926, ["curlyeqprec"] = 8926, ["cuesc"] = 8927, ["curlyeqsucc"] = 8927, - ["nprcue"] = 8928, ["NotPrecedesSlantEqual"] = 8928, - ["nsccue"] = 8929, + ["nprcue"] = 8928, ["NotSucceedsSlantEqual"] = 8929, - ["nsqsube"] = 8930, + ["nsccue"] = 8929, ["NotSquareSubsetEqual"] = 8930, - ["nsqsupe"] = 8931, + ["nsqsube"] = 8930, ["NotSquareSupersetEqual"] = 8931, + ["nsqsupe"] = 8931, ["lnsim"] = 8934, ["gnsim"] = 8935, - ["prnsim"] = 8936, ["precnsim"] = 8936, + ["prnsim"] = 8936, ["scnsim"] = 8937, ["succnsim"] = 8937, + ["NotLeftTriangle"] = 8938, ["nltri"] = 8938, ["ntriangleleft"] = 8938, - ["NotLeftTriangle"] = 8938, + ["NotRightTriangle"] = 8939, ["nrtri"] = 8939, ["ntriangleright"] = 8939, - ["NotRightTriangle"] = 8939, + ["NotLeftTriangleEqual"] = 8940, ["nltrie"] = 8940, ["ntrianglelefteq"] = 8940, - ["NotLeftTriangleEqual"] = 8940, + ["NotRightTriangleEqual"] = 8941, ["nrtrie"] = 8941, ["ntrianglerighteq"] = 8941, - ["NotRightTriangleEqual"] = 8941, ["vellip"] = 8942, ["ctdot"] = 8943, ["utdot"] = 8944, @@ -1639,9 +1686,11 @@ local character_entities = { ["isinsv"] = 8947, ["isins"] = 8948, ["isindot"] = 8949, + ["notindot"] = {8949, 824}, ["notinvc"] = 8950, ["notinvb"] = 8951, ["isinE"] = 8953, + ["notinE"] = {8953, 824}, ["nisd"] = 8954, ["xnis"] = 8955, ["nis"] = 8956, @@ -1651,14 +1700,14 @@ local character_entities = { ["barwedge"] = 8965, ["Barwed"] = 8966, ["doublebarwedge"] = 8966, - ["lceil"] = 8968, ["LeftCeiling"] = 8968, - ["rceil"] = 8969, + ["lceil"] = 8968, ["RightCeiling"] = 8969, - ["lfloor"] = 8970, + ["rceil"] = 8969, ["LeftFloor"] = 8970, - ["rfloor"] = 8971, + ["lfloor"] = 8970, ["RightFloor"] = 8971, + ["rfloor"] = 8971, ["drcrop"] = 8972, ["dlcrop"] = 8973, ["urcrop"] = 8974, @@ -1690,10 +1739,10 @@ local character_entities = { ["lmoustache"] = 9136, ["rmoust"] = 9137, ["rmoustache"] = 9137, - ["tbrk"] = 9140, ["OverBracket"] = 9140, - ["bbrk"] = 9141, + ["tbrk"] = 9140, ["UnderBracket"] = 9141, + ["bbrk"] = 9141, ["bbrktbrk"] = 9142, ["OverParenthesis"] = 9180, ["UnderParenthesis"] = 9181, @@ -1702,10 +1751,10 @@ local character_entities = { ["trpezium"] = 9186, ["elinters"] = 9191, ["blank"] = 9251, - ["oS"] = 9416, ["circledS"] = 9416, - ["boxh"] = 9472, + ["oS"] = 9416, ["HorizontalLine"] = 9472, + ["boxh"] = 9472, ["boxv"] = 9474, ["boxdr"] = 9484, ["boxdl"] = 9488, @@ -1751,50 +1800,50 @@ local character_entities = { ["blk14"] = 9617, ["blk12"] = 9618, ["blk34"] = 9619, + ["Square"] = 9633, ["squ"] = 9633, ["square"] = 9633, - ["Square"] = 9633, - ["squf"] = 9642, - ["squarf"] = 9642, - ["blacksquare"] = 9642, ["FilledVerySmallSquare"] = 9642, + ["blacksquare"] = 9642, + ["squarf"] = 9642, + ["squf"] = 9642, ["EmptyVerySmallSquare"] = 9643, ["rect"] = 9645, ["marker"] = 9646, ["fltns"] = 9649, - ["xutri"] = 9651, ["bigtriangleup"] = 9651, - ["utrif"] = 9652, + ["xutri"] = 9651, ["blacktriangle"] = 9652, - ["utri"] = 9653, + ["utrif"] = 9652, ["triangle"] = 9653, - ["rtrif"] = 9656, + ["utri"] = 9653, ["blacktriangleright"] = 9656, + ["rtrif"] = 9656, ["rtri"] = 9657, ["triangleright"] = 9657, - ["xdtri"] = 9661, ["bigtriangledown"] = 9661, - ["dtrif"] = 9662, + ["xdtri"] = 9661, ["blacktriangledown"] = 9662, + ["dtrif"] = 9662, ["dtri"] = 9663, ["triangledown"] = 9663, - ["ltrif"] = 9666, ["blacktriangleleft"] = 9666, + ["ltrif"] = 9666, ["ltri"] = 9667, ["triangleleft"] = 9667, ["loz"] = 9674, ["lozenge"] = 9674, ["cir"] = 9675, ["tridot"] = 9708, - ["xcirc"] = 9711, ["bigcirc"] = 9711, + ["xcirc"] = 9711, ["ultri"] = 9720, ["urtri"] = 9721, ["lltri"] = 9722, ["EmptySmallSquare"] = 9723, ["FilledSmallSquare"] = 9724, - ["starf"] = 9733, ["bigstar"] = 9733, + ["starf"] = 9733, ["star"] = 9734, ["phone"] = 9742, ["female"] = 9792, @@ -1805,8 +1854,8 @@ local character_entities = { ["clubsuit"] = 9827, ["hearts"] = 9829, ["heartsuit"] = 9829, - ["diams"] = 9830, ["diamondsuit"] = 9830, + ["diams"] = 9830, ["sung"] = 9834, ["flat"] = 9837, ["natur"] = 9838, @@ -1821,51 +1870,53 @@ local character_entities = { ["VerticalSeparator"] = 10072, ["lbbrk"] = 10098, ["rbbrk"] = 10099, - ["lobrk"] = 10214, + ["bsolhsub"] = 10184, + ["suphsol"] = 10185, ["LeftDoubleBracket"] = 10214, - ["robrk"] = 10215, + ["lobrk"] = 10214, ["RightDoubleBracket"] = 10215, - ["lang"] = 10216, + ["robrk"] = 10215, ["LeftAngleBracket"] = 10216, + ["lang"] = 10216, ["langle"] = 10216, - ["rang"] = 10217, ["RightAngleBracket"] = 10217, + ["rang"] = 10217, ["rangle"] = 10217, ["Lang"] = 10218, ["Rang"] = 10219, ["loang"] = 10220, ["roang"] = 10221, - ["xlarr"] = 10229, - ["longleftarrow"] = 10229, ["LongLeftArrow"] = 10229, - ["xrarr"] = 10230, - ["longrightarrow"] = 10230, + ["longleftarrow"] = 10229, + ["xlarr"] = 10229, ["LongRightArrow"] = 10230, - ["xharr"] = 10231, - ["longleftrightarrow"] = 10231, + ["longrightarrow"] = 10230, + ["xrarr"] = 10230, ["LongLeftRightArrow"] = 10231, - ["xlArr"] = 10232, - ["Longleftarrow"] = 10232, + ["longleftrightarrow"] = 10231, + ["xharr"] = 10231, ["DoubleLongLeftArrow"] = 10232, - ["xrArr"] = 10233, - ["Longrightarrow"] = 10233, + ["Longleftarrow"] = 10232, + ["xlArr"] = 10232, ["DoubleLongRightArrow"] = 10233, - ["xhArr"] = 10234, - ["Longleftrightarrow"] = 10234, + ["Longrightarrow"] = 10233, + ["xrArr"] = 10233, ["DoubleLongLeftRightArrow"] = 10234, - ["xmap"] = 10236, + ["Longleftrightarrow"] = 10234, + ["xhArr"] = 10234, ["longmapsto"] = 10236, + ["xmap"] = 10236, ["dzigrarr"] = 10239, ["nvlArr"] = 10498, ["nvrArr"] = 10499, ["nvHarr"] = 10500, ["Map"] = 10501, ["lbarr"] = 10508, - ["rbarr"] = 10509, ["bkarow"] = 10509, + ["rbarr"] = 10509, ["lBarr"] = 10510, - ["rBarr"] = 10511, ["dbkarow"] = 10511, + ["rBarr"] = 10511, ["RBarr"] = 10512, ["drbkarow"] = 10512, ["DDotrahd"] = 10513, @@ -1882,16 +1933,17 @@ local character_entities = { ["rarrbfs"] = 10528, ["nwarhk"] = 10531, ["nearhk"] = 10532, - ["searhk"] = 10533, ["hksearow"] = 10533, - ["swarhk"] = 10534, + ["searhk"] = 10533, ["hkswarow"] = 10534, + ["swarhk"] = 10534, ["nwnear"] = 10535, ["nesear"] = 10536, ["toea"] = 10536, ["seswar"] = 10537, ["tosa"] = 10537, ["swnwar"] = 10538, + ["nrarrc"] = {10547, 824}, ["rarrc"] = 10547, ["cudarrr"] = 10549, ["ldca"] = 10550, @@ -1937,10 +1989,10 @@ local character_entities = { ["llhard"] = 10603, ["rharul"] = 10604, ["lrhard"] = 10605, - ["udhar"] = 10606, ["UpEquilibrium"] = 10606, - ["duhar"] = 10607, + ["udhar"] = 10606, ["ReverseUpEquilibrium"] = 10607, + ["duhar"] = 10607, ["RoundImplies"] = 10608, ["erarr"] = 10609, ["simrarr"] = 10610, @@ -2007,30 +2059,31 @@ local character_entities = { ["trisb"] = 10701, ["rtriltri"] = 10702, ["LeftTriangleBar"] = 10703, + ["NotLeftTriangleBar"] = {10703, 824}, + ["NotRightTriangleBar"] = {10704, 824}, ["RightTriangleBar"] = 10704, - ["race"] = 10714, ["iinfin"] = 10716, ["infintie"] = 10717, ["nvinfin"] = 10718, ["eparsl"] = 10723, ["smeparsl"] = 10724, ["eqvparsl"] = 10725, - ["lozf"] = 10731, ["blacklozenge"] = 10731, + ["lozf"] = 10731, ["RuleDelayed"] = 10740, ["dsol"] = 10742, - ["xodot"] = 10752, ["bigodot"] = 10752, - ["xoplus"] = 10753, + ["xodot"] = 10752, ["bigoplus"] = 10753, - ["xotime"] = 10754, + ["xoplus"] = 10753, ["bigotimes"] = 10754, - ["xuplus"] = 10756, + ["xotime"] = 10754, ["biguplus"] = 10756, - ["xsqcup"] = 10758, + ["xuplus"] = 10756, ["bigsqcup"] = 10758, - ["qint"] = 10764, + ["xsqcup"] = 10758, ["iiiint"] = 10764, + ["qint"] = 10764, ["fpartint"] = 10765, ["cirfnint"] = 10768, ["awint"] = 10769, @@ -2062,8 +2115,8 @@ local character_entities = { ["triplus"] = 10809, ["triminus"] = 10810, ["tritime"] = 10811, - ["iprod"] = 10812, ["intprod"] = 10812, + ["iprod"] = 10812, ["amalg"] = 10815, ["capdot"] = 10816, ["ncup"] = 10818, @@ -2093,27 +2146,35 @@ local character_entities = { ["sdote"] = 10854, ["simdot"] = 10858, ["congdot"] = 10861, + ["ncongdot"] = {10861, 824}, ["easter"] = 10862, ["apacir"] = 10863, ["apE"] = 10864, + ["napE"] = {10864, 824}, ["eplus"] = 10865, ["pluse"] = 10866, ["Esim"] = 10867, ["Colone"] = 10868, ["Equal"] = 10869, - ["eDDot"] = 10871, ["ddotseq"] = 10871, + ["eDDot"] = 10871, ["equivDD"] = 10872, ["ltcir"] = 10873, ["gtcir"] = 10874, ["ltquest"] = 10875, ["gtquest"] = 10876, - ["les"] = 10877, ["LessSlantEqual"] = 10877, + ["NotLessSlantEqual"] = {10877, 824}, ["leqslant"] = 10877, - ["ges"] = 10878, + ["les"] = 10877, + ["nleqslant"] = {10877, 824}, + ["nles"] = {10877, 824}, ["GreaterSlantEqual"] = 10878, + ["NotGreaterSlantEqual"] = {10878, 824}, ["geqslant"] = 10878, + ["ges"] = 10878, + ["ngeqslant"] = {10878, 824}, + ["nges"] = {10878, 824}, ["lesdot"] = 10879, ["gesdot"] = 10880, ["lesdoto"] = 10881, @@ -2157,7 +2218,9 @@ local character_entities = { ["simlE"] = 10911, ["simgE"] = 10912, ["LessLess"] = 10913, + ["NotNestedLessLess"] = {10913, 824}, ["GreaterGreater"] = 10914, + ["NotNestedGreaterGreater"] = {10914, 824}, ["glj"] = 10916, ["gla"] = 10917, ["ltcc"] = 10918, @@ -2167,26 +2230,34 @@ local character_entities = { ["smt"] = 10922, ["lat"] = 10923, ["smte"] = 10924, + ["smtes"] = {10924, 65024}, ["late"] = 10925, + ["lates"] = {10925, 65024}, ["bumpE"] = 10926, + ["NotPrecedesEqual"] = {10927, 824}, + ["PrecedesEqual"] = 10927, + ["npre"] = {10927, 824}, + ["npreceq"] = {10927, 824}, ["pre"] = 10927, ["preceq"] = 10927, - ["PrecedesEqual"] = 10927, + ["NotSucceedsEqual"] = {10928, 824}, + ["SucceedsEqual"] = 10928, + ["nsce"] = {10928, 824}, + ["nsucceq"] = {10928, 824}, ["sce"] = 10928, ["succeq"] = 10928, - ["SucceedsEqual"] = 10928, ["prE"] = 10931, ["scE"] = 10932, - ["prnE"] = 10933, ["precneqq"] = 10933, + ["prnE"] = 10933, ["scnE"] = 10934, ["succneqq"] = 10934, ["prap"] = 10935, ["precapprox"] = 10935, ["scap"] = 10936, ["succapprox"] = 10936, - ["prnap"] = 10937, ["precnapprox"] = 10937, + ["prnap"] = 10937, ["scnap"] = 10938, ["succnapprox"] = 10938, ["Pr"] = 10939, @@ -2199,16 +2270,24 @@ local character_entities = { ["supmult"] = 10946, ["subedot"] = 10947, ["supedot"] = 10948, + ["nsubE"] = {10949, 824}, + ["nsubseteqq"] = {10949, 824}, ["subE"] = 10949, ["subseteqq"] = 10949, + ["nsupE"] = {10950, 824}, + ["nsupseteqq"] = {10950, 824}, ["supE"] = 10950, ["supseteqq"] = 10950, ["subsim"] = 10951, ["supsim"] = 10952, ["subnE"] = 10955, ["subsetneqq"] = 10955, + ["varsubsetneqq"] = {10955, 65024}, + ["vsubnE"] = {10955, 65024}, ["supnE"] = 10956, ["supsetneqq"] = 10956, + ["varsupsetneqq"] = {10956, 65024}, + ["vsupnE"] = {10956, 65024}, ["csub"] = 10959, ["csup"] = 10960, ["csube"] = 10961, @@ -2237,6 +2316,7 @@ local character_entities = { ["topcir"] = 10993, ["nhpar"] = 10994, ["parsim"] = 10995, + ["nparsl"] = {11005, 8421}, ["parsl"] = 11005, ["fflig"] = 64256, ["filig"] = 64257, @@ -2378,22 +2458,45 @@ local character_entities = { ["zopf"] = 120171, } function entities.dec_entity(s) - return unicode.utf8.char(tonumber(s)) + local n = tonumber(s) + if n == nil then + return "&#" .. s .. ";" -- fallback for unknown entities + end + return unicode.utf8.char(n) end function entities.hex_entity(s) - return unicode.utf8.char(tonumber("0x"..s)) + local n = tonumber("0x"..s) + if n == nil then + return "&#x" .. s .. ";" -- fallback for unknown entities + end + return unicode.utf8.char(n) end -function entities.char_entity(s) - local n = character_entities[s] +function entities.hex_entity_with_x_char(x, s) + local n = tonumber("0x"..s) if n == nil then - return "&" .. s .. ";" + return "&#" .. x .. s .. ";" -- fallback for unknown entities end return unicode.utf8.char(n) end +function entities.char_entity(s) + local code_points = character_entities[s] + if code_points == nil then + return "&" .. s .. ";" + end + if type(code_points) ~= 'table' then + code_points = {code_points} + end + local char_table = {} + for _, code_point in ipairs(code_points) do + table.insert(char_table, unicode.utf8.char(code_point)) + end + return table.concat(char_table) +end M.writer = {} function M.writer.new(options) local self = {} self.options = options + self.flatten_inlines = false local slice_specifiers = {} for specifier in options.slice:gmatch("[^%s]+") do table.insert(slice_specifiers, specifier) @@ -2441,7 +2544,18 @@ function M.writer.new(options) if not self.is_writing then return "" end return "\\markdownRendererInterblockSeparator\n{}" end - self.hard_line_break = "\\markdownRendererHardLineBreak\n{}" + function self.paragraphsep() + if not self.is_writing then return "" end + return "\\markdownRendererParagraphSeparator\n{}" + end + self.soft_line_break = function() + if self.flatten_inlines then return "\n" end + return "\\markdownRendererSoftLineBreak\n{}" + end + self.hard_line_break = function() + if self.flatten_inlines then return "\n" end + return "\\markdownRendererHardLineBreak\n{}" + end self.ellipsis = "\\markdownRendererEllipsis{}" function self.thematic_break() if not self.is_writing then return "" end @@ -2475,11 +2589,18 @@ function M.writer.new(options) ["|"] = "\\markdownRendererPipe{}", [entities.hex_entity('0000')] = "\\markdownRendererReplacementCharacter{}", } - local escape_typographic_text = util.escaper( + local function create_escaper(char_escapes, string_escapes) + local escape = util.escaper(char_escapes, string_escapes) + return function(s) + if self.flatten_inlines then return s end + return escape(s) + end + end + local escape_typographic_text = create_escaper( self.escaped_chars, self.escaped_strings) - local escape_programmatic_text = util.escaper( + local escape_programmatic_text = create_escaper( self.escaped_uri_chars, self.escaped_minimal_strings) - local escape_minimal = util.escaper( + local escape_minimal = create_escaper( {}, self.escaped_minimal_strings) self.escape = escape_typographic_text self.math = escape_minimal @@ -2487,12 +2608,15 @@ function M.writer.new(options) self.identifier = escape_minimal self.string = escape_minimal self.uri = escape_minimal + self.infostring = escape_minimal else self.identifier = escape_programmatic_text self.string = escape_typographic_text self.uri = escape_programmatic_text + self.infostring = escape_programmatic_text end function self.code(s, attributes) + if self.flatten_inlines then return s end local buf = {} if attributes ~= nil then table.insert(buf, @@ -2508,6 +2632,7 @@ function M.writer.new(options) return buf end function self.link(lab, src, tit, attributes) + if self.flatten_inlines then return lab end local buf = {} if attributes ~= nil then table.insert(buf, @@ -2525,6 +2650,7 @@ function M.writer.new(options) return buf end function self.image(lab, src, tit, attributes) + if self.flatten_inlines then return lab end local buf = {} if attributes ~= nil then table.insert(buf, @@ -2545,7 +2671,9 @@ function M.writer.new(options) if not self.is_writing then return "" end local buffer = {} for _,item in ipairs(items) do - buffer[#buffer + 1] = self.bulletitem(item) + if item ~= "" then + buffer[#buffer + 1] = self.bulletitem(item) + end end local contents = util.intersperse(buffer,"\n") if tight and options.tightLists then @@ -2565,8 +2693,10 @@ function M.writer.new(options) local buffer = {} local num = startnum for _,item in ipairs(items) do - buffer[#buffer + 1] = self.ordereditem(item,num) - if num ~= nil then + if item ~= "" then + buffer[#buffer + 1] = self.ordereditem(item,num) + end + if num ~= nil and item ~= "" then num = num + 1 end end @@ -2589,14 +2719,11 @@ function M.writer.new(options) end end function self.inline_html_comment(contents) + if self.flatten_inlines then return contents end return {"\\markdownRendererInlineHtmlComment{",contents,"}"} end - function self.block_html_comment(contents) - if not self.is_writing then return "" end - return {"\\markdownRendererBlockHtmlCommentBegin\n",contents, - "\n\\markdownRendererBlockHtmlCommentEnd "} - end function self.inline_html_tag(contents) + if self.flatten_inlines then return contents end return {"\\markdownRendererInlineHtmlTag{",self.string(contents),"}"} end function self.block_html_element(s) @@ -2605,6 +2732,7 @@ function M.writer.new(options) return {"\\markdownRendererInputBlockHtmlElement{",name,"}"} end function self.emphasis(s) + if self.flatten_inlines then return s end return {"\\markdownRendererEmphasis{",s,"}"} end function self.tickbox(f) @@ -2617,10 +2745,11 @@ function M.writer.new(options) end end function self.strong(s) + if self.flatten_inlines then return s end return {"\\markdownRendererStrongEmphasis{",s,"}"} end function self.blockquote(s) - if #util.rope_to_string(s) == 0 then return "" end + if not self.is_writing then return "" end return {"\\markdownRendererBlockQuoteBegin\n",s, "\n\\markdownRendererBlockQuoteEnd "} end @@ -2640,17 +2769,24 @@ function M.writer.new(options) return buf end - function self.attributes(attributes) - local expanded_attributes = {} - local key_value_regex = "([^= ]+)%s*=%s*(.*)" + local seen_identifiers = {} + local key_value_regex = "([^= ]+)%s*=%s*(.*)" + local function normalize_attributes(attributes, auto_identifiers) + -- normalize attributes + local normalized_attributes = {} + local has_explicit_identifiers = false local key, value - for _, attribute in ipairs(attributes) do - if attribute:sub(1, 1) == "#" or attribute:sub(1, 1) == "." then - table.insert(expanded_attributes, attribute) + for _, attribute in ipairs(attributes or {}) do + if attribute:sub(1, 1) == "#" then + table.insert(normalized_attributes, attribute) + has_explicit_identifiers = true + seen_identifiers[attribute:sub(2)] = true + elseif attribute:sub(1, 1) == "." then + table.insert(normalized_attributes, attribute) else key, value = attribute:match(key_value_regex) if key:lower() == "id" then - table.insert(expanded_attributes, "#" .. value) + table.insert(normalized_attributes, "#" .. value) elseif key:lower() == "class" then local classes = {} for class in value:gmatch("%S+") do @@ -2658,23 +2794,67 @@ function M.writer.new(options) end table.sort(classes) for _, class in ipairs(classes) do - table.insert(expanded_attributes, "." .. class) + table.insert(normalized_attributes, "." .. class) end else - table.insert(expanded_attributes, attribute) + table.insert(normalized_attributes, attribute) end end end - table.sort(expanded_attributes) - local buf = {} - local seen = {} - for _, attribute in ipairs(expanded_attributes) do - if seen[attribute] ~= nil then - goto continue -- prevent duplicate attributes - else - seen[attribute] = true + -- if no explicit identifiers exist, add auto identifiers + if not has_explicit_identifiers and auto_identifiers ~= nil then + local seen_auto_identifiers = {} + for _, auto_identifier in ipairs(auto_identifiers) do + if seen_auto_identifiers[auto_identifier] == nil then + seen_auto_identifiers[auto_identifier] = true + if seen_identifiers[auto_identifier] == nil then + seen_identifiers[auto_identifier] = true + table.insert(normalized_attributes, + "#" .. auto_identifier) + else + local auto_identifier_number = 1 + while true do + local numbered_auto_identifier = auto_identifier .. "-" + .. auto_identifier_number + if seen_identifiers[numbered_auto_identifier] == nil then + seen_identifiers[numbered_auto_identifier] = true + table.insert(normalized_attributes, + "#" .. numbered_auto_identifier) + break + end + auto_identifier_number = auto_identifier_number + 1 + end + end + end + end + end + + -- sort and deduplicate normalized attributes + table.sort(normalized_attributes) + local seen_normalized_attributes = {} + local deduplicated_normalized_attributes = {} + for _, attribute in ipairs(normalized_attributes) do + if seen_normalized_attributes[attribute] == nil then + seen_normalized_attributes[attribute] = true + table.insert(deduplicated_normalized_attributes, attribute) end + end + + return deduplicated_normalized_attributes + end + + function self.attributes(attributes, should_normalize_attributes) + local normalized_attributes + if should_normalize_attributes == false then + normalized_attributes = attributes + else + normalized_attributes = normalize_attributes(attributes) + end + + local buf = {} + local key, value + for _, attribute in ipairs(normalized_attributes) do if attribute:sub(1, 1) == "#" then table.insert(buf, {"\\markdownRendererAttributeIdentifier{", attribute:sub(2), "}"}) @@ -2686,12 +2866,14 @@ function M.writer.new(options) table.insert(buf, {"\\markdownRendererAttributeKeyValue{", key, "}{", value, "}"}) end - ::continue:: end return buf end self.active_attributes = {} + self.attribute_type_levels = {} + setmetatable(self.attribute_type_levels, + { __index = function() return 0 end }) local function apply_attributes() local buf = {} for i = 1, #self.active_attributes do @@ -2715,6 +2897,9 @@ function M.writer.new(options) end function self.push_attributes(attribute_type, attributes, start_output, end_output) + local attribute_type_level = self.attribute_type_levels[attribute_type] + self.attribute_type_levels[attribute_type] = attribute_type_level + 1 + -- index attributes in a hash table for easy lookup attributes = attributes or {} for i = 1, #attributes do @@ -2732,7 +2917,6 @@ function M.writer.new(options) end if attributes["#" .. self.slice_begin_identifier] ~= nil and self.slice_begin_type == "^" then - self.is_writing = true table.insert(buf, apply_attributes()) self.is_writing = true end @@ -2755,6 +2939,8 @@ function M.writer.new(options) local attributes, _, end_output current_attribute_type, attributes, _, end_output = table.unpack( self.active_attributes[#self.active_attributes]) + local attribute_type_level = self.attribute_type_levels[current_attribute_type] + self.attribute_type_levels[current_attribute_type] = attribute_type_level - 1 if self.is_writing and end_output ~= nil then table.insert(buf, end_output) end @@ -2775,52 +2961,156 @@ function M.writer.new(options) end return buf end - local current_heading_level = 0 - function self.heading(s, level, attributes) - local buf = {} +local function create_auto_identifier(s) + local buffer = {} + local prev_space = false + local letter_found = false - -- push empty attributes for implied sections - while current_heading_level < level - 1 do - table.insert(buf, - self.push_attributes("heading", - nil, - "\\markdownRendererSectionBegin\n", - "\n\\markdownRendererSectionEnd ")) - current_heading_level = current_heading_level + 1 + for _, code in utf8.codes(uni_algos.normalize.NFC(s)) do + local char = utf8.char(code) + + -- Remove everything up to the first letter. + if not letter_found then + local is_letter = unicode.utf8.match(char, "%a") + if is_letter then + letter_found = true + else + goto continue + end end - -- pop attributes for sections that have ended - while current_heading_level >= level do - table.insert(buf, self.pop_attributes("heading")) - current_heading_level = current_heading_level - 1 + -- Remove all non-alphanumeric characters, except underscores, hyphens, and periods. + if not unicode.utf8.match(char, "[%w_%-%.%s]") then + goto continue end - -- push attributes for the new section - local start_output = {} - local end_output = {} - table.insert(start_output, "\\markdownRendererSectionBegin\n") - if options.headerAttributes and attributes ~= nil and #attributes > 0 then - table.insert(start_output, - "\\markdownRendererHeaderAttributeContextBegin\n") - table.insert(start_output, self.attributes(attributes)) - table.insert(end_output, - "\n\\markdownRendererHeaderAttributeContextEnd ") + -- Replace all spaces and newlines with hyphens. + if unicode.utf8.match(char, "[%s\n]") then + char = "-" + if prev_space then + goto continue + else + prev_space = true + end + else + -- Convert all alphabetic characters to lowercase. + char = unicode.utf8.lower(char) + prev_space = false end - table.insert(end_output, "\n\\markdownRendererSectionEnd ") - table.insert(buf, self.push_attributes("heading", - attributes, - start_output, - end_output)) - current_heading_level = current_heading_level + 1 - assert(current_heading_level == level) + table.insert(buffer, char) - -- produce the renderer - local cmd - level = level + options.shiftHeadings - if level <= 1 then - cmd = "\\markdownRendererHeadingOne" - elseif level == 2 then + ::continue:: + end + + if prev_space then + table.remove(buffer) + end + + local identifier = #buffer == 0 and "section" or table.concat(buffer, "") + return identifier +end +local function create_gfm_auto_identifier(s) + local buffer = {} + local prev_space = false + local letter_found = false + + for _, code in utf8.codes(uni_algos.normalize.NFC(s)) do + local char = utf8.char(code) + + -- Remove everything up to the first non-space. + if not letter_found then + local is_letter = unicode.utf8.match(char, "%S") + if is_letter then + letter_found = true + else + goto continue + end + end + + -- Remove all non-alphanumeric characters, except underscores and hyphens. + if not unicode.utf8.match(char, "[%w_%-%s]") then + prev_space = false + goto continue + end + + -- Replace all spaces and newlines with hyphens. + if unicode.utf8.match(char, "[%s\n]") then + char = "-" + if prev_space then + goto continue + else + prev_space = true + end + else + -- Convert all alphabetic characters to lowercase. + char = unicode.utf8.lower(char) + prev_space = false + end + + table.insert(buffer, char) + + ::continue:: + end + + if prev_space then + table.remove(buffer) + end + + local identifier = #buffer == 0 and "section" or table.concat(buffer, "") + return identifier +end + function self.heading(s, level, attributes) + local buf = {} + local flat_text, inlines = table.unpack(s) + + -- push empty attributes for implied sections + while self.attribute_type_levels["heading"] < level - 1 do + table.insert(buf, + self.push_attributes("heading", + nil, + "\\markdownRendererSectionBegin\n", + "\n\\markdownRendererSectionEnd ")) + end + + -- pop attributes for sections that have ended + while self.attribute_type_levels["heading"] >= level do + table.insert(buf, self.pop_attributes("heading")) + end + + -- construct attributes for the new section + local auto_identifiers = {} + if self.options.autoIdentifiers then + table.insert(auto_identifiers, create_auto_identifier(flat_text)) + end + if self.options.gfmAutoIdentifiers then + table.insert(auto_identifiers, create_gfm_auto_identifier(flat_text)) + end + local normalized_attributes = normalize_attributes(attributes, auto_identifiers) + + -- push attributes for the new section + local start_output = {} + local end_output = {} + table.insert(start_output, "\\markdownRendererSectionBegin\n") + table.insert(end_output, "\n\\markdownRendererSectionEnd ") + + table.insert(buf, self.push_attributes("heading", + normalized_attributes, + start_output, + end_output)) + assert(self.attribute_type_levels["heading"] == level) + + -- render the heading and its attributes + if self.is_writing and #normalized_attributes > 0 then + table.insert(buf, "\\markdownRendererHeaderAttributeContextBegin\n") + table.insert(buf, self.attributes(normalized_attributes, false)) + end + + local cmd + level = level + options.shiftHeadings + if level <= 1 then + cmd = "\\markdownRendererHeadingOne" + elseif level == 2 then cmd = "\\markdownRendererHeadingTwo" elseif level == 3 then cmd = "\\markdownRendererHeadingThree" @@ -2834,7 +3124,11 @@ function M.writer.new(options) cmd = "" end if self.is_writing then - table.insert(buf, {cmd, "{", s, "}"}) + table.insert(buf, {cmd, "{", inlines, "}"}) + end + + if self.is_writing and #normalized_attributes > 0 then + table.insert(buf, "\\markdownRendererHeaderAttributeContextEnd ") end return buf @@ -2842,6 +3136,7 @@ function M.writer.new(options) function self.get_state() return { is_writing=self.is_writing, + flatten_inlines=self.flatten_inlines, active_attributes={table.unpack(self.active_attributes)}, } end @@ -2899,14 +3194,13 @@ parsers.tilde = P("~") parsers.backslash = 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.alphanumeric + parsers.dash)^0 parsers.internal_punctuation = S(":;,.?") parsers.doubleasterisks = P("**") @@ -2928,8 +3222,7 @@ parsers.nonspacechar = parsers.any - parsers.spacing parsers.optionalspace = parsers.spacechar^0 parsers.normalchar = parsers.any - (V("SpecialChar") - + parsers.spacing - + parsers.tightblocksep) + + parsers.spacing) parsers.eof = -parsers.any parsers.nonindentspace = parsers.space^-3 * - parsers.spacechar parsers.indent = parsers.space^-3 * parsers.tab @@ -2949,358 +3242,1263 @@ parsers.spnl = parsers.optionalspace * (parsers.newline * parsers.optionalspace)^-1 parsers.line = parsers.linechar^0 * parsers.newline parsers.nonemptyline = parsers.line - parsers.blankline -parsers.commented_line_letter = parsers.linechar - + parsers.newline - - parsers.backslash - - parsers.percent -parsers.commented_line = Cg(Cc(""), "backslashes") - * ((#(parsers.commented_line_letter - - parsers.newline) - * Cb("backslashes") - * Cs(parsers.commented_line_letter - - parsers.newline)^1 -- initial - * Cg(Cc(""), "backslashes")) - + #(parsers.backslash * parsers.backslash) - * Cg((parsers.backslash -- even backslash - * parsers.backslash)^1, "backslashes") - + (parsers.backslash - * (#parsers.percent - * Cb("backslashes") - / function(backslashes) - return string.rep("\\", #backslashes / 2) - end - * C(parsers.percent) - + #parsers.commented_line_letter - * Cb("backslashes") - * Cc("\\") - * C(parsers.commented_line_letter)) - * Cg(Cc(""), "backslashes")))^0 - * (#parsers.percent - * Cb("backslashes") - / function(backslashes) - return string.rep("\\", #backslashes / 2) - end - * ((parsers.percent -- comment - * parsers.line - * #parsers.blankline) -- blank line - / "\n" - + parsers.percent -- comment - * parsers.line - * parsers.optionalspace) -- leading tabs and spaces - + #(parsers.newline) - * Cb("backslashes") - * C(parsers.newline)) - -parsers.chunk = parsers.line * (parsers.optionallyindentedline - - parsers.blankline)^0 - -parsers.attribute_key_char = parsers.alphanumeric + S("-_:.") -parsers.attribute_key = (parsers.attribute_key_char - - parsers.dash - parsers.digit) - * parsers.attribute_key_char^0 -parsers.attribute_value = ( (parsers.dquote / "") - * (parsers.anyescaped - parsers.dquote)^0 - * (parsers.dquote / "")) - + ( (parsers.squote / "") - * (parsers.anyescaped - parsers.squote)^0 - * (parsers.squote / "")) - + ( parsers.anyescaped - parsers.dquote - parsers.rbrace - - parsers.space)^0 -parsers.attribute = (parsers.dash * Cc(".unnumbered")) - + C((parsers.hash + parsers.period) - * parsers.attribute_key) - + Cs( parsers.attribute_key - * parsers.optionalspace * parsers.equal * parsers.optionalspace - * parsers.attribute_value) -parsers.attributes = parsers.lbrace - * parsers.optionalspace - * parsers.attribute - * (parsers.spacechar^1 - * parsers.attribute)^0 - * parsers.optionalspace - * parsers.rbrace +parsers.leader = parsers.space^-3 -parsers.raw_attribute = parsers.lbrace - * parsers.optionalspace - * parsers.equal - * C(parsers.attribute_key) - * parsers.optionalspace - * parsers.rbrace +local function has_trail(indent_table) + return indent_table ~= nil and + indent_table.trail ~= nil and + next(indent_table.trail) ~= nil +end --- block followed by 0 or more optionally --- indented blocks with first line indented. -parsers.indented_blocks = function(bl) - return Cs( bl - * (parsers.blankline^1 * parsers.indent * -parsers.blankline * bl)^0 - * (parsers.blankline^1 + parsers.eof) ) +local function has_indents(indent_table) + return indent_table ~= nil and + indent_table.indents ~= nil and + next(indent_table.indents) ~= nil end -parsers.bulletchar = C(parsers.plus + parsers.asterisk + parsers.dash) -parsers.bullet = ( parsers.bulletchar * #parsers.spacing - * (parsers.tab + parsers.space^-3) - + parsers.space * parsers.bulletchar * #parsers.spacing - * (parsers.tab + parsers.space^-2) - + parsers.space * parsers.space * parsers.bulletchar - * #parsers.spacing - * (parsers.tab + parsers.space^-1) - + parsers.space * parsers.space * parsers.space - * parsers.bulletchar * #parsers.spacing - ) +local function add_trail(indent_table, trail_info) + indent_table.trail = trail_info + return indent_table +end -local function tickbox(interior) - return parsers.optionalspace * parsers.lbracket - * interior * parsers.rbracket * parsers.spacechar^1 +local function remove_trail(indent_table) + indent_table.trail = nil + return indent_table end -parsers.ticked_box = tickbox(S("xX")) * Cc(1.0) -parsers.halfticked_box = tickbox(S("./")) * Cc(0.5) -parsers.unticked_box = tickbox(parsers.spacechar^1) * Cc(0.0) +local function update_indent_table(indent_table, new_indent, add) + indent_table = remove_trail(indent_table) -parsers.openticks = Cg(parsers.backtick^1, "ticks") + if not has_indents(indent_table) then + indent_table.indents = {} + end -local function captures_equal_length(_,i,a,b) - return #a == #b and i + if add then + indent_table.indents[#indent_table.indents + 1] = new_indent + else + if indent_table.indents[#indent_table.indents].name == new_indent.name then + indent_table.indents[#indent_table.indents] = nil + end + end + + return indent_table end -parsers.closeticks = parsers.space^-1 - * Cmt(C(parsers.backtick^1) - * Cb("ticks"), captures_equal_length) +local function remove_indent(name) + local function remove_indent_level(s, i, indent_table) -- luacheck: ignore s i + indent_table = update_indent_table(indent_table, {name=name}, false) + return true, indent_table + end -parsers.intickschar = (parsers.any - S(" \n\r`")) - + (parsers.newline * -parsers.blankline) - + (parsers.space - parsers.closeticks) - + (parsers.backtick^1 - parsers.closeticks) + return Cg(Cmt(Cb("indent_info"), remove_indent_level), "indent_info") +end -parsers.inticks = parsers.openticks * parsers.space^-1 - * C(parsers.intickschar^0) * parsers.closeticks -parsers.leader = parsers.space^-3 +local function process_starter_spacing(indent, spacing, minimum, left_strip_length) + left_strip_length = left_strip_length or 0 --- content in balanced brackets, parentheses, or quotes: -parsers.bracketed = P{ parsers.lbracket - * (( parsers.backslash / "" * parsers.rbracket - + parsers.any - (parsers.lbracket - + parsers.rbracket - + parsers.blankline^2) - ) + V(1))^0 - * parsers.rbracket } + local count = 0 + local tab_value = 4 - (indent) % 4 -parsers.inparens = P{ parsers.lparent - * ((parsers.anyescaped - (parsers.lparent - + parsers.rparent - + parsers.blankline^2) - ) + V(1))^0 - * parsers.rparent } + local code_started, minimum_found = false, false + local code_start, minimum_remainder = "", "" -parsers.squoted = P{ parsers.squote * parsers.alphanumeric - * ((parsers.anyescaped - (parsers.squote - + parsers.blankline^2) - ) + V(1))^0 - * parsers.squote } + local left_total_stripped = 0 + local full_remainder = "" -parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric - * ((parsers.anyescaped - (parsers.dquote - + parsers.blankline^2) - ) + V(1))^0 - * parsers.dquote } + if spacing ~= nil then + for i = 1, #spacing do + local character = spacing:sub(i, i) --- bracketed tag for markdown links, allowing nested brackets: -parsers.tag = parsers.lbracket - * Cs((parsers.alphanumeric^1 - + parsers.bracketed - + parsers.inticks - + ( parsers.backslash / "" * parsers.rbracket - + parsers.any - - (parsers.rbracket + parsers.blankline^2)))^0) - * parsers.rbracket + if character == "\t" then + count = count + tab_value + tab_value = 4 + elseif character == " " then + count = count + 1 + tab_value = 4 - (1 - tab_value) % 4 + end --- url for markdown links, allowing nested brackets: -parsers.url = parsers.less * Cs((parsers.anyescaped - - parsers.more)^0) - * parsers.more - + Cs((parsers.inparens + (parsers.anyescaped - - parsers.spacing - - parsers.rparent))^1) + if (left_strip_length ~= 0) then + local possible_to_strip = math.min(count, left_strip_length) + count = count - possible_to_strip + left_strip_length = left_strip_length - possible_to_strip + left_total_stripped = left_total_stripped + possible_to_strip + else + full_remainder = full_remainder .. character + end --- quoted text, possibly with nested quotes: -parsers.title_s = parsers.squote * Cs(((parsers.anyescaped-parsers.squote) - + parsers.squoted)^0) - * parsers.squote + if (minimum_found) then + minimum_remainder = minimum_remainder .. character + elseif (count >= minimum) then + minimum_found = true + minimum_remainder = minimum_remainder .. string.rep(" ", count - minimum) + end -parsers.title_d = parsers.dquote * Cs(((parsers.anyescaped-parsers.dquote) - + parsers.dquoted)^0) - * parsers.dquote + if (code_started) then + code_start = code_start .. character + elseif (count >= minimum + 4) then + code_started = true + code_start = code_start .. string.rep(" ", count - (minimum + 4)) + end + end + end -parsers.title_p = parsers.lparent - * Cs((parsers.inparens + (parsers.anyescaped-parsers.rparent))^0) - * parsers.rparent + local remainder + if (code_started) then + remainder = code_start + else + remainder = string.rep(" ", count - minimum) + end -parsers.title = parsers.title_d + parsers.title_s + parsers.title_p + local is_minimum = count >= minimum + return { + is_code = code_started, + remainder = remainder, + left_total_stripped = left_total_stripped, + is_minimum = is_minimum, + minimum_remainder = minimum_remainder, + total_length = count, + full_remainder = full_remainder + } +end -parsers.optionaltitle - = parsers.spnl * parsers.title * parsers.spacechar^0 - + Cc("") +local function count_indent_tab_level(indent_table) + local count = 0 + if not has_indents(indent_table) then + return count + end -parsers.indirect_link - = parsers.tag - * ( C(parsers.spnl) * parsers.tag - + Cc(nil) * Cc(nil) -- always produce exactly two captures - ) + for i=1, #indent_table.indents do + count = count + indent_table.indents[i].length + end + return count +end -parsers.indirect_image - = parsers.exclamation * parsers.indirect_link --- 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) +local function total_delimiter_length(delimiter) + local count = 0 + if type(delimiter) == "string" then return #delimiter end + for _, value in pairs(delimiter) do + count = count + total_delimiter_length(value) end - return parser + return count 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) - * parsers.optionalspace - * P("-->") +local function process_starter_indent(_, _, indent_table, starter, is_blank, indent_type, breakable) + local last_trail = starter[1] + local delimiter = starter[2] + local raw_new_trail = starter[3] -parsers.htmlinstruction = P(""))^0 * P("?>") + if indent_type == "bq" and not breakable then + indent_table.ignore_blockquote_blank = true + end -parsers.openelt_any = parsers.less * parsers.keyword * parsers.htmlattribute^0 - * parsers.sp * parsers.more + if has_trail(indent_table) then + local trail = indent_table.trail + if trail.is_code then + return false + end + last_trail = trail.remainder + else + local sp = process_starter_spacing(0, last_trail, 0, 0) -parsers.openelt_exact = function(s) - return parsers.less * parsers.sp * parsers.keyword_exact(s) - * parsers.htmlattribute^0 * parsers.sp * parsers.more -end + if sp.is_code then + return false + end + last_trail = sp.remainder + end -parsers.openelt_block = parsers.sp * parsers.block_keyword - * parsers.htmlattribute^0 * parsers.sp * parsers.more + local preceding_indentation = count_indent_tab_level(indent_table) % 4 + local last_trail_length = #last_trail + local delimiter_length = total_delimiter_length(delimiter) -parsers.closeelt_any = parsers.less * parsers.sp * parsers.slash - * parsers.keyword * parsers.sp * parsers.more + local total_indent_level = preceding_indentation + last_trail_length + delimiter_length -parsers.closeelt_exact = function(s) - return parsers.less * parsers.sp * parsers.slash * parsers.keyword_exact(s) - * parsers.sp * parsers.more -end + local sp = {} + if not is_blank then + sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + end -parsers.emptyelt_any = parsers.less * parsers.sp * parsers.keyword - * parsers.htmlattribute^0 * parsers.sp * parsers.slash - * parsers.more + local del_trail_length = sp.left_total_stripped + if is_blank then + del_trail_length = 1 + elseif not sp.is_code then + del_trail_length = del_trail_length + #sp.remainder + end -parsers.emptyelt_block = parsers.less * parsers.sp * parsers.block_keyword - * parsers.htmlattribute^0 * parsers.sp * parsers.slash - * parsers.more + local indent_length = last_trail_length + delimiter_length + del_trail_length + local new_indent_info = {name=indent_type, length=indent_length} -parsers.displaytext = (parsers.any - parsers.less)^1 + indent_table = update_indent_table(indent_table, new_indent_info, true) + indent_table = add_trail(indent_table, {is_code=sp.is_code, remainder=sp.remainder, total_length=sp.total_length, + full_remainder=sp.full_remainder}) --- 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) } + return true, indent_table 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) +local function decode_pattern(name) + local delimeter = parsers.succeed + if name == "bq" then + delimeter = parsers.more + end + + return C(parsers.optionalspace) * C(delimeter) * C(parsers.optionalspace) * Cp() end -parsers.in_matched_block_tags = parsers.less - * Cmt(#parsers.openelt_block, parse_matched_tags) +local function left_blank_starter(indent_table) + local blank_starter_index -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.Inline = V("Inline") -parsers.IndentedInline = V("IndentedInline") + if not has_indents(indent_table) then + return + end --- 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) + for i = #indent_table.indents,1,-1 do + local value = indent_table.indents[i] + if value.name == "li" then + blank_starter_index = i + else + break + end + end + + return blank_starter_index end -parsers.urlchar = parsers.anyescaped - - parsers.newline - - parsers.more +local function traverse_indent(s, i, indent_table, is_optional, is_blank) + local new_index = i -parsers.auto_link_url = parsers.less - * C( parsers.alphanumeric^1 * P("://") - * parsers.urlchar^1) - * parsers.more + local preceding_indentation = 0 + local current_trail = {} -parsers.auto_link_email - = parsers.less - * C((parsers.alphanumeric + S("-._+"))^1 - * P("@") * parsers.urlchar^1) - * parsers.more + local blank_starter = left_blank_starter(indent_table) -parsers.auto_link_relative_reference - = parsers.less - * C(parsers.urlchar^1) - * parsers.more + for index = 1,#indent_table.indents do + local value = indent_table.indents[index] + local pattern = decode_pattern(value.name) -parsers.lineof = function(c) - return (parsers.leader * (P(c) * parsers.optionalspace)^3 - * (parsers.newline * parsers.blankline^1 - + parsers.newline^-1 * parsers.eof)) + -- match decoded pattern + local new_indent_info = lpeg.match(Ct(pattern), s, new_index) + if new_indent_info == nil then + local blankline_end = lpeg.match(Ct(parsers.blankline * Cg(Cp(), "pos")), s, new_index) + if is_optional or not indent_table.ignore_blockquote_blank or not blankline_end then + return is_optional, new_index, current_trail + end + + return traverse_indent(s, tonumber(blankline_end.pos), indent_table, is_optional, is_blank) + end + + local raw_last_trail = new_indent_info[1] + local delimiter = new_indent_info[2] + local raw_new_trail = new_indent_info[3] + local next_index = new_indent_info[4] + + local space_only = delimiter == "" + + -- check previous trail + if not space_only and next(current_trail) == nil then + local sp = process_starter_spacing(0, raw_last_trail, 0, 0) + current_trail = {is_code=sp.is_code, remainder=sp.remainder, total_length=sp.total_length, + full_remainder=sp.full_remainder} + end + + if next(current_trail) ~= nil then + if not space_only and current_trail.is_code then + return is_optional, new_index, current_trail + end + if current_trail.internal_remainder ~= nil then + raw_last_trail = current_trail.internal_remainder + end + end + + local raw_last_trail_length = 0 + local delimiter_length = 0 + + if not space_only then + delimiter_length = #delimiter + raw_last_trail_length = #raw_last_trail + end + + local total_indent_level = preceding_indentation + raw_last_trail_length + delimiter_length + + local spacing_to_process + local minimum = 0 + local left_strip_length = 0 + + if not space_only then + spacing_to_process = raw_new_trail + left_strip_length = 1 + else + spacing_to_process = raw_last_trail + minimum = value.length + end + + local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length) + + if space_only and not sp.is_minimum then + return is_optional or (is_blank and blank_starter <= index), new_index, current_trail + end + + local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped + + -- update info for the next pattern + if not space_only then + preceding_indentation = preceding_indentation + indent_length + else + preceding_indentation = preceding_indentation + value.length + end + + current_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder, + total_length=sp.total_length, full_remainder=sp.full_remainder} + new_index = next_index + end + + return true, new_index, current_trail +end + +local function check_trail(expect_code, is_code) + return (expect_code and is_code) or (not expect_code and not is_code) +end + +local function check_trail_joined(s, i, indent_table, spacing, expect_code, omit_remainder) -- luacheck: ignore s i + local is_code + local remainder + + if has_trail(indent_table) then + local trail = indent_table.trail + is_code = trail.is_code + if is_code then + remainder = trail.remainder + else + remainder = trail.full_remainder + end + else + local sp = process_starter_spacing(0, spacing, 0, 0) + is_code = sp.is_code + if is_code then + remainder = sp.remainder + else + remainder = sp.full_remainder + end + end + + local result = check_trail(expect_code, is_code) + if omit_remainder then + return result + end + return result, remainder +end + +local function check_trail_length(s, i, indent_table, spacing, min, max) -- luacheck: ignore s i + local trail + + if has_trail(indent_table) then + trail = indent_table.trail + else + trail = process_starter_spacing(0, spacing, 0, 0) + end + + local total_length = trail.total_length + if total_length == nil then + return false + end + + return min <= total_length and total_length <= max +end + +local function check_continuation_indentation(s, i, indent_table, is_optional, is_blank) + if not has_indents(indent_table) then + return true + end + + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional, is_blank) + + if passes then + indent_table = add_trail(indent_table, current_trail) + return new_index, indent_table + end + return false +end + +local function get_last_indent_name(indent_table) + if has_indents(indent_table) then + return indent_table.indents[#indent_table.indents].name + end +end + +local function remove_remainder_if_blank(indent_table, remainder) + if get_last_indent_name(indent_table) == "li" then + return "" + end + return remainder +end + +local function check_trail_type(s, i, trail, spacing, trail_type) -- luacheck: ignore s i + if trail == nil then + trail = process_starter_spacing(0, spacing, 0, 0) + end + + if trail_type == "non-code" then + return check_trail(false, trail.is_code) + end + if trail_type == "code" then + return check_trail(true, trail.is_code) + end + if trail_type == "full-code" then + if (trail.is_code) then + return i, trail.remainder + end + return i, "" + end + if trail_type == "full-any" then + return i, trail.internal_remainder + end +end + +local function trail_freezing(s, i, indent_table, is_freezing) -- luacheck: ignore s i + if is_freezing then + if indent_table.is_trail_frozen then + indent_table.trail = indent_table.frozen_trail + else + indent_table.frozen_trail = indent_table.trail + indent_table.is_trail_frozen = true + end + else + indent_table.frozen_trail = nil + indent_table.is_trail_frozen = false + end + return true, indent_table +end + +local function check_continuation_indentation_and_trail(s, i, indent_table, is_optional, is_blank, trail_type, + reset_rem, omit_remainder) + if not has_indents(indent_table) then + local spacing, new_index = lpeg.match(C(parsers.spacechar^0) * Cp(), s, i) + local result, remainder = check_trail_type(s, i, indent_table.trail, spacing, trail_type) + if remainder == nil then + if result then + return new_index + end + return false + end + if result then + return new_index, remainder + end + return false + end + + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional, is_blank) + + if passes then + local spacing + if current_trail == nil then + local newer_spacing, newer_index = lpeg.match(C(parsers.spacechar^0) * Cp(), s, i) + current_trail = process_starter_spacing(0, newer_spacing, 0, 0) + new_index = newer_index + spacing = newer_spacing + else + spacing = current_trail.remainder + end + local result, remainder = check_trail_type(s, new_index, current_trail, spacing, trail_type) + if remainder == nil or omit_remainder then + if result then + return new_index + end + return false + end + + if is_blank and reset_rem then + remainder = remove_remainder_if_blank(indent_table, remainder) + end + if result then + return new_index, remainder + end + return false + end + return false +end + +parsers.check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) + +parsers.check_trail_no_rem = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(true), check_trail_joined) + +parsers.check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) + +parsers.check_trail_length_range = function(min, max) + return Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(min) * Cc(max), check_trail_length) +end + +parsers.check_trail_length = function(n) + return parsers.check_trail_length_range(n, n) +end + +parsers.freeze_trail = Cg(Cmt(Cb("indent_info") * Cc(true), trail_freezing), "indent_info") + +parsers.unfreeze_trail = Cg(Cmt(Cb("indent_info") * Cc(false), trail_freezing), "indent_info") + +parsers.check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), check_continuation_indentation) + +parsers.check_optional_indent = Cmt(Cb("indent_info") * Cc(true), check_continuation_indentation) + +parsers.check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false) * Cc(true), check_continuation_indentation) + + +parsers.check_minimal_indent_and_trail = Cmt( Cb("indent_info") + * Cc(false) * Cc(false) * Cc("non-code") * Cc(true), + check_continuation_indentation_and_trail) + +parsers.check_minimal_indent_and_code_trail = Cmt( Cb("indent_info") + * Cc(false) * Cc(false) * Cc("code") * Cc(false), + check_continuation_indentation_and_trail) + +parsers.check_minimal_blank_indent_and_full_code_trail = Cmt( Cb("indent_info") + * Cc(false) * Cc(true) * Cc("full-code") * Cc(true), + check_continuation_indentation_and_trail) + +parsers.check_minimal_indent_and_any_trail = Cmt( Cb("indent_info") + * Cc(false) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false), + check_continuation_indentation_and_trail) + +parsers.check_minimal_blank_indent_and_any_trail = Cmt( Cb("indent_info") + * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false), + check_continuation_indentation_and_trail) + +parsers.check_minimal_blank_indent_and_any_trail_no_rem = Cmt( Cb("indent_info") + * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(true), + check_continuation_indentation_and_trail) + +parsers.check_optional_indent_and_any_trail = Cmt( Cb("indent_info") + * Cc(true) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false), + check_continuation_indentation_and_trail) + +parsers.check_optional_blank_indent_and_any_trail = Cmt( Cb("indent_info") + * Cc(true) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false), + check_continuation_indentation_and_trail) + + +parsers.spnlc_noexc = parsers.optionalspace + * (parsers.newline * parsers.check_minimal_indent_and_any_trail)^-1 + +parsers.spnlc = parsers.optionalspace + * (V("EndlineNoSub"))^-1 + +parsers.spnlc_sep = parsers.optionalspace * V("EndlineNoSub") + + parsers.spacechar^1 + +parsers.only_blank = parsers.spacechar^0 * (parsers.newline + parsers.eof) + +parsers.commented_line_letter = parsers.linechar + + parsers.newline + - parsers.backslash + - parsers.percent +parsers.commented_line = Cg(Cc(""), "backslashes") + * ((#(parsers.commented_line_letter + - parsers.newline) + * Cb("backslashes") + * Cs(parsers.commented_line_letter + - parsers.newline)^1 -- initial + * Cg(Cc(""), "backslashes")) + + #(parsers.backslash * parsers.backslash) + * Cg((parsers.backslash -- even backslash + * parsers.backslash)^1, "backslashes") + + (parsers.backslash + * (#parsers.percent + * Cb("backslashes") + / function(backslashes) + return string.rep("\\", #backslashes / 2) + end + * C(parsers.percent) + + #parsers.commented_line_letter + * Cb("backslashes") + * Cc("\\") + * C(parsers.commented_line_letter)) + * Cg(Cc(""), "backslashes")))^0 + * (#parsers.percent + * Cb("backslashes") + / function(backslashes) + return string.rep("\\", #backslashes / 2) + end + * ((parsers.percent -- comment + * parsers.line + * #parsers.blankline) -- blank line + / "\n" + + parsers.percent -- comment + * parsers.line + * parsers.optionalspace) -- leading tabs and spaces + + #(parsers.newline) + * Cb("backslashes") + * C(parsers.newline)) + +parsers.chunk = parsers.line * (parsers.optionallyindentedline + - parsers.blankline)^0 + +parsers.attribute_key_char = parsers.alphanumeric + S("-_:.") +parsers.attribute_raw_char = parsers.alphanumeric + S("-_") +parsers.attribute_key = (parsers.attribute_key_char + - parsers.dash - parsers.digit) + * parsers.attribute_key_char^0 +parsers.attribute_value = ( (parsers.dquote / "") + * (parsers.anyescaped - parsers.dquote)^0 + * (parsers.dquote / "")) + + ( (parsers.squote / "") + * (parsers.anyescaped - parsers.squote)^0 + * (parsers.squote / "")) + + ( parsers.anyescaped - parsers.dquote - parsers.rbrace + - parsers.space)^0 +parsers.attribute_identifier = parsers.attribute_key_char^1 +parsers.attribute_classname = parsers.letter + * parsers.attribute_key_char^0 +parsers.attribute_raw = parsers.attribute_raw_char^1 + +parsers.attribute = (parsers.dash * Cc(".unnumbered")) + + C( parsers.hash + * parsers.attribute_identifier) + + C( parsers.period + * parsers.attribute_classname) + + Cs( parsers.attribute_key + * parsers.optionalspace * parsers.equal * parsers.optionalspace + * parsers.attribute_value) +parsers.attributes = parsers.lbrace + * parsers.optionalspace + * parsers.attribute + * (parsers.spacechar^1 + * parsers.attribute)^0 + * parsers.optionalspace + * parsers.rbrace + +parsers.raw_attribute = parsers.lbrace + * parsers.optionalspace + * parsers.equal + * C(parsers.attribute_raw) + * parsers.optionalspace + * parsers.rbrace + +-- block followed by 0 or more optionally +-- indented blocks with first line indented. +parsers.indented_blocks = function(bl) + return Cs( bl + * (parsers.blankline^1 * parsers.indent * -parsers.blankline * bl)^0 + * (parsers.blankline^1 + parsers.eof) ) +end +local function repeat_between(pattern, min, max) + return -pattern^(max + 1) * pattern^min +end + +parsers.hexentity = parsers.ampersand * parsers.hash * C(S("Xx")) + * C(repeat_between(parsers.hexdigit, 1, 6)) * parsers.semicolon +parsers.decentity = parsers.ampersand * parsers.hash + * C(repeat_between(parsers.digit, 1, 7)) * parsers.semicolon +parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) + * parsers.semicolon + +parsers.html_entities = parsers.hexentity / entities.hex_entity_with_x_char + + parsers.decentity / entities.dec_entity + + parsers.tagentity / entities.char_entity +parsers.bullet = function(bullet_char, interrupting) + local allowed_end + if interrupting then + allowed_end = C(parsers.spacechar^1) * #parsers.linechar + else + allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof) + end + return parsers.check_trail + * Ct(C(bullet_char) * Cc("")) + * allowed_end +end + +local function tickbox(interior) + return parsers.optionalspace * parsers.lbracket + * interior * parsers.rbracket * parsers.spacechar^1 +end + +parsers.ticked_box = tickbox(S("xX")) * Cc(1.0) +parsers.halfticked_box = tickbox(S("./")) * Cc(0.5) +parsers.unticked_box = tickbox(parsers.spacechar^1) * Cc(0.0) + +parsers.openticks = Cg(parsers.backtick^1, "ticks") + +local function captures_equal_length(_,i,a,b) + return #a == #b and i +end + +parsers.closeticks = Cmt(C(parsers.backtick^1) + * Cb("ticks"), captures_equal_length) + +parsers.intickschar = (parsers.any - S("\n\r`")) + + V("NoSoftLineBreakEndline") + + (parsers.backtick^1 - parsers.closeticks) + +local function process_inticks(s) + s = s:gsub("\n", " ") + s = s:gsub("^ (.*) $", "%1") + return s +end + +parsers.inticks = parsers.openticks + * C(parsers.space^0) + * parsers.closeticks + + parsers.openticks + * Cs(Cs(parsers.intickschar^0) / process_inticks) + * parsers.closeticks + +-- 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.special_block_keyword = + parsers.keyword_exact("pre") + + parsers.keyword_exact("script") + + parsers.keyword_exact("style") + + parsers.keyword_exact("textarea") + +parsers.block_keyword = + parsers.keyword_exact("address") + + parsers.keyword_exact("article") + + parsers.keyword_exact("aside") + + parsers.keyword_exact("base") + + parsers.keyword_exact("basefont") + + parsers.keyword_exact("blockquote") + + parsers.keyword_exact("body") + + parsers.keyword_exact("caption") + + parsers.keyword_exact("center") + + parsers.keyword_exact("col") + + parsers.keyword_exact("colgroup") + + parsers.keyword_exact("dd") + + parsers.keyword_exact("details") + + parsers.keyword_exact("dialog") + + parsers.keyword_exact("dir") + + parsers.keyword_exact("div") + + parsers.keyword_exact("dl") + + parsers.keyword_exact("dt") + + parsers.keyword_exact("fieldset") + + parsers.keyword_exact("figcaption") + + parsers.keyword_exact("figure") + + parsers.keyword_exact("footer") + + parsers.keyword_exact("form") + + parsers.keyword_exact("frame") + + 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("head") + + parsers.keyword_exact("header") + + parsers.keyword_exact("hr") + + parsers.keyword_exact("html") + + parsers.keyword_exact("iframe") + + parsers.keyword_exact("legend") + + parsers.keyword_exact("li") + + parsers.keyword_exact("link") + + parsers.keyword_exact("main") + + parsers.keyword_exact("menu") + + parsers.keyword_exact("menuitem") + + parsers.keyword_exact("nav") + + parsers.keyword_exact("noframes") + + parsers.keyword_exact("ol") + + parsers.keyword_exact("optgroup") + + parsers.keyword_exact("option") + + parsers.keyword_exact("p") + + parsers.keyword_exact("param") + + parsers.keyword_exact("section") + + parsers.keyword_exact("source") + + parsers.keyword_exact("summary") + + parsers.keyword_exact("table") + + parsers.keyword_exact("tbody") + + parsers.keyword_exact("td") + + parsers.keyword_exact("tfoot") + + parsers.keyword_exact("th") + + parsers.keyword_exact("thead") + + parsers.keyword_exact("title") + + parsers.keyword_exact("tr") + + parsers.keyword_exact("track") + + parsers.keyword_exact("ul") + +-- end conditions +parsers.html_blankline_end_condition = parsers.linechar^0 + * ( parsers.newline + * (parsers.check_minimal_blank_indent_and_any_trail + * #parsers.blankline + + parsers.check_minimal_indent_and_any_trail) + * parsers.linechar^1)^0 + * (parsers.newline^-1 / "") + +local function remove_trailing_blank_lines(s) + return s:gsub("[\n\r]+%s*$", "") +end + +parsers.html_until_end = function(end_marker) + return Cs(Cs((parsers.newline + * (parsers.check_minimal_blank_indent_and_any_trail + * #parsers.blankline + + parsers.check_minimal_indent_and_any_trail) + + parsers.linechar - end_marker)^0 + * parsers.linechar^0 * parsers.newline^-1) + / remove_trailing_blank_lines) +end + +-- attributes +parsers.html_attribute_spacing = parsers.optionalspace + * V("NoSoftLineBreakEndline") + * parsers.optionalspace + + parsers.spacechar^1 + +parsers.html_attribute_name = (parsers.letter + parsers.colon + parsers.underscore) + * (parsers.alphanumeric + parsers.colon + parsers.underscore + + parsers.period + parsers.dash)^0 + +parsers.html_attribute_value = parsers.squote + * (parsers.linechar - parsers.squote)^0 + * parsers.squote + + parsers.dquote + * (parsers.linechar - parsers.dquote)^0 + * parsers.dquote + + ( parsers.any - parsers.spacechar - parsers.newline + - parsers.dquote - parsers.squote - parsers.backtick + - parsers.equal - parsers.less - parsers.more)^1 + +parsers.html_inline_attribute_value = parsers.squote + * (V("NoSoftLineBreakEndline") + + parsers.any + - parsers.blankline^2 + - parsers.squote)^0 + * parsers.squote + + parsers.dquote + * (V("NoSoftLineBreakEndline") + + parsers.any + - parsers.blankline^2 + - parsers.dquote)^0 + * parsers.dquote + + (parsers.any - parsers.spacechar - parsers.newline + - parsers.dquote - parsers.squote - parsers.backtick + - parsers.equal - parsers.less - parsers.more)^1 + +parsers.html_attribute_value_specification = parsers.optionalspace + * parsers.equal + * parsers.optionalspace + * parsers.html_attribute_value + +parsers.html_spnl = parsers.optionalspace + * (V("NoSoftLineBreakEndline") * parsers.optionalspace)^-1 + +parsers.html_inline_attribute_value_specification = parsers.html_spnl + * parsers.equal + * parsers.html_spnl + * parsers.html_inline_attribute_value + +parsers.html_attribute = parsers.html_attribute_spacing + * parsers.html_attribute_name + * parsers.html_inline_attribute_value_specification^-1 + +parsers.html_non_newline_attribute = parsers.spacechar^1 + * parsers.html_attribute_name + * parsers.html_attribute_value_specification^-1 + +parsers.nested_breaking_blank = parsers.newline + * parsers.check_minimal_blank_indent + * parsers.blankline + +parsers.html_comment_start = P("") + +parsers.html_comment = Cs( parsers.html_comment_start + * parsers.html_until_end(parsers.html_comment_end)) + +parsers.html_inline_comment = (parsers.html_comment_start / "") + * -P(">") * -P("->") + * Cs((V("NoSoftLineBreakEndline") + parsers.any - P("--") + - parsers.nested_breaking_blank - parsers.html_comment_end)^0) + * (parsers.html_comment_end / "") + +parsers.html_cdatasection_start = P("") + +parsers.html_cdatasection = Cs( parsers.html_cdatasection_start + * parsers.html_until_end(parsers.html_cdatasection_end)) + +parsers.html_inline_cdatasection = parsers.html_cdatasection_start + * Cs(V("NoSoftLineBreakEndline") + parsers.any + - parsers.nested_breaking_blank - parsers.html_cdatasection_end)^0 + * parsers.html_cdatasection_end + +parsers.html_declaration_start = P("") + +parsers.html_declaration = Cs( parsers.html_declaration_start + * parsers.html_until_end(parsers.html_declaration_end)) + +parsers.html_inline_declaration = parsers.html_declaration_start + * Cs(V("NoSoftLineBreakEndline") + parsers.any + - parsers.nested_breaking_blank - parsers.html_declaration_end)^0 + * parsers.html_declaration_end + +parsers.html_instruction_start = P("") + +parsers.html_instruction = Cs( parsers.html_instruction_start + * parsers.html_until_end(parsers.html_instruction_end)) + +parsers.html_inline_instruction = parsers.html_instruction_start + * Cs(V("NoSoftLineBreakEndline") + parsers.any + - parsers.nested_breaking_blank - parsers.html_instruction_end)^0 + * parsers.html_instruction_end + +parsers.html_blankline = parsers.newline + * parsers.optionalspace + * parsers.newline + +parsers.html_tag_start = parsers.less + +parsers.html_tag_closing_start = parsers.less + * parsers.slash + +parsers.html_tag_end = parsers.html_spnl + * parsers.more + +parsers.html_empty_tag_end = parsers.html_spnl + * parsers.slash + * parsers.more + +-- opening tags +parsers.html_any_open_inline_tag = parsers.html_tag_start + * parsers.keyword + * parsers.html_attribute^0 + * parsers.html_tag_end + +parsers.html_any_open_tag = parsers.html_tag_start + * parsers.keyword + * parsers.html_non_newline_attribute^0 + * parsers.html_tag_end + +parsers.html_open_tag = parsers.html_tag_start + * parsers.block_keyword + * parsers.html_attribute^0 + * parsers.html_tag_end + +parsers.html_open_special_tag = parsers.html_tag_start + * parsers.special_block_keyword + * parsers.html_attribute^0 + * parsers.html_tag_end + +-- incomplete tags +parsers.incomplete_tag_following = parsers.spacechar + + parsers.more + + parsers.slash * parsers.more + + #(parsers.newline + parsers.eof) + +parsers.incomplete_special_tag_following = parsers.spacechar + + parsers.more + + #(parsers.newline + parsers.eof) + +parsers.html_incomplete_open_tag = parsers.html_tag_start + * parsers.block_keyword + * parsers.incomplete_tag_following + +parsers.html_incomplete_open_special_tag = parsers.html_tag_start + * parsers.special_block_keyword + * parsers.incomplete_special_tag_following + +parsers.html_incomplete_close_tag = parsers.html_tag_closing_start + * parsers.block_keyword + * parsers.incomplete_tag_following + +parsers.html_incomplete_close_special_tag = parsers.html_tag_closing_start + * parsers.special_block_keyword + * parsers.incomplete_tag_following + +-- closing tags +parsers.html_close_tag = parsers.html_tag_closing_start + * parsers.block_keyword + * parsers.html_tag_end + +parsers.html_any_close_tag = parsers.html_tag_closing_start + * parsers.keyword + * parsers.html_tag_end + +parsers.html_close_special_tag = parsers.html_tag_closing_start + * parsers.special_block_keyword + * parsers.html_tag_end + +-- empty tags +parsers.html_any_empty_inline_tag = parsers.html_tag_start + * parsers.keyword + * parsers.html_attribute^0 + * parsers.html_empty_tag_end + +parsers.html_any_empty_tag = parsers.html_tag_start + * parsers.keyword + * parsers.html_non_newline_attribute^0 + * parsers.optionalspace + * parsers.slash + * parsers.more + +parsers.html_empty_tag = parsers.html_tag_start + * parsers.block_keyword + * parsers.html_attribute^0 + * parsers.html_empty_tag_end + +parsers.html_empty_special_tag = parsers.html_tag_start + * parsers.special_block_keyword + * parsers.html_attribute^0 + * parsers.html_empty_tag_end + +parsers.html_incomplete_blocks = parsers.html_incomplete_open_tag + + parsers.html_incomplete_open_special_tag + + parsers.html_incomplete_close_tag + +-- parse special html blocks +parsers.html_blankline_ending_special_block_opening = (parsers.html_close_special_tag + + parsers.html_empty_special_tag) + * #(parsers.optionalspace + * (parsers.newline + parsers.eof)) + +parsers.html_blankline_ending_special_block = parsers.html_blankline_ending_special_block_opening + * parsers.html_blankline_end_condition + +parsers.html_special_block_opening = parsers.html_incomplete_open_special_tag + - parsers.html_empty_special_tag + +parsers.html_closing_special_block = parsers.html_special_block_opening + * parsers.html_until_end(parsers.html_close_special_tag) + +parsers.html_special_block = parsers.html_blankline_ending_special_block + + parsers.html_closing_special_block + +-- parse html blocks +parsers.html_block_opening = parsers.html_incomplete_open_tag + + parsers.html_incomplete_close_tag + +parsers.html_block = parsers.html_block_opening + * parsers.html_blankline_end_condition + +-- parse any html blocks +parsers.html_any_block_opening = (parsers.html_any_open_tag + + parsers.html_any_close_tag + + parsers.html_any_empty_tag) + * #(parsers.optionalspace * (parsers.newline + parsers.eof)) + +parsers.html_any_block = parsers.html_any_block_opening + * parsers.html_blankline_end_condition + +parsers.html_inline_comment_full = parsers.html_comment_start + * -P(">") * -P("->") + * Cs((V("NoSoftLineBreakEndline") + parsers.any - P("--") + - parsers.nested_breaking_blank - parsers.html_comment_end)^0) + * parsers.html_comment_end + +parsers.html_inline_tags = parsers.html_inline_comment_full + + parsers.html_any_empty_inline_tag + + parsers.html_inline_instruction + + parsers.html_inline_cdatasection + + parsers.html_inline_declaration + + parsers.html_any_open_inline_tag + + parsers.html_any_close_tag + +parsers.urlchar = parsers.anyescaped + - parsers.newline + - parsers.more + +parsers.auto_link_scheme_part = parsers.alphanumeric + + parsers.plus + + parsers.period + + parsers.dash + +parsers.auto_link_scheme = parsers.letter + * parsers.auto_link_scheme_part + * parsers.auto_link_scheme_part^-30 + +parsers.absolute_uri = parsers.auto_link_scheme * parsers.colon + * (parsers.any - parsers.spacing - parsers.less - parsers.more)^0 + +parsers.printable_characters = S(".!#$%&'*+/=?^_`{|}~-") + +parsers.email_address_local_part_char = parsers.alphanumeric + + parsers.printable_characters + +parsers.email_address_local_part = parsers.email_address_local_part_char^1 + +parsers.email_address_dns_label = parsers.alphanumeric + * (parsers.alphanumeric + parsers.dash)^-62 + * B(parsers.alphanumeric) + +parsers.email_address_domain = parsers.email_address_dns_label + * (parsers.period * parsers.email_address_dns_label)^0 + +parsers.email_address = parsers.email_address_local_part + * parsers.at + * parsers.email_address_domain + +parsers.auto_link_url = parsers.less + * C(parsers.absolute_uri) + * parsers.more + +parsers.auto_link_email = parsers.less + * C(parsers.email_address) + * parsers.more + +parsers.auto_link_relative_reference = parsers.less + * C(parsers.urlchar^1) + * parsers.more + +parsers.autolink = parsers.auto_link_url + + parsers.auto_link_email + +-- content in balanced brackets, parentheses, or quotes: +parsers.bracketed = P{ parsers.lbracket + * (( parsers.backslash / "" * parsers.rbracket + + parsers.any - (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 } + +parsers.link_text = parsers.lbracket + * Cs((parsers.alphanumeric^1 + + parsers.bracketed + + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + ( parsers.backslash * parsers.backslash) + + ( parsers.backslash * (parsers.lbracket + parsers.rbracket) + + V("NoSoftLineBreakSpace") + + V("NoSoftLineBreakEndline") + + (parsers.any + - (parsers.newline + parsers.lbracket + parsers.rbracket + parsers.blankline^2))))^0) + * parsers.rbracket + +parsers.link_label = parsers.lbracket + * -#(parsers.sp * parsers.rbracket) + * #((parsers.any - parsers.rbracket)^-999 * parsers.rbracket) + * Cs((parsers.alphanumeric^1 + + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + ( parsers.backslash * parsers.backslash) + + ( parsers.backslash * (parsers.lbracket + parsers.rbracket) + + V("NoSoftLineBreakSpace") + + V("NoSoftLineBreakEndline") + + (parsers.any + - (parsers.newline + parsers.lbracket + parsers.rbracket + parsers.blankline^2))))^1) + * parsers.rbracket + +parsers.inparens_url = P{ parsers.lparent + * ((parsers.anyescaped - (parsers.lparent + + parsers.rparent + + parsers.spacing) + ) + V(1))^0 + * parsers.rparent } + +-- url for markdown links, allowing nested brackets: +parsers.url = parsers.less * Cs((parsers.anyescaped + - parsers.newline + - parsers.less + - parsers.more)^0) + * parsers.more + + -parsers.less + * Cs((parsers.inparens_url + (parsers.anyescaped + - parsers.spacing + - parsers.lparent + - parsers.rparent))^1) + +-- quoted text: +parsers.title_s = parsers.squote + * Cs((parsers.html_entities + + V("NoSoftLineBreakSpace") + + V("NoSoftLineBreakEndline") + + (parsers.anyescaped - parsers.newline - parsers.squote - parsers.blankline^2))^0) + * parsers.squote + +parsers.title_d = parsers.dquote + * Cs((parsers.html_entities + + V("NoSoftLineBreakSpace") + + V("NoSoftLineBreakEndline") + + (parsers.anyescaped - parsers.newline - parsers.dquote - parsers.blankline^2))^0) + * parsers.dquote + +parsers.title_p = parsers.lparent + * Cs((parsers.html_entities + + V("NoSoftLineBreakSpace") + + V("NoSoftLineBreakEndline") + + (parsers.anyescaped - parsers.newline - parsers.lparent - parsers.rparent + - parsers.blankline^2))^0) + * parsers.rparent + +parsers.title = parsers.title_d + parsers.title_s + parsers.title_p + +parsers.optionaltitle + = parsers.spnlc * parsers.title * parsers.spacechar^0 + + Cc("") + +-- parse a reference definition: [foo]: /bar "title" +parsers.define_reference_parser = (parsers.check_trail / "") * parsers.link_label * parsers.colon + * parsers.spnlc * parsers.url + * ( parsers.spnlc_sep * parsers.title * parsers.only_blank + + Cc("") * parsers.only_blank) +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.lineof = function(c) + return (parsers.check_trail_no_rem * (P(c) * parsers.optionalspace)^3 + * (parsers.newline + parsers.eof)) +end + +parsers.thematic_break_lines = parsers.lineof(parsers.asterisk) + + parsers.lineof(parsers.dash) + + parsers.lineof(parsers.underscore) -- parse Atx heading start and return level parsers.heading_start = #parsers.hash * C(parsers.hash^-6) * -parsers.hash / length -- parse setext header ending and return level -parsers.heading_level = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) +parsers.heading_level = parsers.nonindentspace * parsers.equal^1 * parsers.optionalspace * #parsers.newline * Cc(1) + + parsers.nonindentspace * parsers.dash^1 * parsers.optionalspace * #parsers.newline * Cc(2) local function strip_atx_end(s) - return s:gsub("[#%s]*\n$","") + return s:gsub("%s+#*%s*\n$","") end + +parsers.atx_heading = parsers.check_trail_no_rem + * Cg(parsers.heading_start, "level") + * (C( parsers.optionalspace + * parsers.hash^0 + * parsers.optionalspace + * parsers.newline) + + parsers.spacechar^1 + * C(parsers.line)) M.reader = {} function M.reader.new(writer, options) local self = {} @@ -3319,7 +4517,7 @@ function M.reader.new(writer, options) tag = util.rope_to_string(tag) tag = tag:gsub("[ \n\r\t]+", " ") tag = tag:gsub("^ ", ""):gsub(" $", "") - tag = uni_case.casefold(tag, true, false) + tag = uni_algos.case.casefold(tag, true, false) return tag end local function iterlines(s, f) @@ -3386,11 +4584,6 @@ function M.reader.new(writer, options) return parsers.inlines end, false) - self.create_parser("parse_inlines_no_link", - function() - return parsers.inlines_no_link - end, false) - self.create_parser("parse_inlines_no_inline_note", function() return parsers.inlines_no_inline_note @@ -3405,139 +4598,826 @@ function M.reader.new(writer, options) function() return parsers.inlines_nbsp end, false) + self.create_parser("parse_inlines_no_link_or_emphasis", + function() + return parsers.inlines_no_link_or_emphasis + end, false) + parsers.minimally_indented_blankline = parsers.check_minimal_indent * (parsers.blankline / "") + + parsers.minimally_indented_block = parsers.check_minimal_indent * V("Block") + + parsers.minimally_indented_block_or_paragraph = parsers.check_minimal_indent * V("BlockOrParagraph") + + parsers.minimally_indented_paragraph = parsers.check_minimal_indent * V("Paragraph") + + parsers.minimally_indented_plain = parsers.check_minimal_indent * V("Plain") + + parsers.minimally_indented_par_or_plain = parsers.minimally_indented_paragraph + + parsers.minimally_indented_plain + + parsers.minimally_indented_par_or_plain_no_blank = parsers.minimally_indented_par_or_plain + - parsers.minimally_indented_blankline + + parsers.minimally_indented_ref = parsers.check_minimal_indent * V("Reference") + + parsers.minimally_indented_blank = parsers.check_minimal_indent * V("Blank") + + parsers.conditionally_indented_blankline = parsers.check_minimal_blank_indent * (parsers.blankline / "") + + parsers.minimally_indented_ref_or_block = parsers.minimally_indented_ref + + parsers.minimally_indented_block + - parsers.minimally_indented_blankline + + parsers.minimally_indented_ref_or_block_or_par = parsers.minimally_indented_ref + + parsers.minimally_indented_block_or_paragraph + - parsers.minimally_indented_blankline + + + parsers.separator_loop = function(separated_block, paragraph, block_separator, paragraph_separator) + return separated_block + + block_separator + * paragraph + * separated_block + + paragraph_separator + * paragraph + end + + parsers.create_loop_body_pair = function(separated_block, paragraph, block_separator, paragraph_separator) + return { + block = parsers.separator_loop(separated_block, paragraph, block_separator, block_separator), + par = parsers.separator_loop(separated_block, paragraph, block_separator, paragraph_separator) + } + end + + parsers.block_sep_group = function(blank) + return blank^0 * parsers.eof + + ( blank^2 / writer.paragraphsep + + blank^0 / writer.interblocksep + ) + end + + parsers.par_sep_group = function(blank) + return blank^0 * parsers.eof + + blank^0 / writer.paragraphsep + end + + parsers.sep_group_no_output = function(blank) + return blank^0 * parsers.eof + + blank^0 + end + + parsers.content_blank = parsers.minimally_indented_blankline + + parsers.ref_or_block_separated = parsers.sep_group_no_output(parsers.content_blank) + * ( parsers.minimally_indented_ref + - parsers.content_blank) + + parsers.block_sep_group(parsers.content_blank) + * ( parsers.minimally_indented_block + - parsers.content_blank) + + parsers.loop_body_pair = + parsers.create_loop_body_pair(parsers.ref_or_block_separated, + parsers.minimally_indented_par_or_plain_no_blank, + parsers.block_sep_group(parsers.content_blank), + parsers.par_sep_group(parsers.content_blank)) + + parsers.content_loop = ( V("Block") + * parsers.loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.ref_or_block_separated + * parsers.loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.loop_body_pair.par^0) + * parsers.content_blank^0 + + parsers.indented_content = function() + return Ct( (V("Reference") + (parsers.blankline / "")) + * parsers.content_blank^0 + * parsers.check_minimal_indent + * parsers.content_loop + + (V("Reference") + (parsers.blankline / "")) + * parsers.content_blank^0 + + parsers.content_loop) + end + + parsers.add_indent = function(pattern, name, breakable) + return Cg(Cmt( Cb("indent_info") + * Ct(pattern) + * (#parsers.linechar * Cc(false) + Cc(true)) -- check if starter is blank + * Cc(name) + * Cc(breakable), + process_starter_indent), "indent_info") + end + if options.hashEnumerators then parsers.dig = parsers.digit + parsers.hash else parsers.dig = parsers.digit end - parsers.enumerator = C(parsers.dig^3 * parsers.period) * #parsers.spacing - + C(parsers.dig^2 * parsers.period) * #parsers.spacing - * (parsers.tab + parsers.space^1) - + C(parsers.dig * parsers.period) * #parsers.spacing - * (parsers.tab + parsers.space^-2) - + parsers.space * C(parsers.dig^2 * parsers.period) - * #parsers.spacing - + parsers.space * C(parsers.dig * parsers.period) - * #parsers.spacing - * (parsers.tab + parsers.space^-1) - + parsers.space * parsers.space * C(parsers.dig^1 - * parsers.period) * #parsers.spacing - -- 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 - * (-V("BlockquoteExceptions") * parsers.linechar^1 - * parsers.newline)^0 + parsers.enumerator = function(delimiter_type, interrupting) + local delimiter_range + local allowed_end + if interrupting then + delimiter_range = P("1") + allowed_end = C(parsers.spacechar^1) * #parsers.linechar + else + delimiter_range = parsers.dig * parsers.dig^-8 + allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof) + end + + return parsers.check_trail + * Ct(C(delimiter_range) * C(delimiter_type)) + * allowed_end + end + + parsers.starter = parsers.bullet(parsers.dash) + + parsers.bullet(parsers.asterisk) + + parsers.bullet(parsers.plus) + + parsers.enumerator(parsers.period) + + parsers.enumerator(parsers.rparent) + + parsers.blockquote_start = parsers.check_trail * C(parsers.more) * C(parsers.spacechar^0) + + parsers.blockquote_body = parsers.add_indent(parsers.blockquote_start, "bq", true) + * parsers.indented_content() + * remove_indent("bq") + + if not options.breakableBlockquotes then + parsers.blockquote_body = parsers.add_indent(parsers.blockquote_start, "bq", false) + * parsers.indented_content() + * remove_indent("bq") + end + local function parse_content_part(content_part) + local rope = util.rope_to_string(content_part) + local parsed = self.parser_functions.parse_inlines_no_link_or_emphasis(rope) + parsed.indent_info = nil + return parsed + end + + local function collect_emphasis_content(t, opening_index, closing_index) + local content = {} + + local content_part = {} + for i = opening_index, closing_index do + local value = t[i] + + if value.rendered ~= nil then + content[#content + 1] = parse_content_part(content_part) + content_part = {} + content[#content + 1] = value.rendered + value.rendered = nil + else + if value.type == "delimiter" and value.element == "emphasis" then + if value.is_active then + content_part[#content_part + 1] = string.rep(value.character, value.current_count) + end + else + content_part[#content_part + 1] = value.content + end + value.content = '' + value.is_active = false + end + end + + if next(content_part) ~= nil then + content[#content + 1] = parse_content_part(content_part) + end + + return content + end + + local function fill_emph(t, opening_index, closing_index) + local content = collect_emphasis_content(t, opening_index + 1, closing_index - 1) + t[opening_index + 1].is_active = true + t[opening_index + 1].rendered = writer.emphasis(content) + end + + local function fill_strong(t, opening_index, closing_index) + local content = collect_emphasis_content(t, opening_index + 1, closing_index - 1) + t[opening_index + 1].is_active = true + t[opening_index + 1].rendered = writer.strong(content) + end + + local function breaks_three_rule(opening_delimiter, closing_delimiter) + return (opening_delimiter.is_closing or closing_delimiter.is_opening) and + ((opening_delimiter.original_count + closing_delimiter.original_count) % 3 == 0) and + (opening_delimiter.original_count % 3 ~= 0 or closing_delimiter.original_count % 3 ~= 0) + end + + local function find_emphasis_opener(t, bottom_index, latest_index, character, closing_delimiter) + for i = latest_index, bottom_index, -1 do + local value = t[i] + if value.is_active and + value.is_opening and + value.type == "delimiter" and + value.element == "emphasis" and + (value.character == character) and + (value.current_count > 0) then + if not breaks_three_rule(value, closing_delimiter) then + return i + end + end + end + end + + local function process_emphasis(t, opening_index, closing_index) + for i = opening_index, closing_index do + local value = t[i] + if value.type == "delimiter" and value.element == "emphasis" then + local delimiter_length = string.len(value.content) + value.character = string.sub(value.content, 1, 1) + value.current_count = delimiter_length + value.original_count = delimiter_length + end + end + + local openers_bottom = { + ['*'] = { + [true] = {opening_index, opening_index, opening_index}, + [false] = {opening_index, opening_index, opening_index} + }, + ['_'] = { + [true] = {opening_index, opening_index, opening_index}, + [false] = {opening_index, opening_index, opening_index} + } + } + + local current_position = opening_index + local max_position = closing_index + + while current_position <= max_position do + local value = t[current_position] + + if value.type ~= "delimiter" or + value.element ~= "emphasis" or + not value.is_active or + not value.is_closing or + (value.current_count <= 0) then + current_position = current_position + 1 + goto continue + end + + local character = value.character + local is_opening = value.is_opening + local closing_length_modulo_three = value.original_count % 3 + + local current_openers_bottom = openers_bottom[character][is_opening][closing_length_modulo_three + 1] + + local opener_position = find_emphasis_opener(t, current_openers_bottom, current_position - 1, character, value) + + if (opener_position == nil) then + openers_bottom[character][is_opening][closing_length_modulo_three + 1] = current_position + current_position = current_position + 1 + goto continue + end + + local opening_delimiter = t[opener_position] + + local current_opening_count = opening_delimiter.current_count + local current_closing_count = t[current_position].current_count + + if (current_opening_count >= 2) and (current_closing_count >= 2) then + opening_delimiter.current_count = current_opening_count - 2 + t[current_position].current_count = current_closing_count - 2 + fill_strong(t, opener_position, current_position) + else + opening_delimiter.current_count = current_opening_count - 1 + t[current_position].current_count = current_closing_count - 1 + fill_emph(t, opener_position, current_position) + end + + ::continue:: + end + end + + local cont = lpeg.R("\128\191") -- continuation byte + + local function utf8_by_byte_count(n) + if (n == 1) then + return lpeg.R("\0\127") + end + if (n == 2) then + return lpeg.R("\194\223") * cont + end + if (n == 3) then + return lpeg.R("\224\239") * cont * cont + end + if (n == 4) then + return lpeg.R("\240\244") * cont * cont * cont + end + end + + local function check_unicode_type(s, i, start_pos, end_pos, chartype) + local c + local char_length + for pos = start_pos, end_pos, 1 do + if (start_pos < 0) then + char_length = -pos + else + char_length = pos + 1 + end + c = lpeg.match({ C(utf8_by_byte_count(char_length)) },s,i+pos) + if (c ~= nil) and (unicode.utf8.match(c, chartype)) then + return i + end + end + end + + local function check_preceding_unicode_punctuation(s, i) + return check_unicode_type(s, i, -4, -1, "%p") + end + + local function check_preceding_unicode_whitespace(s, i) + return check_unicode_type(s, i, -4, -1, "%s") + end + + local function check_following_unicode_punctuation(s, i) + return check_unicode_type(s, i, 0, 3, "%p") + end + + local function check_following_unicode_whitespace(s, i) + return check_unicode_type(s, i, 0, 3, "%s") + end + + parsers.unicode_preceding_punctuation = B(parsers.escapable) + + Cmt(parsers.succeed, check_preceding_unicode_punctuation) + + parsers.unicode_preceding_whitespace = Cmt(parsers.succeed, check_preceding_unicode_whitespace) + + parsers.unicode_following_punctuation = #parsers.escapable + + Cmt(parsers.succeed, check_following_unicode_punctuation) + + parsers.unicode_following_whitespace = Cmt(parsers.succeed, check_following_unicode_whitespace) + + parsers.delimiter_run = function(character) + return (B(parsers.backslash * character) + -B(character)) + * character^1 + * -#character + end + + parsers.left_flanking_delimiter_run = function(character) + return (B( parsers.any) + * (parsers.unicode_preceding_punctuation + parsers.unicode_preceding_whitespace) + + -B(parsers.any)) + * parsers.delimiter_run(character) + * parsers.unicode_following_punctuation + + parsers.delimiter_run(character) + * -#(parsers.unicode_following_punctuation + parsers.unicode_following_whitespace + + parsers.eof) + end + + parsers.right_flanking_delimiter_run = function(character) + return parsers.unicode_preceding_punctuation + * parsers.delimiter_run(character) + * (parsers.unicode_following_punctuation + parsers.unicode_following_whitespace + + parsers.eof) + + (B(parsers.any) + * -(parsers.unicode_preceding_punctuation + parsers.unicode_preceding_whitespace)) + * parsers.delimiter_run(character) + end + + if options.underscores then + parsers.emph_start = parsers.left_flanking_delimiter_run(parsers.asterisk) + + (-#parsers.right_flanking_delimiter_run(parsers.underscore) + + (parsers.unicode_preceding_punctuation + * #parsers.right_flanking_delimiter_run(parsers.underscore))) + * parsers.left_flanking_delimiter_run(parsers.underscore) + + parsers.emph_end = parsers.right_flanking_delimiter_run(parsers.asterisk) + + (-#parsers.left_flanking_delimiter_run(parsers.underscore) + + #(parsers.left_flanking_delimiter_run(parsers.underscore) + * parsers.unicode_following_punctuation)) + * parsers.right_flanking_delimiter_run(parsers.underscore) + else + parsers.emph_start = parsers.left_flanking_delimiter_run(parsers.asterisk) + + parsers.emph_end = parsers.right_flanking_delimiter_run(parsers.asterisk) + end + + parsers.emph_capturing_open_and_close = #parsers.emph_start * #parsers.emph_end + * Ct( Cg(Cc("delimiter"), "type") + * Cg(Cc("emphasis"), "element") + * Cg(C(parsers.emph_start), "content") + * Cg(Cc(true), "is_opening") + * Cg(Cc(true), "is_closing")) + + parsers.emph_capturing_open = Ct( Cg(Cc("delimiter"), "type") + * Cg(Cc("emphasis"), "element") + * Cg(C(parsers.emph_start), "content") + * Cg(Cc(true), "is_opening") + * Cg(Cc(false), "is_closing")) + + parsers.emph_capturing_close = Ct( Cg(Cc("delimiter"), "type") + * Cg(Cc("emphasis"), "element") + * Cg(C(parsers.emph_end), "content") + * Cg(Cc(false), "is_opening") + * Cg(Cc(true), "is_closing")) + + parsers.emph_open_or_close = parsers.emph_capturing_open_and_close + + parsers.emph_capturing_open + + parsers.emph_capturing_close + + parsers.emph_open = parsers.emph_capturing_open_and_close + + parsers.emph_capturing_open + + parsers.emph_close = parsers.emph_capturing_open_and_close + + parsers.emph_capturing_close + + -- List of references defined in the document + local references + + function self.register_link(_, tag, url, title, + attributes) + local normalized_tag = self.normalize_tag(tag) + if references[normalized_tag] == nil then + references[normalized_tag] = { + url = url, + title = title, + attributes = attributes + } + end + return "" + end + + function self.lookup_reference(tag) + return references[self.normalize_tag(tag)] + end + + parsers.title_s_direct_ref = parsers.squote + * Cs((parsers.html_entities + + (parsers.anyescaped - parsers.squote - parsers.blankline^2))^0) + * parsers.squote + + parsers.title_d_direct_ref = parsers.dquote + * Cs((parsers.html_entities + + (parsers.anyescaped - parsers.dquote - parsers.blankline^2))^0) + * parsers.dquote + + parsers.title_p_direct_ref = parsers.lparent + * Cs((parsers.html_entities + + (parsers.anyescaped - parsers.lparent - parsers.rparent - parsers.blankline^2))^0) + * parsers.rparent + + parsers.title_direct_ref = parsers.title_s_direct_ref + + parsers.title_d_direct_ref + + parsers.title_p_direct_ref + + parsers.inline_direct_ref_inside = parsers.lparent * parsers.spnl + * Cg(parsers.url + Cc(""), "url") + * parsers.spnl + * Cg(parsers.title_direct_ref + Cc(""), "title") + * parsers.spnl * parsers.rparent + + parsers.inline_direct_ref = parsers.lparent * parsers.spnlc + * Cg(parsers.url + Cc(""), "url") + * parsers.spnlc + * Cg(parsers.title + Cc(""), "title") + * parsers.spnlc * parsers.rparent + + parsers.empty_link = parsers.lbracket + * parsers.rbracket + + parsers.inline_link = parsers.link_text + * parsers.inline_direct_ref + + parsers.full_link = parsers.link_text + * parsers.link_label + + parsers.shortcut_link = parsers.link_label + * -(parsers.empty_link + parsers.link_label) + + parsers.collapsed_link = parsers.link_label + * parsers.empty_link + + parsers.image_opening = #(parsers.exclamation * parsers.inline_link) + * Cg(Cc("inline"), "link_type") + + #(parsers.exclamation * parsers.full_link) + * Cg(Cc("full"), "link_type") + + #(parsers.exclamation * parsers.collapsed_link) + * Cg(Cc("collapsed"), "link_type") + + #(parsers.exclamation * parsers.shortcut_link) + * Cg(Cc("shortcut"), "link_type") + + #(parsers.exclamation * parsers.empty_link) + * Cg(Cc("empty"), "link_type") + + parsers.link_opening = #parsers.inline_link + * Cg(Cc("inline"), "link_type") + + #parsers.full_link + * Cg(Cc("full"), "link_type") + + #parsers.collapsed_link + * Cg(Cc("collapsed"), "link_type") + + #parsers.shortcut_link + * Cg(Cc("shortcut"), "link_type") + + #parsers.empty_link + * Cg(Cc("empty_link"), "link_type") + + #parsers.link_text + * Cg(Cc("link_text"), "link_type") + + parsers.link_image_opening = Ct( Cg(Cc("delimiter"), "type") + * Cg(Cc(true), "is_opening") + * Cg(Cc(false), "is_closing") + * ( Cg(Cc("image"), "element") + * parsers.image_opening + * Cg(parsers.exclamation * parsers.lbracket, "content") + + Cg(Cc("link"), "element") + * parsers.link_opening + * Cg(parsers.lbracket, "content"))) + + parsers.link_image_closing = Ct( Cg(Cc("delimiter"), "type") + * Cg(Cc("link"), "element") + * Cg(Cc(false), "is_opening") + * Cg(Cc(true), "is_closing") + * ( Cg(Cc(true), "is_direct") + * Cg(parsers.rbracket * #parsers.inline_direct_ref, "content") + + Cg(Cc(false), "is_direct") + * Cg(parsers.rbracket, "content"))) + + parsers.link_image_open_or_close = parsers.link_image_opening + + parsers.link_image_closing + + if options.html then + parsers.link_emph_precedence = parsers.inticks + + parsers.autolink + + parsers.html_inline_tags + else + parsers.link_emph_precedence = parsers.inticks + + parsers.autolink + end + + parsers.link_and_emph_endline = parsers.newline + * ((parsers.check_minimal_indent + * -V("EndlineExceptions") + + parsers.check_optional_indent + * -V("EndlineExceptions") + * -parsers.starter) / "") + * parsers.spacechar^0 / "\n" + + parsers.link_and_emph_content = Ct( Cg(Cc("content"), "type") + * Cg(Cs(( parsers.link_emph_precedence + + parsers.backslash * parsers.any + + parsers.link_and_emph_endline + + (parsers.linechar + - parsers.blankline^2 + - parsers.link_image_open_or_close + - parsers.emph_open_or_close))^0), "content")) + + parsers.link_and_emph_table = (parsers.link_image_opening + parsers.emph_open) + * parsers.link_and_emph_content + * ((parsers.link_image_open_or_close + parsers.emph_open_or_close) + * parsers.link_and_emph_content)^1 + + local function collect_link_content(t, opening_index, closing_index) + local content = {} + for i = opening_index, closing_index do + content[#content + 1] = t[i].content + end + return util.rope_to_string(content) + end + + local function find_link_opener(t, bottom_index, latest_index) + for i = latest_index, bottom_index, -1 do + local value = t[i] + if value.type == "delimiter" and + value.is_opening and + (value.element == "link" or value.element == "image") + and not value.removed then + if value.is_active then + return i + end + value.removed = true + return nil + end + end + end + + local function find_next_link_closing_index(t, latest_index) + for i = latest_index, #t do + local value = t[i] + if value.is_closing and + value.element == "link" and + not value.removed then + return i + end + end + end + + local function disable_previous_link_openers(t, opening_index) + if t[opening_index].element == "image" then + return + end + + for i = opening_index, 1, -1 do + local value = t[i] + if value.is_active and + value.type == "delimiter" and + value.is_opening and + value.element == "link" then + value.is_active = false + end + end + end + + local function disable_range(t, opening_index, closing_index) + for i = opening_index, closing_index do + local value = t[i] + if value.is_active then + value.is_active = false + if value.type == "delimiter" then + value.removed = true + end + end + end + end + + local function delete_parsed_content_in_range(t, opening_index, closing_index) + for i = opening_index, closing_index do + t[i].rendered = nil + end + end + + local function empty_content_in_range(t, opening_index, closing_index) + for i = opening_index, closing_index do + t[i].content = '' + end + end + + local function join_attributes(reference_attributes, own_attributes) + local merged_attributes = {} + for _, attribute in ipairs(reference_attributes or {}) do + table.insert(merged_attributes, attribute) + end + for _, attribute in ipairs(own_attributes or {}) do + table.insert(merged_attributes, attribute) + end + if next(merged_attributes) == nil then + merged_attributes = nil + end + return merged_attributes + end + + local function render_link_or_image(t, opening_index, closing_index, content_end_index, reference) + process_emphasis(t, opening_index, content_end_index) + local mapped = collect_emphasis_content(t, opening_index + 1, content_end_index - 1) + + local rendered = {} + if (t[opening_index].element == "link") then + rendered = writer.link(mapped, reference.url, reference.title, reference.attributes) + end + + if (t[opening_index].element == "image") then + rendered = writer.image(mapped, reference.url, reference.title, reference.attributes) + end + + t[opening_index].rendered = rendered + delete_parsed_content_in_range(t, opening_index + 1, closing_index) + empty_content_in_range(t, opening_index, closing_index) + disable_previous_link_openers(t, opening_index) + disable_range(t, opening_index, closing_index) + end + + local function resolve_inline_following_content(t, closing_index, match_reference, match_link_attributes) + local content = "" + for i = closing_index + 1, #t do + content = content .. t[i].content + end + + local matching_content = parsers.succeed + + if match_reference then + matching_content = matching_content * parsers.inline_direct_ref_inside + end + + if match_link_attributes then + matching_content = matching_content * Cg(Ct(parsers.attributes^-1), "attributes") + end + + local matched = lpeg.match(Ct(matching_content * Cg(Cp(), "end_position")), content) + + local matched_count = matched.end_position - 1 + for i = closing_index + 1, #t do + local value = t[i] + + local chars_left = matched_count + matched_count = matched_count - #value.content + + if matched_count <= 0 then + value.content = value.content:sub(chars_left + 1) + break + end + + value.content = '' + value.is_active = false + end + + local attributes = matched.attributes + if attributes == nil or next(attributes) == nil then + attributes = nil + end + + return { + url = matched.url or "", + title = matched.title or "", + attributes = attributes + } + end + + local function resolve_inline_link(t, opening_index, closing_index) + local inline_content = resolve_inline_following_content(t, closing_index, true, t.match_link_attributes) + render_link_or_image(t, opening_index, closing_index, closing_index, inline_content) + end + + local function resolve_shortcut_link(t, opening_index, closing_index) + local content = collect_link_content(t, opening_index + 1, closing_index - 1) + local r = self.lookup_reference(content) + + if r then + local inline_content = resolve_inline_following_content(t, closing_index, false, t.match_link_attributes) + r.attributes = join_attributes(r.attributes, inline_content.attributes) + render_link_or_image(t, opening_index, closing_index, closing_index, r) + end + end + + local function resolve_full_link(t, opening_index, closing_index) + local next_link_closing_index = find_next_link_closing_index(t, closing_index + 4) + local next_link_content = collect_link_content(t, closing_index + 3, next_link_closing_index - 1) + local r = self.lookup_reference(next_link_content) - if not options.breakableBlockquotes then - parsers.blockquote_body = parsers.blockquote_body - * (parsers.blankline^0 / "") + if r then + local inline_content = resolve_inline_following_content(t, next_link_closing_index, false, + t.match_link_attributes) + r.attributes = join_attributes(r.attributes, inline_content.attributes) + render_link_or_image(t, opening_index, next_link_closing_index, closing_index, r) + end end - -- List of references defined in the document - local references - function self.register_link(tag, url, title, - attributes) - tag = self.normalize_tag(tag) - references[tag] = { - url = url, - title = title, - attributes = attributes, - } - return "" - end + local function resolve_collapsed_link(t, opening_index, closing_index) + local next_link_closing_index = find_next_link_closing_index(t, closing_index + 4) + local content = collect_link_content(t, opening_index + 1, closing_index - 1) + local r = self.lookup_reference(content) - function self.lookup_reference(label, sps, tag, - attributes) - local tagpart - if not tag then - tag = label - tagpart = "" - elseif tag == "" then - tag = label - tagpart = "[]" - else - tagpart = { - "[", - self.parser_functions.parse_inlines(tag), - "]" - } + if r then + local inline_content = resolve_inline_following_content(t, closing_index, false, t.match_link_attributes) + r.attributes = join_attributes(r.attributes, inline_content.attributes) + render_link_or_image(t, opening_index, next_link_closing_index, closing_index, r) end - if sps then - tagpart = {sps, tagpart} + end + + local function process_links_and_emphasis(t) + for _,value in ipairs(t) do + value.is_active = true end - tag = self.normalize_tag(tag) - local r = references[tag] - if r then - local merged_attributes = {} - for _, attribute in ipairs(r.attributes or {}) do - table.insert(merged_attributes, attribute) + + for i,value in ipairs(t) do + if not value.is_closing or + value.type ~= "delimiter" or + not (value.element == "link" or value.element == "image") then + goto continue end - for _, attribute in ipairs(attributes or {}) do - table.insert(merged_attributes, attribute) + + local opener_position = find_link_opener(t, 1, i - 1) + if (opener_position == nil) then + goto continue end - if #merged_attributes == 0 then - merged_attributes = nil + + local opening_delimiter = t[opener_position] + opening_delimiter.removed = true + + local link_type = opening_delimiter.link_type + + if (link_type == "inline") then + resolve_inline_link(t, opener_position, i) end - return { - url = r.url, - title = r.title, - attributes = merged_attributes, - } - else - return nil, { - "[", - self.parser_functions.parse_inlines(label), - "]", - tagpart - } + if (link_type == "shortcut") then + resolve_shortcut_link(t, opener_position, i) + end + if (link_type == "full") then + resolve_full_link(t, opener_position, i) + end + if (link_type == "collapsed") then + resolve_collapsed_link(t, opener_position, i) + end + + ::continue:: end - end - -- lookup link reference and return a link, if the reference is found, - -- or a bracketed label otherwise. - local function indirect_link(label, sps, tag) - return writer.defer_call(function() - local r,fallback = self.lookup_reference(label, sps, tag) - if r then - return writer.link( - self.parser_functions.parse_inlines_no_link(label), - r.url, r.title) - else - return fallback - end - end) + t[#t].content = t[#t].content:gsub("%s*$","") + + process_emphasis(t, 1, #t) + local final_result = collect_emphasis_content(t, 1, #t) + return final_result end - -- lookup image reference and return an image, if the reference is found, - -- or a bracketed label otherwise. - local function indirect_image(label, sps, tag) + function self.defer_link_and_emphasis_processing(delimiter_table) return writer.defer_call(function() - local r,fallback = self.lookup_reference(label, sps, tag) - if r then - return writer.image(writer.string(label), r.url, r.title) - else - return {"!", fallback} - end + return process_links_and_emphasis(delimiter_table) end) end - parsers.direct_link_tail = parsers.spnl - * parsers.lparent - * (parsers.url + Cc("")) -- link can be empty [foo]() - * parsers.optionaltitle - * parsers.rparent - - parsers.direct_link = (parsers.tag / self.parser_functions.parse_inlines_no_link) - * parsers.direct_link_tail - - parsers.direct_image = parsers.exclamation - * (parsers.tag / self.parser_functions.parse_inlines) - * parsers.direct_link_tail parsers.Str = (parsers.normalchar * (parsers.normalchar + parsers.at)^0) / writer.string - parsers.Symbol = (V("SpecialChar") - parsers.tightblocksep) + parsers.Symbol = (parsers.backtick^1 + V("SpecialChar")) / writer.string parsers.Ellipsis = P("...") / writer.ellipsis @@ -3549,88 +5429,116 @@ function M.reader.new(writer, options) if options.blankBeforeBlockquote then parsers.bqstart = parsers.fail else - parsers.bqstart = parsers.more + parsers.bqstart = parsers.blockquote_start end if options.blankBeforeHeading then parsers.headerstart = parsers.fail else - parsers.headerstart = parsers.hash - + (parsers.line * (parsers.equal^1 + parsers.dash^1) - * parsers.optionalspace * parsers.newline) + parsers.headerstart = parsers.atx_heading + end + + if options.blankBeforeList then + parsers.interrupting_bullets = parsers.fail + parsers.interrupting_enumerators = parsers.fail + else + parsers.interrupting_bullets = parsers.bullet(parsers.dash, true) + + parsers.bullet(parsers.asterisk, true) + + parsers.bullet(parsers.plus, true) + + parsers.interrupting_enumerators = parsers.enumerator(parsers.period, true) + + parsers.enumerator(parsers.rparent, true) + end + + if options.html then + parsers.html_interrupting = parsers.check_trail + * ( parsers.html_incomplete_open_tag + + parsers.html_incomplete_close_tag + + parsers.html_incomplete_open_special_tag + + parsers.html_comment_start + + parsers.html_cdatasection_start + + parsers.html_declaration_start + + parsers.html_instruction_start + - parsers.html_close_special_tag + - parsers.html_empty_special_tag) + else + parsers.html_interrupting = parsers.fail end parsers.EndlineExceptions = parsers.blankline -- paragraph break - + parsers.tightblocksep -- nested list + parsers.eof -- end of document + parsers.bqstart + + parsers.thematic_break_lines + + parsers.interrupting_bullets + + parsers.interrupting_enumerators + parsers.headerstart + + parsers.html_interrupting + + parsers.NoSoftLineBreakEndlineExceptions = parsers.EndlineExceptions - parsers.Endline = parsers.newline + parsers.endline = parsers.newline + * (parsers.check_minimal_indent * -V("EndlineExceptions") - * parsers.spacechar^0 - / (options.hardLineBreaks and writer.hard_line_break - or writer.space) + + parsers.check_optional_indent + * -V("EndlineExceptions") + * -parsers.starter) + * parsers.spacechar^0 + + parsers.Endline = parsers.endline + / writer.soft_line_break + + parsers.EndlineNoSub = parsers.endline + + parsers.NoSoftLineBreakEndline + = parsers.newline + * (parsers.check_minimal_indent + * -V("NoSoftLineBreakEndlineExceptions") + + parsers.check_optional_indent + * -V("NoSoftLineBreakEndlineExceptions") + * -parsers.starter) + * parsers.spacechar^0 + / writer.space + + parsers.EndlineBreak = parsers.backslash * parsers.Endline + / writer.hard_line_break parsers.OptionalIndent = parsers.spacechar^1 / writer.space - parsers.Space = parsers.spacechar^2 * parsers.Endline / writer.hard_line_break - + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / "" + parsers.Space = parsers.spacechar^2 * parsers.Endline + / writer.hard_line_break + + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / self.expandtabs + + parsers.spacechar^1 * parsers.Endline + / writer.soft_line_break + + parsers.spacechar^1 * -parsers.newline / self.expandtabs + + parsers.NoSoftLineBreakSpace + = parsers.spacechar^2 * parsers.Endline + / writer.hard_line_break + + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / self.expandtabs + parsers.spacechar^1 * parsers.Endline - * parsers.optionalspace - / (options.hardLineBreaks - and writer.hard_line_break - or writer.space) - + parsers.spacechar^1 * parsers.optionalspace - / writer.space + / writer.soft_line_break + + parsers.spacechar^1 * -parsers.newline / self.expandtabs parsers.NonbreakingEndline - = parsers.newline - * -V("EndlineExceptions") - * parsers.spacechar^0 - / (options.hardLineBreaks and writer.hard_line_break - or writer.nbsp) + = parsers.endline + / writer.soft_line_break parsers.NonbreakingSpace - = parsers.spacechar^2 * parsers.Endline / writer.hard_line_break + = parsers.spacechar^2 * parsers.Endline + / writer.hard_line_break + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / "" + parsers.spacechar^1 * parsers.Endline * parsers.optionalspace - / (options.hardLineBreaks - and writer.hard_line_break - or writer.nbsp) + / writer.soft_line_break + parsers.spacechar^1 * parsers.optionalspace / writer.nbsp - if options.underscores then - parsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, - parsers.doubleasterisks) - + parsers.between(parsers.Inline, parsers.doubleunderscores, - parsers.doubleunderscores) - ) / writer.strong - - parsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, - parsers.asterisk) - + parsers.between(parsers.Inline, parsers.underscore, - parsers.underscore) - ) / writer.emphasis - else - parsers.Strong = ( parsers.between(parsers.Inline, parsers.doubleasterisks, - parsers.doubleasterisks) - ) / writer.strong - - parsers.Emph = ( parsers.between(parsers.Inline, parsers.asterisk, - parsers.asterisk) - ) / writer.emphasis - end - function self.auto_link_url(url, attributes) return writer.link(writer.escape(url), url, nil, attributes) end - function self.auto_link_email(email, attributes) return writer.link(writer.escape(email), "mailto:"..email, @@ -3648,77 +5556,58 @@ end = parsers.auto_link_relative_reference / self.auto_link_url - parsers.DirectLink = parsers.direct_link - / writer.link - - parsers.IndirectLink = parsers.indirect_link - / indirect_link - - -- parse a link or image (direct or indirect) - parsers.Link = parsers.DirectLink + parsers.IndirectLink - - parsers.DirectImage = parsers.direct_image - / writer.image - - parsers.IndirectImage = parsers.indirect_image - / indirect_image - - parsers.Image = parsers.DirectImage + parsers.IndirectImage - - -- avoid parsing long strings of * or _ as emph/strong - parsers.UlOrStarLine = parsers.asterisk^4 + parsers.underscore^4 - / writer.string + parsers.LinkAndEmph = Ct(parsers.link_and_emph_table) + / self.defer_link_and_emphasis_processing parsers.EscapedChar = parsers.backslash * C(parsers.escapable) / writer.string - parsers.InlineHtml = parsers.emptyelt_any / writer.inline_html_tag - + (parsers.htmlcomment / self.parser_functions.parse_inlines_no_html) - / writer.inline_html_comment - + parsers.htmlinstruction - + parsers.openelt_any / writer.inline_html_tag - + parsers.closeelt_any / writer.inline_html_tag - - parsers.HtmlEntity = parsers.hexentity / entities.hex_entity / writer.string - + parsers.decentity / entities.dec_entity / writer.string - + parsers.tagentity / entities.char_entity / writer.string - parsers.DisplayHtml = (parsers.htmlcomment / self.parser_functions.parse_blocks_nested) - / writer.block_html_comment - + parsers.emptyelt_block / writer.block_html_element - + parsers.openelt_exact("hr") / writer.block_html_element - + parsers.in_matched_block_tags / writer.block_html_element - + parsers.htmlinstruction - - parsers.Verbatim = Cs( (parsers.blanklines - * ((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 + parsers.InlineHtml = Cs(parsers.html_inline_comment) / writer.inline_html_comment + + Cs(parsers.html_any_empty_inline_tag + + parsers.html_inline_instruction + + parsers.html_inline_cdatasection + + parsers.html_inline_declaration + + parsers.html_any_open_inline_tag + + parsers.html_any_close_tag) + / writer.inline_html_tag + + parsers.HtmlEntity = parsers.html_entities / writer.string + parsers.DisplayHtml = Cs(parsers.check_trail + * ( parsers.html_comment + + parsers.html_special_block + + parsers.html_block + + parsers.html_any_block + + parsers.html_instruction + + parsers.html_cdatasection + + parsers.html_declaration)) + / writer.block_html_element + + parsers.indented_non_blank_line = parsers.indentedline - parsers.blankline + + parsers.Verbatim = Cs( + parsers.check_code_trail + * (parsers.line - parsers.blankline) + * ((parsers.check_minimal_blank_indent_and_full_code_trail * parsers.blankline)^0 + * ((parsers.check_minimal_indent / "") * parsers.check_code_trail + * (parsers.line - parsers.blankline))^1)^0 + ) / self.expandtabs / writer.verbatim + + parsers.Blockquote = parsers.blockquote_body / writer.blockquote - parsers.ThematicBreak = ( parsers.lineof(parsers.asterisk) - + parsers.lineof(parsers.dash) - + parsers.lineof(parsers.underscore) - ) / writer.thematic_break + parsers.ThematicBreak = parsers.thematic_break_lines + / writer.thematic_break parsers.Reference = parsers.define_reference_parser - * parsers.blankline^1 / self.register_link - parsers.Paragraph = parsers.nonindentspace * Ct(parsers.Inline^1) - * ( parsers.newline - * ( parsers.blankline^1 - + #V("EndlineExceptions") - ) - + parsers.eof) - / writer.paragraph + parsers.Paragraph = parsers.freeze_trail + * (Ct((parsers.Inline)^1) + * (parsers.newline + parsers.eof) + * parsers.unfreeze_trail + / writer.paragraph) parsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) / writer.plain - parsers.starter = parsers.bullet + parsers.enumerator if options.taskLists then parsers.tickbox = ( parsers.ticked_box @@ -3729,43 +5618,117 @@ end parsers.tickbox = parsers.fail end - -- we use \001 as a separator between a tight list item and a - -- nested list under it. - parsers.NestedList = Cs((parsers.optionallyindentedline - - parsers.starter)^1) - / function(a) return "\001"..a end - - parsers.ListBlockLine = parsers.optionallyindentedline - - parsers.blankline - (parsers.indent^-1 - * parsers.starter) - - parsers.ListBlock = parsers.line * parsers.ListBlockLine^0 - - parsers.ListContinuationBlock = parsers.blanklines * (parsers.indent / "") - * parsers.ListBlock + parsers.list_blank = parsers.conditionally_indented_blankline + + parsers.ref_or_block_list_separated = parsers.sep_group_no_output(parsers.list_blank) + * parsers.minimally_indented_ref + + parsers.block_sep_group(parsers.list_blank) + * parsers.minimally_indented_block + + parsers.ref_or_block_non_separated = parsers.minimally_indented_ref + + (parsers.succeed / writer.interblocksep) + * parsers.minimally_indented_block + - parsers.minimally_indented_blankline + + parsers.tight_list_loop_body_pair = + parsers.create_loop_body_pair(parsers.ref_or_block_non_separated, + parsers.minimally_indented_par_or_plain_no_blank, + (parsers.succeed / writer.interblocksep), + (parsers.succeed / writer.paragraphsep)) + + parsers.loose_list_loop_body_pair = + parsers.create_loop_body_pair(parsers.ref_or_block_list_separated, + parsers.minimally_indented_par_or_plain, + parsers.block_sep_group(parsers.list_blank), + parsers.par_sep_group(parsers.list_blank)) + + parsers.tight_list_content_loop = V("Block") + * parsers.tight_list_loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.ref_or_block_non_separated + * parsers.tight_list_loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.tight_list_loop_body_pair.par^0 + + parsers.loose_list_content_loop = V("Block") + * parsers.loose_list_loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.ref_or_block_list_separated + * parsers.loose_list_loop_body_pair.block^0 + + (V("Paragraph") + V("Plain")) + * parsers.loose_list_loop_body_pair.par^0 + + parsers.list_item_tightness_condition = -#( parsers.list_blank^0 + * parsers.minimally_indented_ref_or_block_or_par) + * remove_indent("li") + + remove_indent("li") + * parsers.fail + + parsers.indented_content_tight = Ct( (parsers.blankline / "") + * #parsers.list_blank + * remove_indent("li") + + ( (V("Reference") + (parsers.blankline / "")) + * parsers.check_minimal_indent + * parsers.tight_list_content_loop + + (V("Reference") + (parsers.blankline / "")) + + (parsers.tickbox^-1 / writer.escape) + * parsers.tight_list_content_loop + ) + * parsers.list_item_tightness_condition + ) + + parsers.indented_content_loose = Ct( (parsers.blankline / "") + * #parsers.list_blank + + ( (V("Reference") + (parsers.blankline / "")) + * parsers.check_minimal_indent + * parsers.loose_list_content_loop + + (V("Reference") + (parsers.blankline / "")) + + (parsers.tickbox^-1 / writer.escape) + * parsers.loose_list_content_loop + ) + ) parsers.TightListItem = function(starter) - return -parsers.ThematicBreak - * (Cs(starter / "" * parsers.tickbox^-1 * parsers.ListBlock * parsers.NestedList^-1) - / self.parser_functions.parse_blocks_nested) - * -(parsers.blanklines * parsers.indent) + return -parsers.ThematicBreak + * parsers.add_indent(starter, "li") + * parsers.indented_content_tight end parsers.LooseListItem = function(starter) - return -parsers.ThematicBreak - * Cs( starter / "" * parsers.tickbox^-1 * parsers.ListBlock * Cc("\n") - * (parsers.NestedList + parsers.ListContinuationBlock^0) - * (parsers.blanklines / "\n\n") - ) / self.parser_functions.parse_blocks_nested + return -parsers.ThematicBreak + * parsers.add_indent(starter, "li") + * parsers.indented_content_loose + * remove_indent("li") end - parsers.BulletList = ( Ct(parsers.TightListItem(parsers.bullet)^1) * Cc(true) - * parsers.skipblanklines * -parsers.bullet - + Ct(parsers.LooseListItem(parsers.bullet)^1) * Cc(false) - * parsers.skipblanklines ) - / writer.bulletlist + parsers.BulletListOfType = function(bullet_type) + local bullet = parsers.bullet(bullet_type) + return ( Ct( parsers.TightListItem(bullet) + * ( (parsers.check_minimal_indent / "") + * parsers.TightListItem(bullet) + )^0 + ) + * Cc(true) + * -#( (parsers.list_blank^0 / "") + * parsers.check_minimal_indent + * (bullet - parsers.ThematicBreak) + ) + + Ct( parsers.LooseListItem(bullet) + * ( (parsers.list_blank^0 / "") + * (parsers.check_minimal_indent / "") + * parsers.LooseListItem(bullet) + )^0 + ) + * Cc(false) + ) / writer.bulletlist + end + + parsers.BulletList = parsers.BulletListOfType(parsers.dash) + + parsers.BulletListOfType(parsers.asterisk) + + parsers.BulletListOfType(parsers.plus) - local function ordered_list(items,tight,startnum) + local function ordered_list(items,tight,starter) + local startnum = starter[2][1] if options.startNumber then startnum = tonumber(startnum) or 1 -- fallback for '#' if startnum ~= nil then @@ -3777,33 +5740,64 @@ end return writer.orderedlist(items,tight,startnum) end - parsers.OrderedList = Cg(parsers.enumerator, "listtype") * - ( Ct(parsers.TightListItem(Cb("listtype")) - * parsers.TightListItem(parsers.enumerator)^0) - * Cc(true) * parsers.skipblanklines * -parsers.enumerator - + Ct(parsers.LooseListItem(Cb("listtype")) - * parsers.LooseListItem(parsers.enumerator)^0) - * Cc(false) * parsers.skipblanklines - ) * Cb("listtype") / ordered_list + parsers.OrderedListOfType = function(delimiter_type) + local enumerator = parsers.enumerator(delimiter_type) + return Cg(enumerator, "listtype") + * (Ct( parsers.TightListItem(Cb("listtype")) + * ((parsers.check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) + * Cc(true) + * -#((parsers.list_blank^0 / "") + * parsers.check_minimal_indent * enumerator) + + Ct( parsers.LooseListItem(Cb("listtype")) + * ((parsers.list_blank^0 / "") + * (parsers.check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) + * Cc(false) + ) * Ct(Cb("listtype")) / ordered_list + end + + parsers.OrderedList = parsers.OrderedListOfType(parsers.period) + + parsers.OrderedListOfType(parsers.rparent) parsers.Blank = parsers.blankline / "" + V("Reference") - + (parsers.tightblocksep / "\n") + function parsers.parse_heading_text(s) + local inlines = self.parser_functions.parse_inlines(s) + local flatten_inlines = self.writer.flatten_inlines + self.writer.flatten_inlines = true + local flat_text = self.parser_functions.parse_inlines(s) + flat_text = util.rope_to_string(flat_text) + self.writer.flatten_inlines = flatten_inlines + return {flat_text, inlines} + end + -- parse atx header - parsers.AtxHeading = Cg(parsers.heading_start, "level") - * parsers.optionalspace - * (C(parsers.line) + parsers.AtxHeading = parsers.check_trail_no_rem + * Cg(parsers.heading_start, "level") + * ((C( parsers.optionalspace + * parsers.hash^0 + * parsers.optionalspace + * parsers.newline) + + parsers.spacechar^1 + * C(parsers.line)) / strip_atx_end - / self.parser_functions.parse_inlines) + / parsers.parse_heading_text) * Cb("level") / writer.heading - parsers.SetextHeading = #(parsers.line * S("=-")) - * Ct(parsers.linechar^1 - / self.parser_functions.parse_inlines) - * parsers.newline - * parsers.heading_level - * parsers.optionalspace + parsers.heading_line = parsers.linechar^1 + - parsers.thematic_break_lines + + parsers.heading_text = parsers.heading_line + * ((V("Endline") / "\n") * (parsers.heading_line - parsers.heading_level))^0 + * parsers.newline^-1 + + parsers.SetextHeading = parsers.freeze_trail * parsers.check_trail_no_rem + * #(parsers.heading_text + * parsers.check_minimal_indent * parsers.check_trail * parsers.heading_level) + * Cs(parsers.heading_text) + / parsers.parse_heading_text + * parsers.check_minimal_indent_and_trail * parsers.heading_level * parsers.newline + * parsers.unfreeze_trail / writer.heading parsers.Heading = parsers.AtxHeading + parsers.SetextHeading @@ -3861,12 +5855,32 @@ end Blocks = V("InitializeState") * ( V("ExpectedJekyllData") - * (V("Blank")^0 / writer.interblocksep))^-1 + * (V("Blank")^0 / writer.interblocksep) + )^-1 * V("Blank")^0 - * V("Block")^-1 - * ( V("Blank")^0 / writer.interblocksep - * V("Block"))^0 - * V("Blank")^0 * parsers.eof, + * ( V("Block") + * ( V("Blank")^0 * parsers.eof + + ( V("Blank")^2 / writer.paragraphsep + + V("Blank")^0 / writer.interblocksep + ) + ) + + ( V("Paragraph") + V("Plain") ) + * ( V("Blank")^0 * parsers.eof + + ( V("Blank")^2 / writer.paragraphsep + + V("Blank")^0 / writer.interblocksep + ) + ) + * V("Block") + * ( V("Blank")^0 * parsers.eof + + ( V("Blank")^2 / writer.paragraphsep + + V("Blank")^0 / writer.interblocksep + ) + ) + + ( V("Paragraph") + V("Plain") ) + * ( V("Blank")^0 * parsers.eof + + V("Blank")^0 / writer.paragraphsep + ) + )^0, ExpectedJekyllData = parsers.fail, @@ -3878,23 +5892,25 @@ end ThematicBreak = parsers.ThematicBreak, BulletList = parsers.BulletList, OrderedList = parsers.OrderedList, - Heading = parsers.Heading, DisplayHtml = parsers.DisplayHtml, + Heading = parsers.Heading, Paragraph = parsers.Paragraph, Plain = parsers.Plain, EndlineExceptions = parsers.EndlineExceptions, - BlockquoteExceptions = parsers.BlockquoteExceptions, + NoSoftLineBreakEndlineExceptions + = parsers.NoSoftLineBreakEndlineExceptions, Str = parsers.Str, Space = parsers.Space, + NoSoftLineBreakSpace = parsers.NoSoftLineBreakSpace, OptionalIndent = parsers.OptionalIndent, Endline = parsers.Endline, - UlOrStarLine = parsers.UlOrStarLine, - Strong = parsers.Strong, - Emph = parsers.Emph, - Link = parsers.Link, - Image = parsers.Image, + EndlineNoSub = parsers.EndlineNoSub, + NoSoftLineBreakEndline + = parsers.NoSoftLineBreakEndline, + EndlineBreak = parsers.EndlineBreak, + LinkAndEmph = parsers.LinkAndEmph, Code = parsers.Code, AutoLinkUrl = parsers.AutoLinkUrl, AutoLinkEmail = parsers.AutoLinkEmail, @@ -3947,9 +5963,14 @@ end self.add_special_character("!") self.add_special_character("\\") self.initialize_named_group = function(name, value) + local pattern = Ct("") + if value ~= nil then + pattern = pattern / value + end syntax.InitializeState = syntax.InitializeState - * Cg(Ct("") / value, name) + * Cg(pattern, name) end + self.initialize_named_group("indent_info") for _, extension in ipairs(extensions) do current_extension_name = extension.name extension.extend_writer(writer) @@ -4004,11 +6025,6 @@ end assert(output_file:write(output)) assert(output_file:close()) end - walkable_syntax["IndentedInline"] = util.table_copy( - walkable_syntax["Inline"]) - self.insert_pattern( - "IndentedInline instead of Space", - "OptionalIndent") for lhs, rule in pairs(walkable_syntax) do syntax[lhs] = parsers.fail for _, rhs in ipairs(rule) do @@ -4056,6 +6072,15 @@ end syntax.AutoLinkRelativeReference = parsers.fail end + if options.contentLevel == "inline" then + syntax[1] = "Inlines" + syntax.Inlines = V("InitializeState") + * parsers.Inline^0 + * ( parsers.spacing^0 + * parsers.eof / "") + syntax.Space = parsers.Space + parsers.blankline / writer.space + end + local blocks_nested_t = util.table_copy(syntax) blocks_nested_t.ExpectedJekyllData = parsers.fail parsers.blocks_nested = Ct(blocks_nested_t) @@ -4070,10 +6095,6 @@ end * parsers.eof / "") parsers.inlines = Ct(inlines_t) - local inlines_no_link_t = util.table_copy(inlines_t) - inlines_no_link_t.Link = parsers.fail - parsers.inlines_no_link = Ct(inlines_no_link_t) - local inlines_no_inline_note_t = util.table_copy(inlines_t) inlines_no_inline_note_t.InlineNote = parsers.fail parsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t) @@ -4088,6 +6109,11 @@ end inlines_nbsp_t.Endline = parsers.NonbreakingEndline inlines_nbsp_t.Space = parsers.NonbreakingSpace parsers.inlines_nbsp = Ct(inlines_nbsp_t) + + local inlines_no_link_or_emphasis_t = util.table_copy(inlines_t) + inlines_no_link_or_emphasis_t.LinkAndEmph = parsers.fail + inlines_no_link_or_emphasis_t.EndlineExceptions = parsers.EndlineExceptions - parsers.eof + parsers.inlines_no_link_or_emphasis = Ct(inlines_no_link_or_emphasis_t) return function(input) input = input:gsub("\r\n?", "\n") if input:sub(-1) ~= "\n" then @@ -4145,6 +6171,7 @@ M.extensions.bracketed_spans = function() name = "built-in bracketed_spans syntax extension", extend_writer = function(self) function self.span(s, attr) + if self.flatten_inlines then return s end return {"\\markdownRendererBracketedSpanAttributeContextBegin", self.attributes(attr), s, @@ -4154,13 +6181,25 @@ M.extensions.bracketed_spans = function() local parsers = self.parsers local writer = self.writer - local Span = parsers.between(parsers.Inline, - parsers.lbracket, - parsers.rbracket) + local span_label = parsers.lbracket + * (Cs((parsers.alphanumeric^1 + + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + ( parsers.backslash * parsers.backslash) + + ( parsers.backslash * (parsers.lbracket + parsers.rbracket) + + V("Space") + V("Endline") + + (parsers.any + - (parsers.newline + parsers.lbracket + parsers.rbracket + + parsers.blankline^2))))^1) + / self.parser_functions.parse_inlines) + * parsers.rbracket + + local Span = span_label * Ct(parsers.attributes) / writer.span - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline before LinkAndEmph", Span, "Span") end } @@ -4170,11 +6209,24 @@ M.extensions.citations = function(citation_nbsps) name = "built-in citations syntax extension", extend_writer = function(self) function self.citations(text_cites, cites) - local buffer = {"\\markdownRenderer", text_cites and "TextCite" or "Cite", - "{", #cites, "}"} - for _,cite in ipairs(cites) do - buffer[#buffer+1] = {cite.suppress_author and "-" or "+", "{", - cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"} + local buffer = {} + if self.flatten_inlines then + for _,cite in ipairs(cites) do + if cite.prenote then + table.insert(buffer, {cite.prenote, " "}) + end + table.insert(buffer, cite.name) + if cite.postnote then + table.insert(buffer, {" ", cite.postnote}) + end + end + else + table.insert(buffer, {"\\markdownRenderer", text_cites and "TextCite" or "Cite", + "{", #cites, "}"}) + for _,cite in ipairs(cites) do + table.insert(buffer, {cite.suppress_author and "-" or "+", "{", + cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"}) + end end return buffer end @@ -4201,42 +6253,51 @@ M.extensions.citations = function(citation_nbsps) = Cs((parsers.alphanumeric^1 + parsers.bracketed + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + V("Space") + V("Endline") + (parsers.anyescaped - - (parsers.rbracket + parsers.blankline^2)) + - (parsers.newline + parsers.rbracket + parsers.blankline^2)) - (parsers.spnl * parsers.dash^-1 * parsers.at))^0) local citation_body_postnote = Cs((parsers.alphanumeric^1 + parsers.bracketed + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + V("Space") + V("Endline") + (parsers.anyescaped - - (parsers.rbracket + parsers.semicolon + - (parsers.newline + parsers.rbracket + parsers.semicolon + parsers.blankline^2)) - (parsers.spnl * parsers.rbracket))^0) local citation_body_chunk = citation_body_prenote - * parsers.spnl * citation_name + * parsers.spnlc * citation_name * (parsers.internal_punctuation - parsers.semicolon)^-1 - * parsers.spnl * citation_body_postnote + * parsers.spnlc * citation_body_postnote local citation_body = citation_body_chunk - * (parsers.semicolon * parsers.spnl + * (parsers.semicolon * parsers.spnlc * citation_body_chunk)^0 local citation_headless_body_postnote = Cs((parsers.alphanumeric^1 + parsers.bracketed + parsers.inticks + + parsers.autolink + + V("InlineHtml") + + V("Space") + V("Endline") + (parsers.anyescaped - - (parsers.rbracket + parsers.at + - (parsers.newline + parsers.rbracket + parsers.at + parsers.semicolon + parsers.blankline^2)) - (parsers.spnl * parsers.rbracket))^0) local citation_headless_body = citation_headless_body_postnote - * (parsers.sp * parsers.semicolon * parsers.spnl + * (parsers.sp * parsers.semicolon * parsers.spnlc * citation_body_chunk)^0 local citations @@ -4265,10 +6326,10 @@ M.extensions.citations = function(citation_nbsps) end local TextCitations - = Ct((parsers.spnl + = Ct((parsers.spnlc * Cc("") * citation_name - * ((parsers.spnl + * ((parsers.spnlc * parsers.lbracket * citation_headless_body * parsers.rbracket) + Cc("")))^1) @@ -4277,7 +6338,7 @@ M.extensions.citations = function(citation_nbsps) end local ParenthesizedCitations - = Ct((parsers.spnl + = Ct((parsers.spnlc * parsers.lbracket * citation_body * parsers.rbracket)^1) @@ -4287,7 +6348,7 @@ M.extensions.citations = function(citation_nbsps) local Citations = TextCitations + ParenthesizedCitations - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline before LinkAndEmph", Citations, "Citations") self.add_special_character("@") @@ -4381,6 +6442,7 @@ M.extensions.content_blocks = function(language_map) = (parsers.less * Cs((parsers.anyescaped - parsers.more + - parsers.spacing - #(parsers.period * onlineimagesuffix * parsers.more @@ -4413,7 +6475,7 @@ M.extensions.content_blocks = function(language_map) * Cc("localfile") local ContentBlock - = parsers.leader + = parsers.check_trail_no_rem * (localfilepath + onlineimageurl) * contentblock_tail / writer.contentblock @@ -4457,18 +6519,26 @@ M.extensions.definition_lists = function(tight_lists) local defstartchar = S("~:") - local defstart = ( defstartchar * #parsers.spacing + local defstart = parsers.check_trail_length(0) * defstartchar * #parsers.spacing * (parsers.tab + parsers.space^-3) - + parsers.space * defstartchar * #parsers.spacing + + parsers.check_trail_length(1) * defstartchar * #parsers.spacing * (parsers.tab + parsers.space^-2) - + parsers.space * parsers.space * defstartchar - * #parsers.spacing + + parsers.check_trail_length(2) * defstartchar * #parsers.spacing * (parsers.tab + parsers.space^-1) - + parsers.space * parsers.space * parsers.space - * defstartchar * #parsers.spacing - ) + + parsers.check_trail_length(3) * defstartchar * #parsers.spacing + + local indented_line = (parsers.check_minimal_indent / "") * parsers.check_code_trail * parsers.line - local dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0) + local blank = parsers.check_minimal_blank_indent_and_any_trail * parsers.optionalspace * parsers.newline + + local dlchunk = Cs(parsers.line * (indented_line - blank)^0) + + local indented_blocks = function(bl) + return Cs( bl + * (blank^1 * (parsers.check_minimal_indent / "") + * parsers.check_code_trail * -parsers.blankline * bl)^0 + * (blank^1 + parsers.eof)) + end local function definition_list_item(term, defs, _) return { term = self.parser_functions.parse_inlines(term), @@ -4476,22 +6546,22 @@ M.extensions.definition_lists = function(tight_lists) end local DefinitionListItemLoose - = C(parsers.line) * parsers.skipblanklines - * Ct((defstart - * parsers.indented_blocks(dlchunk) - / self.parser_functions.parse_blocks_nested)^1) + = C(parsers.line) * blank^0 + * Ct((parsers.check_minimal_indent * (defstart + * indented_blocks(dlchunk) + / self.parser_functions.parse_blocks_nested))^1) * Cc(false) / definition_list_item local DefinitionListItemTight = C(parsers.line) - * Ct((defstart * dlchunk - / self.parser_functions.parse_blocks_nested)^1) + * Ct((parsers.check_minimal_indent * (defstart * dlchunk + / self.parser_functions.parse_blocks_nested))^1) * Cc(true) / definition_list_item local DefinitionList = ( Ct(DefinitionListItemLoose^1) * Cc(false) + Ct(DefinitionListItemTight^1) - * (parsers.skipblanklines + * (blank^0 * -DefinitionListItemLoose * Cc(true)) ) / writer.definitionlist @@ -4511,8 +6581,10 @@ M.extensions.fancy_lists = function() local buffer = {} local num = startnum for _,item in ipairs(items) do - buffer[#buffer + 1] = self.fancyitem(item,num) - if num ~= nil then + if item ~= "" then + buffer[#buffer + 1] = self.fancyitem(item,num) + end + if num ~= nil and item ~= "" then num = num + 1 end end @@ -4540,52 +6612,101 @@ M.extensions.fancy_lists = function() local options = self.options local writer = self.writer - local label = parsers.dig + parsers.letter - local numdelim = parsers.period + parsers.rparent - local enumerator = C(label^3 * numdelim) * #parsers.spacing - + C(label^2 * numdelim) * #parsers.spacing - * (parsers.tab + parsers.space^1) - + C(label * numdelim) * #parsers.spacing - * (parsers.tab + parsers.space^-2) - + parsers.space * C(label^2 * numdelim) - * #parsers.spacing - + parsers.space * C(label * numdelim) - * #parsers.spacing - * (parsers.tab + parsers.space^-1) - + parsers.space * parsers.space * C(label^1 - * numdelim) * #parsers.spacing - local starter = parsers.bullet + enumerator + local function combine_markers_and_delims(markers, delims) + local markers_table = {} + for _,marker in ipairs(markers) do + local start_marker + local continuation_marker + if type(marker) == "table" then + start_marker = marker[1] + continuation_marker = marker[2] + else + start_marker = marker + continuation_marker = marker + end + for _,delim in ipairs(delims) do + table.insert(markers_table, {start_marker, continuation_marker, delim}) + end + end + return markers_table + end + + local function join_table_with_func(func, markers_table) + local pattern = func(table.unpack(markers_table[1])) + for i = 2, #markers_table do + pattern = pattern + func(table.unpack(markers_table[i])) + end + return pattern + end + + local lowercase_letter_marker = R("az") + local uppercase_letter_marker = R("AZ") + + local roman_marker = function(chars) + local m, d, c = P(chars[1]), P(chars[2]), P(chars[3]) + local l, x, v, i = P(chars[4]), P(chars[5]), P(chars[6]), P(chars[7]) + return m^-3 + * (c*m + c*d + d^-1 * c^-3) + * (x*c + x*l + l^-1 * x^-3) + * (i*x + i*v + v^-1 * i^-3) + end + + local lowercase_roman_marker = roman_marker({"m", "d", "c", "l", "x", "v", "i"}) + local uppercase_roman_marker = roman_marker({"M", "D", "C", "L", "X", "V", "I"}) + + local lowercase_opening_roman_marker = P("i") + local uppercase_opening_roman_marker = P("I") + + local digit_marker = parsers.dig * parsers.dig^-8 - local NestedList = Cs((parsers.optionallyindentedline - - starter)^1) - / function(a) return "\001"..a end + local markers = { + {lowercase_opening_roman_marker, lowercase_roman_marker}, + {uppercase_opening_roman_marker, uppercase_roman_marker}, + lowercase_letter_marker, + uppercase_letter_marker, + lowercase_roman_marker, + uppercase_roman_marker, + digit_marker + } + + local delims = { + parsers.period, + parsers.rparent + } + + local markers_table = combine_markers_and_delims(markers, delims) - local ListBlockLine = parsers.optionallyindentedline - - parsers.blankline - (parsers.indent^-1 - * starter) + local function enumerator(start_marker, _, delimiter_type, interrupting) + local delimiter_range + local allowed_end + if interrupting then + delimiter_range = P("1") + allowed_end = C(parsers.spacechar^1) * #parsers.linechar + else + delimiter_range = start_marker + allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof) + end - local ListBlock = parsers.line * ListBlockLine^0 + return parsers.check_trail + * Ct(C(delimiter_range) * C(delimiter_type)) + * allowed_end + end - local ListContinuationBlock = parsers.blanklines * (parsers.indent / "") - * ListBlock + local starter = join_table_with_func(enumerator, markers_table) local TightListItem = function(starter) - return -parsers.ThematicBreak - * (Cs(starter / "" * parsers.tickbox^-1 * ListBlock * NestedList^-1) - / self.parser_functions.parse_blocks_nested) - * -(parsers.blanklines * parsers.indent) + return parsers.add_indent(starter, "li") + * parsers.indented_content_tight end local LooseListItem = function(starter) - return -parsers.ThematicBreak - * Cs( starter / "" * parsers.tickbox^-1 * ListBlock * Cc("\n") - * (NestedList + ListContinuationBlock^0) - * (parsers.blanklines / "\n\n") - ) / self.parser_functions.parse_blocks_nested + return parsers.add_indent(starter, "li") + * parsers.indented_content_loose + * remove_indent("li") end local function roman2number(roman) - local romans = { ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 } + local romans = { ["M"] = 1000, ["D"] = 500, ["C"] = 100, ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 } local numeral = 0 local i = 1 @@ -4604,8 +6725,7 @@ M.extensions.fancy_lists = function() return numeral end - local function sniffstyle(itemprefix) - local numstr, delimend = itemprefix:match("^([A-Za-z0-9]*)([.)]*)") + local function sniffstyle(numstr, delimend) local numdelim if delimend == ")" then numdelim = "OneParen" @@ -4614,46 +6734,72 @@ M.extensions.fancy_lists = function() else numdelim = "Default" end - numstr = numstr or itemprefix local num - num = numstr:match("^([IVXL]+)") + num = numstr:match("^([I])$") if num then return roman2number(num), "UpperRoman", numdelim end - num = numstr:match("^([ivxl]+)") + num = numstr:match("^([i])$") if num then return roman2number(string.upper(num)), "LowerRoman", numdelim end - num = numstr:match("^([A-Z])") + num = numstr:match("^([A-Z])$") if num then return string.byte(num) - string.byte("A") + 1, "UpperAlpha", numdelim end - num = numstr:match("^([a-z])") + num = numstr:match("^([a-z])$") if num then return string.byte(num) - string.byte("a") + 1, "LowerAlpha", numdelim end + num = numstr:match("^([IVXLCDM]+)") + if num then + return roman2number(num), "UpperRoman", numdelim + end + num = numstr:match("^([ivxlcdm]+)") + if num then + return roman2number(string.upper(num)), "LowerRoman", numdelim + end return math.floor(tonumber(numstr) or 1), "Decimal", numdelim end local function fancylist(items,tight,start) - local startnum, numstyle, numdelim = sniffstyle(start) + local startnum, numstyle, numdelim = sniffstyle(start[2][1], start[2][2]) return writer.fancylist(items,tight, - options.startNumber and startnum, + options.startNumber and startnum or 1, numstyle or "Decimal", numdelim or "Default") end - local FancyList = Cg(enumerator, "listtype") * - ( Ct(TightListItem(Cb("listtype")) - * TightListItem(enumerator)^0) - * Cc(true) * parsers.skipblanklines * -enumerator - + Ct(LooseListItem(Cb("listtype")) - * LooseListItem(enumerator)^0) - * Cc(false) * parsers.skipblanklines - ) * Cb("listtype") / fancylist + local FancyListOfType = function(start_marker, continuation_marker, delimiter_type) + local enumerator_start = enumerator(start_marker, continuation_marker, delimiter_type) + local enumerator_cont = enumerator(continuation_marker, continuation_marker, delimiter_type) + return Cg(enumerator_start, "listtype") + * (Ct( TightListItem(Cb("listtype")) + * ((parsers.check_minimal_indent / "") * TightListItem(enumerator_cont))^0) + * Cc(true) + * -#((parsers.conditionally_indented_blankline^0 / "") + * parsers.check_minimal_indent * enumerator_cont) + + Ct( LooseListItem(Cb("listtype")) + * ((parsers.conditionally_indented_blankline^0 / "") + * (parsers.check_minimal_indent / "") * LooseListItem(enumerator_cont))^0) + * Cc(false) + ) * Ct(Cb("listtype")) / fancylist + end + + local FancyList = join_table_with_func(FancyListOfType, markers_table) + + local Endline = parsers.newline + * (parsers.check_minimal_indent + * -parsers.EndlineExceptions + + parsers.check_optional_indent + * -parsers.EndlineExceptions + * -starter) + * parsers.spacechar^0 + / writer.soft_line_break self.update_rule("OrderedList", FancyList) + self.update_rule("Endline", Endline) end } end @@ -4675,7 +6821,7 @@ M.extensions.fenced_code = function(blank_before_code_fence, end local name = util.cache_verbatim(options.cacheDir, s) table.insert(buf, {"\\markdownRendererInputFencedCode{", - name,"}{",self.string(i),"}"}) + name,"}{",self.string(i),"}{",self.infostring(i),"}"}) if attr ~= nil then table.insert(buf, "\\markdownRendererFencedCodeAttributeContextEnd") end @@ -4699,18 +6845,52 @@ M.extensions.fenced_code = function(blank_before_code_fence, return #a >= #b and i end - local tilde_infostring - = C((parsers.linechar - - (parsers.spacechar^1 * parsers.newline))^0) + local function strip_enclosing_whitespaces(str) + return str:gsub("^%s*(.-)%s*$", "%1") + end + + local tilde_infostring = Cs(Cs((V("HtmlEntity") + + parsers.anyescaped + - parsers.newline)^0) + / strip_enclosing_whitespaces) - local backtick_infostring - = C((parsers.linechar - - (parsers.backtick - + parsers.spacechar^1 * parsers.newline))^0) + local backtick_infostring = Cs(Cs((V("HtmlEntity") + + (-#(parsers.backslash * parsers.backtick) * parsers.anyescaped) + - parsers.newline + - parsers.backtick)^0) + / strip_enclosing_whitespaces) local fenceindent + + local function has_trail(indent_table) + return indent_table ~= nil and + indent_table.trail ~= nil and + next(indent_table.trail) ~= nil + end + + local function has_indents(indent_table) + return indent_table ~= nil and + indent_table.indents ~= nil and + next(indent_table.indents) ~= nil + end + + local function get_last_indent_name(indent_table) + if has_indents(indent_table) then + return indent_table.indents[#indent_table.indents].name + end + end + + local function count_fenced_start_indent(_, _, indent_table, trail) + local last_indent_name = get_last_indent_name(indent_table) + fenceindent = 0 + if last_indent_name ~= "li" then + fenceindent = #trail + end + return true + end + local fencehead = function(char, infostring) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end + return Cmt(Cb("indent_info") * parsers.check_trail, count_fenced_start_indent) * Cg(char^3, "fencelength") * parsers.optionalspace * infostring @@ -4718,52 +6898,69 @@ M.extensions.fenced_code = function(blank_before_code_fence, end local fencetail = function(char) - return parsers.nonindentspace + return parsers.check_trail_no_rem * 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 + local function process_fenced_line(s, i, indent_table, line_content, is_blank) -- luacheck: ignore s i + local remainder = "" + if has_trail(indent_table) then + remainder = indent_table.trail.internal_remainder + end + + if is_blank and get_last_indent_name(indent_table) == "li" then + remainder = "" + end + + local str = remainder .. line_content + local index = 1 + local remaining = fenceindent + + while true do + local c = str:sub(index, index) + if c == " " and remaining > 0 then + remaining = remaining - 1 + index = index + 1 + elseif c == "\t" and remaining > 3 then + remaining = remaining - 4 + index = index + 1 + else + break + end + end + + return true, str:sub(index) + end + + local fencedline = function(char) + return Cmt(Cb("indent_info") * C(parsers.line - fencetail(char)) * Cc(false), process_fenced_line) end + local blankfencedline = Cmt(Cb("indent_info") * C(parsers.blankline) * Cc(true), process_fenced_line) + local TildeFencedCode = fencehead(parsers.tilde, tilde_infostring) - * Cs(fencedline(parsers.tilde)^0) - * fencetail(parsers.tilde) + * Cs(((parsers.check_minimal_blank_indent / "") * blankfencedline + + (parsers.check_minimal_indent / "") * fencedline(parsers.tilde))^0) + * ((parsers.check_minimal_indent / "") * fencetail(parsers.tilde) + parsers.succeed) local BacktickFencedCode = fencehead(parsers.backtick, backtick_infostring) - * Cs(fencedline(parsers.backtick)^0) - * fencetail(parsers.backtick) + * Cs(((parsers.check_minimal_blank_indent / "") * blankfencedline + + (parsers.check_minimal_indent / "") * fencedline(parsers.backtick))^0) + * ((parsers.check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed) - local infostring_with_attributes - = Ct(C((parsers.linechar - - ( parsers.optionalspace - * parsers.attributes))^0) - * parsers.optionalspace - * Ct(parsers.attributes)) + local infostring_with_attributes + = Ct(C((parsers.linechar + - ( parsers.optionalspace + * parsers.attributes))^0) + * parsers.optionalspace + * Ct(parsers.attributes)) local FencedCode - = (TildeFencedCode + BacktickFencedCode) + = ((TildeFencedCode + BacktickFencedCode) / function(infostring, code) local expanded_code = self.expandtabs(code) @@ -4784,7 +6981,7 @@ M.extensions.fenced_code = function(blank_before_code_fence, end end return writer.fencedCode(expanded_code, infostring, attr) - end + end) self.insert_pattern("Block after Verbatim", FencedCode, "FencedCode") @@ -4816,7 +7013,7 @@ M.extensions.fenced_divs = function(blank_before_div_fence) function self.div_begin(attributes) local start_output = {"\\markdownRendererFencedDivAttributeContextBegin\n", self.attributes(attributes)} - local end_output = {"\n\\markdownRendererFencedDivAttributeContextEnd "} + local end_output = {"\\markdownRendererFencedDivAttributeContextEnd "} return self.push_attributes("div", attributes, start_output, end_output) end function self.div_end() @@ -4856,6 +7053,31 @@ M.extensions.fenced_divs = function(blank_before_div_fence) , "div_level") end + local non_fenced_div_block = parsers.check_minimal_indent * V("Block") + - parsers.check_minimal_indent_and_trail * fenced_div_end + + local non_fenced_div_paragraph = parsers.check_minimal_indent * V("Paragraph") + - parsers.check_minimal_indent_and_trail * fenced_div_end + + local blank = parsers.minimally_indented_blank + + local block_separated = parsers.block_sep_group(blank) + * non_fenced_div_block + + local loop_body_pair = parsers.create_loop_body_pair(block_separated, + non_fenced_div_paragraph, + parsers.block_sep_group(blank), + parsers.par_sep_group(blank)) + + local content_loop = ( non_fenced_div_block + * loop_body_pair.block^0 + + non_fenced_div_paragraph + * block_separated + * loop_body_pair.block^0 + + non_fenced_div_paragraph + * loop_body_pair.par^0) + * blank^0 + local FencedDiv = fenced_div_begin / function (infostring) local attr = lpeg.match(Ct(parsers.attributes), infostring) @@ -4867,14 +7089,9 @@ M.extensions.fenced_divs = function(blank_before_div_fence) / writer.div_begin * increment_div_level(1) * parsers.skipblanklines - * Ct( (V("Block") - fenced_div_end)^-1 - * ( parsers.blanklines - / function() - return writer.interblocksep - end - * (V("Block") - fenced_div_end))^0) - * parsers.skipblanklines - * fenced_div_end * increment_div_level(-1) + * Ct(content_loop) + * parsers.minimally_indented_blank^0 + * parsers.check_minimal_indent_and_trail * fenced_div_end * increment_div_level(-1) * (Cc("") / writer.div_end) self.insert_pattern("Block after Verbatim", @@ -4890,13 +7107,6 @@ M.extensions.fenced_divs = function(blank_before_div_fence) 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) - if not blank_before_div_fence then self.update_rule("EndlineExceptions", function(previous_pattern) if previous_pattern == nil then @@ -4916,47 +7126,58 @@ M.extensions.header_attributes = function() local parsers = self.parsers local writer = self.writer + local function strip_atx_end(s) + return s:gsub("%s+#*%s*$","") + end + local AtxHeading = Cg(parsers.heading_start, "level") * parsers.optionalspace * (C(((parsers.linechar - - ((parsers.hash^1 + - (parsers.attributes * parsers.optionalspace - * parsers.attributes^-1 - + parsers.attributes) - * parsers.optionalspace - * parsers.newline)) - * (parsers.linechar - - parsers.hash - - parsers.lbrace)^0)^1) - / self.parser_functions.parse_inlines) + * parsers.newline)) + * (parsers.linechar + - parsers.lbrace)^0)^1) + / strip_atx_end + / parsers.parse_heading_text) * Cg(Ct(parsers.newline - + (parsers.hash^1 + + (parsers.attributes * parsers.optionalspace - * parsers.attributes^-1 - + parsers.attributes) - * parsers.optionalspace - * parsers.newline), "attributes") + * parsers.newline)), "attributes") * Cb("level") * Cb("attributes") / writer.heading - local SetextHeading = #(parsers.line * S("=-")) - * (C(((parsers.linechar - - (parsers.attributes - * parsers.optionalspace - * parsers.newline)) - * (parsers.linechar - - parsers.lbrace)^0)^1) - / self.parser_functions.parse_inlines) - * Cg(Ct(parsers.newline - + (parsers.attributes - * parsers.optionalspace - * parsers.newline)), "attributes") - * parsers.heading_level - * Cb("attributes") - * parsers.optionalspace - * parsers.newline - / writer.heading + local function strip_trailing_spaces(s) + return s:gsub("%s*$","") + end + + local heading_line = (parsers.linechar + - (parsers.attributes + * parsers.optionalspace + * parsers.newline))^1 + - parsers.thematic_break_lines + + local heading_text = heading_line + * ((V("Endline") / "\n") * (heading_line - parsers.heading_level))^0 + * parsers.newline^-1 + + local SetextHeading = parsers.freeze_trail * parsers.check_trail_no_rem + * #(heading_text + * (parsers.attributes + * parsers.optionalspace + * parsers.newline)^-1 + * parsers.check_minimal_indent * parsers.check_trail * parsers.heading_level) + * Cs(heading_text) / strip_trailing_spaces + / parsers.parse_heading_text + * Cg(Ct((parsers.attributes + * parsers.optionalspace + * parsers.newline)^-1), "attributes") + * parsers.check_minimal_indent_and_trail * parsers.heading_level + * Cb("attributes") + * parsers.newline + * parsers.unfreeze_trail + / writer.heading local Heading = AtxHeading + SetextHeading self.update_rule("Heading", Heading) @@ -5018,95 +7239,55 @@ M.extensions.line_blocks = function() end } end +M.extensions.mark = function() + return { + name = "built-in mark syntax extension", + extend_writer = function(self) + function self.mark(s) + if self.flatten_inlines then return s end + return {"\\markdownRendererMark{", s, "}"} + end + end, extend_reader = function(self) + local parsers = self.parsers + local writer = self.writer + + local doubleequals = P("==") + + local Mark = parsers.between(V("Inline"), doubleequals, doubleequals) + / function (inlines) return writer.mark(inlines) end + + self.add_special_character("=") + self.insert_pattern("Inline before LinkAndEmph", + Mark, "Mark") + end + } +end M.extensions.link_attributes = function() return { name = "built-in link_attributes syntax extension", extend_writer = function() end, extend_reader = function(self) local parsers = self.parsers - local writer = self.writer local options = self.options - - local define_reference_parser = parsers.define_reference_parser - * ( parsers.spnl - * Ct(parsers.attributes))^-1 + local define_reference_parser = (parsers.check_trail / "") * parsers.link_label * parsers.colon + * parsers.spnlc * parsers.url + * ( parsers.spnlc_sep * parsers.title * (parsers.spnlc * Ct(parsers.attributes)) + * parsers.only_blank + + parsers.spnlc_sep * parsers.title * parsers.only_blank + + Cc("") * (parsers.spnlc * Ct(parsers.attributes)) * parsers.only_blank + + Cc("") * parsers.only_blank) local ReferenceWithAttributes = define_reference_parser - * parsers.blankline^1 / self.register_link self.update_rule("Reference", ReferenceWithAttributes) - local function indirect_link(label, sps, tag, - attribute_text, - attributes) - return writer.defer_call(function() - local r, fallback = self.lookup_reference(label, sps, tag, - attributes) - if r then - return writer.link( - self.parser_functions.parse_inlines_no_link(label), - r.url, r.title, r.attributes) - else - local buf = {fallback} - if attributes then - table.insert(buf, writer.string(attribute_text)) - end - return buf - end - end) - end - - local DirectLinkWithAttributes = parsers.direct_link - * (Ct(parsers.attributes))^-1 - / writer.link - - local IndirectLinkWithAttributes = parsers.indirect_link - * (C(Ct(parsers.attributes)))^-1 - / indirect_link - - local LinkWithAttributes = DirectLinkWithAttributes - + IndirectLinkWithAttributes - - self.update_rule("Link", LinkWithAttributes) - - - local function indirect_image(label, sps, tag, - attribute_text, - attributes) - return writer.defer_call(function() - local r, fallback = self.lookup_reference(label, sps, tag, - attributes) - if r then - return writer.image(writer.string(label), - r.url, r.title, r.attributes) - else - local buf = {"!", fallback} - if attributes then - table.insert(buf, writer.string(attribute_text)) - end - return buf - end - end) - end - - local DirectImageWithAttributes = parsers.direct_image - * Ct(parsers.attributes) - / writer.image - - local IndirectImageWithAttributes = parsers.indirect_image - * C(Ct(parsers.attributes)) - / indirect_image - - local ImageWithAttributes = DirectImageWithAttributes - + IndirectImageWithAttributes - - self.insert_pattern("Inline before Image", - ImageWithAttributes, - "ImageWithAttributes") + local LinkWithAttributesAndEmph = Ct(parsers.link_and_emph_table * Cg(Cc(true), "match_link_attributes")) + / self.defer_link_and_emphasis_processing + self.update_rule("LinkAndEmph", LinkWithAttributesAndEmph) local AutoLinkUrlWithAttributes = parsers.auto_link_url @@ -5149,6 +7330,7 @@ M.extensions.notes = function(notes, inline_notes) name = "built-in notes syntax extension", extend_writer = function(self) function self.note(s) + if self.flatten_inlines then return "" end return {"\\markdownRendererNote{",s,"}"} end end, extend_reader = function(self) @@ -5158,10 +7340,10 @@ M.extensions.notes = function(notes, inline_notes) if inline_notes then local InlineNote = parsers.circumflex - * (parsers.tag / self.parser_functions.parse_inlines_no_inline_note) + * (parsers.link_label / self.parser_functions.parse_inlines_no_inline_note) / writer.note - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline after LinkAndEmph", InlineNote, "InlineNote") end if notes then @@ -5171,7 +7353,7 @@ M.extensions.notes = function(notes, inline_notes) local RawNoteRef = #(parsers.lbracket * parsers.circumflex) - * parsers.tag / strip_first_char + * parsers.link_label / strip_first_char local rawnotes = {} @@ -5190,21 +7372,36 @@ M.extensions.notes = function(notes, inline_notes) end local function register_note(ref,rawnote) - rawnotes[self.normalize_tag(ref)] = rawnote + local normalized_tag = self.normalize_tag(ref) + if rawnotes[normalized_tag] == nil then + rawnotes[normalized_tag] = rawnote + end return "" end local NoteRef = RawNoteRef / lookup_note + local optionally_indented_line = parsers.check_optional_indent_and_any_trail * parsers.line + + local blank = parsers.check_optional_blank_indent_and_any_trail * parsers.optionalspace * parsers.newline + + local chunk = Cs(parsers.line * (optionally_indented_line - blank)^0) + + local indented_blocks = function(bl) + return Cs( bl + * (blank^1 * (parsers.check_optional_indent / "") + * parsers.check_code_trail * -parsers.blankline * bl)^0) + end + local NoteBlock - = parsers.leader * RawNoteRef * parsers.colon - * parsers.spnl * parsers.indented_blocks(parsers.chunk) + = parsers.check_trail_no_rem * RawNoteRef * parsers.colon + * parsers.spnlc * indented_blocks(chunk) / register_note - local Blank = NoteBlock + parsers.Blank - self.update_rule("Blank", Blank) + local Reference = NoteBlock + parsers.Reference - self.insert_pattern("Inline after Emph", + self.update_rule("Reference", Reference) + self.insert_pattern("Inline before LinkAndEmph", NoteRef, "NoteRef") end @@ -5212,7 +7409,7 @@ M.extensions.notes = function(notes, inline_notes) end } end -M.extensions.pipe_tables = function(table_captions) +M.extensions.pipe_tables = function(table_captions, table_attributes) local function make_pipe_table_rectangular(rows) local num_columns = #rows[2] @@ -5270,10 +7467,18 @@ M.extensions.pipe_tables = function(table_captions) return { name = "built-in pipe_tables syntax extension", extend_writer = function(self) - function self.table(rows, caption) + function self.table(rows, caption, attributes) if not self.is_writing then return "" end - local buffer = {"\\markdownRendererTable{", - caption or "", "}{", #rows - 1, "}{", #rows[1], "}"} + local buffer = {} + if attributes ~= nil then + table.insert(buffer, + "\\markdownRendererTableAttributeContextBegin\n") + table.insert(buffer, self.attributes(attributes)) + end + table.insert(buffer, + {"\\markdownRendererTable{", + caption or "", "}{", #rows - 1, "}{", + #rows[1], "}"}) local temp = rows[2] -- put alignments on the first row rows[2] = rows[1] rows[1] = temp @@ -5290,6 +7495,10 @@ M.extensions.pipe_tables = function(table_captions) end table.insert(buffer, "}") end + if attributes ~= nil then + table.insert(buffer, + "\\markdownRendererTableAttributeContextEnd{}") + end return buffer end end, extend_reader = function(self) @@ -5319,31 +7528,65 @@ M.extensions.pipe_tables = function(table_captions) , table_hline_separator , table_hline_column) - local table_caption_beginning = parsers.skipblanklines - * parsers.nonindentspace + local table_caption_beginning = (parsers.check_minimal_blank_indent_and_any_trail_no_rem + * parsers.optionalspace * parsers.newline)^0 + * parsers.check_minimal_indent_and_trail * (P("Table")^-1 * parsers.colon) * parsers.optionalspace + local function strip_trailing_spaces(s) + return s:gsub("%s*$","") + end + local table_row = pipe_table_row(true , (C((parsers.linechar - parsers.pipe)^1) + / strip_trailing_spaces / self.parser_functions.parse_inlines) , parsers.pipe , (C((parsers.linechar - parsers.pipe)^0) + / strip_trailing_spaces / self.parser_functions.parse_inlines)) local table_caption if table_captions then table_caption = #table_caption_beginning * table_caption_beginning - * Ct(parsers.IndentedInline^1) - * parsers.newline + if table_attributes then + table_caption = table_caption + * (C(((( parsers.linechar + - (parsers.attributes + * parsers.optionalspace + * parsers.newline + * -#( parsers.optionalspace + * parsers.linechar))) + + ( parsers.newline + * #( parsers.optionalspace + * parsers.linechar) + * C(parsers.optionalspace) / writer.space)) + * (parsers.linechar + - parsers.lbrace)^0)^1) + / self.parser_functions.parse_inlines) + * (parsers.newline + + ( Ct(parsers.attributes) + * parsers.optionalspace + * parsers.newline)) + else + table_caption = table_caption + * C(( parsers.linechar + + ( parsers.newline + * #( parsers.optionalspace + * parsers.linechar) + * C(parsers.optionalspace) / writer.space))^1) + / self.parser_functions.parse_inlines + * parsers.newline + end else table_caption = parsers.fail end - local PipeTable = Ct(table_row * parsers.newline - * table_hline - * (parsers.newline * table_row)^0) + local PipeTable = Ct(table_row * parsers.newline * (parsers.check_minimal_indent_and_trail / {}) + * table_hline * parsers.newline + * ((parsers.check_minimal_indent / {}) * table_row * parsers.newline)^0) / make_pipe_table_rectangular * table_caption^-1 / writer.table @@ -5361,6 +7604,7 @@ M.extensions.raw_inline = function() function self.rawInline(s, attr) if not self.is_writing then return "" end + if self.flatten_inlines then return s end local name = util.cache_verbatim(options.cacheDir, s) return {"\\markdownRendererInputRawInline{", name,"}{", self.string(attr),"}"} @@ -5382,6 +7626,7 @@ M.extensions.strike_through = function() name = "built-in strike_through syntax extension", extend_writer = function(self) function self.strike_through(s) + if self.flatten_inlines then return s end return {"\\markdownRendererStrikeThrough{",s,"}"} end end, extend_reader = function(self) @@ -5393,7 +7638,7 @@ M.extensions.strike_through = function() parsers.doubletildes) ) / writer.strike_through - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline after LinkAndEmph", StrikeThrough, "StrikeThrough") self.add_special_character("~") @@ -5405,6 +7650,7 @@ M.extensions.subscripts = function() name = "built-in subscripts syntax extension", extend_writer = function(self) function self.subscript(s) + if self.flatten_inlines then return s end return {"\\markdownRendererSubscript{",s,"}"} end end, extend_reader = function(self) @@ -5415,7 +7661,7 @@ M.extensions.subscripts = function() parsers.between(parsers.Str, parsers.tilde, parsers.tilde) ) / writer.subscript - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline after LinkAndEmph", Subscript, "Subscript") self.add_special_character("~") @@ -5427,6 +7673,7 @@ M.extensions.superscripts = function() name = "built-in superscripts syntax extension", extend_writer = function(self) function self.superscript(s) + if self.flatten_inlines then return s end return {"\\markdownRendererSuperscript{",s,"}"} end end, extend_reader = function(self) @@ -5437,7 +7684,7 @@ M.extensions.superscripts = function() parsers.between(parsers.Str, parsers.circumflex, parsers.circumflex) ) / writer.superscript - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline after LinkAndEmph", Superscript, "Superscript") self.add_special_character("^") @@ -5451,11 +7698,11 @@ M.extensions.tex_math = function(tex_math_dollars, name = "built-in tex_math syntax extension", extend_writer = function(self) function self.display_math(s) - if not self.is_writing then return "" end + if self.flatten_inlines then return s end return {"\\markdownRendererDisplayMath{",self.math(s),"}"} end function self.inline_math(s) - if not self.is_writing then return "" end + if self.flatten_inlines then return s end return {"\\markdownRendererInlineMath{",self.math(s),"}"} end end, extend_reader = function(self) @@ -5463,24 +7710,33 @@ M.extensions.tex_math = function(tex_math_dollars, local writer = self.writer local function between(p, starter, ender) - return (starter * C(p * (p - ender)^0) * ender) + return (starter * Cs(p * (p - ender)^0) * ender) + end + + local function strip_preceding_whitespaces(str) + return str:gsub("^%s*(.-)$", "%1") end local allowed_before_closing = B( parsers.backslash * parsers.any - + parsers.any * (parsers.nonspacechar - parsers.backslash)) - local dollar_math_content = parsers.backslash^-1 - * parsers.any + + parsers.any * (parsers.any - parsers.backslash)) + + local allowed_before_closing_no_space = B( parsers.backslash * parsers.any + + parsers.any * (parsers.nonspacechar - parsers.backslash)) + + local dollar_math_content = (parsers.newline * (parsers.check_optional_indent / "") + + parsers.backslash^-1 + * parsers.linechar) - parsers.blankline^2 - parsers.dollar local inline_math_opening_dollars = parsers.dollar * #(parsers.nonspacechar) - local inline_math_closing_dollars = allowed_before_closing + local inline_math_closing_dollars = allowed_before_closing_no_space * parsers.dollar * -#(parsers.digit) - local inline_math_dollars = between(C( dollar_math_content), + local inline_math_dollars = between(Cs( dollar_math_content), inline_math_opening_dollars, inline_math_closing_dollars) @@ -5490,59 +7746,66 @@ M.extensions.tex_math = function(tex_math_dollars, local display_math_closing_dollars = parsers.dollar * parsers.dollar - local display_math_dollars = between(C( dollar_math_content), + local display_math_dollars = between(Cs( dollar_math_content), display_math_opening_dollars, display_math_closing_dollars) - local backslash_math_content = parsers.any + local backslash_math_content = (parsers.newline * (parsers.check_optional_indent / "") + + parsers.linechar) - parsers.blankline^2 local inline_math_opening_double = parsers.backslash * parsers.backslash * parsers.lparent - * #(parsers.nonspacechar) local inline_math_closing_double = allowed_before_closing + * parsers.spacechar^0 * parsers.backslash * parsers.backslash * parsers.rparent - local inline_math_double = between(C( backslash_math_content), + local inline_math_double = between(Cs( backslash_math_content), inline_math_opening_double, inline_math_closing_double) + / strip_preceding_whitespaces local display_math_opening_double = parsers.backslash * parsers.backslash * parsers.lbracket local display_math_closing_double = allowed_before_closing + * parsers.spacechar^0 * parsers.backslash * parsers.backslash * parsers.rbracket - local display_math_double = between(C( backslash_math_content), + local display_math_double = between(Cs( backslash_math_content), display_math_opening_double, display_math_closing_double) + / strip_preceding_whitespaces local inline_math_opening_single = parsers.backslash * parsers.lparent - * #(parsers.nonspacechar) local inline_math_closing_single = allowed_before_closing + * parsers.spacechar^0 * parsers.backslash * parsers.rparent - local inline_math_single = between(C( backslash_math_content), + local inline_math_single = between(Cs( backslash_math_content), inline_math_opening_single, inline_math_closing_single) + / strip_preceding_whitespaces local display_math_opening_single = parsers.backslash * parsers.lbracket local display_math_closing_single = allowed_before_closing + * parsers.spacechar^0 * parsers.backslash * parsers.rbracket - local display_math_single = between(C( backslash_math_content), + local display_math_single = between(Cs( backslash_math_content), display_math_opening_single, display_math_closing_single) + / strip_preceding_whitespaces local display_math = parsers.fail @@ -5566,7 +7829,7 @@ M.extensions.tex_math = function(tex_math_dollars, local TexMath = display_math / writer.display_math + inline_math / writer.inline_math - self.insert_pattern("Inline after Emph", + self.insert_pattern("Inline after LinkAndEmph", TexMath, "TexMath") if tex_math_dollars then @@ -5719,6 +7982,21 @@ function M.new(options) options = options or {} setmetatable(options, { __index = function (_, key) return defaultOptions[key] end }) + if options.singletonCache and singletonCache.convert then + for k, v in pairs(defaultOptions) do + if type(v) == "table" then + for i = 1, math.max(#singletonCache.options[k], #options[k]) do + if singletonCache.options[k][i] ~= options[k][i] then + goto miss + end + end + elseif singletonCache.options[k] ~= options[k] then + goto miss + end + end + return singletonCache.convert + end + ::miss:: local extensions = {} if options.bracketedSpans then @@ -5780,9 +8058,14 @@ function M.new(options) table.insert(extensions, line_block_extension) end + if options.mark then + local mark_extension = M.extensions.mark() + table.insert(extensions, mark_extension) + end + if options.pipeTables then local pipe_tables_extension = M.extensions.pipe_tables( - options.tableCaptions) + options.tableCaptions, options.tableAttributes) table.insert(extensions, pipe_tables_extension) end @@ -5816,11 +8099,9 @@ function M.new(options) table.insert(extensions, tex_math_extension) end - if options.footnotes or options.inlineFootnotes or - options.notes or options.inlineNotes then + if options.notes or options.inlineNotes then local notes_extension = M.extensions.notes( - options.footnotes or options.notes, - options.inlineFootnotes or options.inlineNotes) + options.notes, options.inlineNotes) table.insert(extensions, notes_extension) end @@ -5901,7 +8182,18 @@ function M.new(options) local writer = M.writer.new(options) local reader = M.reader.new(writer, options) local convert = reader.finalize_grammar(extensions) - + collectgarbage("collect") + if options.singletonCache then + local singletonCacheOptions = {} + for k, v in pairs(options) do + singletonCacheOptions[k] = v + end + setmetatable(singletonCacheOptions, + { __index = function (_, key) + return defaultOptions[key] end }) + singletonCache.options = singletonCacheOptions + singletonCache.convert = convert + end return convert end -- cgit v1.2.3