From f2480abba29536f2937cc0fded7bacbd58c93e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Thu, 9 Mar 2023 14:29:48 +0100 Subject: [PATCH 01/22] update headings in unit tests --- tests/testfiles/CommonMark_0.30/block_quotes/001.test | 2 ++ tests/testfiles/CommonMark_0.30/block_quotes/002.test | 2 ++ tests/testfiles/CommonMark_0.30/block_quotes/003.test | 2 ++ tests/testfiles/CommonMark_0.30/block_quotes/005.test | 2 ++ 4 files changed, 8 insertions(+) diff --git a/tests/testfiles/CommonMark_0.30/block_quotes/001.test b/tests/testfiles/CommonMark_0.30/block_quotes/001.test index daf962113..dc82a995c 100644 --- a/tests/testfiles/CommonMark_0.30/block_quotes/001.test +++ b/tests/testfiles/CommonMark_0.30/block_quotes/001.test @@ -15,9 +15,11 @@ >>> documentBegin blockQuoteBegin +BEGIN section headingOne: Foo interblockSeparator emphasis: bar emphasis: baz blockQuoteEnd +END section documentEnd diff --git a/tests/testfiles/CommonMark_0.30/block_quotes/002.test b/tests/testfiles/CommonMark_0.30/block_quotes/002.test index 1eb6c3f29..230fa75d0 100644 --- a/tests/testfiles/CommonMark_0.30/block_quotes/002.test +++ b/tests/testfiles/CommonMark_0.30/block_quotes/002.test @@ -15,9 +15,11 @@ >>> documentBegin blockQuoteBegin +BEGIN section headingOne: Foo interblockSeparator emphasis: bar emphasis: baz blockQuoteEnd +END section documentEnd diff --git a/tests/testfiles/CommonMark_0.30/block_quotes/003.test b/tests/testfiles/CommonMark_0.30/block_quotes/003.test index fc5616f2f..e17e1387a 100644 --- a/tests/testfiles/CommonMark_0.30/block_quotes/003.test +++ b/tests/testfiles/CommonMark_0.30/block_quotes/003.test @@ -15,9 +15,11 @@ >>> documentBegin blockQuoteBegin +BEGIN section headingOne: Foo interblockSeparator emphasis: bar emphasis: baz blockQuoteEnd +END section documentEnd diff --git a/tests/testfiles/CommonMark_0.30/block_quotes/005.test b/tests/testfiles/CommonMark_0.30/block_quotes/005.test index 2f8390b26..284ca1a0a 100644 --- a/tests/testfiles/CommonMark_0.30/block_quotes/005.test +++ b/tests/testfiles/CommonMark_0.30/block_quotes/005.test @@ -15,9 +15,11 @@ >>> documentBegin blockQuoteBegin +BEGIN section headingOne: Foo interblockSeparator emphasis: bar emphasis: baz blockQuoteEnd +END section documentEnd From c59cdc4a2d479d60314e885fa973d4ca1b91fb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Thu, 9 Mar 2023 14:37:25 +0100 Subject: [PATCH 02/22] add indent propagation to blockquotes --- markdown.dtx | 201 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 170 insertions(+), 31 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 7b864df9b..a2f758216 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -22180,7 +22180,6 @@ function M.writer.new(options) % \end{markdown} % \begin{macrocode} function self.blockquote(s) - if #util.rope_to_string(s) == 0 then return "" end return {"\\markdownRendererBlockQuoteBegin\n",s, "\n\\markdownRendererBlockQuoteEnd "} end @@ -23303,15 +23302,154 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - -- 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.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 + + ------------------- + -- indent format -- + ------------------- + + parsers.indent_value = Ct(C(parsers.letter^1) * C(parsers.digit^1)) + + parsers.indent_rope = parsers.indent_value * (parsers.comma * parsers.space * parsers.indent_value)^0 + + local function increment_indent_level(indent_type, increment) + local function update_indent_level(s, i, current_indent) + + local indent_table = lpeg.match(Ct(parsers.indent_rope), current_indent) + + if indent_table == nil then + indent_table = {} + indent_table[#indent_table + 1] = {indent_type, increment} + else + local last_indent = indent_table[#indent_table] + local last_indent_type = last_indent[1] + local last_indent_value = last_indent[2] + + if last_indent_type == indent_type then + indent_table[#indent_table][2] = math.floor(last_indent_value + increment) + else + indent_table[#indent_table + 1] = {indent_type, increment} + end + end + + local joined_values = {} + for _, value in ipairs(indent_table) do + if value[2] > 0 then + joined_values[#joined_values + 1] = value[1] .. value[2] + end + end + + local new_indent_table = table.concat(joined_values, ", ") + return true, new_indent_table + end + + return Cg( Cmt(Cb("relative_indent"), update_indent_level) + , "relative_indent") + end + + ------------------------------- + -- process indent in general -- + ------------------------------- + + -- decodes pattern name from pair to its pattern + local function decode_pattern(name) + if name == "bq" then + return parsers.blockquote_start + end + return parsers.succeed + end + + -- applies decoded pattern + local function traverse_indent(s, i, current_indent, is_optional) + local indent_table = lpeg.match(Ct(parsers.indent_rope), current_indent) + + if indent_table == nil then + return true, i + end + + local new_index = i + + for _, value in ipairs(indent_table) do + local pattern = decode_pattern(value[1]) + local cond_pattern = pattern; + if is_optional then + cond_pattern = pattern^-1 + end + + for j = 1,value[2] do + local possible_next_index = lpeg.match(cond_pattern, s, new_index) + if (possible_next_index ~= nil) then + new_index = possible_next_index + else + if is_optional then + return true, new_index + end + return false, i + end + end + end + + return true, new_index + end + + -- skip only all indent + local function produce_minimal_indent(s, i, current_indent) + + local passes, new_index = traverse_indent(s, i, current_indent, false) + + if passes then + return new_index, "" + end + return false + end + + -- skip maximum of indent + local function produce_optional_indent(s, i, current_indent) + local indent = parsers.succeed + + local passes, new_index = traverse_indent(s, i, current_indent, true) + + if passes then + return new_index, "" + end + return false + end + + -- check required - block continuation line + check_minimal_indent = Cmt(Cb("relative_indent"), produce_minimal_indent) + + -- check optional indent - paragraph continuation + check_optional_indent = Cmt(Cb("relative_indent"), produce_optional_indent) + + parsers.minimally_indented_blank = check_minimal_indent * V("Blank") + + parsers.minimally_indented_block = check_minimal_indent * V("Block") + + parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep + * V("Block") + + parsers.blockquote_body = parsers.blockquote_start + * increment_indent_level("bq", 1) + * (Ct( + V("Blank") + * parsers.minimally_indented_blank^0 + * parsers.minimally_indented_block + * ( parsers.minimally_indented_blank + + parsers.minimally_indented_separated_block)^0 + + V("Blank") + * parsers.minimally_indented_blank^0 + + V("Block") + * ( parsers.minimally_indented_blank + + parsers.minimally_indented_separated_block)^0 + ) + ) + * increment_indent_level("bq", -1) + + -- disabled temporarily if not options.breakableBlockquotes then - parsers.blockquote_body = parsers.blockquote_body - * (parsers.blankline^0 / "") +-- parsers.blockquote_body = parsers.blockquote_body +-- * (parsers.blankline^0 / "") end % \end{macrocode} % \par @@ -23423,11 +23561,11 @@ function M.reader.new(writer, options) = parsers.blankline -- paragraph break + parsers.tightblocksep -- nested list + parsers.eof -- end of document - + parsers.bqstart + + parsers.blockquote_start + parsers.headerstart parsers.Endline = parsers.newline - * -V("EndlineExceptions") + * check_optional_indent * -V("EndlineExceptions") * parsers.spacechar^0 / (options.hardLineBreaks and writer.hard_line_break or writer.space) @@ -23447,7 +23585,7 @@ function M.reader.new(writer, options) parsers.NonbreakingEndline = parsers.newline - * -V("EndlineExceptions") + * check_optional_indent * -V("EndlineExceptions") * parsers.spacechar^0 / (options.hardLineBreaks and writer.hard_line_break or writer.nbsp) @@ -23568,15 +23706,18 @@ function M.reader.new(writer, options) + 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.indented_non_blank_line = parsers.indentedline - parsers.blankline + + parsers.Verbatim = Cs( + parsers.indented_non_blank_line + * ((check_minimal_indent * parsers.blankline)^0 + * (check_minimal_indent * parsers.indented_non_blank_line)^1)^0 + ) / 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.Blockquote = parsers.blockquote_body / writer.blockquote parsers.ThematicBreak = ( parsers.lineof(parsers.asterisk) @@ -23586,11 +23727,9 @@ function M.reader.new(writer, options) parsers.Reference = parsers.define_reference_parser / register_link - parsers.Paragraph = parsers.nonindentspace * Ct(parsers.Inline^1) + parsers.Paragraph = parsers.nonindentspace * Ct((parsers.Inline)^1) * ( parsers.newline - * ( parsers.blankline^1 - + #V("EndlineExceptions") - ) + * #V("EndlineExceptions") + parsers.eof) / writer.paragraph @@ -23703,7 +23842,7 @@ function M.reader.new(writer, options) * Ct(parsers.linechar^1 / self.parser_functions.parse_inlines) * parsers.newline - * parsers.heading_level + * check_minimal_indent * parsers.heading_level * parsers.optionalspace * parsers.newline / writer.heading @@ -23852,7 +23991,7 @@ function M.reader.new(writer, options) Smart = parsers.Smart, Symbol = parsers.Symbol, SpecialChar = parsers.fail, - InitializeState = parsers.succeed, + InitializeState = parsers.succeed * Cg(Ct("") / "", "relative_indent"), --temporary initialization } % \end{macrocode} % \par @@ -25026,15 +25165,15 @@ M.extensions.fenced_code = function(blank_before_code_fence, local BacktickFencedCode = fencehead(parsers.backtick, backtick_infostring) - * Cs(fencedline(parsers.backtick)^0) - * fencetail(parsers.backtick) - - local infostring_with_attributes - = Ct(C((parsers.linechar - - ( parsers.optionalspace - * parsers.attributes))^0) - * parsers.optionalspace - * Ct(parsers.attributes)) + * Cs((check_minimal_indent * fencedline(parsers.backtick))^0) + * (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 FencedCode = (TildeFencedCode + BacktickFencedCode) From 1a01352630bdc9ed0ca907741ff09eba7b84d204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 10:28:25 +0100 Subject: [PATCH 03/22] add breakable blockquotes, formatting --- markdown.dtx | 66 ++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index a2f758216..f774f9397 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -23305,14 +23305,11 @@ function M.reader.new(writer, options) parsers.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 - ------------------- - -- indent format -- - ------------------- - parsers.indent_value = Ct(C(parsers.letter^1) * C(parsers.digit^1)) parsers.indent_rope = parsers.indent_value * (parsers.comma * parsers.space * parsers.indent_value)^0 + -- increments the indent type by a value local function increment_indent_level(indent_type, increment) local function update_indent_level(s, i, current_indent) @@ -23348,10 +23345,6 @@ function M.reader.new(writer, options) , "relative_indent") end - ------------------------------- - -- process indent in general -- - ------------------------------- - -- decodes pattern name from pair to its pattern local function decode_pattern(name) if name == "bq" then @@ -23372,13 +23365,12 @@ function M.reader.new(writer, options) for _, value in ipairs(indent_table) do local pattern = decode_pattern(value[1]) - local cond_pattern = pattern; if is_optional then - cond_pattern = pattern^-1 + pattern = pattern^-1 end for j = 1,value[2] do - local possible_next_index = lpeg.match(cond_pattern, s, new_index) + local possible_next_index = lpeg.match(pattern, s, new_index) if (possible_next_index ~= nil) then new_index = possible_next_index else @@ -23395,7 +23387,6 @@ function M.reader.new(writer, options) -- skip only all indent local function produce_minimal_indent(s, i, current_indent) - local passes, new_index = traverse_indent(s, i, current_indent, false) if passes then @@ -23406,8 +23397,6 @@ function M.reader.new(writer, options) -- skip maximum of indent local function produce_optional_indent(s, i, current_indent) - local indent = parsers.succeed - local passes, new_index = traverse_indent(s, i, current_indent, true) if passes then @@ -23416,10 +23405,10 @@ function M.reader.new(writer, options) return false end - -- check required - block continuation line + -- check required check_minimal_indent = Cmt(Cb("relative_indent"), produce_minimal_indent) - -- check optional indent - paragraph continuation + -- check optional indent check_optional_indent = Cmt(Cb("relative_indent"), produce_optional_indent) parsers.minimally_indented_blank = check_minimal_indent * V("Blank") @@ -23429,27 +23418,34 @@ function M.reader.new(writer, options) parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep * V("Block") + parsers.blockquote_content = function(breakable) + local blank = parsers.minimally_indented_blank + if breakable then + blank = blank + V("Blank") + end + + return Ct( V("Blank") + * blank^0 + * parsers.minimally_indented_block + * ( blank + + parsers.minimally_indented_separated_block)^0 + + V("Blank") + * blank^0 + + V("Block") + * ( blank + + parsers.minimally_indented_separated_block)^0) + end + parsers.blockquote_body = parsers.blockquote_start - * increment_indent_level("bq", 1) - * (Ct( - V("Blank") - * parsers.minimally_indented_blank^0 - * parsers.minimally_indented_block - * ( parsers.minimally_indented_blank - + parsers.minimally_indented_separated_block)^0 - + V("Blank") - * parsers.minimally_indented_blank^0 - + V("Block") - * ( parsers.minimally_indented_blank - + parsers.minimally_indented_separated_block)^0 - ) - ) - * increment_indent_level("bq", -1) - - -- disabled temporarily + * increment_indent_level("bq", 1) + * parsers.blockquote_content(false) + * increment_indent_level("bq", -1) + if not options.breakableBlockquotes then --- parsers.blockquote_body = parsers.blockquote_body --- * (parsers.blankline^0 / "") + parsers.blockquote_body = parsers.blockquote_start + * increment_indent_level("bq", 1) + * parsers.blockquote_content(true) + * increment_indent_level("bq", -1) end % \end{macrocode} % \par From 33303fa628a84d23869d36fec077f45c365b014c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 11:52:40 +0100 Subject: [PATCH 04/22] separate indentation from blockquote patterns --- markdown.dtx | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index f774f9397..22323fc0e 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -23272,33 +23272,7 @@ function M.reader.new(writer, options) % \par % \begin{markdown} % -%#### Parsers Used for Markdown Lists (local) -% -% \end{markdown} -% \begin{macrocode} - 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 -% \end{macrocode} -% \par -% \begin{markdown} -% -%#### Parsers Used for Blockquotes (local) +%#### Parsers Used for Indentation (local) % % \end{markdown} % \begin{macrocode} @@ -23418,6 +23392,41 @@ function M.reader.new(writer, options) parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep * V("Block") +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Markdown Lists (local) +% +% \end{markdown} +% \begin{macrocode} + 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 +% \end{macrocode} +% \par +% \begin{markdown} +% +%#### Parsers Used for Blockquotes (local) +% +% \end{markdown} +% \begin{macrocode} + parsers.blockquote_content = function(breakable) local blank = parsers.minimally_indented_blank if breakable then From 0dfeb4cf639f56b3fd16a759719d28d0e9d0a53b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 11:55:21 +0100 Subject: [PATCH 05/22] add option `blankBeforeList` --- markdown.dtx | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/markdown.dtx b/markdown.dtx index 22323fc0e..a0de9d36a 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -3649,6 +3649,224 @@ defaultOptions.blankBeforeHeading = false % %<*manual-options> +#### Option `blankBeforeList` + +`blankBeforeList` (default value: `false`) + +% \fi +% \begin{markdown} +% +% \Optitem[false]{blankBeforeList}{\opt{true}, \opt{false}} +% +: true + + : Require a blank line between a paragraph and the following list. + + false + + : Do not require a blank line between a paragraph and the following + list. + +% \end{markdown} +% \iffalse + +##### Lua Module Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\directlua{ + local markdown = require("markdown") + local newline = [[^^J^^J]] + local convert, input + + convert = markdown.new() + input = "A paragraph." .. newline .. + "- a list" .. newline + tex.sprint(convert(input)) + + convert = markdown.new({ + blankBeforeList = true}) + input = "A paragraph." .. newline .. + "- not a list" .. newline + tex.sprint(convert(input)) } +\bye +``````` +Then, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +``````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> - a list +> +> A paragraph. - not a list + +##### Lua CLI Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +``` tex +\input markdown +\input lmfonts +\input optionfalse +\input optiontrue +\bye +``````` +Using a text editor, create a text document named `content.md` with the +following content: +```` md +A paragraph. +- a list? +``````` +Next, invoke LuaTeX from the terminal: +``` sh +texlua ⟨CLI pathname⟩ -- content.md optionfalse.tex +texlua ⟨CLI pathname⟩ blankBeforeList=true -- content.md optiontrue.tex +luatex document.tex +``````` +where \meta{CLI pathname} corresponds to the location of the Lua CLI script file, +such as `~/texmf/scripts/markdown/markdown-cli.lua` on UN\*X systems or +`C:\Users\`\meta{Your username}`\texmf\scripts\markdown\markdown-cli.lua` on Windows +systems. Use the command `kpsewhich -a markdown-cli.lua` to locate the Lua CLI +script file using [Kpathsea][]. + +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> - a list? +> +> A paragraph. - a list? + +##### Plain \TeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\input markdown + +\markdownBegin +A paragraph. +- a list +\markdownEnd + +\def\markdownOptionBlankBeforeList{true} +\markdownBegin +A paragraph. +- not a list +\markdownEnd + +\bye +```````` +Next, invoke LuaTeX from the terminal: +``` sh +luatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> - a list +> +> A paragraph. - not a list + +##### \LaTeX{} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\documentclass{article} +\usepackage{markdown} +\begin{document} + +\begin{markdown} +A paragraph. +- a list +\end{markdown} + +\begin{markdown*}{blankBeforeList} +A paragraph. +- not a list +\end{markdown*} + +\end{document} +```````` +Next, invoke LuaTeX from the terminal: +``` sh +lualatex document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> - a list +> +> A paragraph. - not a list + +##### \Hologo{ConTeXt} Example {.unnumbered} + +Using a text editor, create a text document named `document.tex` with the +following content: +```` tex +\usemodule[t][markdown] +\starttext + +\startmarkdown +A paragraph. +- a list +\stopmarkdown + +\setupmarkdown[blankBeforeList = yes] +\startmarkdown +A paragraph. +- not a list +\stopmarkdown + +\stoptext +```````` +Next, invoke LuaTeX from the terminal: +``` sh +context document.tex +`````` +A PDF document named `document.pdf` should be produced and contain the +following text: + +> A paragraph. +> +> - a list +> +> A paragraph. - not a list + +% +%<*tex> +% \fi +% \begin{macrocode} +\@@_add_lua_option:nnn + { blankBeforeList } + { boolean } + { false } +% \end{macrocode} +% \iffalse +% +%<*lua,lua-cli> +% \fi +% \begin{macrocode} +defaultOptions.blankBeforeList = false +% \end{macrocode} +% \par +% \iffalse +% +%<*manual-options> + #### Option `bracketedSpans` `bracketedSpans` (default value: `false`) From 5cb96b15e2f034cfa89908b043a5b27e7cd3b977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 11:56:48 +0100 Subject: [PATCH 06/22] set `preserveTabs` to true --- markdown.dtx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index a0de9d36a..572e417a7 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -7564,12 +7564,12 @@ defaultOptions.pipeTables = false #### Option `preserveTabs` -`preserveTabs` (default value: `false`) +`preserveTabs` (default value: `true`) % \fi % \begin{markdown} % -% \Optitem[false]{preserveTabs}{\opt{true}, \opt{false}} +% \Optitem[true]{preserveTabs}{\opt{true}, \opt{false}} % : true @@ -7588,14 +7588,14 @@ defaultOptions.pipeTables = false \@@_add_lua_option:nnn { preserveTabs } { boolean } - { false } + { true } % \end{macrocode} % \iffalse % %<*lua,lua-cli> % \fi % \begin{macrocode} -defaultOptions.preserveTabs = false +defaultOptions.preserveTabs = true % \end{macrocode} % \par % \iffalse From 8cb693d03703401e5821e814e575afeffb2800fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 12:11:28 +0100 Subject: [PATCH 07/22] fix list unit tests --- tests/testfiles/CommonMark_0.30/list_items/005.test | 1 + tests/testfiles/CommonMark_0.30/lists/021.test | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/testfiles/CommonMark_0.30/list_items/005.test b/tests/testfiles/CommonMark_0.30/list_items/005.test index 588c2d5a3..07201cec1 100644 --- a/tests/testfiles/CommonMark_0.30/list_items/005.test +++ b/tests/testfiles/CommonMark_0.30/list_items/005.test @@ -16,6 +16,7 @@ documentBegin ulBeginTight ulItem +emphasis: one ulItemEnd ulEndTight interblockSeparator diff --git a/tests/testfiles/CommonMark_0.30/lists/021.test b/tests/testfiles/CommonMark_0.30/lists/021.test index e69f220af..67248974c 100644 --- a/tests/testfiles/CommonMark_0.30/lists/021.test +++ b/tests/testfiles/CommonMark_0.30/lists/021.test @@ -25,6 +25,7 @@ documentBegin ulBeginTight ulItem emphasis: a +interblockSeparator blockQuoteBegin emphasis: b blockQuoteEnd From d7b46ce097ad412d23862c4fec6f637be5bebcb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 10 Mar 2023 12:29:57 +0100 Subject: [PATCH 08/22] add bullet type to lists, add interrupting list items --- markdown.dtx | 105 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 572e417a7..9913c26bb 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -22961,18 +22961,12 @@ end % % \end{markdown} % \begin{macrocode} -parsers.bulletchar = C(parsers.plus + parsers.asterisk + parsers.dash) - -parsers.bullet = ( parsers.bulletchar * #parsers.spacing - * (parsers.tab + parsers.space^-3) - + parsers.space * parsers.bulletchar * #parsers.spacing - * (parsers.tab + parsers.space^-2) - + parsers.space * parsers.space * parsers.bulletchar - * #parsers.spacing - * (parsers.tab + parsers.space^-1) - + parsers.space * parsers.space * parsers.space - * parsers.bulletchar * #parsers.spacing - ) +parsers.bullet = function(bullet_char) + return Ct(C(parsers.space^-3) + * C(bullet_char) * Cc("") + * (C(parsers.spacechar^1) + + #(parsers.newline + parsers.eof))) +end local function tickbox(interior) return parsers.optionalspace * parsers.lbracket @@ -23624,18 +23618,11 @@ function M.reader.new(writer, options) 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 + parsers.enumerator = function(delimiter_type) + return Ct(C(parsers.space^-3) + * C(parsers.dig * parsers.dig^-8) * C(delimiter_type) + * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof))) + end % \end{macrocode} % \par % \begin{markdown} @@ -23769,7 +23756,7 @@ 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 @@ -23780,11 +23767,29 @@ function M.reader.new(writer, options) * parsers.optionalspace * parsers.newline) end + if options.blankBeforeList then + parsers.interrupting_bullets = parsers.fail + parsers.interrupting_enumerators = parsers.fail + else + parsers.interrupting_bullets = parsers.space^-3 + * (parsers.dash + parsers.asterisk + parsers.plus) + * parsers.spacechar^1 + * -#(parsers.newline + parsers.eof) + + parsers.interrupting_enumerators = parsers.space^-3 + * P("1") + * (parsers.period + parsers.rparent) + * parsers.spacechar^1 + * -#(parsers.newline + parsers.eof) + end + parsers.EndlineExceptions = parsers.blankline -- paragraph break + parsers.tightblocksep -- nested list + parsers.eof -- end of document - + parsers.blockquote_start + + parsers.bqstart + + parsers.interrupting_bullets + + parsers.interrupting_enumerators + parsers.headerstart parsers.Endline = parsers.newline @@ -23966,7 +23971,11 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - parsers.starter = parsers.bullet + parsers.enumerator + parsers.starter = parsers.bullet(parsers.dash) + + parsers.bullet(parsers.asterisk) + + parsers.bullet(parsers.plus) + + parsers.enumerator(parsers.period) + + parsers.enumerator(parsers.rparent) if options.taskLists then parsers.tickbox = ( parsers.ticked_box @@ -24007,13 +24016,21 @@ function M.reader.new(writer, options) ) / self.parser_functions.parse_blocks_nested 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)^1) * Cc(true) + * parsers.skipblanklines * -bullet + + Ct(parsers.LooseListItem(bullet)^1) * Cc(false) + * parsers.skipblanklines) + / 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] if options.startNumber then startnum = tonumber(startnum) or 1 -- fallback for '#' if startnum ~= nil then @@ -24025,14 +24042,20 @@ function M.reader.new(writer, options) 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(delimeter_type) + local enumerator = parsers.enumerator(delimeter_type) + return Cg(enumerator, "listtype") + * (Ct( parsers.TightListItem(Cb("listtype")) + * parsers.TightListItem(enumerator)^0) + * Cc(true) * parsers.skipblanklines * -enumerator + + Ct( parsers.LooseListItem(Cb("listtype")) + * parsers.LooseListItem(enumerator)^0) + * Cc(false) * parsers.skipblanklines + ) * Cb("listtype") / ordered_list + end + + parsers.OrderedList = parsers.OrderedListOfType(parsers.period) + + parsers.OrderedListOfType(parsers.rparent) % \end{macrocode} % \par % \begin{markdown} From 600bf86ade53ba32369091d1b13d01fc70c29d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Mon, 13 Mar 2023 20:12:36 +0100 Subject: [PATCH 09/22] add tab resolving to blockquotes --- markdown.dtx | 368 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 288 insertions(+), 80 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 9913c26bb..f9be262f1 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -19407,9 +19407,9 @@ texexec --passon=--shell-escape document.tex % \begin{macrocode} 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) % \end{macrocode} % \par % \begin{markdown} @@ -22961,8 +22961,10 @@ end % % \end{markdown} % \begin{macrocode} +parsers.leader = parsers.space^-3 + parsers.bullet = function(bullet_char) - return Ct(C(parsers.space^-3) + return Ct(C(parsers.leader) * C(bullet_char) * Cc("") * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof))) @@ -23010,8 +23012,6 @@ parsers.inticks = parsers.openticks * parsers.space^-1 % % \end{markdown} % \begin{macrocode} -parsers.leader = parsers.space^-3 - -- content in balanced brackets, parentheses, or quotes: parsers.bracketed = P{ parsers.lbracket * (( parsers.backslash / "" * parsers.rbracket @@ -23489,74 +23489,275 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} + -- TODO replace parsers.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 - parsers.indent_value = Ct(C(parsers.letter^1) * C(parsers.digit^1)) + local function add_trail(indent_table, trail_info) + indent_table[#indent_table + 1] = trail_info + return indent_table + end - parsers.indent_rope = parsers.indent_value * (parsers.comma * parsers.space * parsers.indent_value)^0 + local function remove_trail(indent_table) + if indent_table ~= nil and + indent_table[#indent_table] ~= nil and + indent_table[#indent_table]["type"] == "trail" then + indent_table[#indent_table] = nil + end - -- increments the indent type by a value - local function increment_indent_level(indent_type, increment) - local function update_indent_level(s, i, current_indent) + return indent_table + end - local indent_table = lpeg.match(Ct(parsers.indent_rope), current_indent) + local function leave_trail(s, i, indent_table) + indent_table = remove_trail(indent_table) - if indent_table == nil then - indent_table = {} - indent_table[#indent_table + 1] = {indent_type, increment} - else - local last_indent = indent_table[#indent_table] - local last_indent_type = last_indent[1] - local last_indent_value = last_indent[2] + return true, indent_table + end + + local function update_indent_table(indent_table, new_indent, increment) + + indent_table = remove_trail(indent_table) + + local indent_name = new_indent["name"] + local indent_length = new_indent["length"] + + if increment ~= nil and increment > 0 then + indent_table[#indent_table + 1] = { + ["type"]="indent", + ["name"]=indent_name, + ["length"]=tostring(indent_length)} + else + if indent_table[#indent_table]["name"] == indent_name then + indent_table[#indent_table] = nil + end + end + + return indent_table + end + + -- removes the indent type by a value + local function remove_indent_level(s,i,indent_table, indent_type) + indent_table = update_indent_table(indent_table, {["name"]=indent_type}) + return true, indent_table + end + + -- spacing processor + local function process_starter_spacing(indent, spacing, minimum, left_strip_length) + + if (left_strip_length == nil) then + left_strip_length = 0 + end + + local count = 0 + local tab_value = 4 - (indent) % 4 + + local code_started = false + local code_start = "" + + local t = {} + + local left_stripped = false + local left_total_stripped = 0 + + local raw_full_remainder = "" + + if spacing ~= nil then + for i = 1, #spacing do + local character = spacing:sub(i, i) + + if character == "\t" then + count = count + tab_value + tab_value = 4 + end + if character == " " then + count = count + 1 + tab_value = 4 - (4 - tab_value + 1) % 4 + end + + 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 + raw_full_remainder = raw_full_remainder .. character + end - if last_indent_type == indent_type then - indent_table[#indent_table][2] = math.floor(last_indent_value + increment) + if (code_started) then + code_start = code_start .. character else - indent_table[#indent_table + 1] = {indent_type, increment} + if (count >= minimum + 4) then + code_started = true + code_start = code_start .. string.rep(" ", count - (minimum + 4)) + end end end + end + + local remainder = "" + + if (code_started) then + remainder = code_start + else + remainder = string.rep(" ", count - minimum) + end + + return {code_started, remainder, left_total_stripped, raw_full_remainder} + end + + local function count_indent_tab_level(indent_table) + local count = 0 + if indent_table == nil then + return count + end + + for i=1, #indent_table do + if indent_table[i]["type"] == "indent" then + count = count + tonumber(indent_table[i]["length"]) + end + end + return count + end + + local function check_trail_joined(s, i, indent_table, spacing, expect_code, substitute) + local trail = nil + local is_code = false + local remainder = "" - local joined_values = {} - for _, value in ipairs(indent_table) do - if value[2] > 0 then - joined_values[#joined_values + 1] = value[1] .. value[2] + if indent_table ~= nil and indent_table[#indent_table] ~= nil and indent_table[#indent_table]["type"] == "trail" then + trail = indent_table[#indent_table] + is_code = trail["is_code"] + remainder = trail["remainder"] + end + + if trail == nil then + local sp = process_starter_spacing(0, spacing, 0) + is_code = sp[1] + remainder = sp[2] + end + + if expect_code then + if is_code then + if substitute then + return true, remainder end + return true end + return false + end + + if is_code then + return false + end + + if substitute then + return true, "" + end + return true + end + + local function process_starter_indent(s, i, indent_table, starter, indent_type) + local last_trail = starter[1] + local delimiter = starter[2] + local raw_new_trail = starter[3] + + if indent_table ~= nil and indent_table[#indent_table] ~= nil and indent_table[#indent_table]["type"] == "trail" then + if (indent_table[#indent_table]["is_code"]) then + return false + end + last_trail = indent_table[#indent_table]["remainder"] + else + local sp = process_starter_spacing(0, last_trail, 0) + local is_code = sp[1] + local remainder = sp[2] - local new_indent_table = table.concat(joined_values, ", ") - return true, new_indent_table + if (is_code) then + return false + end + last_trail = remainder end - return Cg( Cmt(Cb("relative_indent"), update_indent_level) - , "relative_indent") + local preceding_indentation = count_indent_tab_level(indent_table) % 4 + local last_trail_length = #last_trail + local delimiter_length = #delimiter + + local total_indent_level = preceding_indentation + last_trail_length + delimiter_length + + local sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + + local is_code = sp[1] + local remainder = sp[2] + local left_total_stripped = sp[3] + + local indent_length = last_trail_length + delimiter_length + left_total_stripped + local new_indent_info = {["name"]=indent_type, ["length"]=indent_length} + + local indent_table = update_indent_table(indent_table, new_indent_info, 1) + local new_trail = {["type"]="trail", ["is_code"]=is_code, ["remainder"]=remainder} + indent_table = add_trail(indent_table, new_trail) + + return true, indent_table end - -- decodes pattern name from pair to its pattern local function decode_pattern(name) if name == "bq" then - return parsers.blockquote_start + return C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0) * Cp() end return parsers.succeed end - -- applies decoded pattern - local function traverse_indent(s, i, current_indent, is_optional) - local indent_table = lpeg.match(Ct(parsers.indent_rope), current_indent) - - if indent_table == nil then - return true, i - end - + -- applies decoded pattern iteratively + local function traverse_indent(s, i, indent_table, is_optional) local new_index = i + local preceding_indentation = 0 + local current_trail = {} + for _, value in ipairs(indent_table) do - local pattern = decode_pattern(value[1]) - if is_optional then - pattern = pattern^-1 - end + if value["type"] == "indent" then + + local pattern = decode_pattern(value["name"]) + + local new_indent_info = lpeg.match(Ct(pattern), s, new_index) + if new_indent_info == nil then + if is_optional then + return true, new_index + end + return false, i + end + + local last_trail = new_indent_info[1] + local delimiter = new_indent_info[2] + local raw_new_trail = new_indent_info[3] + local possible_next_index = new_indent_info[4] + + if current_trail ~= nil and current_trail[#current_trail] ~= nil then + if (indent_table[#indent_table]["is_code"]) then + if is_optional then + return true, new_index + end + return false, i + end + last_trail = indent_table[#indent_table]["remainder"] + end + + -- local preceding_indentation + local last_trail_length = #last_trail + local delimiter_length = #delimiter + + local total_indent_level = preceding_indentation + last_trail_length + delimiter_length + + local sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + + local is_code = sp[1] + local remainder = sp[2] + local left_total_stripped = sp[3] + local raw_remainder = sp[4] + + local indent_length = last_trail_length + delimiter_length + left_total_stripped + + preceding_indentation = preceding_indentation + indent_length + current_trail = {["type"]="trail", ["is_code"]=is_code, ["remainder"]=remainder, ["raw_remainder"]=raw_remainder} - for j = 1,value[2] do - local possible_next_index = lpeg.match(pattern, s, new_index) if (possible_next_index ~= nil) then new_index = possible_next_index else @@ -23568,34 +23769,34 @@ function M.reader.new(writer, options) end end - return true, new_index + return true, new_index, current_trail end - -- skip only all indent - local function produce_minimal_indent(s, i, current_indent) - local passes, new_index = traverse_indent(s, i, current_indent, false) + local function start_traverse_indent(s, i, indent_table, is_optional) + if indent_table == nil then + return true + end + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional) if passes then - return new_index, "" + indent_table = add_trail(indent_table, current_trail) + return new_index, indent_table end return false end - -- skip maximum of indent - local function produce_optional_indent(s, i, current_indent) - local passes, new_index = traverse_indent(s, i, current_indent, true) + check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) - if passes then - return new_index, "" - end - return false - end + check_optional_indent = Cmt(Cb("indent_info") * Cc(true), start_traverse_indent) + + check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(true), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - -- check required - check_minimal_indent = Cmt(Cb("relative_indent"), produce_minimal_indent) + check_trail_no_sub = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(false), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - -- check optional indent - check_optional_indent = Cmt(Cb("relative_indent"), produce_optional_indent) + check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true) * Cc(true), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") parsers.minimally_indented_blank = check_minimal_indent * V("Blank") @@ -23619,9 +23820,9 @@ function M.reader.new(writer, options) end parsers.enumerator = function(delimiter_type) - return Ct(C(parsers.space^-3) - * C(parsers.dig * parsers.dig^-8) * C(delimiter_type) - * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof))) + return Ct( C(parsers.leader) + * C(parsers.dig * parsers.dig^-8) * C(delimiter_type) + * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof))) end % \end{macrocode} % \par @@ -23650,16 +23851,21 @@ function M.reader.new(writer, options) + parsers.minimally_indented_separated_block)^0) end - parsers.blockquote_body = parsers.blockquote_start - * increment_indent_level("bq", 1) - * parsers.blockquote_content(false) - * increment_indent_level("bq", -1) + parsers.blockquote_body = Cg(Cmt( Cb("indent_info") + * Ct(C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0)) + * Cc("bq"), + process_starter_indent), "indent_info") + * parsers.blockquote_content(false) + * Cg(Cmt( Cb("indent_info") + * Cc("bq"), + remove_indent_level), "indent_info") + -- TODO if not options.breakableBlockquotes then - parsers.blockquote_body = parsers.blockquote_start - * increment_indent_level("bq", 1) - * parsers.blockquote_content(true) - * increment_indent_level("bq", -1) +-- parsers.blockquote_body = Cg(parsers.blockquote_start, "starter") +-- * increment_indent_level("bq", 1) +-- * parsers.blockquote_content(true) +-- * increment_indent_level("bq", -1) end % \end{macrocode} % \par @@ -23937,9 +24143,10 @@ function M.reader.new(writer, options) parsers.indented_non_blank_line = parsers.indentedline - parsers.blankline parsers.Verbatim = Cs( - parsers.indented_non_blank_line - * ((check_minimal_indent * parsers.blankline)^0 - * (check_minimal_indent * parsers.indented_non_blank_line)^1)^0 + check_code_trail + * (parsers.line - parsers.blankline) + * (((check_minimal_indent / "") * parsers.blankline)^0 + * ((check_minimal_indent / "") * check_code_trail * (parsers.line - parsers.blankline))^1)^0 ) / self.expandtabs / writer.verbatim parsers.BlockquoteExceptions = parsers.leader * parsers.more @@ -23955,7 +24162,8 @@ function M.reader.new(writer, options) parsers.Reference = parsers.define_reference_parser / register_link - parsers.Paragraph = parsers.nonindentspace * Ct((parsers.Inline)^1) + parsers.Paragraph = check_trail_no_sub * + Ct((parsers.Inline)^1) * ( parsers.newline * #V("EndlineExceptions") + parsers.eof) @@ -24237,7 +24445,7 @@ function M.reader.new(writer, options) Smart = parsers.Smart, Symbol = parsers.Symbol, SpecialChar = parsers.fail, - InitializeState = parsers.succeed * Cg(Ct("") / "", "relative_indent"), --temporary initialization + InitializeState = parsers.succeed * Cg(Ct(""), "indent_info"), --temporary initialization } % \end{macrocode} % \par @@ -25411,8 +25619,8 @@ M.extensions.fenced_code = function(blank_before_code_fence, local BacktickFencedCode = fencehead(parsers.backtick, backtick_infostring) - * Cs((check_minimal_indent * fencedline(parsers.backtick))^0) - * (check_minimal_indent * fencetail(parsers.backtick) + parsers.succeed) + * Cs(((check_minimal_indent / "") * fencedline(parsers.backtick))^0) + * ((check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed) local infostring_with_attributes = Ct(C((parsers.linechar From dfd2186bbd38ffe63381a9b000d7897874c63219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Mon, 20 Mar 2023 08:54:27 +0100 Subject: [PATCH 10/22] add indentation to lists --- markdown.dtx | 541 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 327 insertions(+), 214 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index f9be262f1..4edf2a8e8 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -22215,7 +22215,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 @@ -22256,8 +22258,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 @@ -22964,10 +22968,10 @@ end parsers.leader = parsers.space^-3 parsers.bullet = function(bullet_char) - return Ct(C(parsers.leader) - * C(bullet_char) * Cc("") + return C(parsers.leader) + * Ct(C(bullet_char) * Cc("")) * (C(parsers.spacechar^1) - + #(parsers.newline + parsers.eof))) + + #(parsers.newline + parsers.eof)) end local function tickbox(interior) @@ -23489,58 +23493,57 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} - -- TODO replace parsers.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 local function add_trail(indent_table, trail_info) - indent_table[#indent_table + 1] = trail_info + indent_table.trail = trail_info return indent_table end local function remove_trail(indent_table) - if indent_table ~= nil and - indent_table[#indent_table] ~= nil and - indent_table[#indent_table]["type"] == "trail" then - indent_table[#indent_table] = nil - end - + indent_table.trail = nil return indent_table end local function leave_trail(s, i, indent_table) indent_table = remove_trail(indent_table) - return true, indent_table end - local function update_indent_table(indent_table, new_indent, increment) + local function has_trail(indent_table) + return indent_table ~= nil and indent_table.trail ~= nil and next(indent_table.trail) ~= nil + end + local function update_indent_table(indent_table, new_indent, increment) indent_table = remove_trail(indent_table) - local indent_name = new_indent["name"] - local indent_length = new_indent["length"] + if indent_table.indents == nil then + indent_table.indents = {} + end + + local indent_table_indents = indent_table.indents if increment ~= nil and increment > 0 then - indent_table[#indent_table + 1] = { - ["type"]="indent", - ["name"]=indent_name, - ["length"]=tostring(indent_length)} + indent_table_indents[#indent_table_indents + 1] = new_indent else - if indent_table[#indent_table]["name"] == indent_name then - indent_table[#indent_table] = nil + 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 - -- removes the indent type by a value - local function remove_indent_level(s,i,indent_table, indent_type) - indent_table = update_indent_table(indent_table, {["name"]=indent_type}) - return true, indent_table + local function remove_indent(name) + local function remove_indent_level(s, i, indent_table) + indent_table = update_indent_table(indent_table, {name=name}) + return true, indent_table + end + + return Cg(Cmt( Cb("indent_info"), remove_indent_level), "indent_info") end - -- spacing processor + --- process indentation spacing local function process_starter_spacing(indent, spacing, minimum, left_strip_length) if (left_strip_length == nil) then @@ -23553,9 +23556,9 @@ function M.reader.new(writer, options) local code_started = false local code_start = "" - local t = {} + local minimum_found = false + local minimum_remainder = "" - local left_stripped = false local left_total_stripped = 0 local raw_full_remainder = "" @@ -23570,7 +23573,7 @@ function M.reader.new(writer, options) end if character == " " then count = count + 1 - tab_value = 4 - (4 - tab_value + 1) % 4 + tab_value = 4 - (1 - tab_value) % 4 end if (left_strip_length ~= 0) then @@ -23581,6 +23584,15 @@ function M.reader.new(writer, options) else raw_full_remainder = raw_full_remainder .. character end + + if (minimum_found) then + minimum_remainder = minimum_remainder .. character + else + if (count >= minimum) then + minimum_found = true + minimum_remainder = minimum_remainder .. string.rep(" ", count - minimum) + end + end if (code_started) then code_start = code_start .. character @@ -23594,53 +23606,55 @@ function M.reader.new(writer, options) end local remainder = "" - if (code_started) then remainder = code_start else remainder = string.rep(" ", count - minimum) end - return {code_started, remainder, left_total_stripped, raw_full_remainder} + local is_minimum = count >= minimum + return { + is_code = code_started, + remainder = remainder, + left_total_stripped = left_total_stripped, + raw_full_remainder = raw_full_remainder, + is_minimum = is_minimum, + minimum_remainder = minimum_remainder + } end + -- count total indentation from preceding indentation levels local function count_indent_tab_level(indent_table) local count = 0 - if indent_table == nil then + if indent_table == nil or indent_table.indents == nil then return count end - for i=1, #indent_table do - if indent_table[i]["type"] == "indent" then - count = count + tonumber(indent_table[i]["length"]) - end + for i=1, #indent_table.indents do + count = count + indent_table.indents[i].length end return count end - local function check_trail_joined(s, i, indent_table, spacing, expect_code, substitute) + -- check if trail is of expected length + local function check_trail_joined(s, i, indent_table, spacing, expect_code) local trail = nil local is_code = false - local remainder = "" - - if indent_table ~= nil and indent_table[#indent_table] ~= nil and indent_table[#indent_table]["type"] == "trail" then - trail = indent_table[#indent_table] - is_code = trail["is_code"] - remainder = trail["remainder"] - end + local remainder = nil - if trail == nil then - local sp = process_starter_spacing(0, spacing, 0) - is_code = sp[1] - remainder = sp[2] + if has_trail(indent_table) then + trail = indent_table.trail + is_code = trail.is_code + remainder = trail.remainder + else + local sp = process_starter_spacing(0, spacing, 0, 0) + is_code = sp.is_code + remainder = sp.remainder end if expect_code then if is_code then - if substitute then - return true, remainder - end - return true + return true, remainder end return false end @@ -23649,133 +23663,186 @@ function M.reader.new(writer, options) return false end - if substitute then - return true, "" + return true, "" + end + + -- count the total length of a delimiter + 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 true + return count end + -- process container start local function process_starter_indent(s, i, indent_table, starter, indent_type) local last_trail = starter[1] local delimiter = starter[2] local raw_new_trail = starter[3] - if indent_table ~= nil and indent_table[#indent_table] ~= nil and indent_table[#indent_table]["type"] == "trail" then - if (indent_table[#indent_table]["is_code"]) then + if has_trail(indent_table) then + local trail = indent_table.trail + if trail.is_code then return false end - last_trail = indent_table[#indent_table]["remainder"] + last_trail = trail.remainder else - local sp = process_starter_spacing(0, last_trail, 0) - local is_code = sp[1] - local remainder = sp[2] + local sp = process_starter_spacing(0, last_trail, 0, 0) - if (is_code) then + if sp.is_code then return false end - last_trail = remainder + last_trail = sp.remainder end local preceding_indentation = count_indent_tab_level(indent_table) % 4 local last_trail_length = #last_trail - local delimiter_length = #delimiter + local delimiter_length = total_delimiter_length(delimiter) local total_indent_level = preceding_indentation + last_trail_length + delimiter_length - local sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + local sp = nil + if raw_new_trail ~= nil then -- item is not blank + sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + else + sp = {} + end - local is_code = sp[1] - local remainder = sp[2] - local left_total_stripped = sp[3] + local del_trail_length = sp.left_total_stripped + if raw_new_trail == nil then + del_trail_length = 1 + elseif not sp.is_code then + del_trail_length = del_trail_length + #sp.remainder + end - local indent_length = last_trail_length + delimiter_length + left_total_stripped - local new_indent_info = {["name"]=indent_type, ["length"]=indent_length} + local indent_length = last_trail_length + delimiter_length + del_trail_length + local new_indent_info = {name=indent_type, length=indent_length} local indent_table = update_indent_table(indent_table, new_indent_info, 1) - local new_trail = {["type"]="trail", ["is_code"]=is_code, ["remainder"]=remainder} + local new_trail = {is_code=sp.is_code, remainder=sp.remainder} indent_table = add_trail(indent_table, new_trail) return true, indent_table end + parsers.blockquote_opening_condition = C(parsers.leader) * C(parsers.more) * C(parsers.spacechar^0) + + -- find indent pattern mapping, format local function decode_pattern(name) if name == "bq" then return C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0) * Cp() end - return parsers.succeed + if name == "li" then + return C(parsers.spacechar^0) * Cc("") * Cc("") * Cp() + end + return parsers.fail end - -- applies decoded pattern iteratively + -- apply decoded patterns iteratively, local function traverse_indent(s, i, indent_table, is_optional) local new_index = i local preceding_indentation = 0 local current_trail = {} - for _, value in ipairs(indent_table) do - if value["type"] == "indent" then + if indent_table.indents == nil then + return true, new_index, current_trail + end - local pattern = decode_pattern(value["name"]) + for _, value in ipairs(indent_table.indents) do + local pattern = decode_pattern(value.name) - local new_indent_info = lpeg.match(Ct(pattern), s, new_index) - if new_indent_info == nil then - if is_optional then - return true, new_index - end - return false, i + -- match decoded pattern + local new_indent_info = lpeg.match(Ct(pattern), s, new_index) + if new_indent_info == nil then + if is_optional then + return true, new_index end + return false + end - local last_trail = new_indent_info[1] - local delimiter = new_indent_info[2] - local raw_new_trail = new_indent_info[3] - local possible_next_index = new_indent_info[4] + local raw_last_trail = new_indent_info[1] + local delimiter = new_indent_info[2] + local raw_new_trail = new_indent_info[3] + local possible_next_index = new_indent_info[4] - if current_trail ~= nil and current_trail[#current_trail] ~= nil then - if (indent_table[#indent_table]["is_code"]) then - if is_optional then - return true, new_index - end - return false, i + local mid_trail = {} + + -- check previous trail + if delimiter ~= "" and 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} + end + + if current_trail ~= nil then + if delimiter ~= "" and current_trail.is_code then + if is_optional then + return true, new_index end - last_trail = indent_table[#indent_table]["remainder"] + return false + end + if current_trail.internal_remainder ~= nil then + raw_last_trail = current_trail.internal_remainder end + end - -- local preceding_indentation - local last_trail_length = #last_trail - local delimiter_length = #delimiter + local raw_last_trail_length = 0 + local delimiter_length = 0 - local total_indent_level = preceding_indentation + last_trail_length + delimiter_length + if delimiter ~= "" then + delimiter_length = #delimiter + raw_last_trail_length = #raw_last_trail + end - local sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) + local total_indent_level = preceding_indentation + raw_last_trail_length + delimiter_length - local is_code = sp[1] - local remainder = sp[2] - local left_total_stripped = sp[3] - local raw_remainder = sp[4] + local spacing_to_process = "" + local minimum = 0 + local left_strip_length = 0 - local indent_length = last_trail_length + delimiter_length + left_total_stripped + if delimiter ~= "" then + spacing_to_process = raw_new_trail + left_strip_length = 1 + else + spacing_to_process = raw_last_trail + minimum = value.length + end - preceding_indentation = preceding_indentation + indent_length - current_trail = {["type"]="trail", ["is_code"]=is_code, ["remainder"]=remainder, ["raw_remainder"]=raw_remainder} + local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length) - if (possible_next_index ~= nil) then - new_index = possible_next_index - else - if is_optional then + if delimiter == "" and not sp.is_minimum then + if is_optional then return true, new_index end - return false, i - end + return false + end + + local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped + + -- update info for the next pattern + local next_trail = {} + if delimiter ~= "" then + preceding_indentation = preceding_indentation + indent_length + next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.remainder} + else + preceding_indentation = preceding_indentation + value.length + next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} end + + current_trail = next_trail + new_index = possible_next_index end return true, new_index, current_trail end local function start_traverse_indent(s, i, indent_table, is_optional) - if indent_table == nil then + if indent_table == nil or indent_table.indents == nil then return true end + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional) if passes then @@ -23785,17 +23852,41 @@ function M.reader.new(writer, options) return false end + local function start_blank_indent(s, i, indent_table, is_optional) + if indent_table == nil or indent_table.indents == nil then + return true + end + + local non_blank_found = false + local index = 1 + while not non_blank_found and index <= #indent_table.indents do + if indent_table.indents[index].name == "bq" then + non_blank_found = true + end + index = index + 1 + end + + if non_blank_found then + local result, indent_table = start_traverse_indent(s, i, indent_table, is_optional) + if result then + return result, indent_table + end + return false + end + + return true, indent_table + end + check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) check_optional_indent = Cmt(Cb("indent_info") * Cc(true), start_traverse_indent) - check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(true), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") + check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false), start_blank_indent) - check_trail_no_sub = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(false), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") + check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true) * Cc(true), check_trail_joined) + check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") parsers.minimally_indented_blank = check_minimal_indent * V("Blank") @@ -23805,6 +23896,31 @@ function M.reader.new(writer, options) parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep * V("Block") + parsers.indented_content = function(breakable) + local blank = parsers.minimally_indented_blank + if breakable then + blank = blank + V("Blank") + end + + return Ct( V("Blank") + * blank^0 + * parsers.minimally_indented_block + * ( blank + + parsers.minimally_indented_separated_block)^0 + + V("Blank") + * blank^0 + + V("Block") + * ( blank + + parsers.minimally_indented_separated_block)^0) + end + + local function add_indent(pattern, name) + return Cg(Cmt( Cb("indent_info") + * Ct(pattern) + * Cc(name), + process_starter_indent), "indent_info") + end + % \end{macrocode} % \par % \begin{markdown} @@ -23819,11 +23935,22 @@ function M.reader.new(writer, options) parsers.dig = parsers.digit end - parsers.enumerator = function(delimiter_type) - return Ct( C(parsers.leader) - * C(parsers.dig * parsers.dig^-8) * C(delimiter_type) - * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof))) + parsers.enumerator = function(delimiter_type, interrupt) + local delimiter_range = parsers.dig * parsers.dig^-8 + if interrupt then + delimiter_range = P("1") + end + + return C(parsers.leader) + * Ct(C(delimiter_range) * C(delimiter_type)) + * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof)) end + + parsers.starter = parsers.bullet(parsers.dash) + + parsers.bullet(parsers.asterisk) + + parsers.bullet(parsers.plus) + + parsers.enumerator(parsers.period) + + parsers.enumerator(parsers.rparent) % \end{macrocode} % \par % \begin{markdown} @@ -23832,40 +23959,14 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} + parsers.blockquote_body = add_indent(parsers.blockquote_opening_condition, "bq") + * parsers.indented_content(false) + * remove_indent("bq") - parsers.blockquote_content = function(breakable) - local blank = parsers.minimally_indented_blank - if breakable then - blank = blank + V("Blank") - end - - return Ct( V("Blank") - * blank^0 - * parsers.minimally_indented_block - * ( blank - + parsers.minimally_indented_separated_block)^0 - + V("Blank") - * blank^0 - + V("Block") - * ( blank - + parsers.minimally_indented_separated_block)^0) - end - - parsers.blockquote_body = Cg(Cmt( Cb("indent_info") - * Ct(C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0)) - * Cc("bq"), - process_starter_indent), "indent_info") - * parsers.blockquote_content(false) - * Cg(Cmt( Cb("indent_info") - * Cc("bq"), - remove_indent_level), "indent_info") - - -- TODO if not options.breakableBlockquotes then --- parsers.blockquote_body = Cg(parsers.blockquote_start, "starter") --- * increment_indent_level("bq", 1) --- * parsers.blockquote_content(true) --- * increment_indent_level("bq", -1) + parsers.blockquote_body = add_indent(parsers.blockquote_opening_condition, "bq") + * parsers.indented_content(true) + * remove_indent("bq") end % \end{macrocode} % \par @@ -23968,7 +24069,7 @@ function M.reader.new(writer, options) if options.blankBeforeHeading then parsers.headerstart = parsers.fail else - parsers.headerstart = parsers.hash + parsers.headerstart = parsers.nonindentspace * parsers.hash + (parsers.line * (parsers.equal^1 + parsers.dash^1) * parsers.optionalspace * parsers.newline) end @@ -23977,16 +24078,12 @@ function M.reader.new(writer, options) parsers.interrupting_bullets = parsers.fail parsers.interrupting_enumerators = parsers.fail else - parsers.interrupting_bullets = parsers.space^-3 - * (parsers.dash + parsers.asterisk + parsers.plus) - * parsers.spacechar^1 - * -#(parsers.newline + parsers.eof) - - parsers.interrupting_enumerators = parsers.space^-3 - * P("1") - * (parsers.period + parsers.rparent) - * parsers.spacechar^1 - * -#(parsers.newline + parsers.eof) + parsers.interrupting_bullets = parsers.bullet(parsers.dash) + + parsers.bullet(parsers.asterisk) + + parsers.bullet(parsers.plus) + + parsers.interrupting_enumerators = parsers.enumerator(parsers.period, true) + + parsers.enumerator(parsers.rparent, true) end parsers.EndlineExceptions @@ -23999,7 +24096,11 @@ function M.reader.new(writer, options) + parsers.headerstart parsers.Endline = parsers.newline - * check_optional_indent * -V("EndlineExceptions") + * (check_minimal_indent + * -V("EndlineExceptions") + + check_optional_indent + * -V("EndlineExceptions") + * -parsers.starter) * parsers.spacechar^0 / (options.hardLineBreaks and writer.hard_line_break or writer.space) @@ -24019,7 +24120,11 @@ function M.reader.new(writer, options) parsers.NonbreakingEndline = parsers.newline - * check_optional_indent * -V("EndlineExceptions") + * (check_minimal_indent + * -V("EndlineExceptions") + + check_optional_indent + * -V("EndlineExceptions") + * -parsers.starter) * parsers.spacechar^0 / (options.hardLineBreaks and writer.hard_line_break or writer.nbsp) @@ -24145,8 +24250,8 @@ function M.reader.new(writer, options) parsers.Verbatim = Cs( check_code_trail * (parsers.line - parsers.blankline) - * (((check_minimal_indent / "") * parsers.blankline)^0 - * ((check_minimal_indent / "") * check_code_trail * (parsers.line - parsers.blankline))^1)^0 + * (((check_minimal_blank_indent / "") * parsers.blankline)^0 + * ((check_minimal_indent / "") * check_code_trail * (parsers.line - parsers.blankline))^1)^0 ) / self.expandtabs / writer.verbatim parsers.BlockquoteExceptions = parsers.leader * parsers.more @@ -24162,12 +24267,10 @@ function M.reader.new(writer, options) parsers.Reference = parsers.define_reference_parser / register_link - parsers.Paragraph = check_trail_no_sub * - Ct((parsers.Inline)^1) - * ( parsers.newline - * #V("EndlineExceptions") - + parsers.eof) - / writer.paragraph + parsers.Paragraph = (check_trail / "") + * (Ct((parsers.Inline)^1) + * (parsers.newline + parsers.eof) + / writer.paragraph) parsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) / writer.plain @@ -24179,11 +24282,6 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - parsers.starter = parsers.bullet(parsers.dash) - + parsers.bullet(parsers.asterisk) - + parsers.bullet(parsers.plus) - + parsers.enumerator(parsers.period) - + parsers.enumerator(parsers.rparent) if options.taskLists then parsers.tickbox = ( parsers.ticked_box @@ -24194,42 +24292,57 @@ function M.reader.new(writer, options) 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.minimally_indented_non_blank = parsers.minimally_indented_block + - parsers.minimally_indented_blank + + parsers.minimally_indented_separated_non_blank = parsers.minimally_indented_separated_block + - parsers.minimally_indented_blank + + parsers.list_item_tightness_condition = -#((V("Blank")^1 * (parsers.minimally_indented_block)) + * remove_indent("li") + + remove_indent("li") + * parsers.fail) + + parsers.indented_content_tight = Ct( V("Blank") + * -parsers.minimally_indented_non_blank + * remove_indent("li") + + ( V("Blank") + * (parsers.minimally_indented_non_blank) + * (parsers.minimally_indented_separated_non_blank)^0 + + V("Block") + * (parsers.minimally_indented_separated_non_blank)^0) + * parsers.list_item_tightness_condition) + + + parsers.indented_content_loose = Ct( V("Blank") + * (parsers.minimally_indented_non_blank) + * ( V("Blank")^0 + * parsers.minimally_indented_separated_non_blank^1)^0 + + V("Blank") + + V("Block") + * ( V("Blank")^0 + * parsers.minimally_indented_separated_non_blank^1)^0) 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 + * 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 + * add_indent(starter, "li") + * parsers.indented_content_loose + * remove_indent("li") end parsers.BulletListOfType = function(bullet_type) local bullet = parsers.bullet(bullet_type) return ( Ct( parsers.TightListItem(bullet)^1) * Cc(true) - * parsers.skipblanklines * -bullet - + Ct(parsers.LooseListItem(bullet)^1) * Cc(false) - * parsers.skipblanklines) + * -#(parsers.blanklines * bullet) + + Ct(parsers.LooseListItem(bullet) + * ((parsers.blanklines / "") + * parsers.LooseListItem(bullet))^0) * Cc(false)) / writer.bulletlist end @@ -24238,7 +24351,7 @@ function M.reader.new(writer, options) + parsers.BulletListOfType(parsers.plus) local function ordered_list(items,tight,starter) - local startnum = starter[2] + local startnum = starter[2][1] if options.startNumber then startnum = tonumber(startnum) or 1 -- fallback for '#' if startnum ~= nil then @@ -24255,11 +24368,11 @@ function M.reader.new(writer, options) return Cg(enumerator, "listtype") * (Ct( parsers.TightListItem(Cb("listtype")) * parsers.TightListItem(enumerator)^0) - * Cc(true) * parsers.skipblanklines * -enumerator + * Cc(true) * -#(parsers.blanklines * enumerator) + Ct( parsers.LooseListItem(Cb("listtype")) - * parsers.LooseListItem(enumerator)^0) - * Cc(false) * parsers.skipblanklines - ) * Cb("listtype") / ordered_list + * ((parsers.blanklines / "") * parsers.LooseListItem(enumerator))^0) + * Cc(false) + ) * Ct(Cb("listtype")) / ordered_list end parsers.OrderedList = parsers.OrderedListOfType(parsers.period) @@ -25619,7 +25732,7 @@ M.extensions.fenced_code = function(blank_before_code_fence, local BacktickFencedCode = fencehead(parsers.backtick, backtick_infostring) - * Cs(((check_minimal_indent / "") * fencedline(parsers.backtick))^0) + * Cs(((check_minimal_blank_indent / "") * parsers.blankline + (check_minimal_indent / "") * fencedline(parsers.backtick))^0) * ((check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed) local infostring_with_attributes From 5ad2e8f22ddc50ae257c6687d81c8bc2b8a9b79a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Tue, 21 Mar 2023 19:29:28 +0100 Subject: [PATCH 11/22] fix interrupting list items, fix nested blank lines, resolve reference definitions --- markdown.dtx | 192 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 67 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 4edf2a8e8..2394314a3 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -22967,11 +22967,16 @@ end % \begin{macrocode} parsers.leader = parsers.space^-3 -parsers.bullet = function(bullet_char) +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 C(parsers.leader) * Ct(C(bullet_char) * Cc("")) - * (C(parsers.spacechar^1) - + #(parsers.newline + parsers.eof)) + * allowed_end end local function tickbox(interior) @@ -23211,7 +23216,7 @@ parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) -- parse a reference definition: [foo]: /bar "title" parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon * parsers.spacechar^0 * parsers.url - * parsers.optionaltitle * parsers.blankline^1 + * parsers.optionaltitle * (parsers.newline + parsers.eof) % \end{macrocode} % \par % \begin{markdown} @@ -23677,7 +23682,7 @@ function M.reader.new(writer, options) end -- process container start - local function process_starter_indent(s, i, indent_table, starter, indent_type) + local function process_starter_indent(s, i, indent_table, starter, is_blank, indent_type) local last_trail = starter[1] local delimiter = starter[2] local raw_new_trail = starter[3] @@ -23704,14 +23709,14 @@ function M.reader.new(writer, options) local total_indent_level = preceding_indentation + last_trail_length + delimiter_length local sp = nil - if raw_new_trail ~= nil then -- item is not blank + if not is_blank then sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) else sp = {} end local del_trail_length = sp.left_total_stripped - if raw_new_trail == nil then + if is_blank then del_trail_length = 1 elseif not sp.is_code then del_trail_length = del_trail_length + #sp.remainder @@ -23740,9 +23745,24 @@ function M.reader.new(writer, options) return parsers.fail end + -- find the last start of an only blank pattern group + local function left_blank_starter(indent_table) + local blank_starter_index = nil + 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 + -- apply decoded patterns iteratively, - local function traverse_indent(s, i, indent_table, is_optional) - local new_index = i + local function traverse_indent(s, index, indent_table, is_optional, blank_end) + local new_index = index local preceding_indentation = 0 local current_trail = {} @@ -23751,14 +23771,17 @@ function M.reader.new(writer, options) return true, new_index, current_trail end - for _, value in ipairs(indent_table.indents) do + local blank_starter = left_blank_starter(indent_table) + + for i = 1,#indent_table.indents do + local value = indent_table.indents[i] local pattern = decode_pattern(value.name) -- match decoded pattern local new_indent_info = lpeg.match(Ct(pattern), s, new_index) if new_indent_info == nil then if is_optional then - return true, new_index + return true, new_index, current_trail end return false end @@ -23768,8 +23791,6 @@ function M.reader.new(writer, options) local raw_new_trail = new_indent_info[3] local possible_next_index = new_indent_info[4] - local mid_trail = {} - -- check previous trail if delimiter ~= "" and current_trail == nil then local sp = process_starter_spacing(0, raw_last_trail, 0, 0) @@ -23779,7 +23800,7 @@ function M.reader.new(writer, options) if current_trail ~= nil then if delimiter ~= "" and current_trail.is_code then if is_optional then - return true, new_index + return true, new_index, current_trail end return false end @@ -23813,10 +23834,12 @@ function M.reader.new(writer, options) local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length) if delimiter == "" and not sp.is_minimum then - if is_optional then - return true, new_index - end - return false + if is_optional + or (blank_end and blank_starter <= i) + then + return true, new_index, current_trail + end + return false end local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped @@ -23825,7 +23848,7 @@ function M.reader.new(writer, options) local next_trail = {} if delimiter ~= "" then preceding_indentation = preceding_indentation + indent_length - next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.remainder} + next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} else preceding_indentation = preceding_indentation + value.length next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} @@ -23843,7 +23866,7 @@ function M.reader.new(writer, options) return true end - local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional) + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional, false) if passes then indent_table = add_trail(indent_table, current_trail) @@ -23857,24 +23880,13 @@ function M.reader.new(writer, options) return true end - local non_blank_found = false - local index = 1 - while not non_blank_found and index <= #indent_table.indents do - if indent_table.indents[index].name == "bq" then - non_blank_found = true - end - index = index + 1 - end + local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional, true) - if non_blank_found then - local result, indent_table = start_traverse_indent(s, i, indent_table, is_optional) - if result then - return result, indent_table - end - return false + if passes then + indent_table = add_trail(indent_table, current_trail) + return new_index, indent_table end - - return true, indent_table + return false end check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) @@ -23889,25 +23901,32 @@ function M.reader.new(writer, options) check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - parsers.minimally_indented_blank = check_minimal_indent * V("Blank") + parsers.minimally_indented_blank = check_minimal_indent * (parsers.blankline / "") parsers.minimally_indented_block = check_minimal_indent * V("Block") parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep * V("Block") + parsers.minimally_indented_blank_blank = check_minimal_blank_indent * (parsers.blankline / "") + + -- TODO move - needs to call check_trail + parsers.define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * (parsers.newline + parsers.eof) + parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank if breakable then - blank = blank + V("Blank") + blank = blank + (parsers.blankline / "") end - return Ct( V("Blank") + return Ct( (parsers.blankline / "") * blank^0 * parsers.minimally_indented_block * ( blank + parsers.minimally_indented_separated_block)^0 - + V("Blank") + + (parsers.blankline / "") * blank^0 + V("Block") * ( blank @@ -23917,6 +23936,7 @@ function M.reader.new(writer, options) local function add_indent(pattern, name) return Cg(Cmt( Cb("indent_info") * Ct(pattern) + * (#parsers.linechar * Cc(false) + Cc(true)) -- check if starter is blank * Cc(name), process_starter_indent), "indent_info") end @@ -23935,15 +23955,20 @@ function M.reader.new(writer, options) parsers.dig = parsers.digit end - parsers.enumerator = function(delimiter_type, interrupt) - local delimiter_range = parsers.dig * parsers.dig^-8 - if interrupt then + 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 C(parsers.leader) * Ct(C(delimiter_range) * C(delimiter_type)) - * (C(parsers.spacechar^1) + #(parsers.newline + parsers.eof)) + * allowed_end end parsers.starter = parsers.bullet(parsers.dash) @@ -23980,7 +24005,7 @@ function M.reader.new(writer, options) local references -- add a reference to the list - local function register_link(tag,url,title) + local function register_link(_,tag,url,title) references[self.normalize_tag(tag)] = { url = url, title = title } return "" end @@ -24078,9 +24103,9 @@ function M.reader.new(writer, options) parsers.interrupting_bullets = parsers.fail parsers.interrupting_enumerators = parsers.fail else - parsers.interrupting_bullets = parsers.bullet(parsers.dash) - + parsers.bullet(parsers.asterisk) - + parsers.bullet(parsers.plus) + 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) @@ -24292,35 +24317,67 @@ function M.reader.new(writer, options) parsers.tickbox = parsers.fail end + -- TODO move - copied for testing + parsers.ref_or_block = parsers.Reference + V("Block") + + parsers.minimally_indented_ref = check_minimal_indent * parsers.Reference + + parsers.minimally_indented_blank = check_minimal_indent * (parsers.blankline / "") + + parsers.minimally_indented_block = check_minimal_indent * parsers.ref_or_block + + parsers.minimally_indented_separated_block = check_minimal_indent * parsers.Reference + + check_minimal_indent / writer.interblocksep + * V("Block") + parsers.minimally_indented_non_blank = parsers.minimally_indented_block - parsers.minimally_indented_blank parsers.minimally_indented_separated_non_blank = parsers.minimally_indented_separated_block - parsers.minimally_indented_blank - parsers.list_item_tightness_condition = -#((V("Blank")^1 * (parsers.minimally_indented_block)) + parsers.list_item_tightness_condition = -#((parsers.minimally_indented_blank_blank^1 * (parsers.minimally_indented_block)) * remove_indent("li") + remove_indent("li") * parsers.fail) - parsers.indented_content_tight = Ct( V("Blank") - * -parsers.minimally_indented_non_blank + parsers.indented_content_tight = Ct( (parsers.blankline / "") + * #parsers.minimally_indented_blank_blank + * remove_indent("li") + + + (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) + * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 + * parsers.minimally_indented_blank_blank + * #parsers.minimally_indented_blank_blank * remove_indent("li") - + ( V("Blank") + + + ( (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) + * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 * parsers.minimally_indented_blank_blank^-1 + * parsers.minimally_indented_block + * (parsers.minimally_indented_separated_non_blank)^0 + + + (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) + * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 + + + (parsers.blankline / "") * (parsers.minimally_indented_non_blank) * (parsers.minimally_indented_separated_non_blank)^0 - + V("Block") + + + (parsers.blankline / "") + + + V("Block") * (parsers.minimally_indented_separated_non_blank)^0) - * parsers.list_item_tightness_condition) - - parsers.indented_content_loose = Ct( V("Blank") + * parsers.list_item_tightness_condition + ) + + parsers.indented_content_loose = Ct( parsers.blankline * (parsers.minimally_indented_non_blank) - * ( V("Blank")^0 + * ( parsers.minimally_indented_blank_blank^0 * parsers.minimally_indented_separated_non_blank^1)^0 - + V("Blank") - + V("Block") - * ( V("Blank")^0 + + parsers.blankline + + parsers.ref_or_block + * ( parsers.minimally_indented_blank_blank^0 * parsers.minimally_indented_separated_non_blank^1)^0) parsers.TightListItem = function(starter) @@ -24338,11 +24395,12 @@ function M.reader.new(writer, options) parsers.BulletListOfType = function(bullet_type) local bullet = parsers.bullet(bullet_type) - return ( Ct( parsers.TightListItem(bullet)^1) * Cc(true) - * -#(parsers.blanklines * bullet) + return ( Ct( parsers.TightListItem(bullet) + * ((check_minimal_indent / "") * parsers.TightListItem(bullet))^0) * Cc(true) + * -#((parsers.minimally_indented_blank_blank / "")^0 * check_minimal_indent * bullet) + Ct(parsers.LooseListItem(bullet) - * ((parsers.blanklines / "") - * parsers.LooseListItem(bullet))^0) * Cc(false)) + * ((parsers.minimally_indented_blank_blank / "")^0 + * (check_minimal_indent / "") * parsers.LooseListItem(bullet))^0) * Cc(false)) / writer.bulletlist end @@ -24367,10 +24425,10 @@ function M.reader.new(writer, options) local enumerator = parsers.enumerator(delimeter_type) return Cg(enumerator, "listtype") * (Ct( parsers.TightListItem(Cb("listtype")) - * parsers.TightListItem(enumerator)^0) - * Cc(true) * -#(parsers.blanklines * enumerator) + * ((check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) + * Cc(true) * -#((parsers.minimally_indented_blank_blank / "")^0 * check_minimal_indent * enumerator) + Ct( parsers.LooseListItem(Cb("listtype")) - * ((parsers.blanklines / "") * parsers.LooseListItem(enumerator))^0) + * ((parsers.minimally_indented_blank_blank / "")^0 * (check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) * Cc(false) ) * Ct(Cb("listtype")) / ordered_list end From a35e92e9164cab8160a4a2f0aa74eb797f5e6d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Thu, 23 Mar 2023 23:48:02 +0100 Subject: [PATCH 12/22] document indentation functions --- markdown.dtx | 140 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 10 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 2394314a3..1f492e174 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -23500,25 +23500,61 @@ function M.reader.new(writer, options) parsers.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 +% \end{macrocode} +% \begin{markdown} +% +% Add a trail `trail_info` to the indent table `indent_table. +% +% \end{markdown} +% \begin{macrocode} local function add_trail(indent_table, trail_info) indent_table.trail = trail_info return indent_table end +% \end{macrocode} +% \begin{markdown} +% +% Remove a trail `trail_info` from the indent table `indent_table. +% +% \end{markdown} +% \begin{macrocode} local function remove_trail(indent_table) indent_table.trail = nil return indent_table end +% \end{macrocode} +% \begin{markdown} +% +% Leave the current trail of the indent table `indent_table +% +% \end{markdown} +% \begin{macrocode} local function leave_trail(s, i, indent_table) indent_table = remove_trail(indent_table) return true, indent_table end +% \end{macrocode} +% \begin{markdown} +% +% Check if trail exists and is non-empty in the indent table `indent_table. +% +% \end{markdown} +% \begin{macrocode} local function has_trail(indent_table) return indent_table ~= nil and indent_table.trail ~= nil and next(indent_table.trail) ~= nil end +% \end{macrocode} +% \begin{markdown} +% +% Update the indent table `indent_table` by adding `increment > 0` or removing a new +% indent. Indents have properties `name` and `length`. +% +% \end{markdown} +% \begin{macrocode} local function update_indent_table(indent_table, new_indent, increment) indent_table = remove_trail(indent_table) @@ -23539,6 +23575,13 @@ function M.reader.new(writer, options) return indent_table end +% \end{macrocode} +% \begin{markdown} +% +% Remove an indent by its name `name`. +% +% \end{markdown} +% \begin{macrocode} local function remove_indent(name) local function remove_indent_level(s, i, indent_table) indent_table = update_indent_table(indent_table, {name=name}) @@ -23548,7 +23591,18 @@ function M.reader.new(writer, options) return Cg(Cmt( Cb("indent_info"), remove_indent_level), "indent_info") end - --- process indentation spacing +% \end{macrocode} +% \begin{markdown} +% +% Process the spacing of a string of spaces and tabs `spacing` with preceding indent width from +% the start of the line `indent` and strip up to `left_strip_length` spaces. Return the remainder +% `remainder` and whether there is enough spaces to produce a code `is_code`. Return how many +% spaces were stripped, as well as if the minimum was met `is_minimum` and what remainder it +% left `minimum_remainder`. +% +% \end{markdown} +% \begin{macrocode} + -- TODO simplify remainders local function process_starter_spacing(indent, spacing, minimum, left_strip_length) if (left_strip_length == nil) then @@ -23628,7 +23682,13 @@ function M.reader.new(writer, options) } end - -- count total indentation from preceding indentation levels +% \end{macrocode} +% \begin{markdown} +% +% Count the total width of all indents in the indent table `indent_table`. +% +% \end{markdown} +% \begin{macrocode} local function count_indent_tab_level(indent_table) local count = 0 if indent_table == nil or indent_table.indents == nil then @@ -23641,7 +23701,14 @@ function M.reader.new(writer, options) return count end - -- check if trail is of expected length +% \end{macrocode} +% \begin{markdown} +% +% Check if the current trail of the `indent_table` would produce code if `expect_code` is true. +% Otherwise check if it would not. If there is no trail, use the caught spacing `spacing`. +% +% \end{markdown} +% \begin{macrocode} local function check_trail_joined(s, i, indent_table, spacing, expect_code) local trail = nil local is_code = false @@ -23671,7 +23738,13 @@ function M.reader.new(writer, options) return true, "" end - -- count the total length of a delimiter +% \end{macrocode} +% \begin{markdown} +% +% Count the total width of a delimiter `delimiter`. +% +% \end{markdown} +% \begin{macrocode} local function total_delimiter_length(delimiter) local count = 0 if type(delimiter) == "string" then return #delimiter end @@ -23681,7 +23754,14 @@ function M.reader.new(writer, options) return count end - -- process container start +% \end{macrocode} +% \begin{markdown} +% +% Process the container starter `starter` of a type `indent_type`. Adjust the width of the indent +% if the delimiter is followed only by whitespace `is_blank`. +% +% \end{markdown} +% \begin{macrocode} local function process_starter_indent(s, i, indent_table, starter, is_blank, indent_type) local last_trail = starter[1] local delimiter = starter[2] @@ -23734,7 +23814,14 @@ function M.reader.new(writer, options) parsers.blockquote_opening_condition = C(parsers.leader) * C(parsers.more) * C(parsers.spacechar^0) - -- find indent pattern mapping, format +% \end{macrocode} +% \begin{markdown} +% +% Return the pattern corresponding with the indent name `name`. +% +% \end{markdown} +% \begin{macrocode} + -- TODO group indents local function decode_pattern(name) if name == "bq" then return C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0) * Cp() @@ -23745,7 +23832,14 @@ function M.reader.new(writer, options) return parsers.fail end - -- find the last start of an only blank pattern group +% \end{macrocode} +% \begin{markdown} +% +% Find the first blank-only indent of the indent table `indent_table` followed +% by blank-only indents. +% +% \end{markdown} +% \begin{macrocode} local function left_blank_starter(indent_table) local blank_starter_index = nil for i = #indent_table.indents,1,-1 do @@ -23760,7 +23854,17 @@ function M.reader.new(writer, options) return blank_starter_index end - -- apply decoded patterns iteratively, +% \end{macrocode} +% \begin{markdown} +% +% Apply the patterns decoded from the indents of the indent table `indent_table` +% iteratively starting at position `index` of the string `s`. If the `is_optional` +% match as many patterns as possible, else match all or fail. With the option `is_blank`, +% the parsing behaves as optional after the position of a blank-only indent has +% been surpassed. +% +% \end{markdown} +% \begin{macrocode} local function traverse_indent(s, index, indent_table, is_optional, blank_end) local new_index = index @@ -23861,6 +23965,14 @@ function M.reader.new(writer, options) return true, new_index, current_trail end +% \end{macrocode} +% \begin{markdown} +% +% Start traversing and checking the indents for a continuation line with the mode `is_optional` +% selected. +% +% \end{markdown} +% \begin{macrocode} local function start_traverse_indent(s, i, indent_table, is_optional) if indent_table == nil or indent_table.indents == nil then return true @@ -23875,6 +23987,14 @@ function M.reader.new(writer, options) return false end +% \end{macrocode} +% \begin{markdown} +% +% Start traversing and checking the indents for a continuation blank line with the mode `is_optional` +% selected. +% +% \end{markdown} +% \begin{macrocode} local function start_blank_indent(s, i, indent_table, is_optional) if indent_table == nil or indent_table.indents == nil then return true @@ -24421,8 +24541,8 @@ function M.reader.new(writer, options) return writer.orderedlist(items,tight,startnum) end - parsers.OrderedListOfType = function(delimeter_type) - local enumerator = parsers.enumerator(delimeter_type) + parsers.OrderedListOfType = function(delimiter_type) + local enumerator = parsers.enumerator(delimiter_type) return Cg(enumerator, "listtype") * (Ct( parsers.TightListItem(Cb("listtype")) * ((check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) From 2b78e0ed6dbe91c03ec3fb6c070603b32f1649a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 24 Mar 2023 14:17:22 +0100 Subject: [PATCH 13/22] temporary fix for link references registering --- markdown.dtx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index c3f59b93b..2675d5c4f 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24942,7 +24942,7 @@ function M.reader.new(writer, options) -- TODO move - needs to call check_trail parsers.define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon * parsers.spacechar^0 * parsers.url - * parsers.optionaltitle * (parsers.newline + parsers.eof) + * parsers.optionaltitle parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank @@ -25044,8 +25044,9 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - function self.register_link(tag, url, title, + function self.register_link(_,tag, url, title, attributes) + print(tag, url, title, attributes) tag = self.normalize_tag(tag) references[tag] = { url = url, @@ -25391,7 +25392,6 @@ end ) / writer.thematic_break parsers.Reference = parsers.define_reference_parser - * parsers.blankline^1 / self.register_link parsers.Paragraph = (check_trail / "") @@ -27324,7 +27324,6 @@ M.extensions.link_attributes = function() * Ct(parsers.attributes))^-1 local ReferenceWithAttributes = define_reference_parser - * parsers.blankline^1 / self.register_link self.update_rule("Reference", ReferenceWithAttributes) From 3d9d291b344b0c38d22bfe9161dd87a7cc4932a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Sat, 25 Mar 2023 22:09:26 +0100 Subject: [PATCH 14/22] allow reference definitions in blockquotes, clean the list reference definition mess --- markdown.dtx | 113 ++++++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 68 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 2675d5c4f..0e9fe10f1 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24937,12 +24937,23 @@ function M.reader.new(writer, options) parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep * V("Block") - parsers.minimally_indented_blank_blank = check_minimal_blank_indent * (parsers.blankline / "") + parsers.conditionally_indented_blank = check_minimal_blank_indent * (parsers.blankline / "") + + parsers.minimally_indented_ref = check_minimal_indent * V("Reference") + + parsers.minimally_indented_ref_or_block = check_minimal_indent * V("Reference") + + check_minimal_indent * V("Block") + - parsers.minimally_indented_blank + + parsers.minimally_indented_separated_ref_or_block = parsers.minimally_indented_ref + + check_minimal_indent / writer.interblocksep + * V("Block") + - parsers.minimally_indented_blank -- TODO move - needs to call check_trail parsers.define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon * parsers.spacechar^0 * parsers.url - * parsers.optionaltitle + * parsers.optionaltitle * (parsers.newline + parsers.eof) parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank @@ -24950,16 +24961,16 @@ function M.reader.new(writer, options) blank = blank + (parsers.blankline / "") end - return Ct( (parsers.blankline / "") + return Ct( (V("Reference") + (parsers.blankline / "")) * blank^0 - * parsers.minimally_indented_block + * parsers.minimally_indented_ref_or_block * ( blank - + parsers.minimally_indented_separated_block)^0 - + (parsers.blankline / "") + + parsers.minimally_indented_separated_ref_or_block)^0 + + (V("Reference") + (parsers.blankline / "")) * blank^0 + V("Block") * ( blank - + parsers.minimally_indented_separated_block)^0) + + parsers.minimally_indented_separated_ref_or_block)^0) end local function add_indent(pattern, name) @@ -25046,7 +25057,6 @@ function M.reader.new(writer, options) % \begin{macrocode} function self.register_link(_,tag, url, title, attributes) - print(tag, url, title, attributes) tag = self.normalize_tag(tag) references[tag] = { url = url, @@ -25419,68 +25429,32 @@ end parsers.tickbox = parsers.fail end - -- TODO move - copied for testing - parsers.ref_or_block = parsers.Reference + V("Block") - - parsers.minimally_indented_ref = check_minimal_indent * parsers.Reference - - parsers.minimally_indented_blank = check_minimal_indent * (parsers.blankline / "") - - parsers.minimally_indented_block = check_minimal_indent * parsers.ref_or_block - - parsers.minimally_indented_separated_block = check_minimal_indent * parsers.Reference - + check_minimal_indent / writer.interblocksep - * V("Block") - - parsers.minimally_indented_non_blank = parsers.minimally_indented_block - - parsers.minimally_indented_blank - - parsers.minimally_indented_separated_non_blank = parsers.minimally_indented_separated_block - - parsers.minimally_indented_blank - - parsers.list_item_tightness_condition = -#((parsers.minimally_indented_blank_blank^1 * (parsers.minimally_indented_block)) + parsers.list_item_tightness_condition = -#(parsers.conditionally_indented_blank^0 * parsers.minimally_indented_ref_or_block) * remove_indent("li") + remove_indent("li") - * parsers.fail) + * parsers.fail parsers.indented_content_tight = Ct( (parsers.blankline / "") - * #parsers.minimally_indented_blank_blank - * remove_indent("li") - - + (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) - * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 - * parsers.minimally_indented_blank_blank - * #parsers.minimally_indented_blank_blank + * #parsers.conditionally_indented_blank * remove_indent("li") - - + ( (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) - * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 * parsers.minimally_indented_blank_blank^-1 - * parsers.minimally_indented_block - * (parsers.minimally_indented_separated_non_blank)^0 - - + (parsers.Reference + (parsers.blankline / "") * parsers.minimally_indented_ref) - * (parsers.minimally_indented_blank_blank^-1 * parsers.minimally_indented_ref^1)^0 - - + (parsers.blankline / "") - * (parsers.minimally_indented_non_blank) - * (parsers.minimally_indented_separated_non_blank)^0 - - + (parsers.blankline / "") - + + ( (parsers.Reference + (parsers.blankline / "")) + * (parsers.minimally_indented_ref_or_block) + * (parsers.minimally_indented_separated_ref_or_block)^0 + + (parsers.Reference + (parsers.blankline / "")) + V("Block") - * (parsers.minimally_indented_separated_non_blank)^0) - - * parsers.list_item_tightness_condition - ) + * (parsers.minimally_indented_separated_ref_or_block)^0) + * parsers.list_item_tightness_condition) - parsers.indented_content_loose = Ct( parsers.blankline - * (parsers.minimally_indented_non_blank) - * ( parsers.minimally_indented_blank_blank^0 - * parsers.minimally_indented_separated_non_blank^1)^0 - + parsers.blankline - + parsers.ref_or_block - * ( parsers.minimally_indented_blank_blank^0 - * parsers.minimally_indented_separated_non_blank^1)^0) + parsers.indented_content_loose = Ct( (parsers.blankline / "") + * #parsers.conditionally_indented_blank + + ( (parsers.Reference + (parsers.blankline / "")) + * (parsers.minimally_indented_ref_or_block) + * ( parsers.conditionally_indented_blank^0 + * parsers.minimally_indented_separated_ref_or_block^1)^0 + + (parsers.Reference + (parsers.blankline / "")) + + V("Block") + * ( parsers.conditionally_indented_blank^0 + * parsers.minimally_indented_separated_ref_or_block^1)^0)) parsers.TightListItem = function(starter) return -parsers.ThematicBreak @@ -25499,9 +25473,9 @@ end local bullet = parsers.bullet(bullet_type) return ( Ct( parsers.TightListItem(bullet) * ((check_minimal_indent / "") * parsers.TightListItem(bullet))^0) * Cc(true) - * -#((parsers.minimally_indented_blank_blank / "")^0 * check_minimal_indent * bullet) + * -#((parsers.conditionally_indented_blank^0 / "") * check_minimal_indent * bullet) + Ct(parsers.LooseListItem(bullet) - * ((parsers.minimally_indented_blank_blank / "")^0 + * ((parsers.conditionally_indented_blank^0 / "") * (check_minimal_indent / "") * parsers.LooseListItem(bullet))^0) * Cc(false)) / writer.bulletlist end @@ -25528,9 +25502,9 @@ end return Cg(enumerator, "listtype") * (Ct( parsers.TightListItem(Cb("listtype")) * ((check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) - * Cc(true) * -#((parsers.minimally_indented_blank_blank / "")^0 * check_minimal_indent * enumerator) + * Cc(true) * -#((parsers.conditionally_indented_blank / "")^0 * check_minimal_indent * enumerator) + Ct( parsers.LooseListItem(Cb("listtype")) - * ((parsers.minimally_indented_blank_blank / "")^0 * (check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) + * ((parsers.conditionally_indented_blank / "")^0 * (check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) * Cc(false) ) * Ct(Cb("listtype")) / ordered_list end @@ -27319,9 +27293,12 @@ M.extensions.link_attributes = function() % \end{markdown} % \begin{macrocode} - local define_reference_parser = parsers.define_reference_parser + local define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * ( parsers.spnl * Ct(parsers.attributes))^-1 + * parsers.optionalspace * (parsers.newline + parsers.eof) local ReferenceWithAttributes = define_reference_parser / self.register_link From 93f8626ed577a83370ac777ca8638f96132b5d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Sun, 26 Mar 2023 12:01:09 +0200 Subject: [PATCH 15/22] fix global indent checking, move reference definition pattern --- markdown.dtx | 91 ++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 52 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 0e9fe10f1..c26fa4328 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24099,18 +24099,6 @@ parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1) % \par % \begin{markdown} % -%#### Helpers for Link Reference Definitions -% -% \end{markdown} -% \begin{macrocode} --- parse a reference definition: [foo]: /bar "title" -parsers.define_reference_parser = parsers.leader * parsers.tag * parsers.colon - * parsers.spacechar^0 * parsers.url - * parsers.optionaltitle -% \end{macrocode} -% \par -% \begin{markdown} -% %#### Inline Elements % % \end{markdown} @@ -24918,43 +24906,35 @@ function M.reader.new(writer, options) return false end - check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) + parsers.check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) - check_optional_indent = Cmt(Cb("indent_info") * Cc(true), start_traverse_indent) + parsers.check_optional_indent = Cmt(Cb("indent_info") * Cc(true), start_traverse_indent) - check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false), start_blank_indent) + parsers.check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false), start_blank_indent) - check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") + parsers.check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") + parsers.check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) + * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - parsers.minimally_indented_blank = check_minimal_indent * (parsers.blankline / "") + parsers.minimally_indented_blank = parsers.check_minimal_indent * (parsers.blankline / "") - parsers.minimally_indented_block = check_minimal_indent * V("Block") + parsers.minimally_indented_block = parsers.check_minimal_indent * V("Block") - parsers.minimally_indented_separated_block = check_minimal_indent / writer.interblocksep - * V("Block") + parsers.minimally_indented_ref = parsers.check_minimal_indent * V("Reference") - parsers.conditionally_indented_blank = check_minimal_blank_indent * (parsers.blankline / "") + parsers.conditionally_indented_blank = parsers.check_minimal_blank_indent * (parsers.blankline / "") - parsers.minimally_indented_ref = check_minimal_indent * V("Reference") - - parsers.minimally_indented_ref_or_block = check_minimal_indent * V("Reference") - + check_minimal_indent * V("Block") + parsers.minimally_indented_ref_or_block = parsers.minimally_indented_ref + + parsers.minimally_indented_block - parsers.minimally_indented_blank parsers.minimally_indented_separated_ref_or_block = parsers.minimally_indented_ref - + check_minimal_indent / writer.interblocksep + + parsers.check_minimal_indent / writer.interblocksep * V("Block") - parsers.minimally_indented_blank - -- TODO move - needs to call check_trail - parsers.define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon - * parsers.spacechar^0 * parsers.url - * parsers.optionaltitle * (parsers.newline + parsers.eof) - parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank if breakable then @@ -25044,6 +25024,10 @@ function M.reader.new(writer, options) -- List of references defined in the document local references + parsers.define_reference_parser = (parsers.check_trail / "") * parsers.tag * parsers.colon + * parsers.spacechar^0 * parsers.url + * parsers.optionaltitle * (parsers.newline + parsers.eof) + % \end{macrocode} % \par % \begin{markdown} @@ -25224,9 +25208,9 @@ function M.reader.new(writer, options) + parsers.headerstart parsers.Endline = parsers.newline - * (check_minimal_indent + * (parsers.check_minimal_indent * -V("EndlineExceptions") - + check_optional_indent + + parsers.check_optional_indent * -V("EndlineExceptions") * -parsers.starter) * parsers.spacechar^0 @@ -25248,9 +25232,9 @@ function M.reader.new(writer, options) parsers.NonbreakingEndline = parsers.newline - * (check_minimal_indent + * (parsers.check_minimal_indent * -V("EndlineExceptions") - + check_optional_indent + + parsers.check_optional_indent * -V("EndlineExceptions") * -parsers.starter) * parsers.spacechar^0 @@ -25384,10 +25368,10 @@ end parsers.indented_non_blank_line = parsers.indentedline - parsers.blankline parsers.Verbatim = Cs( - check_code_trail + parsers.check_code_trail * (parsers.line - parsers.blankline) - * (((check_minimal_blank_indent / "") * parsers.blankline)^0 - * ((check_minimal_indent / "") * check_code_trail * (parsers.line - parsers.blankline))^1)^0 + * (((parsers.check_minimal_blank_indent / "") * parsers.blankline)^0 + * ((parsers.check_minimal_indent / "") * parsers.check_code_trail * (parsers.line - parsers.blankline))^1)^0 ) / self.expandtabs / writer.verbatim parsers.BlockquoteExceptions = parsers.leader * parsers.more @@ -25404,7 +25388,7 @@ end parsers.Reference = parsers.define_reference_parser / self.register_link - parsers.Paragraph = (check_trail / "") + parsers.Paragraph = (parsers.check_trail / "") * (Ct((parsers.Inline)^1) * (parsers.newline + parsers.eof) / writer.paragraph) @@ -25472,11 +25456,11 @@ end parsers.BulletListOfType = function(bullet_type) local bullet = parsers.bullet(bullet_type) return ( Ct( parsers.TightListItem(bullet) - * ((check_minimal_indent / "") * parsers.TightListItem(bullet))^0) * Cc(true) - * -#((parsers.conditionally_indented_blank^0 / "") * check_minimal_indent * bullet) + * ((parsers.check_minimal_indent / "") * parsers.TightListItem(bullet))^0) * Cc(true) + * -#((parsers.conditionally_indented_blank^0 / "") * parsers.check_minimal_indent * bullet) + Ct(parsers.LooseListItem(bullet) * ((parsers.conditionally_indented_blank^0 / "") - * (check_minimal_indent / "") * parsers.LooseListItem(bullet))^0) * Cc(false)) + * (parsers.check_minimal_indent / "") * parsers.LooseListItem(bullet))^0) * Cc(false)) / writer.bulletlist end @@ -25501,10 +25485,13 @@ end local enumerator = parsers.enumerator(delimiter_type) return Cg(enumerator, "listtype") * (Ct( parsers.TightListItem(Cb("listtype")) - * ((check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) - * Cc(true) * -#((parsers.conditionally_indented_blank / "")^0 * check_minimal_indent * enumerator) + * ((parsers.check_minimal_indent / "") * parsers.TightListItem(enumerator))^0) + * Cc(true) + * -#((parsers.conditionally_indented_blank^0 / "") + * parsers.check_minimal_indent * enumerator) + Ct( parsers.LooseListItem(Cb("listtype")) - * ((parsers.conditionally_indented_blank / "")^0 * (check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) + * ((parsers.conditionally_indented_blank^0 / "") + * (parsers.check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0) * Cc(false) ) * Ct(Cb("listtype")) / ordered_list end @@ -25543,7 +25530,7 @@ end * Ct(parsers.linechar^1 / self.parser_functions.parse_inlines) * parsers.newline - * check_minimal_indent * parsers.heading_level + * parsers.check_minimal_indent * parsers.heading_level * parsers.optionalspace * parsers.newline / writer.heading @@ -26893,8 +26880,8 @@ M.extensions.fenced_code = function(blank_before_code_fence, local BacktickFencedCode = fencehead(parsers.backtick, backtick_infostring) - * Cs(((check_minimal_blank_indent / "") * parsers.blankline + (check_minimal_indent / "") * fencedline(parsers.backtick))^0) - * ((check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed) + * Cs(((parsers.check_minimal_blank_indent / "") * parsers.blankline + (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 @@ -27293,7 +27280,7 @@ M.extensions.link_attributes = function() % \end{markdown} % \begin{macrocode} - local define_reference_parser = (check_trail / "") * parsers.tag * parsers.colon + local define_reference_parser = (parsers.check_trail / "") * parsers.tag * parsers.colon * parsers.spacechar^0 * parsers.url * parsers.optionaltitle * ( parsers.spnl From 7fb16c7482b24aa5f98ecef3c37ce5e2b21f11ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Mon, 27 Mar 2023 22:40:26 +0200 Subject: [PATCH 16/22] fix wording in indentation docs --- markdown.dtx | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index c26fa4328..81b1e7599 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24436,7 +24436,7 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Check if trail exists and is non-empty in the indent table `indent_table. +% Check if a trail exists and is non-empty in the indent table `indent_table. % % \end{markdown} % \begin{macrocode} @@ -24447,12 +24447,12 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Update the indent table `indent_table` by adding `increment > 0` or removing a new -% indent. Indents have properties `name` and `length`. +% Update the indent table `indent_table` by adding or removing a new +% indent `add`. % % \end{markdown} % \begin{macrocode} - local function update_indent_table(indent_table, new_indent, increment) + local function update_indent_table(indent_table, new_indent, add) indent_table = remove_trail(indent_table) if indent_table.indents == nil then @@ -24461,7 +24461,7 @@ function M.reader.new(writer, options) local indent_table_indents = indent_table.indents - if increment ~= nil and increment > 0 then + 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 @@ -24481,7 +24481,7 @@ function M.reader.new(writer, options) % \begin{macrocode} local function remove_indent(name) local function remove_indent_level(s, i, indent_table) - indent_table = update_indent_table(indent_table, {name=name}) + indent_table = update_indent_table(indent_table, {name=name}, false) return true, indent_table end @@ -24499,7 +24499,6 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - -- TODO simplify remainders local function process_starter_spacing(indent, spacing, minimum, left_strip_length) if (left_strip_length == nil) then @@ -24602,7 +24601,7 @@ function M.reader.new(writer, options) % \begin{markdown} % % Check if the current trail of the `indent_table` would produce code if `expect_code` is true. -% Otherwise check if it would not. If there is no trail, use the caught spacing `spacing`. +% Otherwise check if it would not. If there is no trail, use the current spacing `spacing`. % % \end{markdown} % \begin{macrocode} @@ -24655,7 +24654,7 @@ function M.reader.new(writer, options) % \begin{markdown} % % Process the container starter `starter` of a type `indent_type`. Adjust the width of the indent -% if the delimiter is followed only by whitespace `is_blank`. +% if the delimiter is followed only by whitespaces `is_blank`. % % \end{markdown} % \begin{macrocode} @@ -24702,7 +24701,7 @@ function M.reader.new(writer, options) local indent_length = last_trail_length + delimiter_length + del_trail_length local new_indent_info = {name=indent_type, length=indent_length} - local indent_table = update_indent_table(indent_table, new_indent_info, 1) + local indent_table = update_indent_table(indent_table, new_indent_info, true) local new_trail = {is_code=sp.is_code, remainder=sp.remainder} indent_table = add_trail(indent_table, new_trail) @@ -24718,7 +24717,6 @@ function M.reader.new(writer, options) % % \end{markdown} % \begin{macrocode} - -- TODO group indents local function decode_pattern(name) if name == "bq" then return C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0) * Cp() @@ -24756,9 +24754,9 @@ function M.reader.new(writer, options) % % Apply the patterns decoded from the indents of the indent table `indent_table` % iteratively starting at position `index` of the string `s`. If the `is_optional` -% match as many patterns as possible, else match all or fail. With the option `is_blank`, -% the parsing behaves as optional after the position of a blank-only indent has -% been surpassed. +% mode is selected, match as many patterns as possible, else match all or fail. +% With the option `is_blank`, the parsing behaves as optional after the position +% of a blank-only indent has been surpassed. % % \end{markdown} % \begin{macrocode} @@ -24865,8 +24863,8 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Start traversing and checking the indents for a continuation line with the mode `is_optional` -% selected. +% Start traversing and checking the indents for a continuation line, optionally with +% the mode `is_optional` selected. % % \end{markdown} % \begin{macrocode} @@ -24887,8 +24885,8 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Start traversing and checking the indents for a continuation blank line with the mode `is_optional` -% selected. +% Start traversing and checking the indents for a continuation blank line, optionally with +% the mode `is_optional` selected. % % \end{markdown} % \begin{macrocode} From 1751123a26ca059f1dea2abd6ab7ee740e9df188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Tue, 28 Mar 2023 21:13:45 +0200 Subject: [PATCH 17/22] fix fence code start indent propagation, add docs to indentation parsers, fix trail leaving --- markdown.dtx | 141 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 43 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 81b1e7599..ff5880d02 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24397,6 +24397,17 @@ function M.reader.new(writer, options) parsers.blockquote_start = parsers.leader * parsers.more * parsers.space^-1 +% \end{macrocode} +% \begin{markdown} +% +% Check if a trail exists and is non-empty in the indent table `indent_table. +% +% \end{markdown} +% \begin{macrocode} + function has_trail(indent_table) + return indent_table ~= nil and indent_table.trail ~= nil and next(indent_table.trail) ~= nil + end + % \end{macrocode} % \begin{markdown} % @@ -24433,17 +24444,6 @@ function M.reader.new(writer, options) return true, indent_table end -% \end{macrocode} -% \begin{markdown} -% -% Check if a trail exists and is non-empty in the indent table `indent_table. -% -% \end{markdown} -% \begin{macrocode} - local function has_trail(indent_table) - return indent_table ~= nil and indent_table.trail ~= nil and next(indent_table.trail) ~= nil - end - % \end{macrocode} % \begin{markdown} % @@ -24631,7 +24631,7 @@ function M.reader.new(writer, options) return false end - return true, "" + return true, remainder end % \end{macrocode} @@ -24904,18 +24904,32 @@ function M.reader.new(writer, options) return false end +% \end{macrocode} +% \begin{markdown} +% +% The following patterns check whitespace indentation at the start of a block. +% +% \end{markdown} +% \begin{macrocode} + parsers.leave_trail = Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") + + parsers.check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) + + parsers.check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) + +% \end{macrocode} +% \begin{markdown} +% +% The following patterns check indentation in continuation lines as defined by the container start. +% +% \end{markdown} +% \begin{macrocode} parsers.check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), start_traverse_indent) parsers.check_optional_indent = Cmt(Cb("indent_info") * Cc(true), start_traverse_indent) parsers.check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false), start_blank_indent) - parsers.check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - - parsers.check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined) - * Cg(Cmt(Cb("indent_info"), leave_trail), "indent_info") - parsers.minimally_indented_blank = parsers.check_minimal_indent * (parsers.blankline / "") parsers.minimally_indented_block = parsers.check_minimal_indent * V("Block") @@ -24933,6 +24947,14 @@ function M.reader.new(writer, options) * V("Block") - parsers.minimally_indented_blank +% \end{macrocode} +% \begin{markdown} +% +% The following pattern parses the properly indented content that follows the initial container start, +% optionally with blank lines allowed `breakable`. +% +% \end{markdown} +% \begin{macrocode} parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank if breakable then @@ -25025,6 +25047,7 @@ function M.reader.new(writer, options) parsers.define_reference_parser = (parsers.check_trail / "") * parsers.tag * parsers.colon * parsers.spacechar^0 * parsers.url * parsers.optionaltitle * (parsers.newline + parsers.eof) + * parsers.leave_trail % \end{macrocode} % \par @@ -25389,6 +25412,7 @@ end parsers.Paragraph = (parsers.check_trail / "") * (Ct((parsers.Inline)^1) * (parsers.newline + parsers.eof) + * parsers.leave_trail / writer.paragraph) parsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1) @@ -26835,12 +26859,30 @@ M.extensions.fenced_code = function(blank_before_code_fence, + parsers.spacechar^1 * parsers.newline))^0) local fenceindent + + local function get_last_indent_name(indent_table) + if indent_table ~= nil and indent_table.indents ~= nil then + return indent_table.indents[#indent_table.indents].name + end + return + end + + local function count_fenced_start_indent(s, i, 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 * (parsers.newline + parsers.eof) + * parsers.leave_trail end local fencetail = function(char) @@ -26850,35 +26892,46 @@ M.extensions.fenced_code = function(blank_before_code_fence, + 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) + local trail = "" + if has_trail(indent_table) then + trail = indent_table.trail.internal_remainder + end + + local str = trail .. 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)), process_fenced_line) end local TildeFencedCode = fencehead(parsers.tilde, tilde_infostring) - * Cs(fencedline(parsers.tilde)^0) - * fencetail(parsers.tilde) + * Cs(((parsers.check_minimal_blank_indent / "") * parsers.blankline + + (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(((parsers.check_minimal_blank_indent / "") * parsers.blankline + (parsers.check_minimal_indent / "") * fencedline(parsers.backtick))^0) + * Cs(((parsers.check_minimal_blank_indent / "") * parsers.blankline + + (parsers.check_minimal_indent / "") * fencedline(parsers.backtick))^0) * ((parsers.check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed) local infostring_with_attributes @@ -26889,7 +26942,7 @@ M.extensions.fenced_code = function(blank_before_code_fence, * Ct(parsers.attributes)) local FencedCode - = (TildeFencedCode + BacktickFencedCode) + = ((TildeFencedCode + BacktickFencedCode) / function(infostring, code) local expanded_code = self.expandtabs(code) @@ -26910,7 +26963,8 @@ M.extensions.fenced_code = function(blank_before_code_fence, end end return writer.fencedCode(expanded_code, infostring, attr) - end + end) + * parsers.leave_trail self.insert_pattern("Block after Verbatim", FencedCode, "FencedCode") @@ -27284,6 +27338,7 @@ M.extensions.link_attributes = function() * ( parsers.spnl * Ct(parsers.attributes))^-1 * parsers.optionalspace * (parsers.newline + parsers.eof) + * parsers.leave_trail local ReferenceWithAttributes = define_reference_parser / self.register_link From ba687e8944f25fb051b2fe914a561248b0a77654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Wed, 29 Mar 2023 09:25:33 +0200 Subject: [PATCH 18/22] fix nested breakable blockquotes --- markdown.dtx | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index ff5880d02..8aee85c16 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24408,6 +24408,17 @@ function M.reader.new(writer, options) return indent_table ~= nil and indent_table.trail ~= nil and next(indent_table.trail) ~= nil end +% \end{macrocode} +% \begin{markdown} +% +% Check if indent table `indent_table` has any indents. +% +% \end{markdown} +% \begin{macrocode} + function has_indents(indent_table) + return indent_table ~= nil and indent_table.indents ~= nil and next(indent_table.indents) ~= nil + end + % \end{macrocode} % \begin{markdown} % @@ -24455,7 +24466,7 @@ function M.reader.new(writer, options) local function update_indent_table(indent_table, new_indent, add) indent_table = remove_trail(indent_table) - if indent_table.indents == nil then + if not has_indents(indent_table) then indent_table.indents = {} end @@ -24587,7 +24598,7 @@ function M.reader.new(writer, options) % \begin{macrocode} local function count_indent_tab_level(indent_table) local count = 0 - if indent_table == nil or indent_table.indents == nil then + if not has_indents(indent_table) then return count end @@ -24606,9 +24617,9 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function check_trail_joined(s, i, indent_table, spacing, expect_code) - local trail = nil + local trail local is_code = false - local remainder = nil + local remainder if has_trail(indent_table) then trail = indent_table.trail @@ -24684,7 +24695,7 @@ function M.reader.new(writer, options) local total_indent_level = preceding_indentation + last_trail_length + delimiter_length - local sp = nil + local sp if not is_blank then sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) else @@ -24736,7 +24747,12 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function left_blank_starter(indent_table) - local blank_starter_index = nil + local blank_starter_index + + if not has_indents(indent_table) then + return + end + for i = #indent_table.indents,1,-1 do local value = indent_table.indents[i] if value.name == "li" then @@ -24766,7 +24782,7 @@ function M.reader.new(writer, options) local preceding_indentation = 0 local current_trail = {} - if indent_table.indents == nil then + if not has_indents(indent_table) then return true, new_index, current_trail end @@ -24869,7 +24885,7 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function start_traverse_indent(s, i, indent_table, is_optional) - if indent_table == nil or indent_table.indents == nil then + if not has_indents(indent_table) then return true end @@ -24891,7 +24907,7 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function start_blank_indent(s, i, indent_table, is_optional) - if indent_table == nil or indent_table.indents == nil then + if not has_indents(indent_table) then return true end @@ -24958,7 +24974,7 @@ function M.reader.new(writer, options) parsers.indented_content = function(breakable) local blank = parsers.minimally_indented_blank if breakable then - blank = blank + (parsers.blankline / "") + blank = blank + parsers.check_optional_indent * (parsers.blankline / "") end return Ct( (V("Reference") + (parsers.blankline / "")) @@ -25016,6 +25032,7 @@ function M.reader.new(writer, options) + parsers.bullet(parsers.plus) + parsers.enumerator(parsers.period) + parsers.enumerator(parsers.rparent) + % \end{macrocode} % \par % \begin{markdown} @@ -25025,8 +25042,8 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} parsers.blockquote_body = add_indent(parsers.blockquote_opening_condition, "bq") - * parsers.indented_content(false) - * remove_indent("bq") + * parsers.indented_content(false) + * remove_indent("bq") if not options.breakableBlockquotes then parsers.blockquote_body = add_indent(parsers.blockquote_opening_condition, "bq") @@ -26861,7 +26878,7 @@ M.extensions.fenced_code = function(blank_before_code_fence, local fenceindent local function get_last_indent_name(indent_table) - if indent_table ~= nil and indent_table.indents ~= nil then + if has_indents(indent_table) then return indent_table.indents[#indent_table.indents].name end return From e240a89e709fe81c73e85b7b9533a9f1053cd470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Wed, 29 Mar 2023 16:22:31 +0200 Subject: [PATCH 19/22] refactor returns --- markdown.dtx | 80 +++++++++++++++++++--------------------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 8aee85c16..48268ad53 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24608,43 +24608,6 @@ function M.reader.new(writer, options) return count end -% \end{macrocode} -% \begin{markdown} -% -% Check if the current trail of the `indent_table` would produce code if `expect_code` is true. -% Otherwise check if it would not. If there is no trail, use the current spacing `spacing`. -% -% \end{markdown} -% \begin{macrocode} - local function check_trail_joined(s, i, indent_table, spacing, expect_code) - local trail - local is_code = false - local remainder - - if has_trail(indent_table) then - trail = indent_table.trail - is_code = trail.is_code - remainder = trail.remainder - else - local sp = process_starter_spacing(0, spacing, 0, 0) - is_code = sp.is_code - remainder = sp.remainder - end - - if expect_code then - if is_code then - return true, remainder - end - return false - end - - if is_code then - return false - end - - return true, remainder - end - % \end{macrocode} % \begin{markdown} % @@ -24795,10 +24758,7 @@ function M.reader.new(writer, options) -- match decoded pattern local new_indent_info = lpeg.match(Ct(pattern), s, new_index) if new_indent_info == nil then - if is_optional then - return true, new_index, current_trail - end - return false + return is_optional, new_index, current_trail end local raw_last_trail = new_indent_info[1] @@ -24814,10 +24774,7 @@ function M.reader.new(writer, options) if current_trail ~= nil then if delimiter ~= "" and current_trail.is_code then - if is_optional then - return true, new_index, current_trail - end - return false + return is_optional, new_index, current_trail end if current_trail.internal_remainder ~= nil then raw_last_trail = current_trail.internal_remainder @@ -24849,12 +24806,7 @@ function M.reader.new(writer, options) local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length) if delimiter == "" and not sp.is_minimum then - if is_optional - or (blank_end and blank_starter <= i) - then - return true, new_index, current_trail - end - return false + return is_optional or (blank_end and blank_starter <= i), new_index, current_trail end local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped @@ -24920,6 +24872,32 @@ function M.reader.new(writer, options) return false end +% \end{macrocode} +% \begin{markdown} +% +% Check if the current trail of the `indent_table` would produce code if it is expected `expect_code` +% or it would not if it is not. If there is no trail, process and check the current spacing `spacing`. +% +% \end{markdown} +% \begin{macrocode} + local function check_trail_joined(s, i, indent_table, spacing, expect_code) + local is_code = false + local remainder + + if has_trail(indent_table) then + local trail = indent_table.trail + is_code = trail.is_code + remainder = trail.remainder + else + local sp = process_starter_spacing(0, spacing, 0, 0) + is_code = sp.is_code + remainder = sp.remainder + end + + local result = (expect_code and is_code) or (not expect_code and not is_code) + return result, remainder + end + % \end{macrocode} % \begin{markdown} % From fd0010ca80eb93a208d111a5484f174895fd8765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Wed, 29 Mar 2023 17:52:21 +0200 Subject: [PATCH 20/22] fix starter continuation, simplify value assignments --- markdown.dtx | 79 +++++++++++++++++++--------------------------------- 1 file changed, 29 insertions(+), 50 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 48268ad53..a607311bf 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24511,24 +24511,16 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function process_starter_spacing(indent, spacing, minimum, left_strip_length) - - if (left_strip_length == nil) then - left_strip_length = 0 - end + left_strip_length = left_strip_length or 0 local count = 0 local tab_value = 4 - (indent) % 4 - local code_started = false - local code_start = "" - - local minimum_found = false - local minimum_remainder = "" + local code_started, minimum_found = false, false + local code_start, minimum_remainder = "", "" local left_total_stripped = 0 - local raw_full_remainder = "" - if spacing ~= nil then for i = 1, #spacing do local character = spacing:sub(i, i) @@ -24536,8 +24528,7 @@ function M.reader.new(writer, options) if character == "\t" then count = count + tab_value tab_value = 4 - end - if character == " " then + elseif character == " " then count = count + 1 tab_value = 4 - (1 - tab_value) % 4 end @@ -24547,26 +24538,20 @@ function M.reader.new(writer, options) count = count - possible_to_strip left_strip_length = left_strip_length - possible_to_strip left_total_stripped = left_total_stripped + possible_to_strip - else - raw_full_remainder = raw_full_remainder .. character end if (minimum_found) then minimum_remainder = minimum_remainder .. character - else - if (count >= minimum) then - minimum_found = true - minimum_remainder = minimum_remainder .. string.rep(" ", count - minimum) - end + elseif (count >= minimum) then + minimum_found = true + minimum_remainder = minimum_remainder .. string.rep(" ", count - minimum) end if (code_started) then code_start = code_start .. character - else - if (count >= minimum + 4) then - code_started = true - code_start = code_start .. string.rep(" ", count - (minimum + 4)) - end + elseif (count >= minimum + 4) then + code_started = true + code_start = code_start .. string.rep(" ", count - (minimum + 4)) end end end @@ -24583,7 +24568,6 @@ function M.reader.new(writer, options) is_code = code_started, remainder = remainder, left_total_stripped = left_total_stripped, - raw_full_remainder = raw_full_remainder, is_minimum = is_minimum, minimum_remainder = minimum_remainder } @@ -24658,11 +24642,9 @@ function M.reader.new(writer, options) local total_indent_level = preceding_indentation + last_trail_length + delimiter_length - local sp + local sp = {} if not is_blank then sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1) - else - sp = {} end local del_trail_length = sp.left_total_stripped @@ -24675,9 +24657,8 @@ function M.reader.new(writer, options) local indent_length = last_trail_length + delimiter_length + del_trail_length local new_indent_info = {name=indent_type, length=indent_length} - local indent_table = update_indent_table(indent_table, new_indent_info, true) - local new_trail = {is_code=sp.is_code, remainder=sp.remainder} - indent_table = add_trail(indent_table, new_trail) + 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}) return true, indent_table end @@ -24692,13 +24673,12 @@ function M.reader.new(writer, options) % \end{markdown} % \begin{macrocode} local function decode_pattern(name) + local delimeter = parsers.succeed if name == "bq" then - return C(parsers.spacechar^0) * C(parsers.more) * C(parsers.spacechar^0) * Cp() + delimeter = parsers.more end - if name == "li" then - return C(parsers.spacechar^0) * Cc("") * Cc("") * Cp() - end - return parsers.fail + + return C(parsers.optionalspace) * C(delimeter) * C(parsers.optionalspace) * Cp() end % \end{macrocode} @@ -24743,7 +24723,7 @@ function M.reader.new(writer, options) local new_index = index local preceding_indentation = 0 - local current_trail = {} + local current_trail if not has_indents(indent_table) then return true, new_index, current_trail @@ -24764,16 +24744,18 @@ function M.reader.new(writer, options) local raw_last_trail = new_indent_info[1] local delimiter = new_indent_info[2] local raw_new_trail = new_indent_info[3] - local possible_next_index = new_indent_info[4] + local next_index = new_indent_info[4] + + local space_only = delimiter == "" -- check previous trail - if delimiter ~= "" and current_trail == nil then + if not space_only and 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} end if current_trail ~= nil then - if delimiter ~= "" and current_trail.is_code 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 @@ -24784,7 +24766,7 @@ function M.reader.new(writer, options) local raw_last_trail_length = 0 local delimiter_length = 0 - if delimiter ~= "" then + if not space_only then delimiter_length = #delimiter raw_last_trail_length = #raw_last_trail end @@ -24795,7 +24777,7 @@ function M.reader.new(writer, options) local minimum = 0 local left_strip_length = 0 - if delimiter ~= "" then + if not space_only then spacing_to_process = raw_new_trail left_strip_length = 1 else @@ -24805,24 +24787,21 @@ function M.reader.new(writer, options) local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length) - if delimiter == "" and not sp.is_minimum then + if space_only and not sp.is_minimum then return is_optional or (blank_end and blank_starter <= i), new_index, current_trail end local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped -- update info for the next pattern - local next_trail = {} - if delimiter ~= "" then + if not space_only then preceding_indentation = preceding_indentation + indent_length - next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} else preceding_indentation = preceding_indentation + value.length - next_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} end - current_trail = next_trail - new_index = possible_next_index + current_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder} + new_index = next_index end return true, new_index, current_trail From 88fbdba8c75c04f5abb81c2dea35256dc12ebc79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Fri, 31 Mar 2023 21:36:48 +0200 Subject: [PATCH 21/22] fix formatting --- markdown.dtx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index a607311bf..e4e692da7 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -24400,7 +24400,7 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Check if a trail exists and is non-empty in the indent table `indent_table. +% Check if a trail exists and is non-empty in the indent table `indent_table`. % % \end{markdown} % \begin{macrocode} @@ -24422,7 +24422,7 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Add a trail `trail_info` to the indent table `indent_table. +% Add a trail `trail_info` to the indent table `indent_table`. % % \end{markdown} % \begin{macrocode} @@ -24434,7 +24434,7 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Remove a trail `trail_info` from the indent table `indent_table. +% Remove a trail `trail_info` from the indent table `indent_table`. % % \end{markdown} % \begin{macrocode} @@ -24446,7 +24446,7 @@ function M.reader.new(writer, options) % \end{macrocode} % \begin{markdown} % -% Leave the current trail of the indent table `indent_table +% Leave the current trail of the indent table `indent_table` % % \end{markdown} % \begin{macrocode} @@ -25409,7 +25409,8 @@ end parsers.tickbox = parsers.fail end - parsers.list_item_tightness_condition = -#(parsers.conditionally_indented_blank^0 * parsers.minimally_indented_ref_or_block) + parsers.list_item_tightness_condition = -#( parsers.conditionally_indented_blank^0 + * parsers.minimally_indented_ref_or_block) * remove_indent("li") + remove_indent("li") * parsers.fail From bda84c350fa810f9017f174d5ec21cc0b479fe80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrej=20Gen=C4=8Dur?= Date: Sat, 1 Apr 2023 10:53:45 +0200 Subject: [PATCH 22/22] remove duplicated code from merging --- markdown.dtx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/markdown.dtx b/markdown.dtx index 47fad6165..db3955193 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -7754,14 +7754,12 @@ defaultOptions.pipeTables = false #### Option `preserveTabs` -`preserveTabs` (default value: `true`) `preserveTabs` (default value: `true`) % \fi % \begin{markdown} % % \Optitem[true]{preserveTabs}{\opt{true}, \opt{false}} -% \Optitem[true]{preserveTabs}{\opt{true}, \opt{false}} % : true @@ -7781,7 +7779,6 @@ defaultOptions.pipeTables = false { preserveTabs } { boolean } { true } - { true } % \end{macrocode} % \iffalse % @@ -7789,7 +7786,6 @@ defaultOptions.pipeTables = false % \fi % \begin{macrocode} defaultOptions.preserveTabs = true -defaultOptions.preserveTabs = true % \end{macrocode} % \par % \iffalse