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(
270 function (content) return ensureList(content) end
275-- @tparam table key_value_map a string-indexed map of meta values
276M.MetaMap = M.MetaValue:create_constructor(
278 function (mm) return mm end
281--- Creates string to be used in meta data.
282-- Does nothing, lua strings are meta strings.
283-- @function MetaString
284-- @tparam string str string value
285function M.MetaString(str)
289--- Creates boolean to be used in meta data.
290-- Does nothing, lua booleans are meta booleans.
292-- @tparam boolean bool boolean value
293function M.MetaBool(bool)
297------------------------------------------------------------------------
302M.Block = AstElement:make_subtype'Block'
304--- Creates a block quote element
305-- @function BlockQuote
306-- @tparam {Block,...} content block content
307-- @treturn Block block quote element
308M.BlockQuote = M.Block:create_constructor(
310 function(content) return {c = ensureList(content)} end,
314--- Creates a bullet (i.e. unordered) list.
315-- @function BulletList
316-- @tparam {{Block,...},...} content list of items
317-- @treturn Block bullet list element
318M.BulletList = M.Block:create_constructor(
320 function(content) return {c = ensureList(content)} end,
324--- Creates a code block element
325-- @function CodeBlock
326-- @tparam string text code string
327-- @tparam[opt] Attr attr element attributes
328-- @treturn Block code block element
329M.CodeBlock = M.Block:create_constructor(
331 function(text, attr) return {c = {attr or M.Attr(), text}} end,
332 {{attr = {"identifier", "classes", "attributes"}}, "text"}
335--- Creates a definition list, containing terms and their explanation.
336-- @function DefinitionList
337-- @tparam {{{Inline,...},{Block,...}},...} content list of items
338-- @treturn Block definition list element
339M.DefinitionList = M.Block:create_constructor(
341 function(content) return {c = ensureList(content)} end,
345--- Creates a div element
347-- @tparam {Block,...} content block content
348-- @tparam[opt] Attr attr element attributes
349-- @treturn Block div element
350M.Div = M.Block:create_constructor(
352 function(content, attr)
353 return {c = {attr or M.Attr(), ensureList(content)}}
355 {{attr = {"identifier", "classes", "attributes"}}, "content"}
358--- Creates a header element.
360-- @tparam int level header level
361-- @tparam {Inline,...} content inline content
362-- @tparam[opt] Attr attr element attributes
363-- @treturn Block header element
364M.Header = M.Block:create_constructor(
366 function(level, content, attr)
367 return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
369 {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
372--- Creates a horizontal rule.
373-- @function HorizontalRule
374-- @treturn Block horizontal rule
375M.HorizontalRule = M.Block:create_constructor(
377 function() return {} end
380--- Creates a line block element.
381-- @function LineBlock
382-- @tparam {{Inline,...},...} content inline content
383-- @treturn Block line block element
384M.LineBlock = M.Block:create_constructor(
386 function(content) return {c = ensureList(content)} end,
390--- Creates a null element.
392-- @treturn Block null element
393M.Null = M.Block:create_constructor(
395 function() return {} end
398--- Creates an ordered list.
399-- @function OrderedList
400-- @tparam {{Block,...},...} items list items
401-- @param[opt] listAttributes list parameters
402-- @treturn Block ordered list element
403M.OrderedList = M.Block:create_constructor(
405 function(items, listAttributes)
406 listAttributes = listAttributes or {1, M.DefaultStyle, M.DefaultDelim}
407 return {c = {listAttributes, ensureList(items)}}
409 {{listAttributes = {"start", "style", "delimiter"}}, "content"}
412--- Creates a para element.
414-- @tparam {Inline,...} content inline content
415-- @treturn Block paragraph element
416M.Para = M.Block:create_constructor(
418 function(content) return {c = ensureInlineList(content)} end,
422--- Creates a plain element.
424-- @tparam {Inline,...} content inline content
425-- @treturn Block plain element
426M.Plain = M.Block:create_constructor(
428 function(content) return {c = ensureInlineList(content)} end,
432--- Creates a raw content block of the specified format.
434-- @tparam string format format of content
435-- @tparam string text string content
436-- @treturn Block raw block element
437M.RawBlock = M.Block:create_constructor(
439 function(format, text) return {c = {format, text}} end,
443--- Creates a table element.
445-- @tparam {Inline,...} caption table caption
446-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
447-- @tparam {int,...} widths column widths
448-- @tparam {Block,...} headers header row
449-- @tparam {{Block,...}} rows table rows
450-- @treturn Block table element
451M.Table = M.Block:create_constructor(
453 function(caption, aligns, widths, headers, rows)
456 ensureInlineList(caption),
464 {"caption", "aligns", "widths", "headers", "rows"}
468------------------------------------------------------------------------
472--- Inline element class
473M.Inline = AstElement:make_subtype'Inline'
475--- Creates a Cite inline element
477-- @tparam {Inline,...} content List of inlines
478-- @tparam {Citation,...} citations List of citations
479-- @treturn Inline citations element
480M.Cite = M.Inline:create_constructor(
482 function(content, citations)
483 return {c = {ensureList(citations), ensureInlineList(content)}}
485 {"citations", "content"}
488--- Creates a Code inline element
490-- @tparam string text brief image description
491-- @tparam[opt] Attr attr additional attributes
492-- @treturn Inline code element
493M.Code = M.Inline:create_constructor(
495 function(text, attr) return {c = {attr or M.Attr(), text}} end,
496 {{attr = {"identifier", "classes", "attributes"}}, "text"}
499--- Creates an inline element representing emphasised text.
501-- @tparam {Inline,..} content inline content
502-- @treturn Inline emphasis element
503M.Emph = M.Inline:create_constructor(
505 function(content) return {c = ensureInlineList(content)} end,
509--- Creates a Image inline element
511-- @tparam {Inline,..} caption text used to describe the image
512-- @tparam string src path to the image file
513-- @tparam[opt] string title brief image description
514-- @tparam[opt] Attr attr additional attributes
515-- @treturn Inline image element
516M.Image = M.Inline:create_constructor(
518 function(caption, src, title, attr)
520 attr = attr or M.Attr()
521 return {c = {attr, ensureInlineList(caption), {src, title}}}
523 {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
526--- Create a LineBreak inline element
527-- @function LineBreak
528-- @treturn Inline linebreak element
529M.LineBreak = M.Inline:create_constructor(
531 function() return {} end
534--- Creates a link inline element, usually a hyperlink.
536-- @tparam {Inline,..} content text for this link
537-- @tparam string target the link target
538-- @tparam[opt] string title brief link description
539-- @tparam[opt] Attr attr additional attributes
540-- @treturn Inline image element
541M.Link = M.Inline:create_constructor(
543 function(content, target, title, attr)
545 attr = attr or M.Attr()
546 return {c = {attr, ensureInlineList(content), {target, title}}}
548 {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
551--- Creates a Math element, either inline or displayed.
553-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
554-- @tparam string text Math content
555-- @treturn Inline Math element
556M.Math = M.Inline:create_constructor(
558 function(mathtype, text)
559 return {c = {mathtype, text}}
563--- Creates a DisplayMath element (DEPRECATED).
564-- @function DisplayMath
565-- @tparam string text Math content
566-- @treturn Inline Math element
567M.DisplayMath = M.Inline:create_constructor(
569 function(text) return M.Math("DisplayMath", text) end,
572--- Creates an InlineMath inline element (DEPRECATED).
573-- @function InlineMath
574-- @tparam string text Math content
575-- @treturn Inline Math element
576M.InlineMath = M.Inline:create_constructor(
578 function(text) return M.Math("InlineMath", text) end,
582--- Creates a Note inline element
584-- @tparam {Block,...} content footnote block content
585M.Note = M.Inline:create_constructor(
587 function(content) return {c = ensureList(content)} end,
591--- Creates a Quoted inline element given the quote type and quoted content.
593-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
594-- @tparam {Inline,..} content inline content
595-- @treturn Inline quoted element
596M.Quoted = M.Inline:create_constructor(
598 function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
599 {"quotetype", "content"}
601--- Creates a single-quoted inline element (DEPRECATED).
602-- @function SingleQuoted
603-- @tparam {Inline,..} content inline content
604-- @treturn Inline quoted element
606M.SingleQuoted = M.Inline:create_constructor(
608 function(content) return M.Quoted(M.SingleQuote, content) end,
609 {"quotetype", "content"}
611--- Creates a single-quoted inline element (DEPRECATED).
612-- @function DoubleQuoted
613-- @tparam {Inline,..} content inline content
614-- @treturn Inline quoted element
616M.DoubleQuoted = M.Inline:create_constructor(
618 function(content) return M.Quoted("DoubleQuote", content) end,
619 {"quotetype", "content"}
622--- Creates a RawInline inline element
623-- @function RawInline
624-- @tparam string format format of the contents
625-- @tparam string text string content
626-- @treturn Inline raw inline element
627M.RawInline = M.Inline:create_constructor(
629 function(format, text) return {c = {format, text}} end,
633--- Creates text rendered in small caps
634-- @function SmallCaps
635-- @tparam {Inline,..} content inline content
636-- @treturn Inline smallcaps element
637M.SmallCaps = M.Inline:create_constructor(
639 function(content) return {c = ensureInlineList(content)} end,
643--- Creates a SoftBreak inline element.
644-- @function SoftBreak
645-- @treturn Inline softbreak element
646M.SoftBreak = M.Inline:create_constructor(
648 function() return {} end
651--- Create a Space inline element
653-- @treturn Inline space element
654M.Space = M.Inline:create_constructor(
656 function() return {} end
659--- Creates a Span inline element
661-- @tparam {Inline,..} content inline content
662-- @tparam[opt] Attr attr additional attributes
663-- @treturn Inline span element
664M.Span = M.Inline:create_constructor(
666 function(content, attr)
667 return {c = {attr or M.Attr(), ensureInlineList(content)}}
669 {{attr = {"identifier", "classes", "attributes"}}, "content"}
672--- Creates a Str inline element
674-- @tparam string text content
675-- @treturn Inline string element
676M.Str = M.Inline:create_constructor(
678 function(text) return {c = text} end,
682--- Creates text which is striked out.
683-- @function Strikeout
684-- @tparam {Inline,..} content inline content
685-- @treturn Inline strikeout element
686M.Strikeout = M.Inline:create_constructor(
688 function(content) return {c = ensureInlineList(content)} end,
692--- Creates a Strong element, whose text is usually displayed in a bold font.
694-- @tparam {Inline,..} content inline content
695-- @treturn Inline strong element
696M.Strong = M.Inline:create_constructor(
698 function(content) return {c = ensureInlineList(content)} end,
702--- Creates a Subscript inline element
703-- @function Subscript
704-- @tparam {Inline,..} content inline content
705-- @treturn Inline subscript element
706M.Subscript = M.Inline:create_constructor(
708 function(content) return {c = ensureInlineList(content)} end,
712--- Creates a Superscript inline element
713-- @function Superscript
714-- @tparam {Inline,..} content inline content
715-- @treturn Inline strong element
716M.Superscript = M.Inline:create_constructor(
718 function(content) return {c = ensureInlineList(content)} end,
723------------------------------------------------------------------------
725-- @section components
727--- Check if the first element of a pair matches the given value.
728-- @param x key value to be checked
729-- @return function returning true iff first element of its argument matches x
731local function assoc_key_equals (x)
732 return function (y) return y[1] == x end
735--- Lookup a value in an associative list
738-- @tparam {{key, value},...} alist associative list
739-- @param key key for which the associated value is to be looked up
740local function lookup(alist, key)
741 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
744--- Return an iterator which returns key-value pairs of an associative list.
747-- @tparam {{key, value},...} alist associative list
748local apairs = function (alist)
752 cur = rawget(alist, i)
755 return cur[1], cur[2]
762--- AttributeList, a metatable to allow table-like access to attribute lists
763-- represented by associative lists.
765local AttributeList = {
766 __index = function (t, k)
767 if type(k) == "number" then
774 __newindex = function (t, k, v)
775 local cur, idx = List.find_if(t, assoc_key_equals(k))
780 elseif type(k) == "number" then
783 rawset(t, #t + 1, {k, v})
790--- Convert a table to an associative list. The order of key-value pairs in the
791-- alist is undefined. The table should either contain no numeric keys or
792-- already be an associative list.
794-- @tparam table tbl associative list or table without numeric keys.
795-- @treturn table associative list
796local to_alist = function (tbl)
797 if #tbl ~= 0 or next(tbl) == nil then
798 -- probably already an alist
803 for k, v in pairs(tbl) do
812--- Create a new set of attributes (Attr).
814-- @tparam[opt] string identifier element identifier
815-- @tparam[opt] {string,...} classes element classes
816-- @tparam[opt] table attributes table containing string keys and values
817-- @return element attributes
818M.Attr = AstElement:make_subtype'Attr'
819function M.Attr:new (identifier, classes, attributes)
820 identifier = identifier or ''
821 classes = ensureList(classes or {})
822 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
823 return {identifier, classes, attributes}
825M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
826M.Attr.behavior.__index = function(t, k)
827 return rawget(t, getmetatable(t)._field_names[k]) or
830M.Attr.behavior.__newindex = function(t, k, v)
831 if getmetatable(t)._field_names[k] then
832 rawset(t, getmetatable(t)._field_names[k], v)
839M.Citation = AstElement:make_subtype'Citation'
841--- Creates a single citation.
843-- @tparam string id citation identifier (like a bibtex key)
844-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
845-- @tparam[opt] {Inline,...} prefix citation prefix
846-- @tparam[opt] {Inline,...} suffix citation suffix
847-- @tparam[opt] int note_num note number
848-- @tparam[opt] int hash hash number
849function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
853 prefix = ensureList(prefix or {}),
854 suffix = ensureList(suffix or {}),
855 note_num = note_num or 0,
861------------------------------------------------------------------------
865--- Author name is mentioned in the text.
868M.AuthorInText = "AuthorInText"
870--- Author name is suppressed.
873M.SuppressAuthor = "SuppressAuthor"
875--- Default citation style is used.
878M.NormalCitation = "NormalCitation"
880--- Table cells aligned left.
882M.AlignLeft = "AlignLeft"
884--- Table cells right-aligned.
886M.AlignRight = "AlignRight"
888--- Table cell content is centered.
890M.AlignCenter = "AlignCenter"
892--- Table cells are alignment is unaltered.
894M.AlignDefault = "AlignDefault"
896--- Default list number delimiters are used.
898M.DefaultDelim = "DefaultDelim"
900--- List numbers are delimited by a period.
904--- List numbers are delimited by a single parenthesis.
906M.OneParen = "OneParen"
908--- List numbers are delimited by a double parentheses.
910M.TwoParens = "TwoParens"
912--- List are numbered in the default style
914M.DefaultStyle = "DefaultStyle"
916--- List items are numbered as examples.
920--- List are numbered using decimal integers.
924--- List are numbered using lower-case roman numerals.
926M.LowerRoman = "LowerRoman"
928--- List are numbered using upper-case roman numerals
930M.UpperRoman = "UpperRoman"
932--- List are numbered using lower-case alphabetic characters.
934M.LowerAlpha = "LowerAlpha"
936--- List are numbered using upper-case alphabetic characters.
938M.UpperAlpha = "UpperAlpha"
940------------------------------------------------------------------------
941-- Functions which have moved to different modules
942local 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