diff options
author | Karl Berry <karl@freefriends.org> | 2023-02-02 21:15:03 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2023-02-02 21:15:03 +0000 |
commit | dcd4b33437ee2d76762844fd5b757285a0495900 (patch) | |
tree | 1f7ede581dffb07f22b683e1cdb16e62b1b871d1 /Master/texmf-dist/tex/luatex | |
parent | bfbe2870d22742db03085257b26f5d5ea9d23e5f (diff) |
markdown (2feb23)
git-svn-id: svn://tug.org/texlive/trunk@65715 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r-- | Master/texmf-dist/tex/luatex/markdown/markdown.lua | 400 |
1 files changed, 237 insertions, 163 deletions
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 8a5a6ce9f56..4d5a96e56cb 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -58,7 +58,7 @@ -- those in the standard .ins files. -- local metadata = { - version = "2.19.0-0-g80fcf20", + version = "2.20.0-0-gf64ade1", comment = "A module for the conversion from markdown to plain TeX", author = "John MacFarlane, Hans Hagen, Vít Novotný", copyright = {"2009-2016 John MacFarlane, Hans Hagen", @@ -135,6 +135,7 @@ metadata.grammar_version = 2 defaultOptions.extensions = {} defaultOptions.fancyLists = false defaultOptions.fencedCode = false +defaultOptions.fencedCodeAttributes = false defaultOptions.fencedDivs = false defaultOptions.finalizeCache = false defaultOptions.frozenCacheCounter = 0 @@ -146,6 +147,7 @@ defaultOptions.hybrid = false defaultOptions.inlineFootnotes = false defaultOptions.inlineNotes = false defaultOptions.jekyllData = false +defaultOptions.lineBlocks = false defaultOptions.footnotes = false defaultOptions.notes = false defaultOptions.pipeTables = false @@ -192,7 +194,6 @@ function util.cache(dir, string, salt, transform, suffix) return name end function util.cache_verbatim(dir, string) - string = string:gsub('[\r\n%s]*$', '') local name = util.cache(dir, string, nil, nil, ".verbatim") return name end @@ -2411,7 +2412,7 @@ function M.writer.new(options) return s end function self.pack(name) - return [[\input ]] .. name .. [[\relax]] + return [[\input{]] .. name .. [[}\relax]] end function self.interblocksep() if not self.is_writing then return "" end @@ -2423,31 +2424,35 @@ function M.writer.new(options) if not self.is_writing then return "" end return "\\markdownRendererThematicBreak{}" end - self.escaped_uri_chars = { - ["{"] = "\\markdownRendererLeftBrace{}", - ["}"] = "\\markdownRendererRightBrace{}", - ["\\"] = "\\markdownRendererBackslash{}", - } - self.escaped_minimal_strings = { - ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", - ["☒"] = "\\markdownRendererTickedBox{}", - ["⌛"] = "\\markdownRendererHalfTickedBox{}", - ["☐"] = "\\markdownRendererUntickedBox{}", - } + self.escaped_uri_chars = { + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["\\"] = "\\markdownRendererBackslash{}", + } + self.escaped_minimal_strings = { + ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ", + ["☒"] = "\\markdownRendererTickedBox{}", + ["⌛"] = "\\markdownRendererHalfTickedBox{}", + ["☐"] = "\\markdownRendererUntickedBox{}", + [entities.hex_entity('FFFD')] = "\\markdownRendererReplacementCharacter{}", + } + self.escaped_strings = util.table_copy(self.escaped_minimal_strings) + self.escaped_strings[entities.hex_entity('00A0')] = self.nbsp self.escaped_chars = { - ["{"] = "\\markdownRendererLeftBrace{}", - ["}"] = "\\markdownRendererRightBrace{}", - ["%"] = "\\markdownRendererPercentSign{}", - ["\\"] = "\\markdownRendererBackslash{}", - ["#"] = "\\markdownRendererHash{}", - ["$"] = "\\markdownRendererDollarSign{}", - ["&"] = "\\markdownRendererAmpersand{}", - ["_"] = "\\markdownRendererUnderscore{}", - ["^"] = "\\markdownRendererCircumflex{}", - ["~"] = "\\markdownRendererTilde{}", - ["|"] = "\\markdownRendererPipe{}", - } - self.escape = util.escaper(self.escaped_chars, self.escaped_minimal_strings) + ["{"] = "\\markdownRendererLeftBrace{}", + ["}"] = "\\markdownRendererRightBrace{}", + ["%"] = "\\markdownRendererPercentSign{}", + ["\\"] = "\\markdownRendererBackslash{}", + ["#"] = "\\markdownRendererHash{}", + ["$"] = "\\markdownRendererDollarSign{}", + ["&"] = "\\markdownRendererAmpersand{}", + ["_"] = "\\markdownRendererUnderscore{}", + ["^"] = "\\markdownRendererCircumflex{}", + ["~"] = "\\markdownRendererTilde{}", + ["|"] = "\\markdownRendererPipe{}", + [entities.hex_entity('0000')] = "\\markdownRendererReplacementCharacter{}", + } + self.escape = util.escaper(self.escaped_chars, self.escaped_strings) self.escape_uri = util.escaper(self.escaped_uri_chars, self.escaped_minimal_strings) self.escape_minimal = util.escaper({}, self.escaped_minimal_strings) if options.hybrid then @@ -2557,6 +2562,7 @@ function M.writer.new(options) end function self.verbatim(s) if not self.is_writing then return "" end + s = s:gsub("\n$", "") local name = util.cache_verbatim(options.cacheDir, s) return {"\\markdownRendererInputVerbatim{",name,"}"} end @@ -2882,6 +2888,13 @@ parsers.attributes = parsers.lbrace * parsers.optionalspace * parsers.rbrace +parsers.raw_attribute = parsers.lbrace + * parsers.optionalspace + * parsers.equal + * C(parsers.attribute_key) + * parsers.optionalspace + * parsers.rbrace + -- block followed by 0 or more optionally -- indented blocks with first line indented. parsers.indented_blocks = function(bl) @@ -2928,65 +2941,6 @@ parsers.intickschar = (parsers.any - S(" \n\r`")) parsers.inticks = parsers.openticks * parsers.space^-1 * C(parsers.intickschar^0) * parsers.closeticks -local function captures_geq_length(_,i,a,b) - return #a >= #b and i -end - -parsers.tilde_infostring - = C((parsers.linechar - - (parsers.spacechar^1 * parsers.newline))^0) - * parsers.optionalspace - * (parsers.newline + parsers.eof) - -parsers.backtick_infostring - = C((parsers.linechar - - (parsers.backtick - + parsers.spacechar^1 * parsers.newline))^0) - * parsers.optionalspace - * (parsers.newline + parsers.eof) - -local fenceindent -parsers.fencehead = function(char, infostring) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end - * Cg(char^3, "fencelength") - * parsers.optionalspace * infostring -end - -parsers.fencehead_with_attributes - = function(char) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end - * Cg(char^3, "fencelength") - * parsers.optionalspace * Ct(parsers.attributes) - * parsers.optionalspace * (parsers.newline + parsers.eof) -end - -parsers.fencetail = function(char) - return parsers.nonindentspace - * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) - * parsers.optionalspace * (parsers.newline + parsers.eof) - + parsers.eof -end - -parsers.fencedline = function(char) - return C(parsers.line - parsers.fencetail(char)) - / function(s) - local i = 1 - local remaining = fenceindent - while true do - local c = s:sub(i, i) - if c == " " and remaining > 0 then - remaining = remaining - 1 - i = i + 1 - elseif c == "\t" and remaining > 3 then - remaining = remaining - 4 - i = i + 1 - else - break - end - end - return s:sub(i) - end -end parsers.leader = parsers.space^-3 -- content in balanced brackets, parentheses, or quotes: @@ -3171,18 +3125,6 @@ parsers.between = function(p, starter, ender) end parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more -parsers.TildeFencedCode - = parsers.fencehead(parsers.tilde, - parsers.tilde_infostring) - * Cs(parsers.fencedline(parsers.tilde)^0) - * parsers.fencetail(parsers.tilde) - -parsers.BacktickFencedCode - = parsers.fencehead(parsers.backtick, - parsers.backtick_infostring) - * Cs(parsers.fencedline(parsers.backtick)^0) - * parsers.fencetail(parsers.backtick) - parsers.lineof = function(c) return (parsers.leader * (P(c) * parsers.optionalspace)^3 * (parsers.newline * parsers.blankline^1 @@ -3320,8 +3262,7 @@ function M.reader.new(writer, options) -- strip off leading > and indents, and run through blocks parsers.blockquote_body = ((parsers.leader * parsers.more * parsers.space^-1)/"" * parsers.linechar^0 * parsers.newline)^1 - * (-(parsers.leader * parsers.more - + parsers.blankline) * parsers.linechar^1 + * (-V("BlockquoteExceptions") * parsers.linechar^1 * parsers.newline)^0 if not options.breakableBlockquotes then @@ -3563,6 +3504,9 @@ function M.reader.new(writer, options) * ((parsers.indentedline - parsers.blankline))^1)^1 ) / self.expandtabs / writer.verbatim + parsers.BlockquoteExceptions = parsers.leader * parsers.more + + parsers.blankline + parsers.Blockquote = Cs(parsers.blockquote_body^1) / self.parser_functions.parse_blocks_nested / writer.blockquote @@ -3749,7 +3693,9 @@ function M.reader.new(writer, options) DisplayHtml = parsers.DisplayHtml, Paragraph = parsers.Paragraph, Plain = parsers.Plain, + EndlineExceptions = parsers.EndlineExceptions, + BlockquoteExceptions = parsers.BlockquoteExceptions, Str = parsers.Str, Space = parsers.Space, @@ -3798,7 +3744,6 @@ function M.reader.new(writer, options) end self.add_special_character("*") - self.add_special_character("`") self.add_special_character("[") self.add_special_character("]") self.add_special_character("<") @@ -3888,6 +3833,8 @@ function M.reader.new(writer, options) if not options.codeSpans then syntax.Code = parsers.fail + else + self.add_special_character("`") end if not options.html then @@ -3945,6 +3892,10 @@ function M.reader.new(writer, options) inlines_nbsp_t.Space = parsers.NonbreakingSpace parsers.inlines_nbsp = Ct(inlines_nbsp_t) return function(input) + input = input:gsub("\r\n?", "\n") + if input:sub(-1) ~= "\n" then + input = input .. "\n" + end references = {} local opt_string = {} for k, _ in pairs(defaultOptions) do @@ -4526,29 +4477,134 @@ M.extensions.fancy_lists = function() end } end -M.extensions.fenced_code = function(blank_before_code_fence) +M.extensions.fenced_code = function(blank_before_code_fence, + allow_attributes, + allow_raw_blocks) return { name = "built-in fenced_code syntax extension", extend_writer = function(self) local options = self.options - function self.fencedCode(s, i) + function self.fencedCode(s, i, attr) if not self.is_writing then return "" end + s = s:gsub("\n$", "") + local buf = {} + if attr ~= nil then + table.insert(buf, {"\\markdownRendererFencedCodeAttributeContextBegin", + self.attributes(attr)}) + end local name = util.cache_verbatim(options.cacheDir, s) - return {"\\markdownRendererInputFencedCode{", - name,"}{",self.string(i),"}"} + table.insert(buf, {"\\markdownRendererInputFencedCode{", + name,"}{",self.string(i),"}"}) + if attr ~= nil then + table.insert(buf, "\\markdownRendererFencedCodeAttributeContextEnd") + end + return buf + end + + if allow_raw_blocks then + function self.rawBlock(s, attr) + if not self.is_writing then return "" end + s = s:gsub("\n$", "") + local name = util.cache_verbatim(options.cacheDir, s) + return {"\\markdownRendererInputRawBlock{", + name,"}{", self.string(attr),"}"} + end end end, extend_reader = function(self) local parsers = self.parsers local writer = self.writer - local FencedCode = (parsers.TildeFencedCode - + parsers.BacktickFencedCode) - / function(infostring, code) - local expanded_code = self.expandtabs(code) - return writer.fencedCode(expanded_code, - infostring) - end + local function captures_geq_length(_,i,a,b) + return #a >= #b and i + end + + local tilde_infostring + = C((parsers.linechar + - (parsers.spacechar^1 * parsers.newline))^0) + + local backtick_infostring + = C((parsers.linechar + - (parsers.backtick + + parsers.spacechar^1 * parsers.newline))^0) + + local fenceindent + local fencehead = function(char, infostring) + return C(parsers.nonindentspace) / function(s) fenceindent = #s end + * Cg(char^3, "fencelength") + * parsers.optionalspace + * infostring + * (parsers.newline + parsers.eof) + end + + local fencetail = function(char) + return parsers.nonindentspace + * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length) + * parsers.optionalspace * (parsers.newline + parsers.eof) + + parsers.eof + end + + local fencedline = function(char) + return C(parsers.line - fencetail(char)) + / function(s) + local i = 1 + local remaining = fenceindent + while true do + local c = s:sub(i, i) + if c == " " and remaining > 0 then + remaining = remaining - 1 + i = i + 1 + elseif c == "\t" and remaining > 3 then + remaining = remaining - 4 + i = i + 1 + else + break + end + end + return s:sub(i) + end + end + + local TildeFencedCode + = fencehead(parsers.tilde, tilde_infostring) + * Cs(fencedline(parsers.tilde)^0) + * fencetail(parsers.tilde) + + local BacktickFencedCode + = fencehead(parsers.backtick, backtick_infostring) + * Cs(fencedline(parsers.backtick)^0) + * fencetail(parsers.backtick) + + local infostring_with_attributes + = Ct(C((parsers.linechar + - ( parsers.optionalspace + * parsers.attributes))^0) + * parsers.optionalspace + * Ct(parsers.attributes)) + + local FencedCode + = (TildeFencedCode + BacktickFencedCode) + / function(infostring, code) + local expanded_code = self.expandtabs(code) + + if allow_raw_blocks then + local raw_attr = lpeg.match(parsers.raw_attribute, + infostring) + if raw_attr then + return writer.rawBlock(expanded_code, raw_attr) + end + end + + local attr = nil + if allow_attributes then + local match = lpeg.match(infostring_with_attributes, + infostring) + if match then + infostring, attr = table.unpack(match) + end + end + return writer.fencedCode(expanded_code, infostring, attr) + end self.insert_pattern("Block after Verbatim", FencedCode, "FencedCode") @@ -4557,10 +4613,8 @@ M.extensions.fenced_code = function(blank_before_code_fence) if blank_before_code_fence then fencestart = parsers.fail else - fencestart = parsers.fencehead(parsers.backtick, - parsers.backtick_infostring) - + parsers.fencehead(parsers.tilde, - parsers.tilde_infostring) + fencestart = fencehead(parsers.backtick, backtick_infostring) + + fencehead(parsers.tilde, tilde_infostring) end self.update_rule("EndlineExceptions", function(previous_pattern) @@ -4570,6 +4624,7 @@ M.extensions.fenced_code = function(blank_before_code_fence) return previous_pattern + fencestart end) + self.add_special_character("`") self.add_special_character("~") end } @@ -4641,14 +4696,23 @@ M.extensions.fenced_divs = function(blank_before_div_fence) FencedDiv, "FencedDiv") self.add_special_character(":") - if not blank_before_div_fence then - local function check_div_level(s, i, current_level) -- luacheck: ignore s i - current_level = tonumber(current_level) - return current_level > 0 + + local function check_div_level(s, i, current_level) -- luacheck: ignore s i + current_level = tonumber(current_level) + return current_level > 0 + end + + local is_inside_div = Cmt(Cb("div_level"), check_div_level) + local fencestart = is_inside_div * fenced_div_end + + self.update_rule("BlockquoteExceptions", function(previous_pattern) + if previous_pattern == nil then + previous_pattern = parsers.BlockquoteExceptions end + return previous_pattern + fencestart + end) - local is_inside_div = Cmt(Cb("div_level"), check_div_level) - local fencestart = is_inside_div * fenced_div_end + if not blank_before_div_fence then self.update_rule("EndlineExceptions", function(previous_pattern) if previous_pattern == nil then previous_pattern = parsers.EndlineExceptions @@ -4714,6 +4778,44 @@ M.extensions.header_attributes = function() end } end +M.extensions.line_blocks = function() + return { + name = "built-in line_blocks syntax extension", + extend_writer = function(self) + function self.lineblock(lines) + if not self.is_writing then return "" end + local buffer = {} + for i = 1, #lines - 1 do + buffer[#buffer + 1] = { lines[i], self.linebreak } + end + buffer[#buffer + 1] = lines[#lines] + + return {"\\markdownRendererLineBlockBegin\n" + ,buffer, + "\n\\markdownRendererLineBlockEnd "} + end + end, extend_reader = function(self) + local parsers = self.parsers + local writer = self.writer + + local LineBlock = Ct( + (Cs( + ( (parsers.pipe * parsers.space)/"" + * ((parsers.space)/entities.char_entity("nbsp"))^0 + * parsers.linechar^0 * (parsers.newline/"")) + * (-parsers.pipe + * (parsers.space^1/" ") + * parsers.linechar^1 + * (parsers.newline/"") + )^0 + * (parsers.blankline/"")^0 + ) / self.parser_functions.parse_inlines)^1) / writer.lineblock + + self.insert_pattern("Block after Blockquote", + LineBlock, "LineBlock") + end + } +end M.extensions.notes = function(notes, inline_notes) assert(notes or inline_notes) return { @@ -4924,9 +5026,9 @@ M.extensions.pipe_tables = function(table_captions) end } end -M.extensions.raw_attribute = function() +M.extensions.raw_inline = function() return { - name = "built-in raw_attribute syntax extension", + name = "built-in raw_inline syntax extension", extend_writer = function(self) local options = self.options @@ -4936,50 +5038,15 @@ M.extensions.raw_attribute = function() return {"\\markdownRendererInputRawInline{", name,"}{", self.string(attr),"}"} end - - if options.fencedCode then - function self.rawBlock(s, attr) - if not self.is_writing then return "" end - local name = util.cache_verbatim(options.cacheDir, s) - return {"\\markdownRendererInputRawBlock{", - name,"}{", self.string(attr),"}"} - end - end end, extend_reader = function(self) - local options = self.options local writer = self.writer - local raw_attribute = parsers.lbrace - * parsers.optionalspace - * parsers.equal - * C(parsers.attribute_key) - * parsers.optionalspace - * parsers.rbrace - local RawInline = parsers.inticks - * raw_attribute + * parsers.raw_attribute / writer.rawInline self.insert_pattern("Inline before Code", RawInline, "RawInline") - - if options.fencedCode then - local RawBlock = (parsers.TildeFencedCode - + parsers.BacktickFencedCode) - / function(infostring, code) - local expanded_code = self.expandtabs(code) - local attr = lpeg.match(raw_attribute, infostring) - if attr then - return writer.rawBlock(expanded_code, attr) - else - return writer.fencedCode(expanded_code, - infostring) - end - end - - self.insert_pattern("Block after Verbatim", - RawBlock, "RawBlock") - end end } end @@ -5206,7 +5273,9 @@ function M.new(options) if options.fencedCode then local fenced_code_extension = M.extensions.fenced_code( - options.blankBeforeCodeFence) + options.blankBeforeCodeFence, + options.fencedCodeAttributes, + options.rawAttribute) table.insert(extensions, fenced_code_extension) end @@ -5234,8 +5303,8 @@ function M.new(options) end if options.rawAttribute then - local raw_attribute_extension = M.extensions.raw_attribute() - table.insert(extensions, raw_attribute_extension) + local raw_inline_extension = M.extensions.raw_inline() + table.insert(extensions, raw_inline_extension) end if options.strikeThrough then @@ -5253,6 +5322,11 @@ function M.new(options) table.insert(extensions, superscript_extension) end + if options.lineBlocks then + local line_block_extension = M.extensions.line_blocks() + table.insert(extensions, line_block_extension) + end + if options.footnotes or options.inlineFootnotes or options.notes or options.inlineNotes then local notes_extension = M.extensions.notes( |