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
29local List = require 'pandoc.List'
31------------------------------------------------------------------------
34-- Create metatables which allow to access numerical indices via accessor
39--- Create a new indexing function.
40-- @param template function template
41-- @param indices list of indices, starting with the most deeply nested
42-- @return newly created function
44function make_indexing_function(template, indices)
45 local loadstring = loadstring or load
47 for i = 1, #indices do
48 bracketed[i] = string.format('[%d]', indices[#indices - i + 1])
50 local fnstr = string.format('return ' .. template, table.concat(bracketed))
51 return assert(loadstring(fnstr))()
54--- Create accessor functions using a function template.
55-- @param fn_template function template in which '%s' is replacd with indices
56-- @param accessors list of accessors
57-- @return mapping from accessor names to accessor functions
59local function create_accessor_functions (fn_template, accessors)
61 function add_accessors(acc, ...)
62 if type(acc) == "string" then
63 res[acc] = make_indexing_function(fn_template, {...})
65 for i = 1, #(acc or {}) do
66 add_accessors(acc[i], i, ...)
70 add_accessors(accessors)
74--- Create a new table which allows to access numerical indices via accessor
77local function create_accessor_behavior (tag, accessors)
78 local behavior = {tag = tag}
79 behavior.getters = create_accessor_functions(
80 'function (x) return x.c%s end',
83 behavior.setters = create_accessor_functions(
84 'function (x, v) x.c%s = v end',
87 behavior.__index = function(t, k)
88 if getmetatable(t).getters[k] then
89 return getmetatable(t).getters[k](t)
91 return getmetatable(t)["tag"]
93 return getmetatable(t)[k]
96 behavior.__newindex = function(t, k, v)
97 if getmetatable(t).setters[k] then
98 getmetatable(t).setters[k](t, v)
107------------------------------------------------------------------------
108-- The base class for types
118 setmetatable(obj, self)
122Type.behavior.__index = Type.behavior
124--- Set a new behavior for the type, inheriting that of the parent type if none
125--- is specified explicitely
126-- @param behavior the behavior object for this type.
128function Type:set_behavior (behavior)
129 behavior = behavior or {}
130 behavior.__index = rawget(behavior, '__index') or behavior
131 behavior.__type = self
132 if not getmetatable(behavior) and getmetatable(self) then
133 setmetatable(behavior, getmetatable(self).behavior)
135 self.behavior = behavior
138--- Create a new subtype, using the given table as base.
139-- @param name name of the new type
140-- @param[opt] behavior behavioral object for the new type.
143function Type:make_subtype(name, behavior)
144 local newtype = setmetatable({}, self)
146 newtype.__index = newtype
147 newtype:set_behavior(behavior)
152------------------------------------------------------------------------
153-- The base class for pandoc's AST elements.
156local AstElement = Type:make_subtype 'AstElement'
157AstElement.__call = function(t, ...)
158 local success, ret = pcall(t.new, t, ...)
160 return setmetatable(ret, t.behavior)
162 error(string.format('Constructor for %s failed: %s\n', t.name, ret))
166--- Make a new subtype which constructs a new value when called.
168function AstElement:make_subtype(...)
169 local newtype = Type.make_subtype(self, ...)
170 newtype.__call = self.__call
174--- Create a new constructor
176-- @param tag Tag used to identify the constructor
177-- @param fn Function to be called when constructing a new element
178-- @param accessors names to use as accessors for numerical fields
179-- @return function that constructs a new element
180function AstElement:create_constructor(tag, fn, accessors)
181 local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
182 function constr:new(...)
183 return setmetatable(fn(...), self.behavior)
185 self.constructor = self.constructor or {}
186 self.constructor[tag] = constr
190------------------------------------------------------------------------
194--- A complete pandoc document
196-- @tparam {Block,...} blocks document content
197-- @tparam[opt] Meta meta document meta data
198M.Pandoc = AstElement:make_subtype'Pandoc'
199function M.Pandoc:new (blocks, meta)
201 blocks = List:new(blocks),
206-- DEPRECATED synonym:
209------------------------------------------------------------------------
213--- Create a new Meta object. It sets the metatable of the given table to
216-- @tparam meta table table containing document meta information
217M.Meta = AstElement:make_subtype'Meta'
218function M.Meta:new (meta) return meta end
221------------------------------------------------------------------------
224M.MetaValue = AstElement:make_subtype('MetaValue')
227-- @function MetaBlocks
228-- @tparam {Block,...} blocks blocks
229M.MetaBlocks = M.MetaValue:create_constructor(
231 function (content) return List:new(content) end
235-- @function MetaInlines
236-- @tparam {Inline,...} inlines inlines
237M.MetaInlines = M.MetaValue:create_constructor(
239 function (content) return List:new(content) end
244-- @tparam {MetaValue,...} meta_values list of meta values
245M.MetaList = M.MetaValue:create_constructor(
247 function (content) return List:new(content) end
252-- @tparam table key_value_map a string-indexed map of meta values
253M.MetaMap = M.MetaValue:create_constructor(
255 function (mm) return mm end
258--- Creates string to be used in meta data.
259-- Does nothing, lua strings are meta strings.
260-- @function MetaString
261-- @tparam string str string value
262function M.MetaString(str)
266--- Creates boolean to be used in meta data.
267-- Does nothing, lua booleans are meta booleans.
269-- @tparam boolean bool boolean value
270function M.MetaBool(bool)
274------------------------------------------------------------------------
279M.Block = AstElement:make_subtype'Block'
281--- Creates a block quote element
282-- @function BlockQuote
283-- @tparam {Block,...} content block content
284-- @treturn Block block quote element
285M.BlockQuote = M.Block:create_constructor(
287 function(content) return {c = content} end,
291--- Creates a bullet (i.e. unordered) list.
292-- @function BulletList
293-- @tparam {{Block,...},...} content list of items
294-- @treturn Block bullet list element
295M.BulletList = M.Block:create_constructor(
297 function(content) return {c = content} end,
301--- Creates a code block element
302-- @function CodeBlock
303-- @tparam string text code string
304-- @tparam[opt] Attr attr element attributes
305-- @treturn Block code block element
306M.CodeBlock = M.Block:create_constructor(
308 function(text, attr) return {c = {attr or M.Attr(), text}} end,
309 {{"identifier", "classes", "attributes"}, "text"}
312--- Creates a definition list, containing terms and their explanation.
313-- @function DefinitionList
314-- @tparam {{{Inline,...},{Block,...}},...} content list of items
315-- @treturn Block definition list element
316M.DefinitionList = M.Block:create_constructor(
318 function(content) return {c = List:new(content)} end,
322--- Creates a div element
324-- @tparam {Block,...} content block content
325-- @tparam[opt] Attr attr element attributes
326-- @treturn Block div element
327M.Div = M.Block:create_constructor(
329 function(content, attr)
330 return {c = {attr or M.Attr(), List:new(content)}}
332 {{"identifier", "classes", "attributes"}, "content"}
335--- Creates a header element.
337-- @tparam int level header level
338-- @tparam {Inline,...} content inline content
339-- @tparam[opt] Attr attr element attributes
340-- @treturn Block header element
341M.Header = M.Block:create_constructor(
343 function(level, content, attr)
344 return {c = {level, attr or M.Attr(), content}}
346 {"level", {"identifier", "classes", "attributes"}, "content"}
349--- Creates a horizontal rule.
350-- @function HorizontalRule
351-- @treturn Block horizontal rule
352M.HorizontalRule = M.Block:create_constructor(
354 function() return {} end
357--- Creates a line block element.
358-- @function LineBlock
359-- @tparam {{Inline,...},...} content inline content
360-- @treturn Block line block element
361M.LineBlock = M.Block:create_constructor(
363 function(content) return {c = List:new(content)} end,
367--- Creates a null element.
369-- @treturn Block null element
370M.Null = M.Block:create_constructor(
372 function() return {} end
375--- Creates an ordered list.
376-- @function OrderedList
377-- @tparam {{Block,...},...} items list items
378-- @param[opt] listAttributes list parameters
379-- @treturn Block ordered list element
380M.OrderedList = M.Block:create_constructor(
382 function(items, listAttributes)
383 listAttributes = listAttributes or {1, M.DefaultStyle, M.DefaultDelim}
384 return {c = {listAttributes, List:new(items)}}
386 {{"start", "style", "delimiter"}, "content"}
389--- Creates a para element.
391-- @tparam {Inline,...} content inline content
392-- @treturn Block paragraph element
393M.Para = M.Block:create_constructor(
395 function(content) return {c = List:new(content)} end,
399--- Creates a plain element.
401-- @tparam {Inline,...} content inline content
402-- @treturn Block plain element
403M.Plain = M.Block:create_constructor(
405 function(content) return {c = List:new(content)} end,
409--- Creates a raw content block of the specified format.
411-- @tparam string format format of content
412-- @tparam string text string content
413-- @treturn Block raw block element
414M.RawBlock = M.Block:create_constructor(
416 function(format, text) return {c = {format, text}} end,
420--- Creates a table element.
422-- @tparam {Inline,...} caption table caption
423-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
424-- @tparam {int,...} widths column widths
425-- @tparam {Block,...} headers header row
426-- @tparam {{Block,...}} rows table rows
427-- @treturn Block table element
428M.Table = M.Block:create_constructor(
430 function(caption, aligns, widths, headers, rows)
441 {"caption", "aligns", "widths", "headers", "rows"}
445------------------------------------------------------------------------
449--- Inline element class
450M.Inline = AstElement:make_subtype'Inline'
452--- Creates a Cite inline element
454-- @tparam {Inline,...} content List of inlines
455-- @tparam {Citation,...} citations List of citations
456-- @treturn Inline citations element
457M.Cite = M.Inline:create_constructor(
459 function(content, citations)
460 return {c = {List:new(citations), List:new(content)}}
462 {"citations", "content"}
465--- Creates a Code inline element
467-- @tparam string text brief image description
468-- @tparam[opt] Attr attr additional attributes
469-- @treturn Inline code element
470M.Code = M.Inline:create_constructor(
472 function(text, attr) return {c = {attr or M.Attr(), text}} end,
473 {{"identifier", "classes", "attributes"}, "text"}
476--- Creates an inline element representing emphasised text.
478-- @tparam {Inline,..} content inline content
479-- @treturn Inline emphasis element
480M.Emph = M.Inline:create_constructor(
482 function(content) return {c = List:new(content)} end,
486--- Creates a Image inline element
488-- @tparam {Inline,..} caption text used to describe the image
489-- @tparam string src path to the image file
490-- @tparam[opt] string title brief image description
491-- @tparam[opt] Attr attr additional attributes
492-- @treturn Inline image element
493M.Image = M.Inline:create_constructor(
495 function(caption, src, title, attr)
497 attr = attr or M.Attr()
498 return {c = {attr, List:new(caption), {src, title}}}
500 {{"identifier", "classes", "attributes"}, "caption", {"src", "title"}}
503--- Create a LineBreak inline element
504-- @function LineBreak
505-- @treturn Inline linebreak element
506M.LineBreak = M.Inline:create_constructor(
508 function() return {} end
511--- Creates a link inline element, usually a hyperlink.
513-- @tparam {Inline,..} content text for this link
514-- @tparam string target the link target
515-- @tparam[opt] string title brief link description
516-- @tparam[opt] Attr attr additional attributes
517-- @treturn Inline image element
518M.Link = M.Inline:create_constructor(
520 function(content, target, title, attr)
522 attr = attr or M.Attr()
523 return {c = {attr, List:new(content), {target, title}}}
525 {{"identifier", "classes", "attributes"}, "content", {"target", "title"}}
528--- Creates a Math element, either inline or displayed.
530-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
531-- @tparam string text Math content
532-- @treturn Inline Math element
533M.Math = M.Inline:create_constructor(
535 function(mathtype, text)
536 return {c = {mathtype, text}}
540--- Creates a DisplayMath element (DEPRECATED).
541-- @function DisplayMath
542-- @tparam string text Math content
543-- @treturn Inline Math element
544M.DisplayMath = M.Inline:create_constructor(
546 function(text) return M.Math("DisplayMath", text) end,
549--- Creates an InlineMath inline element (DEPRECATED).
550-- @function InlineMath
551-- @tparam string text Math content
552-- @treturn Inline Math element
553M.InlineMath = M.Inline:create_constructor(
555 function(text) return M.Math("InlineMath", text) end,
559--- Creates a Note inline element
561-- @tparam {Block,...} content footnote block content
562M.Note = M.Inline:create_constructor(
564 function(content) return {c = List:new(content)} end,
568--- Creates a Quoted inline element given the quote type and quoted content.
570-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
571-- @tparam {Inline,..} content inline content
572-- @treturn Inline quoted element
573M.Quoted = M.Inline:create_constructor(
575 function(quotetype, content) return {c = {quotetype, List:new(content)}} end,
576 {"quotetype", "content"}
578--- Creates a single-quoted inline element (DEPRECATED).
579-- @function SingleQuoted
580-- @tparam {Inline,..} content inline content
581-- @treturn Inline quoted element
583M.SingleQuoted = M.Inline:create_constructor(
585 function(content) return M.Quoted(M.SingleQuote, content) end,
586 {"quotetype", "content"}
588--- Creates a single-quoted inline element (DEPRECATED).
589-- @function DoubleQuoted
590-- @tparam {Inline,..} content inline content
591-- @treturn Inline quoted element
593M.DoubleQuoted = M.Inline:create_constructor(
595 function(content) return M.Quoted("DoubleQuote", content) end,
596 {"quotetype", "content"}
599--- Creates a RawInline inline element
600-- @function RawInline
601-- @tparam string format format of the contents
602-- @tparam string text string content
603-- @treturn Inline raw inline element
604M.RawInline = M.Inline:create_constructor(
606 function(format, text) return {c = {format, text}} end,
610--- Creates text rendered in small caps
611-- @function SmallCaps
612-- @tparam {Inline,..} content inline content
613-- @treturn Inline smallcaps element
614M.SmallCaps = M.Inline:create_constructor(
616 function(content) return {c = List:new(content)} end,
620--- Creates a SoftBreak inline element.
621-- @function SoftBreak
622-- @treturn Inline softbreak element
623M.SoftBreak = M.Inline:create_constructor(
625 function() return {} end
628--- Create a Space inline element
630-- @treturn Inline space element
631M.Space = M.Inline:create_constructor(
633 function() return {} end
636--- Creates a Span inline element
638-- @tparam {Inline,..} content inline content
639-- @tparam[opt] Attr attr additional attributes
640-- @treturn Inline span element
641M.Span = M.Inline:create_constructor(
643 function(content, attr)
644 return {c = {attr or M.Attr(), List:new(content)}}
646 {{"identifier", "classes", "attributes"}, "content"}
649--- Creates a Str inline element
651-- @tparam string text content
652-- @treturn Inline string element
653M.Str = M.Inline:create_constructor(
655 function(text) return {c = text} end,
659--- Creates text which is striked out.
660-- @function Strikeout
661-- @tparam {Inline,..} content inline content
662-- @treturn Inline strikeout element
663M.Strikeout = M.Inline:create_constructor(
665 function(content) return {c = List:new(content)} end,
669--- Creates a Strong element, whose text is usually displayed in a bold font.
671-- @tparam {Inline,..} content inline content
672-- @treturn Inline strong element
673M.Strong = M.Inline:create_constructor(
675 function(content) return {c = List:new(content)} end,
679--- Creates a Subscript inline element
680-- @function Subscript
681-- @tparam {Inline,..} content inline content
682-- @treturn Inline subscript element
683M.Subscript = M.Inline:create_constructor(
685 function(content) return {c = List:new(content)} end,
689--- Creates a Superscript inline element
690-- @function Superscript
691-- @tparam {Inline,..} content inline content
692-- @treturn Inline strong element
693M.Superscript = M.Inline:create_constructor(
695 function(content) return {c = List:new(content)} end,
700------------------------------------------------------------------------
702-- @section components
704--- Check if the first element of a pair matches the given value.
705-- @param x key value to be checked
706-- @return function returning true iff first element of its argument matches x
708local function assoc_key_equals (x)
709 return function (y) return y[1] == x end
712--- Lookup a value in an associative list
715-- @tparam {{key, value},...} alist associative list
716-- @param key key for which the associated value is to be looked up
717local function lookup(alist, key)
718 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
721--- Return an iterator which returns key-value pairs of an associative list.
724-- @tparam {{key, value},...} alist associative list
725local apairs = function (alist)
729 cur = rawget(alist, i)
732 return cur[1], cur[2]
739--- AttributeList, a metatable to allow table-like access to attribute lists
740-- represented by associative lists.
742local AttributeList = {
743 __index = function (t, k)
744 if type(k) == "number" then
751 __newindex = function (t, k, v)
752 local cur, idx = List.find_if(t, assoc_key_equals(k))
757 elseif type(k) == "number" then
760 rawset(t, #t + 1, {k, v})
767--- Convert a table to an associative list. The order of key-value pairs in the
768-- alist is undefined. The table should either contain no numeric keys or
769-- already be an associative list.
771-- @tparam table tbl associative list or table without numeric keys.
772-- @treturn table associative list
773local to_alist = function (tbl)
774 if #tbl ~= 0 or next(tbl) == nil then
775 -- probably already an alist
780 for k, v in pairs(tbl) do
789--- Create a new set of attributes (Attr).
791-- @tparam[opt] string identifier element identifier
792-- @tparam[opt] {string,...} classes element classes
793-- @tparam[opt] table attributes table containing string keys and values
794-- @return element attributes
795M.Attr = AstElement:make_subtype'Attr'
796function M.Attr:new (identifier, classes, attributes)
797 identifier = identifier or ''
798 classes = List:new(classes or {})
799 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
800 return {identifier, classes, attributes}
802M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
803M.Attr.behavior.__index = function(t, k)
804 return rawget(t, getmetatable(t)._field_names[k]) or
807M.Attr.behavior.__newindex = function(t, k, v)
808 if getmetatable(t)._field_names[k] then
809 rawset(t, getmetatable(t)._field_names[k], v)
816M.Citation = AstElement:make_subtype'Citation'
818--- Creates a single citation.
820-- @tparam string id citation identifier (like a bibtex key)
821-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
822-- @tparam[opt] {Inline,...} prefix citation prefix
823-- @tparam[opt] {Inline,...} suffix citation suffix
824-- @tparam[opt] int note_num note number
825-- @tparam[opt] int hash hash number
826function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
830 prefix = prefix or {},
831 suffix = suffix or {},
832 note_num = note_num or 0,
838------------------------------------------------------------------------
842--- Author name is mentioned in the text.
845M.AuthorInText = "AuthorInText"
847--- Author name is suppressed.
850M.SuppressAuthor = "SuppressAuthor"
852--- Default citation style is used.
855M.NormalCitation = "NormalCitation"
857--- Table cells aligned left.
859M.AlignLeft = "AlignLeft"
861--- Table cells right-aligned.
863M.AlignRight = "AlignRight"
865--- Table cell content is centered.
867M.AlignCenter = "AlignCenter"
869--- Table cells are alignment is unaltered.
871M.AlignDefault = "AlignDefault"
873--- Default list number delimiters are used.
875M.DefaultDelim = "DefaultDelim"
877--- List numbers are delimited by a period.
881--- List numbers are delimited by a single parenthesis.
883M.OneParen = "OneParen"
885--- List numbers are delimited by a double parentheses.
887M.TwoParens = "TwoParens"
889--- List are numbered in the default style
891M.DefaultStyle = "DefaultStyle"
893--- List items are numbered as examples.
897--- List are numbered using decimal integers.
901--- List are numbered using lower-case roman numerals.
903M.LowerRoman = "LowerRoman"
905--- List are numbered using upper-case roman numerals
907M.UpperRoman = "UpperRoman"
909--- List are numbered using lower-case alphabetic characters.
911M.LowerAlpha = "LowerAlpha"
913--- List are numbered using upper-case alphabetic characters.
915M.UpperAlpha = "UpperAlpha"
917------------------------------------------------------------------------
918-- Functions which have moved to different modules
919local 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