4Copyright © 2017–2018 Albert Krewinkel
6Permission to use, copy, modify, and/or distribute this software for any purpose
7with or without fee is hereby granted, provided that the above copyright notice
8and this permission notice appear in all copies.
10THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
12FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
14OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
20-- Lua functions for pandoc scripts.
22-- @author Albert Krewinkel
23-- @copyright © 2017–2018 Albert Krewinkel
27local List = require 'pandoc.List'
29------------------------------------------------------------------------
32-- Create metatables which allow to access numerical indices via accessor
37--- Create a new indexing function.
38-- @param template function template
39-- @param indices list of indices, starting with the most deeply nested
40-- @return newly created function
42function make_indexing_function(template, indices)
43 local loadstring = loadstring or load
45 for i = 1, #indices do
46 bracketed[i] = string.format('[%d]', indices[#indices - i + 1])
48 local fnstr = string.format('return ' .. template, table.concat(bracketed))
49 return assert(loadstring(fnstr))()
52--- Create accessor functions using a function template.
53-- @param fn_template function template in which '%s' is replacd with indices
54-- @param accessors list of accessors
55-- @return mapping from accessor names to accessor functions
57local function create_accessor_functions (fn_template, accessors)
59 function add_accessors(acc, ...)
60 if type(acc) == 'string' then
61 res[acc] = make_indexing_function(fn_template, {...})
62 elseif type(acc) == 'table' and #acc == 0 and next(acc) then
63 local name, substructure = next(acc)
64 res[name] = make_indexing_function(fn_template, {...})
65 add_accessors(substructure, ...)
67 for i = 1, #(acc or {}) do
68 add_accessors(acc[i], i, ...)
72 add_accessors(accessors)
76--- Create a new table which allows to access numerical indices via accessor
79local function create_accessor_behavior (tag, accessors)
80 local behavior = {tag = tag}
81 behavior.getters = create_accessor_functions(
82 'function (x) return x.c%s end',
85 behavior.setters = create_accessor_functions(
86 'function (x, v) x.c%s = v end',
89 behavior.__index = function(t, k)
90 if getmetatable(t).getters[k] then
91 return getmetatable(t).getters[k](t)
93 return getmetatable(t)["tag"]
95 return getmetatable(t)[k]
98 behavior.__newindex = function(t, k, v)
99 if getmetatable(t).setters[k] then
100 getmetatable(t).setters[k](t, v)
109------------------------------------------------------------------------
110-- The base class for types
120 setmetatable(obj, self)
124Type.behavior.__index = Type.behavior
126--- Set a new behavior for the type, inheriting that of the parent type if none
127--- is specified explicitly
128-- @param behavior the behavior object for this type.
130function Type:set_behavior (behavior)
131 behavior = behavior or {}
132 behavior.__index = rawget(behavior, '__index') or behavior
133 behavior.__type = self
134 if not getmetatable(behavior) and getmetatable(self) then
135 setmetatable(behavior, getmetatable(self).behavior)
137 self.behavior = behavior
140--- Create a new subtype, using the given table as base.
141-- @param name name of the new type
142-- @param[opt] behavior behavioral object for the new type.
145function Type:make_subtype(name, behavior)
146 local newtype = setmetatable({}, self)
148 newtype.__index = newtype
149 newtype:set_behavior(behavior)
154------------------------------------------------------------------------
155-- The base class for pandoc's AST elements.
158local AstElement = Type:make_subtype 'AstElement'
159AstElement.__call = function(t, ...)
160 local success, ret = pcall(t.new, t, ...)
162 return setmetatable(ret, t.behavior)
164 error(string.format('Constructor for %s failed: %s\n', t.name, ret))
168--- Make a new subtype which constructs a new value when called.
170function AstElement:make_subtype(...)
171 local newtype = Type.make_subtype(self, ...)
172 newtype.__call = self.__call
176--- Create a new constructor
178-- @param tag Tag used to identify the constructor
179-- @param fn Function to be called when constructing a new element
180-- @param accessors names to use as accessors for numerical fields
181-- @return function that constructs a new element
182function AstElement:create_constructor(tag, fn, accessors)
183 local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
184 function constr:new(...)
185 return setmetatable(fn(...), self.behavior)
187 self.constructor = self.constructor or {}
188 self.constructor[tag] = constr
192--- Convert AstElement input into a list if necessary.
194local function ensureList (x)
196 -- Lists are not tagged, but all elements are
203--- Ensure a given object is an Inline element, or convert it into one.
205local function ensureInlineList (x)
206 if type(x) == 'string' then
207 return List:new{M.Str(x)}
213------------------------------------------------------------------------
217--- A complete pandoc document
219-- @tparam {Block,...} blocks document content
220-- @tparam[opt] Meta meta document meta data
221M.Pandoc = AstElement:make_subtype'Pandoc'
222function M.Pandoc:new (blocks, meta)
224 blocks = ensureList(blocks),
229-- DEPRECATED synonym:
232------------------------------------------------------------------------
236--- Create a new Meta object. It sets the metatable of the given table to
239-- @tparam meta table table containing document meta information
240M.Meta = AstElement:make_subtype'Meta'
241function M.Meta:new (meta) return meta end
244------------------------------------------------------------------------
247M.MetaValue = AstElement:make_subtype('MetaValue')
250-- @function MetaBlocks
251-- @tparam {Block,...} blocks blocks
252M.MetaBlocks = M.MetaValue:create_constructor(
254 function (content) return ensureList(content) end
258-- @function MetaInlines
259-- @tparam {Inline,...} inlines inlines
260M.MetaInlines = M.MetaValue:create_constructor(
262 function (content) return ensureInlineList(content) end
267-- @tparam {MetaValue,...} meta_values list of meta values
268M.MetaList = M.MetaValue:create_constructor(
271 if content.tag == 'MetaList' then
274 return ensureList(content)
280-- @tparam table key_value_map a string-indexed map of meta values
281M.MetaMap = M.MetaValue:create_constructor(
283 function (mm) return mm end
286--- Creates string to be used in meta data.
287-- Does nothing, lua strings are meta strings.
288-- @function MetaString
289-- @tparam string str string value
290function M.MetaString(str)
294--- Creates boolean to be used in meta data.
295-- Does nothing, lua booleans are meta booleans.
297-- @tparam boolean bool boolean value
298function M.MetaBool(bool)
302------------------------------------------------------------------------
307M.Block = AstElement:make_subtype'Block'
309--- Creates a block quote element
310-- @function BlockQuote
311-- @tparam {Block,...} content block content
312-- @treturn Block block quote element
313M.BlockQuote = M.Block:create_constructor(
315 function(content) return {c = ensureList(content)} end,
319--- Creates a bullet (i.e. unordered) list.
320-- @function BulletList
321-- @tparam {{Block,...},...} content list of items
322-- @treturn Block bullet list element
323M.BulletList = M.Block:create_constructor(
325 function(content) return {c = ensureList(content)} end,
329--- Creates a code block element
330-- @function CodeBlock
331-- @tparam string text code string
332-- @tparam[opt] Attr attr element attributes
333-- @treturn Block code block element
334M.CodeBlock = M.Block:create_constructor(
336 function(text, attr) return {c = {attr or M.Attr(), text}} end,
337 {{attr = {"identifier", "classes", "attributes"}}, "text"}
340--- Creates a definition list, containing terms and their explanation.
341-- @function DefinitionList
342-- @tparam {{{Inline,...},{Block,...}},...} content list of items
343-- @treturn Block definition list element
344M.DefinitionList = M.Block:create_constructor(
346 function(content) return {c = ensureList(content)} end,
350--- Creates a div element
352-- @tparam {Block,...} content block content
353-- @tparam[opt] Attr attr element attributes
354-- @treturn Block div element
355M.Div = M.Block:create_constructor(
357 function(content, attr)
358 return {c = {attr or M.Attr(), ensureList(content)}}
360 {{attr = {"identifier", "classes", "attributes"}}, "content"}
363--- Creates a header element.
365-- @tparam int level header level
366-- @tparam {Inline,...} content inline content
367-- @tparam[opt] Attr attr element attributes
368-- @treturn Block header element
369M.Header = M.Block:create_constructor(
371 function(level, content, attr)
372 return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
374 {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
377--- Creates a horizontal rule.
378-- @function HorizontalRule
379-- @treturn Block horizontal rule
380M.HorizontalRule = M.Block:create_constructor(
382 function() return {} end
385--- Creates a line block element.
386-- @function LineBlock
387-- @tparam {{Inline,...},...} content inline content
388-- @treturn Block line block element
389M.LineBlock = M.Block:create_constructor(
391 function(content) return {c = ensureList(content)} end,
395--- Creates a null element.
397-- @treturn Block null element
398M.Null = M.Block:create_constructor(
400 function() return {} end
403--- Creates an ordered list.
404-- @function OrderedList
405-- @tparam {{Block,...},...} items list items
406-- @param[opt] listAttributes list parameters
407-- @treturn Block ordered list element
408M.OrderedList = M.Block:create_constructor(
410 function(items, listAttributes)
411 listAttributes = listAttributes or M.ListAttributes()
412 return {c = {listAttributes, ensureList(items)}}
414 {{listAttributes = {"start", "style", "delimiter"}}, "content"}
417--- Creates a para element.
419-- @tparam {Inline,...} content inline content
420-- @treturn Block paragraph element
421M.Para = M.Block:create_constructor(
423 function(content) return {c = ensureInlineList(content)} end,
427--- Creates a plain element.
429-- @tparam {Inline,...} content inline content
430-- @treturn Block plain element
431M.Plain = M.Block:create_constructor(
433 function(content) return {c = ensureInlineList(content)} end,
437--- Creates a raw content block of the specified format.
439-- @tparam string format format of content
440-- @tparam string text string content
441-- @treturn Block raw block element
442M.RawBlock = M.Block:create_constructor(
444 function(format, text) return {c = {format, text}} end,
448--- Creates a table element.
450-- @tparam {Inline,...} caption table caption
451-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
452-- @tparam {int,...} widths column widths
453-- @tparam {Block,...} headers header row
454-- @tparam {{Block,...}} rows table rows
455-- @treturn Block table element
456M.Table = M.Block:create_constructor(
458 function(caption, aligns, widths, headers, rows)
461 ensureInlineList(caption),
469 {"caption", "aligns", "widths", "headers", "rows"}
473------------------------------------------------------------------------
477--- Inline element class
478M.Inline = AstElement:make_subtype'Inline'
480--- Creates a Cite inline element
482-- @tparam {Inline,...} content List of inlines
483-- @tparam {Citation,...} citations List of citations
484-- @treturn Inline citations element
485M.Cite = M.Inline:create_constructor(
487 function(content, citations)
488 return {c = {ensureList(citations), ensureInlineList(content)}}
490 {"citations", "content"}
493--- Creates a Code inline element
495-- @tparam string text code string
496-- @tparam[opt] Attr attr additional attributes
497-- @treturn Inline code element
498M.Code = M.Inline:create_constructor(
500 function(text, attr) return {c = {attr or M.Attr(), text}} end,
501 {{attr = {"identifier", "classes", "attributes"}}, "text"}
504--- Creates an inline element representing emphasised text.
506-- @tparam {Inline,..} content inline content
507-- @treturn Inline emphasis element
508M.Emph = M.Inline:create_constructor(
510 function(content) return {c = ensureInlineList(content)} end,
514--- Creates a Image inline element
516-- @tparam {Inline,..} caption text used to describe the image
517-- @tparam string src path to the image file
518-- @tparam[opt] string title brief image description
519-- @tparam[opt] Attr attr additional attributes
520-- @treturn Inline image element
521M.Image = M.Inline:create_constructor(
523 function(caption, src, title, attr)
525 attr = attr or M.Attr()
526 return {c = {attr, ensureInlineList(caption), {src, title}}}
528 {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
531--- Create a LineBreak inline element
532-- @function LineBreak
533-- @treturn Inline linebreak element
534M.LineBreak = M.Inline:create_constructor(
536 function() return {} end
539--- Creates a link inline element, usually a hyperlink.
541-- @tparam {Inline,..} content text for this link
542-- @tparam string target the link target
543-- @tparam[opt] string title brief link description
544-- @tparam[opt] Attr attr additional attributes
545-- @treturn Inline image element
546M.Link = M.Inline:create_constructor(
548 function(content, target, title, attr)
550 attr = attr or M.Attr()
551 return {c = {attr, ensureInlineList(content), {target, title}}}
553 {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
556--- Creates a Math element, either inline or displayed.
558-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
559-- @tparam string text Math content
560-- @treturn Inline Math element
561M.Math = M.Inline:create_constructor(
563 function(mathtype, text)
564 return {c = {mathtype, text}}
568--- Creates a DisplayMath element (DEPRECATED).
569-- @function DisplayMath
570-- @tparam string text Math content
571-- @treturn Inline Math element
572M.DisplayMath = M.Inline:create_constructor(
574 function(text) return M.Math("DisplayMath", text) end,
577--- Creates an InlineMath inline element (DEPRECATED).
578-- @function InlineMath
579-- @tparam string text Math content
580-- @treturn Inline Math element
581M.InlineMath = M.Inline:create_constructor(
583 function(text) return M.Math("InlineMath", text) end,
587--- Creates a Note inline element
589-- @tparam {Block,...} content footnote block content
590M.Note = M.Inline:create_constructor(
592 function(content) return {c = ensureList(content)} end,
596--- Creates a Quoted inline element given the quote type and quoted content.
598-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
599-- @tparam {Inline,..} content inline content
600-- @treturn Inline quoted element
601M.Quoted = M.Inline:create_constructor(
603 function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
604 {"quotetype", "content"}
606--- Creates a single-quoted inline element (DEPRECATED).
607-- @function SingleQuoted
608-- @tparam {Inline,..} content inline content
609-- @treturn Inline quoted element
611M.SingleQuoted = M.Inline:create_constructor(
613 function(content) return M.Quoted(M.SingleQuote, content) end,
614 {"quotetype", "content"}
616--- Creates a single-quoted inline element (DEPRECATED).
617-- @function DoubleQuoted
618-- @tparam {Inline,..} content inline content
619-- @treturn Inline quoted element
621M.DoubleQuoted = M.Inline:create_constructor(
623 function(content) return M.Quoted("DoubleQuote", content) end,
624 {"quotetype", "content"}
627--- Creates a RawInline inline element
628-- @function RawInline
629-- @tparam string format format of the contents
630-- @tparam string text string content
631-- @treturn Inline raw inline element
632M.RawInline = M.Inline:create_constructor(
634 function(format, text) return {c = {format, text}} end,
638--- Creates text rendered in small caps
639-- @function SmallCaps
640-- @tparam {Inline,..} content inline content
641-- @treturn Inline smallcaps element
642M.SmallCaps = M.Inline:create_constructor(
644 function(content) return {c = ensureInlineList(content)} end,
648--- Creates a SoftBreak inline element.
649-- @function SoftBreak
650-- @treturn Inline softbreak element
651M.SoftBreak = M.Inline:create_constructor(
653 function() return {} end
656--- Create a Space inline element
658-- @treturn Inline space element
659M.Space = M.Inline:create_constructor(
661 function() return {} end
664--- Creates a Span inline element
666-- @tparam {Inline,..} content inline content
667-- @tparam[opt] Attr attr additional attributes
668-- @treturn Inline span element
669M.Span = M.Inline:create_constructor(
671 function(content, attr)
672 return {c = {attr or M.Attr(), ensureInlineList(content)}}
674 {{attr = {"identifier", "classes", "attributes"}}, "content"}
677--- Creates a Str inline element
679-- @tparam string text content
680-- @treturn Inline string element
681M.Str = M.Inline:create_constructor(
683 function(text) return {c = text} end,
687--- Creates text which is striked out.
688-- @function Strikeout
689-- @tparam {Inline,..} content inline content
690-- @treturn Inline strikeout element
691M.Strikeout = M.Inline:create_constructor(
693 function(content) return {c = ensureInlineList(content)} end,
697--- Creates a Strong element, whose text is usually displayed in a bold font.
699-- @tparam {Inline,..} content inline content
700-- @treturn Inline strong element
701M.Strong = M.Inline:create_constructor(
703 function(content) return {c = ensureInlineList(content)} end,
707--- Creates a Subscript inline element
708-- @function Subscript
709-- @tparam {Inline,..} content inline content
710-- @treturn Inline subscript element
711M.Subscript = M.Inline:create_constructor(
713 function(content) return {c = ensureInlineList(content)} end,
717--- Creates a Superscript inline element
718-- @function Superscript
719-- @tparam {Inline,..} content inline content
720-- @treturn Inline strong element
721M.Superscript = M.Inline:create_constructor(
723 function(content) return {c = ensureInlineList(content)} end,
728------------------------------------------------------------------------
730-- @section components
732--- Check if the first element of a pair matches the given value.
733-- @param x key value to be checked
734-- @return function returning true iff first element of its argument matches x
736local function assoc_key_equals (x)
737 return function (y) return y[1] == x end
740--- Lookup a value in an associative list
743-- @tparam {{key, value},...} alist associative list
744-- @param key key for which the associated value is to be looked up
745local function lookup(alist, key)
746 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
749--- Return an iterator which returns key-value pairs of an associative list.
752-- @tparam {{key, value},...} alist associative list
753local apairs = function (alist)
757 cur = rawget(alist, i)
760 return cur[1], cur[2]
767--- AttributeList, a metatable to allow table-like access to attribute lists
768-- represented by associative lists.
770local AttributeList = {
771 __index = function (t, k)
772 if type(k) == "number" then
779 __newindex = function (t, k, v)
780 local cur, idx = List.find_if(t, assoc_key_equals(k))
785 elseif type(k) == "number" then
788 rawset(t, #t + 1, {k, v})
795--- Convert a table to an associative list. The order of key-value pairs in the
796-- alist is undefined. The table should either contain no numeric keys or
797-- already be an associative list.
799-- @tparam table tbl associative list or table without numeric keys.
800-- @treturn table associative list
801local to_alist = function (tbl)
802 if #tbl ~= 0 or next(tbl) == nil then
803 -- probably already an alist
808 for k, v in pairs(tbl) do
817--- Create a new set of attributes (Attr).
819-- @tparam[opt] string identifier element identifier
820-- @tparam[opt] {string,...} classes element classes
821-- @tparam[opt] table attributes table containing string keys and values
822-- @return element attributes
823M.Attr = AstElement:make_subtype'Attr'
824function M.Attr:new (identifier, classes, attributes)
825 identifier = identifier or ''
826 classes = ensureList(classes or {})
827 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
828 return {identifier, classes, attributes}
830M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
831M.Attr.behavior.__index = function(t, k)
832 return rawget(t, getmetatable(t)._field_names[k]) or
835M.Attr.behavior.__newindex = function(t, k, v)
836 if getmetatable(t)._field_names[k] then
837 rawset(t, getmetatable(t)._field_names[k], v)
844M.Citation = AstElement:make_subtype'Citation'
846--- Creates a single citation.
848-- @tparam string id citation identifier (like a bibtex key)
849-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
850-- @tparam[opt] {Inline,...} prefix citation prefix
851-- @tparam[opt] {Inline,...} suffix citation suffix
852-- @tparam[opt] int note_num note number
853-- @tparam[opt] int hash hash number
854function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
858 prefix = ensureList(prefix or {}),
859 suffix = ensureList(suffix or {}),
860 note_num = note_num or 0,
866M.ListAttributes = AstElement:make_subtype 'ListAttributes'
868--- Creates a set of list attributes.
869-- @function ListAttributes
870-- @tparam[opt] integer start number of the first list item
871-- @tparam[opt] string style style used for list numbering
872-- @tparam[opt] DefaultDelim|Period|OneParen|TwoParens delimiter delimiter of list numbers
873-- @treturn table list attributes table
874function M.ListAttributes:new (start, style, delimiter)
876 style = style or 'DefaultStyle'
877 delimiter = delimiter or 'DefaultDelim'
878 return {start, style, delimiter}
880M.ListAttributes.behavior._field_names = {start = 1, style = 2, delimiter = 3}
881M.ListAttributes.behavior.__index = function (t, k)
882 return rawget(t, getmetatable(t)._field_names[k]) or
885M.ListAttributes.behavior.__newindex = function (t, k, v)
886 if getmetatable(t)._field_names[k] then
887 rawset(t, getmetatable(t)._field_names[k], v)
894------------------------------------------------------------------------
898--- Author name is mentioned in the text.
901M.AuthorInText = "AuthorInText"
903--- Author name is suppressed.
906M.SuppressAuthor = "SuppressAuthor"
908--- Default citation style is used.
911M.NormalCitation = "NormalCitation"
913--- Table cells aligned left.
915M.AlignLeft = "AlignLeft"
917--- Table cells right-aligned.
919M.AlignRight = "AlignRight"
921--- Table cell content is centered.
923M.AlignCenter = "AlignCenter"
925--- Table cells are alignment is unaltered.
927M.AlignDefault = "AlignDefault"
929--- Default list number delimiters are used.
931M.DefaultDelim = "DefaultDelim"
933--- List numbers are delimited by a period.
937--- List numbers are delimited by a single parenthesis.
939M.OneParen = "OneParen"
941--- List numbers are delimited by a double parentheses.
943M.TwoParens = "TwoParens"
945--- List are numbered in the default style
947M.DefaultStyle = "DefaultStyle"
949--- List items are numbered as examples.
953--- List are numbered using decimal integers.
957--- List are numbered using lower-case roman numerals.
959M.LowerRoman = "LowerRoman"
961--- List are numbered using upper-case roman numerals
963M.UpperRoman = "UpperRoman"
965--- List are numbered using lower-case alphabetic characters.
967M.LowerAlpha = "LowerAlpha"
969--- List are numbered using upper-case alphabetic characters.
971M.UpperAlpha = "UpperAlpha"
973------------------------------------------------------------------------
974-- Functions which have moved to different modules
975local utils = require 'pandoc.utils'
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list