summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/markdown/markdown.lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-08-26 19:56:57 +0000
committerKarl Berry <karl@freefriends.org>2022-08-26 19:56:57 +0000
commit09bced275b43579d54d22b41a416382b2a0cdb80 (patch)
tree7237a85adc00ef83cee55e139b445fff3398dc6a /Master/texmf-dist/tex/luatex/markdown/markdown.lua
parent514aac2f29abee64350e7f44a1454cbed42e1680 (diff)
markdown (26aug22)
git-svn-id: svn://tug.org/texlive/trunk@64200 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/markdown/markdown.lua')
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown.lua370
1 files changed, 314 insertions, 56 deletions
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua
index 8e5d29f0133..091e7052bb9 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.15.4-0-g4cbe4e3",
+ version = "2.16.0-5-g5bb83fb",
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",
@@ -94,6 +94,7 @@ defaultOptions.contentBlocksLanguageMap = "markdown-languages.json"
defaultOptions.definitionLists = false
defaultOptions.eagerCache = true
defaultOptions.expectJekyllData = false
+defaultOptions.fancyLists = false
defaultOptions.fencedCode = false
defaultOptions.finalizeCache = false
defaultOptions.footnotes = false
@@ -112,7 +113,10 @@ defaultOptions.shiftHeadings = 0
defaultOptions.slice = "^ $"
defaultOptions.smartEllipses = false
defaultOptions.startNumber = true
+defaultOptions.strikeThrough = false
defaultOptions.stripIndent = false
+defaultOptions.subscripts = false
+defaultOptions.superscripts = false
defaultOptions.tableCaptions = false
defaultOptions.taskLists = false
defaultOptions.texComments = false
@@ -2303,8 +2307,7 @@ end
M.writer = {}
function M.writer.new(options)
local self = {}
- self.cacheDir = options.cacheDir
- self.hybrid = options.hybrid
+ self.options = options
local slice_specifiers = {}
for specifier in options.slice:gmatch("[^%s]+") do
table.insert(slice_specifiers, specifier)
@@ -2403,16 +2406,11 @@ function M.writer.new(options)
"{",self.uri(src),"}",
"{",self.string(tit or ""),"}"}
end
- local function ulitem(s)
- return {"\\markdownRendererUlItem ",s,
- "\\markdownRendererUlItemEnd "}
- 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)
+ buffer[#buffer + 1] = self.bulletitem(item)
end
local contents = util.intersperse(buffer,"\n")
if tight and options.tightLists then
@@ -2423,22 +2421,16 @@ function M.writer.new(options)
"\n\\markdownRendererUlEnd "}
end
end
- local function olitem(s,num)
- if num ~= nil then
- return {"\\markdownRendererOlItemWithNumber{",num,"}",s,
- "\\markdownRendererOlItemEnd "}
- else
- return {"\\markdownRendererOlItem ",s,
- "\\markdownRendererOlItemEnd "}
- end
+ function self.bulletitem(s)
+ return {"\\markdownRendererUlItem ",s,
+ "\\markdownRendererUlItemEnd "}
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
- buffer[#buffer + 1] = olitem(item,num)
+ buffer[#buffer + 1] = self.ordereditem(item,num)
if num ~= nil then
num = num + 1
end
@@ -2452,6 +2444,15 @@ function M.writer.new(options)
"\n\\markdownRendererOlEnd "}
end
end
+ function self.ordereditem(s,num)
+ if num ~= nil then
+ return {"\\markdownRendererOlItemWithNumber{",num,"}",s,
+ "\\markdownRendererOlItemEnd "}
+ else
+ return {"\\markdownRendererOlItem ",s,
+ "\\markdownRendererOlItemEnd "}
+ end
+ end
function self.inline_html_comment(contents)
return {"\\markdownRendererInlineHtmlComment{",contents,"}"}
end
@@ -2465,7 +2466,7 @@ function M.writer.new(options)
end
function self.block_html_element(s)
if not self.is_writing then return "" end
- local name = util.cache(self.cacheDir, s, nil, nil, ".verbatim")
+ local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
return {"\\markdownRendererInputBlockHtmlElement{",name,"}"}
end
function self.emphasis(s)
@@ -2491,7 +2492,7 @@ function M.writer.new(options)
function self.verbatim(s)
if not self.is_writing then return "" end
s = string.gsub(s, '[\r\n%s]*$', '')
- local name = util.cache(self.cacheDir, s, nil, nil, ".verbatim")
+ local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
return {"\\markdownRendererInputVerbatim{",name,"}"}
end
function self.document(d)
@@ -2601,7 +2602,7 @@ function M.writer.new(options)
table.insert(buf, {"\\markdownRendererAttributeClassName{",
attributes[i]:sub(2), "}"})
else
- key, value = attributes[i]:match("(%w+)=(%w+)")
+ key, value = attributes[i]:match("([^= ]+)%s*=%s*(.*)")
table.insert(buf, {"\\markdownRendererAttributeKeyValue{",
key, "}{", value, "}"})
end
@@ -2702,12 +2703,13 @@ parsers.internal_punctuation = S(":;,.?")
parsers.doubleasterisks = P("**")
parsers.doubleunderscores = P("__")
+parsers.doubletildes = P("~~")
parsers.fourspaces = P(" ")
parsers.any = P(1)
parsers.fail = parsers.any - 1
-parsers.escapable = S("\\`*_{}[]()+_.!<>#-~:^@;")
+parsers.escapable = S("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
parsers.anyescaped = parsers.backslash / "" * parsers.escapable
+ parsers.any
@@ -2783,21 +2785,15 @@ parsers.commented_line = Cg(Cc(""), "backslashes")
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_key_char = parsers.any - parsers.space
- - parsers.squote - parsers.dquote
- - parsers.more - parsers.slash
- - parsers.equal
-parsers.attribute_value_char = parsers.any - parsers.space
- - parsers.dquote - parsers.more
+parsers.attribute_key_char = parsers.alphanumeric + S("_-")
+parsers.attribute_key = (parsers.attribute_key_char
+ - parsers.dash - parsers.digit)
+ * parsers.attribute_key_char^0
+parsers.attribute_value = ( (parsers.dquote / "")
+ * (parsers.anyescaped - parsers.dquote)^0
+ * (parsers.dquote / ""))
+ + ( parsers.anyescaped - parsers.dquote - parsers.rbrace
+ - parsers.space)^0
-- block followed by 0 or more optionally
-- indented blocks with first line indented.
@@ -2891,9 +2887,10 @@ parsers.leader = parsers.space^-3
-- content in balanced brackets, parentheses, or quotes:
parsers.bracketed = P{ parsers.lbracket
- * ((parsers.anyescaped - (parsers.lbracket
- + parsers.rbracket
- + parsers.blankline^2)
+ * (( parsers.backslash / "" * parsers.rbracket
+ + parsers.any - (parsers.lbracket
+ + parsers.rbracket
+ + parsers.blankline^2)
) + V(1))^0
* parsers.rbracket }
@@ -2921,7 +2918,8 @@ parsers.tag = parsers.lbracket
* Cs((parsers.alphanumeric^1
+ parsers.bracketed
+ parsers.inticks
- + (parsers.anyescaped
+ + ( parsers.backslash / "" * parsers.rbracket
+ + parsers.any
- (parsers.rbracket + parsers.blankline^2)))^0)
* parsers.rbracket
@@ -3074,16 +3072,18 @@ parsers.lineof = function(c)
* (parsers.newline * parsers.blankline^1
+ parsers.newline^-1 * parsers.eof))
end
-parsers.heading_attribute = C(parsers.css_identifier)
- + C((parsers.attribute_key_char
- - parsers.rbrace)^1
- * parsers.equal
- * (parsers.attribute_value_char
- - parsers.rbrace)^1)
+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
@@ -3100,6 +3100,7 @@ M.reader = {}
function M.reader.new(writer, options, extensions)
local self = {}
self.writer = writer
+ self.options = options
self.parsers = {}
(function(parsers)
setmetatable(self.parsers, {
@@ -3530,16 +3531,16 @@ function M.reader.new(writer, options, extensions)
* parsers.skipblanklines )
/ writer.bulletlist
- local function ordered_list(items,tight,startNumber)
+ local function ordered_list(items,tight,startnum)
if options.startNumber then
- startNumber = tonumber(startNumber) or 1 -- fallback for '#'
- if startNumber ~= nil then
- startNumber = math.floor(startNumber)
+ startnum = tonumber(startnum) or 1 -- fallback for '#'
+ if startnum ~= nil then
+ startnum = math.floor(startnum)
end
else
- startNumber = nil
+ startnum = nil
end
- return writer.orderedlist(items,tight,startNumber)
+ return writer.orderedlist(items,tight,startnum)
end
parsers.OrderedList = Cg(parsers.enumerator, "listtype") *
@@ -3625,6 +3626,9 @@ function M.reader.new(writer, options, extensions)
+ V("UlOrStarLine")
+ V("Strong")
+ V("Emph")
+ + V("StrikeThrough")
+ + V("Superscript")
+ + V("Subscript")
+ V("InlineNote")
+ V("NoteRef")
+ V("Citations")
@@ -3646,6 +3650,9 @@ function M.reader.new(writer, options, extensions)
+ V("UlOrStarLine")
+ V("Strong")
+ V("Emph")
+ + V("StrikeThrough")
+ + V("Superscript")
+ + V("Subscript")
+ V("InlineNote")
+ V("NoteRef")
+ V("Citations")
@@ -3668,6 +3675,9 @@ function M.reader.new(writer, options, extensions)
UlOrStarLine = parsers.UlOrStarLine,
Strong = parsers.Strong,
Emph = parsers.Emph,
+ StrikeThrough = parsers.fail,
+ Superscript = parsers.fail,
+ Subscript = parsers.fail,
InlineNote = parsers.fail,
NoteRef = parsers.fail,
Citations = parsers.fail,
@@ -3807,10 +3817,12 @@ M.extensions.citations = function(citation_nbsps)
}
return {
extend_writer = function(self)
+ local options = self.options
+
local escape_citation = util.escaper(
escaped_citation_chars,
self.escaped_minimal_strings)
- if self.hybrid then
+ if options.hybrid then
self.citation = self.escape_minimal
else
self.citation = escape_citation
@@ -4154,10 +4166,12 @@ end
M.extensions.fenced_code = function(blank_before_code_fence)
return {
extend_writer = function(self)
+ local options = self.options
+
function self.fencedCode(i, s)
if not self.is_writing then return "" end
s = string.gsub(s, '[\r\n%s]*$', '')
- local name = util.cache(self.cacheDir, s, nil, nil, ".verbatim")
+ local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
return {"\\markdownRendererInputFencedCode{",name,"}{",i,"}"}
end
end, extend_reader = function(self)
@@ -4237,6 +4251,8 @@ M.extensions.fenced_code = function(blank_before_code_fence)
parsers.EndlineExceptions = parsers.EndlineExceptions + fencestart
syntax.EndlineExceptions = parsers.EndlineExceptions
+
+ self.add_special_character("~")
end
}
end
@@ -4631,6 +4647,228 @@ M.extensions.pipe_tables = function(table_captions)
end
}
end
+M.extensions.strike_through = function()
+ return {
+ extend_writer = function(self)
+ function self.strike_through(s)
+ return {"\\markdownRendererStrikeThrough{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local syntax = self.syntax
+ local writer = self.writer
+
+ local StrikeThrough = (
+ parsers.between(parsers.Inline, parsers.doubletildes,
+ parsers.doubletildes)
+ ) / writer.strike_through
+
+ syntax.StrikeThrough = StrikeThrough
+
+ self.add_special_character("~")
+ end
+ }
+end
+M.extensions.superscripts = function()
+ return {
+ extend_writer = function(self)
+ function self.superscript(s)
+ return {"\\markdownRendererSuperscript{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local syntax = self.syntax
+ local writer = self.writer
+
+ local Superscript = (
+ parsers.between(parsers.Str, parsers.circumflex, parsers.circumflex)
+ ) / writer.superscript
+
+ syntax.Superscript = Superscript
+
+ self.add_special_character("^")
+ end
+ }
+end
+M.extensions.subscripts = function()
+ return {
+ extend_writer = function(self)
+ function self.subscript(s)
+ return {"\\markdownRendererSubscript{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local syntax = self.syntax
+ local writer = self.writer
+
+ local Subscript = (
+ parsers.between(parsers.Str, parsers.tilde, parsers.tilde)
+ ) / writer.subscript
+
+ syntax.Subscript = Subscript
+
+ self.add_special_character("~")
+ end
+ }
+end
+M.extensions.fancy_lists = function()
+ return {
+ extend_writer = function(self)
+ local options = self.options
+
+ function self.fancylist(items,tight,startnum,numstyle,numdelim)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ local num = startnum
+ for _,item in ipairs(items) do
+ buffer[#buffer + 1] = self.fancyitem(item,num)
+ if num ~= nil then
+ num = num + 1
+ end
+ end
+ local contents = util.intersperse(buffer,"\n")
+ if tight and options.tightLists then
+ return {"\\markdownRendererFancyOlBeginTight{",
+ numstyle,"}{",numdelim,"}",contents,
+ "\n\\markdownRendererFancyOlEndTight "}
+ else
+ return {"\\markdownRendererFancyOlBegin{",
+ numstyle,"}{",numdelim,"}",contents,
+ "\n\\markdownRendererFancyOlEnd "}
+ end
+ end
+ function self.fancyitem(s,num)
+ if num ~= nil then
+ return {"\\markdownRendererFancyOlItemWithNumber{",num,"}",s,
+ "\\markdownRendererFancyOlItemEnd "}
+ else
+ return {"\\markdownRendererFancyOlItem ",s,"\\markdownRendererFancyOlItemEnd "}
+ end
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local options = self.options
+ local syntax = self.syntax
+ local writer = self.writer
+
+ local label = parsers.dig + parsers.letter
+ local numdelim = parsers.period + parsers.rparent
+ local enumerator = C(label^3 * numdelim) * #parsers.spacing
+ + C(label^2 * numdelim) * #parsers.spacing
+ * (parsers.tab + parsers.space^1)
+ + C(label * numdelim) * #parsers.spacing
+ * (parsers.tab + parsers.space^-2)
+ + parsers.space * C(label^2 * numdelim)
+ * #parsers.spacing
+ + parsers.space * C(label * numdelim)
+ * #parsers.spacing
+ * (parsers.tab + parsers.space^-1)
+ + parsers.space * parsers.space * C(label^1
+ * numdelim) * #parsers.spacing
+ local starter = parsers.bullet + enumerator
+
+ local NestedList = Cs((parsers.optionallyindentedline
+ - starter)^1)
+ / function(a) return "\001"..a end
+
+ local ListBlockLine = parsers.optionallyindentedline
+ - parsers.blankline - (parsers.indent^-1
+ * starter)
+
+ local ListBlock = parsers.line * ListBlockLine^0
+
+ local ListContinuationBlock = parsers.blanklines * (parsers.indent / "")
+ * ListBlock
+
+ local TightListItem = function(starter)
+ return -parsers.HorizontalRule
+ * (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
+ * Cs( starter / "" * parsers.tickbox^-1 * ListBlock * Cc("\n")
+ * (NestedList + ListContinuationBlock^0)
+ * (parsers.blanklines / "\n\n")
+ ) / self.parser_functions.parse_blocks_nested
+ end
+
+ local function roman2number(roman)
+ local romans = { ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 }
+ local numeral = 0
+
+ local i = 1
+ local len = string.len(roman)
+ while i < len do
+ local z1, z2 = romans[ string.sub(roman, i, i) ], romans[ string.sub(roman, i+1, i+1) ]
+ if z1 < z2 then
+ numeral = numeral + (z2 - z1)
+ i = i + 2
+ else
+ numeral = numeral + z1
+ i = i + 1
+ end
+ end
+ if i <= len then numeral = numeral + romans[ string.sub(roman,i,i) ] end
+ return numeral
+ end
+
+ local function sniffstyle(itemprefix)
+ local numstr, delimend = itemprefix:match("^([A-Za-z0-9]*)([.)]*)")
+ local numdelim
+ if delimend == ")" then
+ numdelim = "OneParen"
+ elseif delimend == "." then
+ numdelim = "Period"
+ else
+ numdelim = "Default"
+ end
+ numstr = numstr or itemprefix
+
+ local num
+ num = numstr:match("^([IVXL]+)")
+ if num then
+ return roman2number(num), "UpperRoman", numdelim
+ end
+ num = numstr:match("^([ivxl]+)")
+ if num then
+ return roman2number(string.upper(num)), "LowerRoman", numdelim
+ end
+ num = numstr:match("^([A-Z])")
+ if num then
+ return string.byte(num) - string.byte("A") + 1, "UpperAlpha", numdelim
+ end
+ num = numstr:match("^([a-z])")
+ if num then
+ return string.byte(num) - string.byte("a") + 1, "LowerAlpha", numdelim
+ end
+ return math.floor(tonumber(numstr) or 1), "Decimal", numdelim
+ end
+
+ local function fancylist(items,tight,start)
+ local startnum, numstyle, numdelim = sniffstyle(start)
+ return writer.fancylist(items,tight,
+ options.startNumber and startnum,
+ numstyle or "Decimal",
+ numdelim or "Default")
+ end
+
+ local FancyList = Cg(enumerator, "listtype") *
+ ( Ct(TightListItem(Cb("listtype"))
+ * TightListItem(enumerator)^0)
+ * Cc(true) * parsers.skipblanklines * -enumerator
+ + Ct(LooseListItem(Cb("listtype"))
+ * LooseListItem(enumerator)^0)
+ * Cc(false) * parsers.skipblanklines
+ ) * Cb("listtype") / fancylist
+
+ syntax.OrderedList = FancyList
+
+ end
+ }
+end
function M.new(options)
options = options or {}
setmetatable(options, { __index = function (_, key)
@@ -4683,6 +4921,26 @@ function M.new(options)
table.insert(extensions, pipe_tables_extension)
end
+ if options.strikeThrough then
+ local strike_through_extension = M.extensions.strike_through()
+ table.insert(extensions, strike_through_extension)
+ end
+
+ if options.subscripts then
+ local subscript_extension = M.extensions.subscripts()
+ table.insert(extensions, subscript_extension)
+ end
+
+ if options.superscripts then
+ local superscript_extension = M.extensions.superscripts()
+ table.insert(extensions, superscript_extension)
+ end
+
+ if options.fancyLists then
+ local fancy_lists_extension = M.extensions.fancy_lists()
+ table.insert(extensions, fancy_lists_extension)
+ end
+
local writer = M.writer.new(options)
local reader = M.reader.new(writer, options, extensions)