summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/markdown/markdown.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/luatex/markdown/markdown.lua')
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown.lua400
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(