From d559ccaca60acb46c6a12c256ea2a1dcc867d0f8 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 5 Apr 2019 21:09:01 +0000 Subject: markdown (5apr19) git-svn-id: svn://tug.org/texlive/trunk@50784 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/tex/luatex/markdown/markdown.lua | 253 +++++++++++++++++---- 1 file changed, 207 insertions(+), 46 deletions(-) (limited to 'Master/texmf-dist/tex/luatex') diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua index 25d45c32da2..9614434b81f 100644 --- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua +++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua @@ -20,7 +20,7 @@ -- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -- --- Copyright (C) 2018 Vít Novotný +-- Copyright (C) 2016-2019 Vít Novotný -- -- This work may be distributed and/or modified under the -- conditions of the LaTeX Project Public License, either version 1.3 @@ -58,11 +58,11 @@ -- those in the standard .ins files. -- local metadata = { - version = "2.5.6", + version = "2.7.0", 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", - "2016-2018 Vít Novotný"}, + "2016-2019 Vít Novotný"}, license = "LPPL 1.3" } @@ -87,10 +87,12 @@ defaultOptions.definitionLists = false defaultOptions.fencedCode = false defaultOptions.footnotes = false defaultOptions.hashEnumerators = false +defaultOptions.headerAttributes = false defaultOptions.html = false defaultOptions.hybrid = false defaultOptions.inlineFootnotes = false defaultOptions.preserveTabs = false +defaultOptions.slice = "^ $" defaultOptions.smartEllipses = false defaultOptions.startNumber = true defaultOptions.tightLists = true @@ -498,6 +500,31 @@ function M.writer.new(options) options = options or {} setmetatable(options, { __index = function (_, key) return defaultOptions[key] end }) + local slice_specifiers = {} + for specifier in options.slice:gmatch("[^%s]+") do + table.insert(slice_specifiers, specifier) + end + + if #slice_specifiers == 2 then + self.slice_begin, self.slice_end = table.unpack(slice_specifiers) + local slice_begin_type = self.slice_begin:sub(1, 1) + if slice_begin_type ~= "^" and slice_begin_type ~= "$" then + self.slice_begin = "^" .. self.slice_begin + end + local slice_end_type = self.slice_end:sub(1, 1) + if slice_end_type ~= "^" and slice_end_type ~= "$" then + self.slice_end = "$" .. self.slice_end + end + elseif #slice_specifiers == 1 then + self.slice_begin = "^" .. slice_specifiers[1] + self.slice_end = "$" .. slice_specifiers[1] + end + + if self.slice_begin == "^" and self.slice_end ~= "^" then + self.is_writing = true + else + self.is_writing = false + end self.suffix = ".tex" self.space = " " self.nbsp = "\\markdownRendererNbsp{}" @@ -505,16 +532,23 @@ function M.writer.new(options) return s end function self.paragraph(s) + if not self.is_writing then return "" end 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 + return "\\markdownRendererInterblockSeparator\n{}" end - self.interblocksep = "\\markdownRendererInterblockSeparator\n{}" self.eof = [[\relax]] self.linebreak = "\\markdownRendererLineBreak\n{}" self.ellipsis = "\\markdownRendererEllipsis{}" - self.hrule = "\\markdownRendererHorizontalRule{}" + function self.hrule() + if not self.is_writing then return "" end + return "\\markdownRendererHorizontalRule{}" + end local escaped_chars = { ["{"] = "\\markdownRendererLeftBrace{}", ["}"] = "\\markdownRendererRightBrace{}", @@ -572,30 +606,31 @@ function M.writer.new(options) "{",self.uri(src),"}", "{",self.string(tit or ""),"}"} end -local languages_json = (function() - local kpse = require("kpse") - kpse.set_program_name("luatex") - local base, prev, curr - for _, file in ipairs{kpse.lookup(options.contentBlocksLanguageMap, - { all=true })} do - json = io.open(file, "r"):read("*all") - :gsub('("[^\n]-"):','[%1]=') - curr = (function() - local _ENV={ json=json, load=load } -- run in sandbox - return load("return "..json)() - end)() - if type(curr) == "table" then - if base == nil then - base = curr - else - setmetatable(prev, { __index = curr }) + local languages_json = (function() + local kpse = require("kpse") + kpse.set_program_name("luatex") + local base, prev, curr + for _, file in ipairs{kpse.lookup(options.contentBlocksLanguageMap, + { all=true })} do + json = io.open(file, "r"):read("*all") + :gsub('("[^\n]-"):','[%1]=') + curr = (function() + local _ENV={ json=json, load=load } -- run in sandbox + return load("return "..json)() + end)() + if type(curr) == "table" then + if base == nil then + base = curr + else + setmetatable(prev, { __index = curr }) + end + prev = curr end - prev = curr end - end - return base or {} -end)() + return base or {} + end)() function self.contentblock(src,suf,type,tit) + if not self.is_writing then return "" end src = src.."."..suf suf = suf:lower() if type == "onlineimage" then @@ -622,6 +657,7 @@ end)() end function self.bulletlist(items,tight) + if not self.is_writing then return "" end local buffer = {} for _,item in ipairs(items) do buffer[#buffer + 1] = ulitem(item) @@ -646,6 +682,7 @@ end)() end function self.orderedlist(items,tight,startnum) + if not self.is_writing then return "" end local buffer = {} local num = startnum for _,item in ipairs(items) do @@ -676,6 +713,7 @@ end)() end function self.definitionlist(items,tight) + if not self.is_writing then return "" end local buffer = {} for _,item in ipairs(items) do buffer[#buffer + 1] = dlitem(item.term, item.definitions) @@ -695,18 +733,66 @@ end)() return {"\\markdownRendererStrongEmphasis{",s,"}"} end function self.blockquote(s) + if #util.rope_to_string(s) == 0 then return "" end return {"\\markdownRendererBlockQuoteBegin\n",s, "\n\\markdownRendererBlockQuoteEnd "} end function self.verbatim(s) + if not self.is_writing then return "" end local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") return {"\\markdownRendererInputVerbatim{",name,"}"} end function self.fencedCode(i, s) + if not self.is_writing then return "" end local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim") return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"} end - function self.heading(s,level) + self.active_headings = {} + function self.heading(s,level,attributes) + local active_headings = self.active_headings + local slice_begin_type = self.slice_begin:sub(1, 1) + local slice_begin_identifier = self.slice_begin:sub(2) or "" + local slice_end_type = self.slice_end:sub(1, 1) + local slice_end_identifier = self.slice_end:sub(2) or "" + + while #active_headings < level do + -- push empty identifiers for implied sections + table.insert(active_headings, {}) + end + + while #active_headings >= level do + -- pop identifiers for sections that have ended + local active_identifiers = active_headings[#active_headings] + if active_identifiers[slice_begin_identifier] ~= nil + and slice_begin_type == "$" then + self.is_writing = true + end + if active_identifiers[slice_end_identifier] ~= nil + and slice_end_type == "$" then + self.is_writing = false + end + table.remove(active_headings, #active_headings) + end + + -- push identifiers for the new section + attributes = attributes or {} + local identifiers = {} + for index = 1, #attributes do + attribute = attributes[index] + identifiers[attribute:sub(2)] = true + end + if identifiers[slice_begin_identifier] ~= nil + and slice_begin_type == "^" then + self.is_writing = true + end + if identifiers[slice_end_identifier] ~= nil + and slice_end_type == "^" then + self.is_writing = false + end + table.insert(active_headings, identifiers) + + if not self.is_writing then return "" end + local cmd if level == 1 then cmd = "\\markdownRendererHeadingOne" @@ -761,6 +847,8 @@ parsers.lparent = P("(") parsers.rparent = P(")") parsers.lbracket = P("[") parsers.rbracket = P("]") +parsers.lbrace = P("{") +parsers.rbrace = P("}") parsers.circumflex = P("^") parsers.slash = P("/") parsers.equal = P("=") @@ -827,6 +915,22 @@ parsers.nonemptyline = parsers.line - parsers.blankline parsers.chunk = parsers.line * (parsers.optionallyindentedline - parsers.blankline)^0 +parsers.css_identifier_char = R("AZ", "az", "09") + S("-_") +parsers.css_identifier = (parsers.hash + parsers.period) + * (((parsers.css_identifier_char + - parsers.dash - parsers.digit) + * parsers.css_identifier_char^1) + + (parsers.dash + * (parsers.css_identifier_char + - parsers.digit) + * parsers.css_identifier_char^0)) +parsers.attribute_name_char = parsers.any - parsers.space + - parsers.squote - parsers.dquote + - parsers.more - parsers.slash + - parsers.equal +parsers.attribute_value_char = parsers.any - parsers.dquote + - parsers.more + -- block followed by 0 or more optionally -- indented blocks with first line indented. parsers.indented_blocks = function(bl) @@ -1063,9 +1167,8 @@ parsers.citation_body_postnote parsers.citation_body_chunk = parsers.citation_body_prenote * parsers.spnl * parsers.citation_name - * ((parsers.internal_punctuation - parsers.semicolon) - * parsers.spnl)^-1 - * parsers.citation_body_postnote + * (parsers.internal_punctuation - parsers.semicolon)^-1 + * parsers.spnl * parsers.citation_body_postnote parsers.citation_body = parsers.citation_body_chunk @@ -1255,6 +1358,18 @@ parsers.defstart = ( parsers.defstartchar * #parsers.spacing ) parsers.dlchunk = Cs(parsers.line * (parsers.indentedline - parsers.blankline)^0) +parsers.heading_attribute = C(parsers.css_identifier) + + C((parsers.attribute_name_char + - parsers.rbrace)^1 + * parsers.equal + * (parsers.attribute_value_char + - parsers.rbrace)^1) +parsers.HeadingAttributes = parsers.lbrace + * parsers.heading_attribute + * (parsers.spacechar^1 + * parsers.heading_attribute)^0 + * parsers.rbrace + -- parse Atx heading start and return level parsers.HeadingStart = #parsers.hash * C(parsers.hash^-6) * -parsers.hash / length @@ -1721,6 +1836,9 @@ function M.reader.new(writer, options) local function ordered_list(items,tight,startNumber) if options.startNumber then startNumber = tonumber(startNumber) or 1 -- fallback for '#' + if startNumber ~= nil then + startNumber = math.floor(startNumber) + end else startNumber = nil end @@ -1761,27 +1879,70 @@ function M.reader.new(writer, options) + larsers.Reference + (parsers.tightblocksep / "\n") -- parse atx header - larsers.AtxHeading = Cg(parsers.HeadingStart,"level") - * parsers.optionalspace - * (C(parsers.line) / strip_atx_end / parse_inlines) - * Cb("level") - / writer.heading - - -- parse setext header - larsers.SetextHeading = #(parsers.line * S("=-")) - * Ct(parsers.line / parse_inlines) - * parsers.HeadingLevel - * parsers.optionalspace * parsers.newline - / writer.heading + if options.headerAttributes then + larsers.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) + / parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.hash^1 + * parsers.optionalspace + * parsers.HeadingAttributes^-1 + + parsers.HeadingAttributes) + * parsers.optionalspace + * parsers.newline), "attributes") + * Cb("level") + * Cb("attributes") + / writer.heading + + larsers.SetextHeading = #(parsers.line * S("=-")) + * (C(((parsers.linechar + - (parsers.HeadingAttributes + * parsers.optionalspace + * parsers.newline)) + * (parsers.linechar + - parsers.lbrace)^0)^1) + / parse_inlines) + * Cg(Ct(parsers.newline + + (parsers.HeadingAttributes + * parsers.optionalspace + * parsers.newline)), "attributes") + * parsers.HeadingLevel + * Cb("attributes") + * parsers.optionalspace + * parsers.newline + / writer.heading + else + larsers.AtxHeading = Cg(parsers.HeadingStart,"level") + * parsers.optionalspace + * (C(parsers.line) / strip_atx_end / parse_inlines) + * Cb("level") + / writer.heading + + larsers.SetextHeading = #(parsers.line * S("=-")) + * Ct(parsers.linechar^1 / parse_inlines) + * parsers.newline + * parsers.HeadingLevel + * parsers.optionalspace + * parsers.newline + / writer.heading + end larsers.Heading = larsers.AtxHeading + larsers.SetextHeading local syntax = { "Blocks", Blocks = larsers.Blank^0 * parsers.Block^-1 - * (larsers.Blank^0 / function() - return writer.interblocksep - end + * (larsers.Blank^0 / writer.interblocksep * parsers.Block)^0 * larsers.Blank^0 * parsers.eof, -- cgit v1.2.3