diff --git a/markdown.dtx b/markdown.dtx index 183ea8dd4..a6f86ef11 100644 --- a/markdown.dtx +++ b/markdown.dtx @@ -18709,22 +18709,12 @@ function M.writer.new(options) % \par % \begin{markdown} % -% Make `options.cacheDir` available as \luamdef{writer->cacheDir}, so that it -% is accessible from extensions. -% -% \end{markdown} -% \begin{macrocode} - self.cacheDir = options.cacheDir -% \end{macrocode} -% \par -% \begin{markdown} -% -% Make `options.hybrid` available as \luamdef{writer->hybrid}, so that it is +% Make `options` available as \luamdef{writer->options}, so that it is % accessible from extensions. % % \end{markdown} % \begin{macrocode} - self.hybrid = options.hybrid + self.options = options % \end{macrocode} % \par % \begin{markdown} @@ -19003,16 +18993,11 @@ function M.writer.new(options) % % \end{markdown} % \begin{macrocode} - 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 @@ -19024,33 +19009,36 @@ function M.writer.new(options) end end % \end{macrocode} -% \par % \begin{markdown} % -% Define \luamdef{writer->ollist} as a function that will transform an input -% ordered list to the output format, where `items` is an array of the list -% items and `tight` specifies, whether the list is tight or not. If the -% optional parameter `startnum` is present, it should be used as the number -% of the first list item. +% Define \luamdef{writer->bulletitem} as a function that will transform an +% input bulleted list item to the output format, where `s` is the text of +% the list item. % % \end{markdown} % \begin{macrocode} - 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 - +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->orderedlist} as a function that will transform an +% input ordered list to the output format, where `items` is an array of the +% list items and `tight` specifies, whether the list is tight or not. If the +% optional parameter `startnum` is present, it is the number of the first list +% item. +% +% \end{markdown} +% \begin{macrocode} 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 @@ -19065,6 +19053,25 @@ function M.writer.new(options) end end % \end{macrocode} +% \begin{markdown} +% +% Define \luamdef{writer->ordereditem} as a function that will transform an +% input ordered list item to the output format, where `s` is the text of +% the list item. If the optional parameter `num` is present, it is the number +% of the list item. +% +% \end{markdown} +% \begin{macrocode} + function self.ordereditem(s,num) + if num ~= nil then + return {"\\markdownRendererOlItemWithNumber{",num,"}",s, + "\\markdownRendererOlItemEnd "} + else + return {"\\markdownRendererOlItem ",s, + "\\markdownRendererOlItemEnd "} + end + end +% \end{macrocode} % \par % \begin{markdown} % @@ -19118,7 +19125,7 @@ function M.writer.new(options) % \begin{macrocode} 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 % \end{macrocode} @@ -19189,7 +19196,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 % \end{macrocode} @@ -20038,12 +20045,14 @@ function M.reader.new(writer, options, extensions) % \par % \begin{markdown} % -% Make the `writer` parameter available as \luamdef{reader->writer}, so that it -% is accessible from extensions. +% Make the `writer` and `options` parameters available as +% \luamdef{reader->writer} and \luamdef{reader->options}, respectively, so +% that they are accessible from extensions. % % \end{markdown} % \begin{macrocode} self.writer = writer + self.options = options % \end{macrocode} % \par % \begin{markdown} @@ -20616,16 +20625,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") * @@ -21016,6 +21025,8 @@ M.extensions.citations = function(citation_nbsps) } return { extend_writer = function(self) + local options = self.options + % \end{macrocode} % \par % \begin{markdown} @@ -21039,7 +21050,7 @@ M.extensions.citations = function(citation_nbsps) % % \end{markdown} % \begin{macrocode} - if self.hybrid then + if options.hybrid then self.citation = self.escape_minimal else self.citation = escape_citation @@ -21483,6 +21494,8 @@ end M.extensions.fenced_code = function(blank_before_code_fence) return { extend_writer = function(self) + local options = self.options + % \end{macrocode} % \par % \begin{markdown} @@ -21496,7 +21509,7 @@ M.extensions.fenced_code = function(blank_before_code_fence) 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) @@ -22176,6 +22189,161 @@ end % \end{macrocode} % \begin{markdown} % +%#### Fancy Lists +% +% The \luamdef{extensions.fancy_lists} function implements the Pandoc fancy +% list extension. +% +% \end{markdown} +% \begin{macrocode} +M.extensions.fancy_lists = function() + return { + extend_writer = function(self) + local options = self.options + +% \end{macrocode} +% \par +% \begin{markdown} +% +% Define \luamdef{writer->fancylist} as a function that will transform an +% input ordered list to the output format, where: +% +%- `items` is an array of the list items, +%- `tight` specifies, whether the list is tight or not, +%- `startnum` is the number of the first list item, +%- `numstyle` is the style of the list item labels from among the following: +% - `Decimal` -- decimal arabic numbers, +% - `LowerRoman` -- lower roman numbers, +% - `UpperRoman` -- upper roman numbers, +% - `LowerAlpha` -- lower ASCII alphabetic characters, and +% - `UpperAlpha` -- upper ASCII alphabetic characters, and +%- `numdelim` is the style of the delimiters between list item labels and +% texts: +% - `Default` -- default style, +% - `OneParen` -- parentheses, and +% - `Period` -- periods. +% +% \end{markdown} +% \begin{macrocode} + 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.ordereditem(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,"}\n",contents, + "\n\\markdownRendererFancyOlEndTight "} + else + return {"\\markdownRendererFancyOlBegin{", + numstyle,"}{",numdelim,"}\n",contents, + "\n\\markdownRendererFancyOlEnd "} + 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 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(parsers.TightListItem(Cb("listtype")) + * parsers.TightListItem(enumerator)^0) + * Cc(true) * parsers.skipblanklines * -enumerator + + Ct(parsers.LooseListItem(Cb("listtype")) + * parsers.LooseListItem(enumerator)^0) + * Cc(false) * parsers.skipblanklines + ) * Cb("listtype") / fancylist + + syntax.OrderedList = FancyList + + end + } +end +% \end{macrocode} +% \begin{markdown} +% %### Conversion from Markdown to Plain \TeX{} % % The \luamref{new} method returns the \luamref{reader->convert} function of a reader