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)
277for k, v in pairs(List) do
278 M.MetaList.behavior[k] = v
283-- @tparam table key_value_map a string-indexed map of meta values
284M.MetaMap = M.MetaValue:create_constructor(
286 function (mm) return mm end
289--- Creates string to be used in meta data.
290-- Does nothing, lua strings are meta strings.
291-- @function MetaString
292-- @tparam string str string value
293function M.MetaString(str)
297--- Creates boolean to be used in meta data.
298-- Does nothing, lua booleans are meta booleans.
300-- @tparam boolean bool boolean value
301function M.MetaBool(bool)
305------------------------------------------------------------------------
310M.Block = AstElement:make_subtype'Block'
312--- Creates a block quote element
313-- @function BlockQuote
314-- @tparam {Block,...} content block content
315-- @treturn Block block quote element
316M.BlockQuote = M.Block:create_constructor(
318 function(content) return {c = ensureList(content)} end,
322--- Creates a bullet (i.e. unordered) list.
323-- @function BulletList
324-- @tparam {{Block,...},...} content list of items
325-- @treturn Block bullet list element
326M.BulletList = M.Block:create_constructor(
328 function(content) return {c = ensureList(content)} end,
332--- Creates a code block element
333-- @function CodeBlock
334-- @tparam string text code string
335-- @tparam[opt] Attr attr element attributes
336-- @treturn Block code block element
337M.CodeBlock = M.Block:create_constructor(
339 function(text, attr) return {c = {attr or M.Attr(), text}} end,
340 {{attr = {"identifier", "classes", "attributes"}}, "text"}
343--- Creates a definition list, containing terms and their explanation.
344-- @function DefinitionList
345-- @tparam {{{Inline,...},{Block,...}},...} content list of items
346-- @treturn Block definition list element
347M.DefinitionList = M.Block:create_constructor(
349 function(content) return {c = ensureList(content)} end,
353--- Creates a div element
355-- @tparam {Block,...} content block content
356-- @tparam[opt] Attr attr element attributes
357-- @treturn Block div element
358M.Div = M.Block:create_constructor(
360 function(content, attr)
361 return {c = {attr or M.Attr(), ensureList(content)}}
363 {{attr = {"identifier", "classes", "attributes"}}, "content"}
366--- Creates a header element.
368-- @tparam int level header level
369-- @tparam {Inline,...} content inline content
370-- @tparam[opt] Attr attr element attributes
371-- @treturn Block header element
372M.Header = M.Block:create_constructor(
374 function(level, content, attr)
375 return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
377 {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
380--- Creates a horizontal rule.
381-- @function HorizontalRule
382-- @treturn Block horizontal rule
383M.HorizontalRule = M.Block:create_constructor(
385 function() return {} end
388--- Creates a line block element.
389-- @function LineBlock
390-- @tparam {{Inline,...},...} content inline content
391-- @treturn Block line block element
392M.LineBlock = M.Block:create_constructor(
394 function(content) return {c = ensureList(content)} end,
398--- Creates a null element.
400-- @treturn Block null element
401M.Null = M.Block:create_constructor(
403 function() return {} end
406--- Creates an ordered list.
407-- @function OrderedList
408-- @tparam {{Block,...},...} items list items
409-- @param[opt] listAttributes list parameters
410-- @treturn Block ordered list element
411M.OrderedList = M.Block:create_constructor(
413 function(items, listAttributes)
414 listAttributes = listAttributes or M.ListAttributes()
415 return {c = {listAttributes, ensureList(items)}}
417 {{listAttributes = {"start", "style", "delimiter"}}, "content"}
420--- Creates a para element.
422-- @tparam {Inline,...} content inline content
423-- @treturn Block paragraph element
424M.Para = M.Block:create_constructor(
426 function(content) return {c = ensureInlineList(content)} end,
430--- Creates a plain element.
432-- @tparam {Inline,...} content inline content
433-- @treturn Block plain element
434M.Plain = M.Block:create_constructor(
436 function(content) return {c = ensureInlineList(content)} end,
440--- Creates a raw content block of the specified format.
442-- @tparam string format format of content
443-- @tparam string text string content
444-- @treturn Block raw block element
445M.RawBlock = M.Block:create_constructor(
447 function(format, text) return {c = {format, text}} end,
451--- Creates a table element.
453-- @tparam {Inline,...} caption table caption
454-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
455-- @tparam {int,...} widths column widths
456-- @tparam {Block,...} headers header row
457-- @tparam {{Block,...}} rows table rows
458-- @treturn Block table element
459M.Table = M.Block:create_constructor(
461 function(caption, aligns, widths, headers, rows)
464 ensureInlineList(caption),
472 {"caption", "aligns", "widths", "headers", "rows"}
476------------------------------------------------------------------------
480--- Inline element class
481M.Inline = AstElement:make_subtype'Inline'
483--- Creates a Cite inline element
485-- @tparam {Inline,...} content List of inlines
486-- @tparam {Citation,...} citations List of citations
487-- @treturn Inline citations element
488M.Cite = M.Inline:create_constructor(
490 function(content, citations)
491 return {c = {ensureList(citations), ensureInlineList(content)}}
493 {"citations", "content"}
496--- Creates a Code inline element
498-- @tparam string text code string
499-- @tparam[opt] Attr attr additional attributes
500-- @treturn Inline code element
501M.Code = M.Inline:create_constructor(
503 function(text, attr) return {c = {attr or M.Attr(), text}} end,
504 {{attr = {"identifier", "classes", "attributes"}}, "text"}
507--- Creates an inline element representing emphasised text.
509-- @tparam {Inline,..} content inline content
510-- @treturn Inline emphasis element
511M.Emph = M.Inline:create_constructor(
513 function(content) return {c = ensureInlineList(content)} end,
517--- Creates a Image inline element
519-- @tparam {Inline,..} caption text used to describe the image
520-- @tparam string src path to the image file
521-- @tparam[opt] string title brief image description
522-- @tparam[opt] Attr attr additional attributes
523-- @treturn Inline image element
524M.Image = M.Inline:create_constructor(
526 function(caption, src, title, attr)
528 attr = attr or M.Attr()
529 return {c = {attr, ensureInlineList(caption), {src, title}}}
531 {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
534--- Create a LineBreak inline element
535-- @function LineBreak
536-- @treturn Inline linebreak element
537M.LineBreak = M.Inline:create_constructor(
539 function() return {} end
542--- Creates a link inline element, usually a hyperlink.
544-- @tparam {Inline,..} content text for this link
545-- @tparam string target the link target
546-- @tparam[opt] string title brief link description
547-- @tparam[opt] Attr attr additional attributes
548-- @treturn Inline image element
549M.Link = M.Inline:create_constructor(
551 function(content, target, title, attr)
553 attr = attr or M.Attr()
554 return {c = {attr, ensureInlineList(content), {target, title}}}
556 {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
559--- Creates a Math element, either inline or displayed.
561-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
562-- @tparam string text Math content
563-- @treturn Inline Math element
564M.Math = M.Inline:create_constructor(
566 function(mathtype, text)
567 return {c = {mathtype, text}}
571--- Creates a DisplayMath element (DEPRECATED).
572-- @function DisplayMath
573-- @tparam string text Math content
574-- @treturn Inline Math element
575M.DisplayMath = M.Inline:create_constructor(
577 function(text) return M.Math("DisplayMath", text) end,
580--- Creates an InlineMath inline element (DEPRECATED).
581-- @function InlineMath
582-- @tparam string text Math content
583-- @treturn Inline Math element
584M.InlineMath = M.Inline:create_constructor(
586 function(text) return M.Math("InlineMath", text) end,
590--- Creates a Note inline element
592-- @tparam {Block,...} content footnote block content
593M.Note = M.Inline:create_constructor(
595 function(content) return {c = ensureList(content)} end,
599--- Creates a Quoted inline element given the quote type and quoted content.
601-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
602-- @tparam {Inline,..} content inline content
603-- @treturn Inline quoted element
604M.Quoted = M.Inline:create_constructor(
606 function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
607 {"quotetype", "content"}
609--- Creates a single-quoted inline element (DEPRECATED).
610-- @function SingleQuoted
611-- @tparam {Inline,..} content inline content
612-- @treturn Inline quoted element
614M.SingleQuoted = M.Inline:create_constructor(
616 function(content) return M.Quoted(M.SingleQuote, content) end,
617 {"quotetype", "content"}
619--- Creates a single-quoted inline element (DEPRECATED).
620-- @function DoubleQuoted
621-- @tparam {Inline,..} content inline content
622-- @treturn Inline quoted element
624M.DoubleQuoted = M.Inline:create_constructor(
626 function(content) return M.Quoted("DoubleQuote", content) end,
627 {"quotetype", "content"}
630--- Creates a RawInline inline element
631-- @function RawInline
632-- @tparam string format format of the contents
633-- @tparam string text string content
634-- @treturn Inline raw inline element
635M.RawInline = M.Inline:create_constructor(
637 function(format, text) return {c = {format, text}} end,
641--- Creates text rendered in small caps
642-- @function SmallCaps
643-- @tparam {Inline,..} content inline content
644-- @treturn Inline smallcaps element
645M.SmallCaps = M.Inline:create_constructor(
647 function(content) return {c = ensureInlineList(content)} end,
651--- Creates a SoftBreak inline element.
652-- @function SoftBreak
653-- @treturn Inline softbreak element
654M.SoftBreak = M.Inline:create_constructor(
656 function() return {} end
659--- Create a Space inline element
661-- @treturn Inline space element
662M.Space = M.Inline:create_constructor(
664 function() return {} end
667--- Creates a Span inline element
669-- @tparam {Inline,..} content inline content
670-- @tparam[opt] Attr attr additional attributes
671-- @treturn Inline span element
672M.Span = M.Inline:create_constructor(
674 function(content, attr)
675 return {c = {attr or M.Attr(), ensureInlineList(content)}}
677 {{attr = {"identifier", "classes", "attributes"}}, "content"}
680--- Creates a Str inline element
682-- @tparam string text content
683-- @treturn Inline string element
684M.Str = M.Inline:create_constructor(
686 function(text) return {c = text} end,
690--- Creates text which is striked out.
691-- @function Strikeout
692-- @tparam {Inline,..} content inline content
693-- @treturn Inline strikeout element
694M.Strikeout = M.Inline:create_constructor(
696 function(content) return {c = ensureInlineList(content)} end,
700--- Creates a Strong element, whose text is usually displayed in a bold font.
702-- @tparam {Inline,..} content inline content
703-- @treturn Inline strong element
704M.Strong = M.Inline:create_constructor(
706 function(content) return {c = ensureInlineList(content)} end,
710--- Creates a Subscript inline element
711-- @function Subscript
712-- @tparam {Inline,..} content inline content
713-- @treturn Inline subscript element
714M.Subscript = M.Inline:create_constructor(
716 function(content) return {c = ensureInlineList(content)} end,
720--- Creates a Superscript inline element
721-- @function Superscript
722-- @tparam {Inline,..} content inline content
723-- @treturn Inline strong element
724M.Superscript = M.Inline:create_constructor(
726 function(content) return {c = ensureInlineList(content)} end,
731------------------------------------------------------------------------
733-- @section components
735--- Check if the first element of a pair matches the given value.
736-- @param x key value to be checked
737-- @return function returning true iff first element of its argument matches x
739local function assoc_key_equals (x)
740 return function (y) return y[1] == x end
743--- Lookup a value in an associative list
746-- @tparam {{key, value},...} alist associative list
747-- @param key key for which the associated value is to be looked up
748local function lookup(alist, key)
749 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
752--- Return an iterator which returns key-value pairs of an associative list.
755-- @tparam {{key, value},...} alist associative list
756local apairs = function (alist)
760 cur = rawget(alist, i)
763 return cur[1], cur[2]
770--- AttributeList, a metatable to allow table-like access to attribute lists
771-- represented by associative lists.
773local AttributeList = {
774 __index = function (t, k)
775 if type(k) == "number" then
782 __newindex = function (t, k, v)
783 local cur, idx = List.find_if(t, assoc_key_equals(k))
788 elseif type(k) == "number" then
791 rawset(t, #t + 1, {k, v})
798--- Convert a table to an associative list. The order of key-value pairs in the
799-- alist is undefined. The table should either contain no numeric keys or
800-- already be an associative list.
802-- @tparam table tbl associative list or table without numeric keys.
803-- @treturn table associative list
804local to_alist = function (tbl)
805 if #tbl ~= 0 or next(tbl) == nil then
806 -- probably already an alist
811 for k, v in pairs(tbl) do
820--- Create a new set of attributes (Attr).
822-- @tparam[opt] string identifier element identifier
823-- @tparam[opt] {string,...} classes element classes
824-- @tparam[opt] table attributes table containing string keys and values
825-- @return element attributes
826M.Attr = AstElement:make_subtype'Attr'
827function M.Attr:new (identifier, classes, attributes)
828 identifier = identifier or ''
829 classes = ensureList(classes or {})
830 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
831 return {identifier, classes, attributes}
833M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
834M.Attr.behavior.__index = function(t, k)
835 return rawget(t, getmetatable(t)._field_names[k]) or
838M.Attr.behavior.__newindex = function(t, k, v)
839 if getmetatable(t)._field_names[k] then
840 rawset(t, getmetatable(t)._field_names[k], v)
847M.Citation = AstElement:make_subtype'Citation'
849--- Creates a single citation.
851-- @tparam string id citation identifier (like a bibtex key)
852-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
853-- @tparam[opt] {Inline,...} prefix citation prefix
854-- @tparam[opt] {Inline,...} suffix citation suffix
855-- @tparam[opt] int note_num note number
856-- @tparam[opt] int hash hash number
857function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
861 prefix = ensureList(prefix or {}),
862 suffix = ensureList(suffix or {}),
863 note_num = note_num or 0,
869M.ListAttributes = AstElement:make_subtype 'ListAttributes'
871--- Creates a set of list attributes.
872-- @function ListAttributes
873-- @tparam[opt] integer start number of the first list item
874-- @tparam[opt] string style style used for list numbering
875-- @tparam[opt] DefaultDelim|Period|OneParen|TwoParens delimiter delimiter of list numbers
876-- @treturn table list attributes table
877function M.ListAttributes:new (start, style, delimiter)
879 style = style or 'DefaultStyle'
880 delimiter = delimiter or 'DefaultDelim'
881 return {start, style, delimiter}
883M.ListAttributes.behavior._field_names = {start = 1, style = 2, delimiter = 3}
884M.ListAttributes.behavior.__index = function (t, k)
885 return rawget(t, getmetatable(t)._field_names[k]) or
888M.ListAttributes.behavior.__newindex = function (t, k, v)
889 if getmetatable(t)._field_names[k] then
890 rawset(t, getmetatable(t)._field_names[k], v)
897------------------------------------------------------------------------
901--- Author name is mentioned in the text.
904M.AuthorInText = "AuthorInText"
906--- Author name is suppressed.
909M.SuppressAuthor = "SuppressAuthor"
911--- Default citation style is used.
914M.NormalCitation = "NormalCitation"
916--- Table cells aligned left.
918M.AlignLeft = "AlignLeft"
920--- Table cells right-aligned.
922M.AlignRight = "AlignRight"
924--- Table cell content is centered.
926M.AlignCenter = "AlignCenter"
928--- Table cells are alignment is unaltered.
930M.AlignDefault = "AlignDefault"
932--- Default list number delimiters are used.
934M.DefaultDelim = "DefaultDelim"
936--- List numbers are delimited by a period.
940--- List numbers are delimited by a single parenthesis.
942M.OneParen = "OneParen"
944--- List numbers are delimited by a double parentheses.
946M.TwoParens = "TwoParens"
948--- List are numbered in the default style
950M.DefaultStyle = "DefaultStyle"
952--- List items are numbered as examples.
956--- List are numbered using decimal integers.
960--- List are numbered using lower-case roman numerals.
962M.LowerRoman = "LowerRoman"
964--- List are numbered using upper-case roman numerals
966M.UpperRoman = "UpperRoman"
968--- List are numbered using lower-case alphabetic characters.
970M.LowerAlpha = "LowerAlpha"
972--- List are numbered using upper-case alphabetic characters.
974M.UpperAlpha = "UpperAlpha"
976------------------------------------------------------------------------
977-- Functions which have moved to different modules
978local 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