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
26local List = require 'pandoc.List'
30------------------------------------------------------------------------
33-- Create metatables which allow to access numerical indices via accessor
38--- Create a new indexing function.
39-- @param template function template
40-- @param indices list of indices, starting with the most deeply nested
41-- @return newly created function
43function make_indexing_function(template, indices)
44 local loadstring = loadstring or load
46 for i = 1, #indices do
47 bracketed[i] = string.format('[%d]', indices[#indices - i + 1])
49 local fnstr = string.format('return ' .. template, table.concat(bracketed))
50 return assert(loadstring(fnstr))()
53--- Create accessor functions using a function template.
54-- @param fn_template function template in which '%s' is replacd with indices
55-- @param accessors list of accessors
56-- @return mapping from accessor names to accessor functions
58local function create_accessor_functions (fn_template, accessors)
60 function add_accessors(acc, ...)
61 if type(acc) == "string" then
62 res[acc] = make_indexing_function(fn_template, {...})
64 for i = 1, #(acc or {}) do
65 add_accessors(acc[i], i, ...)
69 add_accessors(accessors)
73--- Create a new table which allows to access numerical indices via accessor
76local function create_accessor_behavior (tag, accessors)
77 local behavior = {tag = tag}
78 behavior.getters = create_accessor_functions(
79 'function (x) return x.c%s end',
82 behavior.setters = create_accessor_functions(
83 'function (x, v) x.c%s = v end',
86 behavior.__index = function(t, k)
87 if getmetatable(t).getters[k] then
88 return getmetatable(t).getters[k](t)
90 return getmetatable(t)["tag"]
92 return getmetatable(t)[k]
95 behavior.__newindex = function(t, k, v)
96 if getmetatable(t).setters[k] then
97 getmetatable(t).setters[k](t, v)
106------------------------------------------------------------------------
107-- The base class for types
117 setmetatable(obj, self)
121Type.behavior.__index = Type.behavior
123--- Set a new behavior for the type, inheriting that of the parent type if none
124--- is specified explicitely
125-- @param behavior the behavior object for this type.
127function Type:set_behavior (behavior)
128 behavior = behavior or {}
129 behavior.__index = rawget(behavior, '__index') or behavior
130 behavior.__type = self
131 if not getmetatable(behavior) and getmetatable(self) then
132 setmetatable(behavior, getmetatable(self).behavior)
134 self.behavior = behavior
137--- Create a new subtype, using the given table as base.
138-- @param name name of the new type
139-- @param[opt] behavior behavioral object for the new type.
142function Type:make_subtype(name, behavior)
143 local newtype = setmetatable({}, self)
145 newtype.__index = newtype
146 newtype:set_behavior(behavior)
151------------------------------------------------------------------------
152-- The base class for pandoc's AST elements.
155local AstElement = Type:make_subtype 'AstElement'
156AstElement.__call = function(t, ...)
157 local success, ret = pcall(t.new, t, ...)
159 return setmetatable(ret, t.behavior)
161 error(string.format('Constructor for %s failed: %s\n', t.name, ret))
165--- Make a new subtype which constructs a new value when called.
167function AstElement:make_subtype(...)
168 local newtype = Type.make_subtype(self, ...)
169 newtype.__call = self.__call
173--- Create a new constructor
175-- @param tag Tag used to identify the constructor
176-- @param fn Function to be called when constructing a new element
177-- @param accessors names to use as accessors for numerical fields
178-- @return function that constructs a new element
179function AstElement:create_constructor(tag, fn, accessors)
180 local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
181 function constr:new(...)
182 return setmetatable(fn(...), self.behavior)
184 self.constructor = self.constructor or {}
185 self.constructor[tag] = constr
189--- Ensure a given object is an Inline element, or convert it into one.
190local function ensureInlineList (x)
191 if type(x) == string then
192 return List:new{M.Str(x)}
194 -- Lists are not tagged, but all elements are
201------------------------------------------------------------------------
205--- A complete pandoc document
207-- @tparam {Block,...} blocks document content
208-- @tparam[opt] Meta meta document meta data
209M.Pandoc = AstElement:make_subtype'Pandoc'
210function M.Pandoc:new (blocks, meta)
212 blocks = List:new(blocks),
217-- DEPRECATED synonym:
220------------------------------------------------------------------------
224--- Create a new Meta object. It sets the metatable of the given table to
227-- @tparam meta table table containing document meta information
228M.Meta = AstElement:make_subtype'Meta'
229function M.Meta:new (meta) return meta end
232------------------------------------------------------------------------
235M.MetaValue = AstElement:make_subtype('MetaValue')
238-- @function MetaBlocks
239-- @tparam {Block,...} blocks blocks
240M.MetaBlocks = M.MetaValue:create_constructor(
242 function (content) return List:new(content) end
246-- @function MetaInlines
247-- @tparam {Inline,...} inlines inlines
248M.MetaInlines = M.MetaValue:create_constructor(
250 function (content) return ensureInlineList(content) end
255-- @tparam {MetaValue,...} meta_values list of meta values
256M.MetaList = M.MetaValue:create_constructor(
258 function (content) return List:new(content) end
263-- @tparam table key_value_map a string-indexed map of meta values
264M.MetaMap = M.MetaValue:create_constructor(
266 function (mm) return mm end
269--- Creates string to be used in meta data.
270-- Does nothing, lua strings are meta strings.
271-- @function MetaString
272-- @tparam string str string value
273function M.MetaString(str)
277--- Creates boolean to be used in meta data.
278-- Does nothing, lua booleans are meta booleans.
280-- @tparam boolean bool boolean value
281function M.MetaBool(bool)
285------------------------------------------------------------------------
290M.Block = AstElement:make_subtype'Block'
292--- Creates a block quote element
293-- @function BlockQuote
294-- @tparam {Block,...} content block content
295-- @treturn Block block quote element
296M.BlockQuote = M.Block:create_constructor(
298 function(content) return {c = content} end,
302--- Creates a bullet (i.e. unordered) list.
303-- @function BulletList
304-- @tparam {{Block,...},...} content list of items
305-- @treturn Block bullet list element
306M.BulletList = M.Block:create_constructor(
308 function(content) return {c = content} end,
312--- Creates a code block element
313-- @function CodeBlock
314-- @tparam string text code string
315-- @tparam[opt] Attr attr element attributes
316-- @treturn Block code block element
317M.CodeBlock = M.Block:create_constructor(
319 function(text, attr) return {c = {attr or M.Attr(), text}} end,
320 {{"identifier", "classes", "attributes"}, "text"}
323--- Creates a definition list, containing terms and their explanation.
324-- @function DefinitionList
325-- @tparam {{{Inline,...},{Block,...}},...} content list of items
326-- @treturn Block definition list element
327M.DefinitionList = M.Block:create_constructor(
329 function(content) return {c = List:new(content)} end,
333--- Creates a div element
335-- @tparam {Block,...} content block content
336-- @tparam[opt] Attr attr element attributes
337-- @treturn Block div element
338M.Div = M.Block:create_constructor(
340 function(content, attr)
341 return {c = {attr or M.Attr(), List:new(content)}}
343 {{"identifier", "classes", "attributes"}, "content"}
346--- Creates a header element.
348-- @tparam int level header level
349-- @tparam {Inline,...} content inline content
350-- @tparam[opt] Attr attr element attributes
351-- @treturn Block header element
352M.Header = M.Block:create_constructor(
354 function(level, content, attr)
355 return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
357 {"level", {"identifier", "classes", "attributes"}, "content"}
360--- Creates a horizontal rule.
361-- @function HorizontalRule
362-- @treturn Block horizontal rule
363M.HorizontalRule = M.Block:create_constructor(
365 function() return {} end
368--- Creates a line block element.
369-- @function LineBlock
370-- @tparam {{Inline,...},...} content inline content
371-- @treturn Block line block element
372M.LineBlock = M.Block:create_constructor(
374 function(content) return {c = List:new(content)} end,
378--- Creates a null element.
380-- @treturn Block null element
381M.Null = M.Block:create_constructor(
383 function() return {} end
386--- Creates an ordered list.
387-- @function OrderedList
388-- @tparam {{Block,...},...} items list items
389-- @param[opt] listAttributes list parameters
390-- @treturn Block ordered list element
391M.OrderedList = M.Block:create_constructor(
393 function(items, listAttributes)
394 listAttributes = listAttributes or {1, M.DefaultStyle, M.DefaultDelim}
395 return {c = {listAttributes, List:new(items)}}
397 {{"start", "style", "delimiter"}, "content"}
400--- Creates a para element.
402-- @tparam {Inline,...} content inline content
403-- @treturn Block paragraph element
404M.Para = M.Block:create_constructor(
406 function(content) return {c = ensureInlineList(content)} end,
410--- Creates a plain element.
412-- @tparam {Inline,...} content inline content
413-- @treturn Block plain element
414M.Plain = M.Block:create_constructor(
416 function(content) return {c = ensureInlineList(content)} end,
420--- Creates a raw content block of the specified format.
422-- @tparam string format format of content
423-- @tparam string text string content
424-- @treturn Block raw block element
425M.RawBlock = M.Block:create_constructor(
427 function(format, text) return {c = {format, text}} end,
431--- Creates a table element.
433-- @tparam {Inline,...} caption table caption
434-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
435-- @tparam {int,...} widths column widths
436-- @tparam {Block,...} headers header row
437-- @tparam {{Block,...}} rows table rows
438-- @treturn Block table element
439M.Table = M.Block:create_constructor(
441 function(caption, aligns, widths, headers, rows)
444 ensureInlineList(caption),
452 {"caption", "aligns", "widths", "headers", "rows"}
456------------------------------------------------------------------------
460--- Inline element class
461M.Inline = AstElement:make_subtype'Inline'
463--- Creates a Cite inline element
465-- @tparam {Inline,...} content List of inlines
466-- @tparam {Citation,...} citations List of citations
467-- @treturn Inline citations element
468M.Cite = M.Inline:create_constructor(
470 function(content, citations)
471 return {c = {List:new(citations), ensureInlineList(content)}}
473 {"citations", "content"}
476--- Creates a Code inline element
478-- @tparam string text brief image description
479-- @tparam[opt] Attr attr additional attributes
480-- @treturn Inline code element
481M.Code = M.Inline:create_constructor(
483 function(text, attr) return {c = {attr or M.Attr(), text}} end,
484 {{"identifier", "classes", "attributes"}, "text"}
487--- Creates an inline element representing emphasised text.
489-- @tparam {Inline,..} content inline content
490-- @treturn Inline emphasis element
491M.Emph = M.Inline:create_constructor(
493 function(content) return {c = ensureInlineList(content)} end,
497--- Creates a Image inline element
499-- @tparam {Inline,..} caption text used to describe the image
500-- @tparam string src path to the image file
501-- @tparam[opt] string title brief image description
502-- @tparam[opt] Attr attr additional attributes
503-- @treturn Inline image element
504M.Image = M.Inline:create_constructor(
506 function(caption, src, title, attr)
508 attr = attr or M.Attr()
509 return {c = {attr, ensureInlineList(caption), {src, title}}}
511 {{"identifier", "classes", "attributes"}, "caption", {"src", "title"}}
514--- Create a LineBreak inline element
515-- @function LineBreak
516-- @treturn Inline linebreak element
517M.LineBreak = M.Inline:create_constructor(
519 function() return {} end
522--- Creates a link inline element, usually a hyperlink.
524-- @tparam {Inline,..} content text for this link
525-- @tparam string target the link target
526-- @tparam[opt] string title brief link description
527-- @tparam[opt] Attr attr additional attributes
528-- @treturn Inline image element
529M.Link = M.Inline:create_constructor(
531 function(content, target, title, attr)
533 attr = attr or M.Attr()
534 return {c = {attr, ensureInlineList(content), {target, title}}}
536 {{"identifier", "classes", "attributes"}, "content", {"target", "title"}}
539--- Creates a Math element, either inline or displayed.
541-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
542-- @tparam string text Math content
543-- @treturn Inline Math element
544M.Math = M.Inline:create_constructor(
546 function(mathtype, text)
547 return {c = {mathtype, text}}
551--- Creates a DisplayMath element (DEPRECATED).
552-- @function DisplayMath
553-- @tparam string text Math content
554-- @treturn Inline Math element
555M.DisplayMath = M.Inline:create_constructor(
557 function(text) return M.Math("DisplayMath", text) end,
560--- Creates an InlineMath inline element (DEPRECATED).
561-- @function InlineMath
562-- @tparam string text Math content
563-- @treturn Inline Math element
564M.InlineMath = M.Inline:create_constructor(
566 function(text) return M.Math("InlineMath", text) end,
570--- Creates a Note inline element
572-- @tparam {Block,...} content footnote block content
573M.Note = M.Inline:create_constructor(
575 function(content) return {c = List:new(content)} end,
579--- Creates a Quoted inline element given the quote type and quoted content.
581-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
582-- @tparam {Inline,..} content inline content
583-- @treturn Inline quoted element
584M.Quoted = M.Inline:create_constructor(
586 function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
587 {"quotetype", "content"}
589--- Creates a single-quoted inline element (DEPRECATED).
590-- @function SingleQuoted
591-- @tparam {Inline,..} content inline content
592-- @treturn Inline quoted element
594M.SingleQuoted = M.Inline:create_constructor(
596 function(content) return M.Quoted(M.SingleQuote, content) end,
597 {"quotetype", "content"}
599--- Creates a single-quoted inline element (DEPRECATED).
600-- @function DoubleQuoted
601-- @tparam {Inline,..} content inline content
602-- @treturn Inline quoted element
604M.DoubleQuoted = M.Inline:create_constructor(
606 function(content) return M.Quoted("DoubleQuote", content) end,
607 {"quotetype", "content"}
610--- Creates a RawInline inline element
611-- @function RawInline
612-- @tparam string format format of the contents
613-- @tparam string text string content
614-- @treturn Inline raw inline element
615M.RawInline = M.Inline:create_constructor(
617 function(format, text) return {c = {format, text}} end,
621--- Creates text rendered in small caps
622-- @function SmallCaps
623-- @tparam {Inline,..} content inline content
624-- @treturn Inline smallcaps element
625M.SmallCaps = M.Inline:create_constructor(
627 function(content) return {c = ensureInlineList(content)} end,
631--- Creates a SoftBreak inline element.
632-- @function SoftBreak
633-- @treturn Inline softbreak element
634M.SoftBreak = M.Inline:create_constructor(
636 function() return {} end
639--- Create a Space inline element
641-- @treturn Inline space element
642M.Space = M.Inline:create_constructor(
644 function() return {} end
647--- Creates a Span inline element
649-- @tparam {Inline,..} content inline content
650-- @tparam[opt] Attr attr additional attributes
651-- @treturn Inline span element
652M.Span = M.Inline:create_constructor(
654 function(content, attr)
655 return {c = {attr or M.Attr(), ensureInlineList(content)}}
657 {{"identifier", "classes", "attributes"}, "content"}
660--- Creates a Str inline element
662-- @tparam string text content
663-- @treturn Inline string element
664M.Str = M.Inline:create_constructor(
666 function(text) return {c = text} end,
670--- Creates text which is striked out.
671-- @function Strikeout
672-- @tparam {Inline,..} content inline content
673-- @treturn Inline strikeout element
674M.Strikeout = M.Inline:create_constructor(
676 function(content) return {c = ensureInlineList(content)} end,
680--- Creates a Strong element, whose text is usually displayed in a bold font.
682-- @tparam {Inline,..} content inline content
683-- @treturn Inline strong element
684M.Strong = M.Inline:create_constructor(
686 function(content) return {c = ensureInlineList(content)} end,
690--- Creates a Subscript inline element
691-- @function Subscript
692-- @tparam {Inline,..} content inline content
693-- @treturn Inline subscript element
694M.Subscript = M.Inline:create_constructor(
696 function(content) return {c = ensureInlineList(content)} end,
700--- Creates a Superscript inline element
701-- @function Superscript
702-- @tparam {Inline,..} content inline content
703-- @treturn Inline strong element
704M.Superscript = M.Inline:create_constructor(
706 function(content) return {c = ensureInlineList(content)} end,
711------------------------------------------------------------------------
713-- @section components
715--- Check if the first element of a pair matches the given value.
716-- @param x key value to be checked
717-- @return function returning true iff first element of its argument matches x
719local function assoc_key_equals (x)
720 return function (y) return y[1] == x end
723--- Lookup a value in an associative list
726-- @tparam {{key, value},...} alist associative list
727-- @param key key for which the associated value is to be looked up
728local function lookup(alist, key)
729 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
732--- Return an iterator which returns key-value pairs of an associative list.
735-- @tparam {{key, value},...} alist associative list
736local apairs = function (alist)
740 cur = rawget(alist, i)
743 return cur[1], cur[2]
750--- AttributeList, a metatable to allow table-like access to attribute lists
751-- represented by associative lists.
753local AttributeList = {
754 __index = function (t, k)
755 if type(k) == "number" then
762 __newindex = function (t, k, v)
763 local cur, idx = List.find_if(t, assoc_key_equals(k))
768 elseif type(k) == "number" then
771 rawset(t, #t + 1, {k, v})
778--- Convert a table to an associative list. The order of key-value pairs in the
779-- alist is undefined. The table should either contain no numeric keys or
780-- already be an associative list.
782-- @tparam table tbl associative list or table without numeric keys.
783-- @treturn table associative list
784local to_alist = function (tbl)
785 if #tbl ~= 0 or next(tbl) == nil then
786 -- probably already an alist
791 for k, v in pairs(tbl) do
800--- Create a new set of attributes (Attr).
802-- @tparam[opt] string identifier element identifier
803-- @tparam[opt] {string,...} classes element classes
804-- @tparam[opt] table attributes table containing string keys and values
805-- @return element attributes
806M.Attr = AstElement:make_subtype'Attr'
807function M.Attr:new (identifier, classes, attributes)
808 identifier = identifier or ''
809 classes = List:new(classes or {})
810 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
811 return {identifier, classes, attributes}
813M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
814M.Attr.behavior.__index = function(t, k)
815 return rawget(t, getmetatable(t)._field_names[k]) or
818M.Attr.behavior.__newindex = function(t, k, v)
819 if getmetatable(t)._field_names[k] then
820 rawset(t, getmetatable(t)._field_names[k], v)
827M.Citation = AstElement:make_subtype'Citation'
829--- Creates a single citation.
831-- @tparam string id citation identifier (like a bibtex key)
832-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
833-- @tparam[opt] {Inline,...} prefix citation prefix
834-- @tparam[opt] {Inline,...} suffix citation suffix
835-- @tparam[opt] int note_num note number
836-- @tparam[opt] int hash hash number
837function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
841 prefix = prefix or {},
842 suffix = suffix or {},
843 note_num = note_num or 0,
849------------------------------------------------------------------------
853--- Author name is mentioned in the text.
856M.AuthorInText = "AuthorInText"
858--- Author name is suppressed.
861M.SuppressAuthor = "SuppressAuthor"
863--- Default citation style is used.
866M.NormalCitation = "NormalCitation"
868--- Table cells aligned left.
870M.AlignLeft = "AlignLeft"
872--- Table cells right-aligned.
874M.AlignRight = "AlignRight"
876--- Table cell content is centered.
878M.AlignCenter = "AlignCenter"
880--- Table cells are alignment is unaltered.
882M.AlignDefault = "AlignDefault"
884--- Default list number delimiters are used.
886M.DefaultDelim = "DefaultDelim"
888--- List numbers are delimited by a period.
892--- List numbers are delimited by a single parenthesis.
894M.OneParen = "OneParen"
896--- List numbers are delimited by a double parentheses.
898M.TwoParens = "TwoParens"
900--- List are numbered in the default style
902M.DefaultStyle = "DefaultStyle"
904--- List items are numbered as examples.
908--- List are numbered using decimal integers.
912--- List are numbered using lower-case roman numerals.
914M.LowerRoman = "LowerRoman"
916--- List are numbered using upper-case roman numerals
918M.UpperRoman = "UpperRoman"
920--- List are numbered using lower-case alphabetic characters.
922M.LowerAlpha = "LowerAlpha"
924--- List are numbered using upper-case alphabetic characters.
926M.UpperAlpha = "UpperAlpha"
928------------------------------------------------------------------------
929-- Functions which have moved to different modules
930local 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