summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-12-23 21:03:50 +0000
committerKarl Berry <karl@freefriends.org>2022-12-23 21:03:50 +0000
commit8d383d484835575910b71ef5e1746d57be9afef3 (patch)
tree5d61e2067af838ba094af5faed2682ca07373ff1 /Master/texmf-dist/tex/luatex
parent23f484c87d10a1d39e2ea85bab67f04e17adff4a (diff)
markdown (23dec22)
git-svn-id: svn://tug.org/texlive/trunk@65339 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown.lua909
1 files changed, 542 insertions, 367 deletions
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua
index 3afe0a924d4..8a5a6ce9f56 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.18.0-0-gd8ae860",
+ version = "2.19.0-0-g80fcf20",
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",
@@ -118,7 +118,9 @@ defaultOptions.debugExtensionsFileName = "debug-extensions.json"
defaultOptions.frozenCacheFileName = "frozenCache.tex"
defaultOptions.blankBeforeBlockquote = false
defaultOptions.blankBeforeCodeFence = false
+defaultOptions.blankBeforeDivFence = false
defaultOptions.blankBeforeHeading = false
+defaultOptions.bracketedSpans = false
defaultOptions.breakableBlockquotes = false
defaultOptions.citationNbsps = true
defaultOptions.citations = false
@@ -127,15 +129,14 @@ defaultOptions.contentBlocks = false
defaultOptions.debugExtensions = false
defaultOptions.definitionLists = false
defaultOptions.eagerCache = true
+defaultOptions.expectJekyllData = false
metadata.user_extension_api_version = 2
metadata.grammar_version = 2
defaultOptions.extensions = {}
-defaultOptions.expectJekyllData = false
defaultOptions.fancyLists = false
defaultOptions.fencedCode = false
+defaultOptions.fencedDivs = false
defaultOptions.finalizeCache = false
-defaultOptions.footnotes = false
-defaultOptions.notes = false
defaultOptions.frozenCacheCounter = 0
defaultOptions.hardLineBreaks = false
defaultOptions.hashEnumerators = false
@@ -145,6 +146,8 @@ defaultOptions.hybrid = false
defaultOptions.inlineFootnotes = false
defaultOptions.inlineNotes = false
defaultOptions.jekyllData = false
+defaultOptions.footnotes = false
+defaultOptions.notes = false
defaultOptions.pipeTables = false
defaultOptions.preserveTabs = false
defaultOptions.rawAttribute = true
@@ -2423,7 +2426,6 @@ function M.writer.new(options)
self.escaped_uri_chars = {
["{"] = "\\markdownRendererLeftBrace{}",
["}"] = "\\markdownRendererRightBrace{}",
- ["%"] = "\\markdownRendererPercentSign{}",
["\\"] = "\\markdownRendererBackslash{}",
}
self.escaped_minimal_strings = {
@@ -2577,6 +2579,27 @@ function M.writer.new(options)
return buf
end
+ function self.attributes(attr)
+ local buf = {}
+
+ table.sort(attr)
+ local key, value
+ for i = 1, #attr do
+ if attr[i]:sub(1, 1) == "#" then
+ table.insert(buf, {"\\markdownRendererAttributeIdentifier{",
+ attr[i]:sub(2), "}"})
+ elseif attr[i]:sub(1, 1) == "." then
+ table.insert(buf, {"\\markdownRendererAttributeClassName{",
+ attr[i]:sub(2), "}"})
+ else
+ key, value = attr[i]:match("([^= ]+)%s*=%s*(.*)")
+ table.insert(buf, {"\\markdownRendererAttributeKeyValue{",
+ key, "}{", value, "}"})
+ end
+ end
+
+ return buf
+ end
self.active_attributes = {}
function self.heading(s, level, attributes)
attributes = attributes or {}
@@ -2655,21 +2678,7 @@ function M.writer.new(options)
end
if self.is_writing then
- table.sort(attributes)
- local key, value
- for i = 1, #attributes do
- if attributes[i]:sub(1, 1) == "#" then
- table.insert(buf, {"\\markdownRendererAttributeIdentifier{",
- attributes[i]:sub(2), "}"})
- elseif attributes[i]:sub(1, 1) == "." then
- table.insert(buf, {"\\markdownRendererAttributeClassName{",
- attributes[i]:sub(2), "}"})
- else
- key, value = attributes[i]:match("([^= ]+)%s*=%s*(.*)")
- table.insert(buf, {"\\markdownRendererAttributeKeyValue{",
- key, "}{", value, "}"})
- end
- end
+ table.insert(buf, self.attributes(attributes))
end
local cmd
@@ -2770,7 +2779,8 @@ parsers.doubletildes = P("~~")
parsers.fourspaces = P(" ")
parsers.any = P(1)
-parsers.fail = parsers.any - 1
+parsers.succeed = P(true)
+parsers.fail = P(false)
parsers.escapable = S("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
parsers.anyescaped = parsers.backslash / "" * parsers.escapable
@@ -2922,14 +2932,31 @@ 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.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)
+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 * C(parsers.infostring)
+ * parsers.optionalspace * Ct(parsers.attributes)
* parsers.optionalspace * (parsers.newline + parsers.eof)
end
@@ -3145,12 +3172,14 @@ end
parsers.urlchar = parsers.anyescaped - parsers.newline - parsers.more
parsers.TildeFencedCode
- = parsers.fencehead(parsers.tilde)
+ = parsers.fencehead(parsers.tilde,
+ parsers.tilde_infostring)
* Cs(parsers.fencedline(parsers.tilde)^0)
* parsers.fencetail(parsers.tilde)
parsers.BacktickFencedCode
- = parsers.fencehead(parsers.backtick)
+ = parsers.fencehead(parsers.backtick,
+ parsers.backtick_infostring)
* Cs(parsers.fencedline(parsers.backtick)^0)
* parsers.fencetail(parsers.backtick)
@@ -3698,12 +3727,12 @@ function M.reader.new(writer, options)
local syntax =
{ "Blocks",
- Blocks = ( V("ExpectedJekyllData")
- * (V("Blank")^0 / writer.interblocksep)
- )^-1
+ Blocks = V("InitializeState")
+ * ( V("ExpectedJekyllData")
+ * (V("Blank")^0 / writer.interblocksep))^-1
* V("Blank")^0
* V("Block")^-1
- * (V("Blank")^0 / writer.interblocksep
+ * ( V("Blank")^0 / writer.interblocksep
* V("Block"))^0
* V("Blank")^0 * parsers.eof,
@@ -3742,12 +3771,24 @@ function M.reader.new(writer, options)
Smart = parsers.Smart,
Symbol = parsers.Symbol,
SpecialChar = parsers.fail,
+ InitializeState = parsers.succeed,
}
- self.update_rule = function(rule_name, pattern)
+ self.update_rule = function(rule_name, get_pattern)
assert(current_extension_name ~= nil)
assert(syntax[rule_name] ~= nil,
[[Rule ]] .. rule_name .. [[ -> ... does not exist in markdown grammar]])
- local accountable_pattern = { pattern, current_extension_name, rule_name }
+ local previous_pattern
+ local extension_name
+ if walkable_syntax[rule_name] then
+ local previous_accountable_pattern = walkable_syntax[rule_name][1]
+ previous_pattern = previous_accountable_pattern[1]
+ extension_name = previous_accountable_pattern[2] .. ", " .. current_extension_name
+ else
+ previous_pattern = nil
+ extension_name = current_extension_name
+ end
+ local pattern = get_pattern(previous_pattern)
+ local accountable_pattern = { pattern, extension_name, rule_name }
walkable_syntax[rule_name] = { accountable_pattern }
end
local special_characters = {}
@@ -3763,6 +3804,10 @@ function M.reader.new(writer, options)
self.add_special_character("<")
self.add_special_character("!")
self.add_special_character("\\")
+ self.initialize_named_group = function(name, value)
+ syntax.InitializeState = syntax.InitializeState
+ * Cg(Ct("") / value, name)
+ end
for _, extension in ipairs(extensions) do
current_extension_name = extension.name
extension.extend_writer(writer)
@@ -3875,7 +3920,10 @@ function M.reader.new(writer, options)
local inlines_t = util.table_copy(syntax)
inlines_t[1] = "Inlines"
- inlines_t.Inlines = parsers.Inline^0 * (parsers.spacing^0 * parsers.eof / "")
+ inlines_t.Inlines = V("InitializeState")
+ * parsers.Inline^0
+ * ( parsers.spacing^0
+ * parsers.eof / "")
parsers.inlines = Ct(inlines_t)
local inlines_no_link_t = util.table_copy(inlines_t)
@@ -3944,6 +3992,31 @@ function M.reader.new(writer, options)
return self
end
M.extensions = {}
+M.extensions.bracketed_spans = function()
+ return {
+ name = "built-in bracketed_spans syntax extension",
+ extend_writer = function(self)
+ function self.span(s, attr)
+ return {"\\markdownRendererBracketedSpanAttributeContextBegin",
+ self.attributes(attr),
+ s,
+ "\\markdownRendererBracketedSpanAttributeContextEnd{}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local Span = parsers.between(parsers.Inline,
+ parsers.lbracket,
+ parsers.rbracket)
+ * Ct(parsers.attributes)
+ / writer.span
+
+ self.insert_pattern("Inline after Emph",
+ Span, "Span")
+ end
+ }
+end
M.extensions.citations = function(citation_nbsps)
local escaped_citation_chars = {
["{"] = "\\markdownRendererLeftBrace{}",
@@ -4296,6 +4369,163 @@ M.extensions.definition_lists = function(tight_lists)
end
}
end
+M.extensions.fancy_lists = function()
+ return {
+ name = "built-in fancy_lists syntax extension",
+ 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 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.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.ThematicBreak
+ * 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
+
+ self.update_rule("OrderedList", function() return FancyList end)
+ end
+ }
+end
M.extensions.fenced_code = function(blank_before_code_fence)
return {
name = "built-in fenced_code syntax extension",
@@ -4313,12 +4543,12 @@ M.extensions.fenced_code = function(blank_before_code_fence)
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
+ + parsers.BacktickFencedCode)
+ / function(infostring, code)
+ local expanded_code = self.expandtabs(code)
+ return writer.fencedCode(expanded_code,
+ infostring)
+ end
self.insert_pattern("Block after Verbatim",
FencedCode, "FencedCode")
@@ -4327,83 +4557,105 @@ 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.fencehead(parsers.tilde)
+ fencestart = parsers.fencehead(parsers.backtick,
+ parsers.backtick_infostring)
+ + parsers.fencehead(parsers.tilde,
+ parsers.tilde_infostring)
end
- local EndlineExceptions = parsers.EndlineExceptions + fencestart
- self.update_rule("EndlineExceptions", EndlineExceptions)
+ self.update_rule("EndlineExceptions", function(previous_pattern)
+ if previous_pattern == nil then
+ previous_pattern = parsers.EndlineExceptions
+ end
+ return previous_pattern + fencestart
+ end)
self.add_special_character("~")
end
}
end
-M.extensions.notes = function(notes, inline_notes)
- assert(notes or inline_notes)
+M.extensions.fenced_divs = function(blank_before_div_fence)
return {
- name = "built-in notes syntax extension",
+ name = "built-in fenced_divs syntax extension",
extend_writer = function(self)
- function self.note(s)
- return {"\\markdownRendererNote{",s,"}"}
+ function self.div(c, attr)
+ return {"\\markdownRendererFencedDivAttributeContextBegin",
+ self.attributes(attr),
+ c,
+ "\\markdownRendererFencedDivAttributeContextEnd"}
end
end, extend_reader = function(self)
local parsers = self.parsers
local writer = self.writer
-
- if inline_notes then
- local InlineNote
- = parsers.circumflex
- * (parsers.tag / self.parser_functions.parse_inlines_no_inline_note)
- / writer.note
-
- self.insert_pattern("Inline after Emph",
- InlineNote, "InlineNote")
- end
- if notes then
- local function strip_first_char(s)
- return s:sub(2)
+ local fenced_div_infostring
+ = C((parsers.linechar
+ - ( parsers.spacechar^1
+ * parsers.colon^1))^1)
+
+ local fenced_div_begin = parsers.nonindentspace
+ * parsers.colon^3
+ * parsers.optionalspace
+ * fenced_div_infostring
+ * ( parsers.spacechar^1
+ * parsers.colon^1)^0
+ * parsers.optionalspace
+ * (parsers.newline + parsers.eof)
+
+ local fenced_div_end = parsers.nonindentspace
+ * parsers.colon^3
+ * parsers.optionalspace
+ * (parsers.newline + parsers.eof)
+ self.initialize_named_group("div_level", "0")
+
+ local function increment_div_level(increment)
+ local function update_div_level(s, i, current_level) -- luacheck: ignore s i
+ current_level = tonumber(current_level)
+ local next_level = tostring(current_level + increment)
+ return true, next_level
end
- local RawNoteRef
- = #(parsers.lbracket * parsers.circumflex)
- * parsers.tag / strip_first_char
+ return Cg( Cmt(Cb("div_level"), update_div_level)
+ , "div_level")
+ end
- local rawnotes = {}
+ local FencedDiv = fenced_div_begin * increment_div_level(1)
+ * parsers.skipblanklines
+ * Ct( (V("Block") - fenced_div_end)^-1
+ * ( parsers.blanklines
+ / function()
+ return writer.interblocksep
+ end
+ * (V("Block") - fenced_div_end))^0)
+ * parsers.skipblanklines
+ * fenced_div_end * increment_div_level(-1)
+ / function (infostring, div)
+ local attr = lpeg.match(Ct(parsers.attributes), infostring)
+ if attr == nil then
+ attr = {"." .. infostring}
+ end
+ return div, attr
+ end
+ / writer.div
- -- like indirect_link
- local function lookup_note(ref)
- return writer.defer_call(function()
- local found = rawnotes[self.normalize_tag(ref)]
- if found then
- return writer.note(
- self.parser_functions.parse_blocks_nested(found))
- else
- return {"[",
- self.parser_functions.parse_inlines("^" .. ref), "]"}
- end
- end)
- end
+ self.insert_pattern("Block after Verbatim",
+ FencedDiv, "FencedDiv")
- local function register_note(ref,rawnote)
- rawnotes[self.normalize_tag(ref)] = rawnote
- return ""
+ 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
end
- local NoteRef = RawNoteRef / lookup_note
-
- local NoteBlock
- = parsers.leader * RawNoteRef * parsers.colon
- * parsers.spnl * parsers.indented_blocks(parsers.chunk)
- / register_note
-
- local Blank = NoteBlock + parsers.Blank
- self.update_rule("Blank", Blank)
-
- self.insert_pattern("Inline after Emph",
- NoteRef, "NoteRef")
+ local is_inside_div = Cmt(Cb("div_level"), check_div_level)
+ local fencestart = is_inside_div * fenced_div_end
+ self.update_rule("EndlineExceptions", function(previous_pattern)
+ if previous_pattern == nil then
+ previous_pattern = parsers.EndlineExceptions
+ end
+ return previous_pattern + fencestart
+ end)
end
-
- self.add_special_character("^")
end
}
end
@@ -4458,138 +4710,76 @@ M.extensions.header_attributes = function()
/ writer.heading
local Heading = AtxHeading + SetextHeading
- self.update_rule("Heading", Heading)
+ self.update_rule("Heading", function() return Heading end)
end
}
end
-M.extensions.jekyll_data = function(expect_jekyll_data)
+M.extensions.notes = function(notes, inline_notes)
+ assert(notes or inline_notes)
return {
- name = "built-in jekyll_data syntax extension",
+ name = "built-in notes syntax extension",
extend_writer = function(self)
- function self.jekyllData(d, t, p)
- if not self.is_writing then return "" end
+ function self.note(s)
+ return {"\\markdownRendererNote{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
- local buf = {}
+ if inline_notes then
+ local InlineNote
+ = parsers.circumflex
+ * (parsers.tag / self.parser_functions.parse_inlines_no_inline_note)
+ / writer.note
- local keys = {}
- for k, _ in pairs(d) do
- table.insert(keys, k)
+ self.insert_pattern("Inline after Emph",
+ InlineNote, "InlineNote")
+ end
+ if notes then
+ local function strip_first_char(s)
+ return s:sub(2)
end
- table.sort(keys)
- if not p then
- table.insert(buf, "\\markdownRendererJekyllDataBegin")
- end
+ local RawNoteRef
+ = #(parsers.lbracket * parsers.circumflex)
+ * parsers.tag / strip_first_char
- if #d > 0 then
- table.insert(buf, "\\markdownRendererJekyllDataSequenceBegin{")
- table.insert(buf, self.uri(p or "null"))
- table.insert(buf, "}{")
- table.insert(buf, #keys)
- table.insert(buf, "}")
- else
- table.insert(buf, "\\markdownRendererJekyllDataMappingBegin{")
- table.insert(buf, self.uri(p or "null"))
- table.insert(buf, "}{")
- table.insert(buf, #keys)
- table.insert(buf, "}")
- end
+ local rawnotes = {}
- for _, k in ipairs(keys) do
- local v = d[k]
- local typ = type(v)
- k = tostring(k or "null")
- if typ == "table" and next(v) ~= nil then
- table.insert(
- buf,
- self.jekyllData(v, t, k)
- )
- else
- k = self.uri(k)
- v = tostring(v)
- if typ == "boolean" then
- table.insert(buf, "\\markdownRendererJekyllDataBoolean{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, v)
- table.insert(buf, "}")
- elseif typ == "number" then
- table.insert(buf, "\\markdownRendererJekyllDataNumber{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, v)
- table.insert(buf, "}")
- elseif typ == "string" then
- table.insert(buf, "\\markdownRendererJekyllDataString{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, t(v))
- table.insert(buf, "}")
- elseif typ == "table" then
- table.insert(buf, "\\markdownRendererJekyllDataEmpty{")
- table.insert(buf, k)
- table.insert(buf, "}")
+ -- like indirect_link
+ local function lookup_note(ref)
+ return writer.defer_call(function()
+ local found = rawnotes[self.normalize_tag(ref)]
+ if found then
+ return writer.note(
+ self.parser_functions.parse_blocks_nested(found))
else
- error(format("Unexpected type %s for value of " ..
- "YAML key %s", typ, k))
+ return {"[",
+ self.parser_functions.parse_inlines("^" .. ref), "]"}
end
- end
- end
-
- if #d > 0 then
- table.insert(buf, "\\markdownRendererJekyllDataSequenceEnd")
- else
- table.insert(buf, "\\markdownRendererJekyllDataMappingEnd")
+ end)
end
- if not p then
- table.insert(buf, "\\markdownRendererJekyllDataEnd")
+ local function register_note(ref,rawnote)
+ rawnotes[self.normalize_tag(ref)] = rawnote
+ return ""
end
- return buf
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local JekyllData
- = Cmt( C((parsers.line - P("---") - P("..."))^0)
- , function(s, i, text) -- luacheck: ignore s i
- local data
- local ran_ok, _ = pcall(function()
- local tinyyaml = require("markdown-tinyyaml")
- data = tinyyaml.parse(text, {timestamps=false})
- end)
- if ran_ok and data ~= nil then
- return true, writer.jekyllData(data, function(s)
- return self.parser_functions.parse_blocks_nested(s)
- end, nil)
- else
- return false
- end
- end
- )
+ local NoteRef = RawNoteRef / lookup_note
- local UnexpectedJekyllData
- = P("---")
- * parsers.blankline / 0
- * #(-parsers.blankline) -- if followed by blank, it's thematic break
- * JekyllData
- * (P("---") + P("..."))
+ local NoteBlock
+ = parsers.leader * RawNoteRef * parsers.colon
+ * parsers.spnl * parsers.indented_blocks(parsers.chunk)
+ / register_note
- local ExpectedJekyllData
- = ( P("---")
- * parsers.blankline / 0
- * #(-parsers.blankline) -- if followed by blank, it's thematic break
- )^-1
- * JekyllData
- * (P("---") + P("..."))^-1
+ local Blank = NoteBlock + parsers.Blank
+ self.update_rule("Blank", function() return Blank end)
- self.insert_pattern("Block before Blockquote",
- UnexpectedJekyllData, "UnexpectedJekyllData")
- if expect_jekyll_data then
- self.update_rule("ExpectedJekyllData", ExpectedJekyllData)
+ self.insert_pattern("Inline after Emph",
+ NoteRef, "NoteRef")
end
+
+ self.add_special_character("^")
end
}
end
@@ -4775,17 +4965,17 @@ M.extensions.raw_attribute = function()
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
+ + 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")
@@ -4816,28 +5006,6 @@ M.extensions.strike_through = function()
end
}
end
-M.extensions.superscripts = function()
- return {
- name = "built-in superscripts syntax extension",
- extend_writer = function(self)
- function self.superscript(s)
- return {"\\markdownRendererSuperscript{",s,"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local Superscript = (
- parsers.between(parsers.Str, parsers.circumflex, parsers.circumflex)
- ) / writer.superscript
-
- self.insert_pattern("Inline after Emph",
- Superscript, "Superscript")
-
- self.add_special_character("^")
- end
- }
-end
M.extensions.subscripts = function()
return {
name = "built-in subscripts syntax extension",
@@ -4860,160 +5028,156 @@ M.extensions.subscripts = function()
end
}
end
-M.extensions.fancy_lists = function()
+M.extensions.superscripts = function()
return {
- name = "built-in fancy_lists syntax extension",
+ name = "built-in superscripts syntax extension",
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
+ function self.superscript(s)
+ return {"\\markdownRendererSuperscript{",s,"}"}
end
end, extend_reader = function(self)
local parsers = self.parsers
- local options = self.options
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 Superscript = (
+ parsers.between(parsers.Str, parsers.circumflex, parsers.circumflex)
+ ) / writer.superscript
- local ListBlockLine = parsers.optionallyindentedline
- - parsers.blankline - (parsers.indent^-1
- * starter)
+ self.insert_pattern("Inline after Emph",
+ Superscript, "Superscript")
- local ListBlock = parsers.line * ListBlockLine^0
+ self.add_special_character("^")
+ end
+ }
+end
+M.extensions.jekyll_data = function(expect_jekyll_data)
+ return {
+ name = "built-in jekyll_data syntax extension",
+ extend_writer = function(self)
+ function self.jekyllData(d, t, p)
+ if not self.is_writing then return "" end
- local ListContinuationBlock = parsers.blanklines * (parsers.indent / "")
- * ListBlock
+ local buf = {}
- local TightListItem = function(starter)
- return -parsers.ThematicBreak
- * (Cs(starter / "" * parsers.tickbox^-1 * ListBlock * NestedList^-1)
- / self.parser_functions.parse_blocks_nested)
- * -(parsers.blanklines * parsers.indent)
- end
+ local keys = {}
+ for k, _ in pairs(d) do
+ table.insert(keys, k)
+ end
+ table.sort(keys)
- local LooseListItem = function(starter)
- return -parsers.ThematicBreak
- * Cs( starter / "" * parsers.tickbox^-1 * ListBlock * Cc("\n")
- * (NestedList + ListContinuationBlock^0)
- * (parsers.blanklines / "\n\n")
- ) / self.parser_functions.parse_blocks_nested
- end
+ if not p then
+ table.insert(buf, "\\markdownRendererJekyllDataBegin")
+ end
- local function roman2number(roman)
- local romans = { ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 }
- local numeral = 0
+ if #d > 0 then
+ table.insert(buf, "\\markdownRendererJekyllDataSequenceBegin{")
+ table.insert(buf, self.uri(p or "null"))
+ table.insert(buf, "}{")
+ table.insert(buf, #keys)
+ table.insert(buf, "}")
+ else
+ table.insert(buf, "\\markdownRendererJekyllDataMappingBegin{")
+ table.insert(buf, self.uri(p or "null"))
+ table.insert(buf, "}{")
+ table.insert(buf, #keys)
+ table.insert(buf, "}")
+ end
- 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
+ for _, k in ipairs(keys) do
+ local v = d[k]
+ local typ = type(v)
+ k = tostring(k or "null")
+ if typ == "table" and next(v) ~= nil then
+ table.insert(
+ buf,
+ self.jekyllData(v, t, k)
+ )
else
- numeral = numeral + z1
- i = i + 1
+ k = self.uri(k)
+ v = tostring(v)
+ if typ == "boolean" then
+ table.insert(buf, "\\markdownRendererJekyllDataBoolean{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, v)
+ table.insert(buf, "}")
+ elseif typ == "number" then
+ table.insert(buf, "\\markdownRendererJekyllDataNumber{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, v)
+ table.insert(buf, "}")
+ elseif typ == "string" then
+ table.insert(buf, "\\markdownRendererJekyllDataString{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, t(v))
+ table.insert(buf, "}")
+ elseif typ == "table" then
+ table.insert(buf, "\\markdownRendererJekyllDataEmpty{")
+ table.insert(buf, k)
+ table.insert(buf, "}")
+ else
+ error(format("Unexpected type %s for value of " ..
+ "YAML key %s", typ, k))
+ end
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"
+ if #d > 0 then
+ table.insert(buf, "\\markdownRendererJekyllDataSequenceEnd")
else
- numdelim = "Default"
+ table.insert(buf, "\\markdownRendererJekyllDataMappingEnd")
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
+ if not p then
+ table.insert(buf, "\\markdownRendererJekyllDataEnd")
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")
+ return buf
end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
- 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
+ local JekyllData
+ = Cmt( C((parsers.line - P("---") - P("..."))^0)
+ , function(s, i, text) -- luacheck: ignore s i
+ local data
+ local ran_ok, _ = pcall(function()
+ local tinyyaml = require("markdown-tinyyaml")
+ data = tinyyaml.parse(text, {timestamps=false})
+ end)
+ if ran_ok and data ~= nil then
+ return true, writer.jekyllData(data, function(s)
+ return self.parser_functions.parse_blocks_nested(s)
+ end, nil)
+ else
+ return false
+ end
+ end
+ )
- self.update_rule("OrderedList", FancyList)
+ local UnexpectedJekyllData
+ = P("---")
+ * parsers.blankline / 0
+ * #(-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 thematic break
+ )^-1
+ * JekyllData
+ * (P("---") + P("..."))^-1
+
+ self.insert_pattern("Block before Blockquote",
+ UnexpectedJekyllData, "UnexpectedJekyllData")
+ if expect_jekyll_data then
+ self.update_rule("ExpectedJekyllData", function() return ExpectedJekyllData end)
+ end
end
}
end
@@ -5023,6 +5187,11 @@ function M.new(options)
return defaultOptions[key] end })
local extensions = {}
+ if options.bracketedSpans then
+ local bracketed_spans_extension = M.extensions.bracketed_spans()
+ table.insert(extensions, bracketed_spans_extension)
+ end
+
if options.contentBlocks then
local content_blocks_extension = M.extensions.content_blocks(
options.contentBlocksLanguageMap)
@@ -5041,6 +5210,12 @@ function M.new(options)
table.insert(extensions, fenced_code_extension)
end
+ if options.fencedDivs then
+ local fenced_div_extension = M.extensions.fenced_divs(
+ options.blankBeforeDivFence)
+ table.insert(extensions, fenced_div_extension)
+ end
+
if options.headerAttributes then
local header_attributes_extension = M.extensions.header_attributes()
table.insert(extensions, header_attributes_extension)