Skip to content

Commit

Permalink
Add fancy_lists syntax extension
Browse files Browse the repository at this point in the history
  • Loading branch information
Witiko committed Aug 18, 2022
1 parent f67cb77 commit 2474d50
Showing 1 changed file with 214 additions and 46 deletions.
260 changes: 214 additions & 46 deletions markdown.dtx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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}
%
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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") *
Expand Down Expand Up @@ -21016,6 +21025,8 @@ M.extensions.citations = function(citation_nbsps)
}
return {
extend_writer = function(self)
local options = self.options

% \end{macrocode}
% \par
% \begin{markdown}
Expand All @@ -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
Expand Down Expand Up @@ -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}
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 2474d50

Please sign in to comment.