diff options
author | Karl Berry <karl@freefriends.org> | 2022-10-31 19:44:45 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2022-10-31 19:44:45 +0000 |
commit | b85211b0d457e8ea4625ba00efe5133ba6f42350 (patch) | |
tree | 5fe5a427c680f122e0292cfd107fbdea47125f90 /Master/texmf-dist/tex/luatex/markdown | |
parent | 32a5e5c9e3c474a4be7e4ea8ab3101d0d6f208fe (diff) |
markdown (31oct22)
git-svn-id: svn://tug.org/texlive/trunk@64879 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/markdown')
-rw-r--r-- | Master/texmf-dist/tex/luatex/markdown/markdown.lua | 343 |
1 files changed, 187 insertions, 156 deletions
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 9ad26df6dbe..3afe0a924d4 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.17.1-0-g8ca83f5", + version = "2.18.0-0-gd8ae860", 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", @@ -83,7 +83,7 @@ local walkable_syntax = { Block = { "Blockquote", "Verbatim", - "HorizontalRule", + "ThematicBreak", "BulletList", "OrderedList", "Heading", @@ -128,13 +128,14 @@ defaultOptions.debugExtensions = false defaultOptions.definitionLists = false defaultOptions.eagerCache = true metadata.user_extension_api_version = 2 -metadata.grammar_version = 1 +metadata.grammar_version = 2 defaultOptions.extensions = {} defaultOptions.expectJekyllData = false defaultOptions.fancyLists = false defaultOptions.fencedCode = false defaultOptions.finalizeCache = false defaultOptions.footnotes = false +defaultOptions.notes = false defaultOptions.frozenCacheCounter = 0 defaultOptions.hardLineBreaks = false defaultOptions.hashEnumerators = false @@ -142,9 +143,11 @@ defaultOptions.headerAttributes = false defaultOptions.html = false defaultOptions.hybrid = false defaultOptions.inlineFootnotes = false +defaultOptions.inlineNotes = false defaultOptions.jekyllData = false defaultOptions.pipeTables = false defaultOptions.preserveTabs = false +defaultOptions.rawAttribute = true defaultOptions.relativeReferences = false defaultOptions.shiftHeadings = 0 defaultOptions.slice = "^ $" @@ -185,6 +188,11 @@ function util.cache(dir, string, salt, transform, suffix) end 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 function util.table_copy(t) local u = { } for k, v in pairs(t) do u[k] = v end @@ -2408,9 +2416,9 @@ function M.writer.new(options) end self.linebreak = "\\markdownRendererLineBreak\n{}" self.ellipsis = "\\markdownRendererEllipsis{}" - function self.hrule() + function self.thematic_break() if not self.is_writing then return "" end - return "\\markdownRendererHorizontalRule{}" + return "\\markdownRendererThematicBreak{}" end self.escaped_uri_chars = { ["{"] = "\\markdownRendererLeftBrace{}", @@ -2547,8 +2555,7 @@ function M.writer.new(options) end function self.verbatim(s) if not self.is_writing then return "" end - s = string.gsub(s, '[\r\n%s]*$', '') - local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") + local name = util.cache_verbatim(options.cacheDir, s) return {"\\markdownRendererInputVerbatim{",name,"}"} end function self.document(d) @@ -2851,6 +2858,20 @@ parsers.attribute_value = ( (parsers.dquote / "") + ( parsers.anyescaped - parsers.dquote - parsers.rbrace - parsers.space)^0 +parsers.attribute = (parsers.dash * Cc(".unnumbered")) + + C((parsers.hash + parsers.period) + * parsers.attribute_key) + + Cs( parsers.attribute_key + * parsers.optionalspace * parsers.equal * parsers.optionalspace + * parsers.attribute_value) +parsers.attributes = parsers.lbrace + * parsers.optionalspace + * parsers.attribute + * (parsers.spacechar^1 + * parsers.attribute)^0 + * parsers.optionalspace + * parsers.rbrace + -- block followed by 0 or more optionally -- indented blocks with first line indented. parsers.indented_blocks = function(bl) @@ -2901,8 +2922,8 @@ local function captures_geq_length(_,i,a,b) return #a >= #b and i end -parsers.infostring = (parsers.linechar - (parsers.backtick - + parsers.space^1 * (parsers.newline + parsers.eof)))^0 +parsers.infostring = (parsers.linechar - (parsers.backtick + + parsers.space^1 * (parsers.newline + parsers.eof)))^0 local fenceindent parsers.fencehead = function(char) @@ -3123,31 +3144,27 @@ parsers.between = function(p, starter, ender) end parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more +parsers.TildeFencedCode + = parsers.fencehead(parsers.tilde) + * Cs(parsers.fencedline(parsers.tilde)^0) + * parsers.fencetail(parsers.tilde) + +parsers.BacktickFencedCode + = parsers.fencehead(parsers.backtick) + * Cs(parsers.fencedline(parsers.backtick)^0) + * parsers.fencetail(parsers.backtick) + parsers.lineof = function(c) return (parsers.leader * (P(c) * parsers.optionalspace)^3 * (parsers.newline * parsers.blankline^1 + parsers.newline^-1 * parsers.eof)) end -parsers.heading_attribute = (parsers.dash * Cc(".unnumbered")) - + C((parsers.hash + parsers.period) - * parsers.attribute_key) - + Cs( parsers.attribute_key - * parsers.optionalspace * parsers.equal * parsers.optionalspace - * parsers.attribute_value) -parsers.HeadingAttributes = parsers.lbrace - * parsers.optionalspace - * parsers.heading_attribute - * (parsers.spacechar^1 - * parsers.heading_attribute)^0 - * parsers.optionalspace - * parsers.rbrace - -- parse Atx heading start and return level -parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6) - * -parsers.hash / length +parsers.heading_start = #parsers.hash * C(parsers.hash^-6) + * -parsers.hash / length -- parse setext header ending and return level -parsers.HeadingLevel = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) +parsers.heading_level = parsers.equal^1 * Cc(1) + parsers.dash^1 * Cc(2) local function strip_atx_end(s) return s:gsub("[#%s]*\n$","") @@ -3207,8 +3224,8 @@ function M.reader.new(writer, options) str = str:gsub('^' .. min_prefix, '') end if toplevel and (options.texComments or options.hybrid) then - str = lpeg.match(Ct(parsers.commented_line^1), str) - str = util.rope_to_string(str) + str = lpeg.match(Ct(parsers.commented_line^1), str) + str = util.rope_to_string(str) end local res = lpeg.match(grammar(), str) if res == nil then @@ -3521,10 +3538,10 @@ function M.reader.new(writer, options) / self.parser_functions.parse_blocks_nested / writer.blockquote - parsers.HorizontalRule = ( parsers.lineof(parsers.asterisk) - + parsers.lineof(parsers.dash) - + parsers.lineof(parsers.underscore) - ) / writer.hrule + parsers.ThematicBreak = ( parsers.lineof(parsers.asterisk) + + parsers.lineof(parsers.dash) + + parsers.lineof(parsers.underscore) + ) / writer.thematic_break parsers.Reference = parsers.define_reference_parser / register_link @@ -3567,14 +3584,14 @@ function M.reader.new(writer, options) * parsers.ListBlock parsers.TightListItem = function(starter) - return -parsers.HorizontalRule + return -parsers.ThematicBreak * (Cs(starter / "" * parsers.tickbox^-1 * parsers.ListBlock * parsers.NestedList^-1) / self.parser_functions.parse_blocks_nested) * -(parsers.blanklines * parsers.indent) end parsers.LooseListItem = function(starter) - return -parsers.HorizontalRule + return -parsers.ThematicBreak * Cs( starter / "" * parsers.tickbox^-1 * parsers.ListBlock * Cc("\n") * (parsers.NestedList + parsers.ListContinuationBlock^0) * (parsers.blanklines / "\n\n") @@ -3611,7 +3628,7 @@ function M.reader.new(writer, options) + parsers.Reference + (parsers.tightblocksep / "\n") -- parse atx header - parsers.AtxHeading = Cg(parsers.HeadingStart,"level") + parsers.AtxHeading = Cg(parsers.heading_start, "level") * parsers.optionalspace * (C(parsers.line) / strip_atx_end @@ -3623,7 +3640,7 @@ function M.reader.new(writer, options) * Ct(parsers.linechar^1 / self.parser_functions.parse_inlines) * parsers.newline - * parsers.HeadingLevel + * parsers.heading_level * parsers.optionalspace * parsers.newline / writer.heading @@ -3696,7 +3713,7 @@ function M.reader.new(writer, options) Blockquote = parsers.Blockquote, Verbatim = parsers.Verbatim, - HorizontalRule = parsers.HorizontalRule, + ThematicBreak = parsers.ThematicBreak, BulletList = parsers.BulletList, OrderedList = parsers.OrderedList, Heading = parsers.Heading, @@ -4285,74 +4302,22 @@ M.extensions.fenced_code = function(blank_before_code_fence) extend_writer = function(self) local options = self.options - function self.fencedCode(i, s) + function self.fencedCode(s, i) if not self.is_writing then return "" end - s = string.gsub(s, '[\r\n%s]*$', '') - local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") - return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} + local name = util.cache_verbatim(options.cacheDir, s) + return {"\\markdownRendererInputFencedCode{", + name,"}{",self.string(i),"}"} end end, extend_reader = function(self) local parsers = self.parsers local writer = self.writer - local function captures_geq_length(_,i,a,b) - return #a >= #b and i - end - - local infostring = (parsers.linechar - (parsers.backtick - + parsers.space^1 * (parsers.newline + parsers.eof)))^0 - - local fenceindent - local fencehead = function(char) - return C(parsers.nonindentspace) / function(s) fenceindent = #s end - * Cg(char^3, "fencelength") - * parsers.optionalspace * C(infostring) - * parsers.optionalspace * (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) - * Cs(fencedline(parsers.tilde)^0) - * fencetail(parsers.tilde) - - local BacktickFencedCode - = fencehead(parsers.backtick) - * Cs(fencedline(parsers.backtick)^0) - * fencetail(parsers.backtick) - - local FencedCode = (TildeFencedCode - + BacktickFencedCode) + local FencedCode = (parsers.TildeFencedCode + + parsers.BacktickFencedCode) / function(infostring, code) - return writer.fencedCode(writer.string(infostring), - self.expandtabs(code)) + local expanded_code = self.expandtabs(code) + return writer.fencedCode(expanded_code, + infostring) end self.insert_pattern("Block after Verbatim", @@ -4362,8 +4327,8 @@ M.extensions.fenced_code = function(blank_before_code_fence) if blank_before_code_fence then fencestart = parsers.fail else - fencestart = fencehead(parsers.backtick) - + fencehead(parsers.tilde) + fencestart = parsers.fencehead(parsers.backtick) + + parsers.fencehead(parsers.tilde) end local EndlineExceptions = parsers.EndlineExceptions + fencestart @@ -4373,19 +4338,19 @@ M.extensions.fenced_code = function(blank_before_code_fence) end } end -M.extensions.footnotes = function(footnotes, inline_footnotes) - assert(footnotes or inline_footnotes) +M.extensions.notes = function(notes, inline_notes) + assert(notes or inline_notes) return { - name = "built-in footnotes syntax extension", + name = "built-in notes syntax extension", extend_writer = function(self) function self.note(s) - return {"\\markdownRendererFootnote{",s,"}"} + return {"\\markdownRendererNote{",s,"}"} end end, extend_reader = function(self) local parsers = self.parsers local writer = self.writer - if inline_footnotes then + if inline_notes then local InlineNote = parsers.circumflex * (parsers.tag / self.parser_functions.parse_inlines_no_inline_note) @@ -4394,7 +4359,7 @@ M.extensions.footnotes = function(footnotes, inline_footnotes) self.insert_pattern("Inline after Emph", InlineNote, "InlineNote") end - if footnotes then + if notes then local function strip_first_char(s) return s:sub(2) end @@ -4450,49 +4415,49 @@ M.extensions.header_attributes = function() local parsers = self.parsers local writer = self.writer - parsers.AtxHeading = Cg(parsers.HeadingStart,"level") - * parsers.optionalspace - * (C(((parsers.linechar - - ((parsers.hash^1 - * parsers.optionalspace - * parsers.HeadingAttributes^-1 - + parsers.HeadingAttributes) - * parsers.optionalspace - * parsers.newline)) - * (parsers.linechar - - parsers.hash - - parsers.lbrace)^0)^1) - / self.parser_functions.parse_inlines) - * Cg(Ct(parsers.newline - + (parsers.hash^1 - * parsers.optionalspace - * parsers.HeadingAttributes^-1 - + parsers.HeadingAttributes) + local AtxHeading = Cg(parsers.heading_start, "level") + * parsers.optionalspace + * (C(((parsers.linechar + - ((parsers.hash^1 * parsers.optionalspace - * parsers.newline), "attributes") - * Cb("level") - * Cb("attributes") - / writer.heading - - parsers.SetextHeading = #(parsers.line * S("=-")) - * (C(((parsers.linechar - - (parsers.HeadingAttributes - * parsers.optionalspace - * parsers.newline)) - * (parsers.linechar - - parsers.lbrace)^0)^1) - / self.parser_functions.parse_inlines) - * Cg(Ct(parsers.newline - + (parsers.HeadingAttributes - * parsers.optionalspace - * parsers.newline)), "attributes") - * parsers.HeadingLevel - * Cb("attributes") - * parsers.optionalspace - * parsers.newline - / writer.heading - - local Heading = parsers.AtxHeading + parsers.SetextHeading + * parsers.attributes^-1 + + parsers.attributes) + * parsers.optionalspace + * parsers.newline)) + * (parsers.linechar + - parsers.hash + - parsers.lbrace)^0)^1) + / self.parser_functions.parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.hash^1 + * parsers.optionalspace + * parsers.attributes^-1 + + parsers.attributes) + * parsers.optionalspace + * parsers.newline), "attributes") + * Cb("level") + * Cb("attributes") + / writer.heading + + local SetextHeading = #(parsers.line * S("=-")) + * (C(((parsers.linechar + - (parsers.attributes + * parsers.optionalspace + * parsers.newline)) + * (parsers.linechar + - parsers.lbrace)^0)^1) + / self.parser_functions.parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.attributes + * parsers.optionalspace + * parsers.newline)), "attributes") + * parsers.heading_level + * Cb("attributes") + * parsers.optionalspace + * parsers.newline + / writer.heading + + local Heading = AtxHeading + SetextHeading self.update_rule("Heading", Heading) end } @@ -4608,14 +4573,14 @@ M.extensions.jekyll_data = function(expect_jekyll_data) local UnexpectedJekyllData = P("---") * parsers.blankline / 0 - * #(-parsers.blankline) -- if followed by blank, it's an hrule + * #(-parsers.blankline) -- if followed by blank, it's thematic break * JekyllData * (P("---") + P("...")) local ExpectedJekyllData = ( P("---") * parsers.blankline / 0 - * #(-parsers.blankline) -- if followed by blank, it's an hrule + * #(-parsers.blankline) -- if followed by blank, it's thematic break )^-1 * JekyllData * (P("---") + P("..."))^-1 @@ -4769,6 +4734,65 @@ M.extensions.pipe_tables = function(table_captions) end } end +M.extensions.raw_attribute = function() + return { + name = "built-in raw_attribute syntax extension", + extend_writer = function(self) + local options = self.options + + function self.rawInline(s, attr) + if not self.is_writing then return "" end + local name = util.cache_verbatim(options.cacheDir, s) + 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 + / 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 M.extensions.strike_through = function() return { name = "built-in strike_through syntax extension", @@ -4906,14 +4930,14 @@ M.extensions.fancy_lists = function() * ListBlock local TightListItem = function(starter) - return -parsers.HorizontalRule + return -parsers.ThematicBreak * (Cs(starter / "" * parsers.tickbox^-1 * ListBlock * NestedList^-1) / self.parser_functions.parse_blocks_nested) * -(parsers.blanklines * parsers.indent) end local LooseListItem = function(starter) - return -parsers.HorizontalRule + return -parsers.ThematicBreak * Cs( starter / "" * parsers.tickbox^-1 * ListBlock * Cc("\n") * (NestedList + ListContinuationBlock^0) * (parsers.blanklines / "\n\n") @@ -5034,6 +5058,11 @@ function M.new(options) table.insert(extensions, pipe_tables_extension) end + if options.rawAttribute then + local raw_attribute_extension = M.extensions.raw_attribute() + table.insert(extensions, raw_attribute_extension) + end + if options.strikeThrough then local strike_through_extension = M.extensions.strike_through() table.insert(extensions, strike_through_extension) @@ -5049,10 +5078,12 @@ function M.new(options) table.insert(extensions, superscript_extension) end - if options.footnotes or options.inlineFootnotes then - local footnotes_extension = M.extensions.footnotes( - options.footnotes, options.inlineFootnotes) - table.insert(extensions, footnotes_extension) + if options.footnotes or options.inlineFootnotes or + options.notes or options.inlineNotes then + local notes_extension = M.extensions.notes( + options.footnotes or options.notes, + options.inlineFootnotes or options.inlineNotes) + table.insert(extensions, notes_extension) end if options.citations then |