git.iko.soy/typeable/pandoc
on c0caaae help sign in
typeable/pandoc/data/pandoc.lua
1042 lines 31 kB history raw
1--[[
2pandoc.lua
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
16THIS SOFTWARE.
17]]
19---
20-- Lua functions for pandoc scripts.
21--
22-- @author Albert Krewinkel
23-- @copyright © 2017–2018 Albert Krewinkel
24-- @license MIT
25local M = {}
27local List = require 'pandoc.List'
28local utils = require 'pandoc.utils'
30------------------------------------------------------------------------
31-- Accessor objects
32--
33-- Create metatables which allow to access numerical indices via accessor
34-- methods.
35-- @section
36-- @local
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
42-- @local
43function make_indexing_function(template, indices)
44 local loadstring = loadstring or load
45 local bracketed = {}
46 for i = 1, #indices do
47 bracketed[i] = string.format('[%d]', indices[#indices - i + 1])
48 end
49 local fnstr = string.format('return ' .. template, table.concat(bracketed))
50 return assert(loadstring(fnstr))()
51end
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
57-- @local
58local function create_accessor_functions (fn_template, accessors)
59 local res = {}
60 function add_accessors(acc, ...)
61 if type(acc) == 'string' then
62 res[acc] = make_indexing_function(fn_template, {...})
63 elseif type(acc) == 'table' and #acc == 0 and next(acc) then
64 local name, substructure = next(acc)
65 res[name] = make_indexing_function(fn_template, {...})
66 add_accessors(substructure, ...)
67 else
68 for i = 1, #(acc or {}) do
69 add_accessors(acc[i], i, ...)
70 end
71 end
72 end
73 add_accessors(accessors)
74 return res
75end
77--- Get list of top-level fields from field descriptor table.
78-- E.g.: `top_level_fields{'foo', {bar='baz'}, {'qux', 'quux'}}`
79-- gives {'foo, 'bar', 'qux', 'quux'}
80-- @local
81local function top_level_fields (fields)
82 local result = List:new{}
83 for _, v in ipairs(fields) do
84 if type(v) == 'string' then
85 table.insert(result, v)
86 elseif type(v) == 'table' and #v == 0 and next(v) then
87 table.insert(result, (next(v)))
88 else
89 result:extend(top_level_fields(v))
90 end
91 end
92 return result
93end
95--- Creates a function which behaves like next, but respects field names.
96-- @local
97local function make_next_function (fields)
98 local field_indices = {}
99 for i, f in ipairs(fields) do
100 field_indices[f] = i
101 end
103 return function (t, field)
104 local raw_idx = field == nil and 0 or field_indices[field]
105 local next_field = fields[raw_idx + 1]
106 return next_field, t[next_field]
107 end
108end
110--- Create a new table which allows to access numerical indices via accessor
111-- functions.
112-- @local
113local function create_accessor_behavior (tag, accessors)
114 local behavior = {tag = tag}
115 behavior.getters = create_accessor_functions(
116 'function (x) return x.c%s end',
117 accessors
118 )
119 behavior.setters = create_accessor_functions(
120 'function (x, v) x.c%s = v end',
121 accessors
122 )
123 behavior.__eq = utils.equals
124 behavior.__index = function(t, k)
125 if getmetatable(t).getters[k] then
126 return getmetatable(t).getters[k](t)
127 elseif k == "t" then
128 return getmetatable(t)["tag"]
129 else
130 return getmetatable(t)[k]
131 end
132 end
133 behavior.__newindex = function(t, k, v)
134 if getmetatable(t).setters[k] then
135 getmetatable(t).setters[k](t, v)
136 else
137 rawset(t, k, v)
138 end
139 end
140 behavior.__pairs = function (t)
141 if accessors == nil then
142 return next, t
143 end
144 local iterable_fields = type(accessors) == 'string'
145 and {accessors}
146 or top_level_fields(accessors)
147 return make_next_function(iterable_fields), t
148 end
149 return behavior
150end
153------------------------------------------------------------------------
154-- The base class for types
155-- @type Type
156-- @local
157local Type = {}
158Type.name = 'Type'
159Type.__index = Type
160Type.behavior = {
161 __type = Type,
162 new = function (obj)
163 obj = obj or {}
164 setmetatable(obj, self)
165 return obj
166 end
168Type.behavior.__index = Type.behavior
170--- Set a new behavior for the type, inheriting that of the parent type if none
171--- is specified explicitly
172-- @param behavior the behavior object for this type.
173-- @local
174function Type:set_behavior (behavior)
175 behavior = behavior or {}
176 behavior.__index = rawget(behavior, '__index') or behavior
177 behavior.__type = self
178 if not getmetatable(behavior) and getmetatable(self) then
179 setmetatable(behavior, getmetatable(self).behavior)
180 end
181 self.behavior = behavior
182end
184--- Create a new subtype, using the given table as base.
185-- @param name name of the new type
186-- @param[opt] behavior behavioral object for the new type.
187-- @return a new type
188-- @local
189function Type:make_subtype(name, behavior)
190 local newtype = setmetatable({}, self)
191 newtype.name = name
192 newtype.__index = newtype
193 newtype:set_behavior(behavior)
194 return newtype
195end
198------------------------------------------------------------------------
199-- The base class for pandoc's AST elements.
200-- @type AstElement
201-- @local
202local AstElement = Type:make_subtype 'AstElement'
203AstElement.__call = function(t, ...)
204 local success, ret = pcall(t.new, t, ...)
205 if success then
206 return setmetatable(ret, t.behavior)
207 else
208 error(string.format('Constructor for %s failed: %s\n', t.name, ret))
209 end
210end
212--- Make a new subtype which constructs a new value when called.
213-- @local
214function AstElement:make_subtype(...)
215 local newtype = Type.make_subtype(self, ...)
216 newtype.__call = self.__call
217 return newtype
218end
220--- Create a new constructor
221-- @local
222-- @param tag Tag used to identify the constructor
223-- @param fn Function to be called when constructing a new element
224-- @param accessors names to use as accessors for numerical fields
225-- @return function that constructs a new element
226function AstElement:create_constructor(tag, fn, accessors)
227 local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
228 function constr:new(...)
229 return setmetatable(fn(...), self.behavior)
230 end
231 self.constructor = self.constructor or {}
232 self.constructor[tag] = constr
233 return constr
234end
236--- Convert AstElement input into a list if necessary.
237-- @local
238local function ensureList (x)
239 if x.tag then
240 -- Lists are not tagged, but all elements are
241 return List:new{x}
242 else
243 return List:new(x)
244 end
245end
247--- Ensure a given object is an Inline element, or convert it into one.
248-- @local
249local function ensureInlineList (x)
250 if type(x) == 'string' then
251 return List:new{M.Str(x)}
252 else
253 return ensureList(x)
254 end
255end
257------------------------------------------------------------------------
258--- Pandoc Document
259-- @section document
261--- A complete pandoc document
262-- @function Pandoc
263-- @tparam {Block,...} blocks document content
264-- @tparam[opt] Meta meta document meta data
265M.Pandoc = AstElement:make_subtype'Pandoc'
266function M.Pandoc:new (blocks, meta)
267 return {
268 blocks = ensureList(blocks),
269 meta = meta or {},
270 }
271end
273-- DEPRECATED synonym:
274M.Doc = M.Pandoc
276------------------------------------------------------------------------
277-- Meta
278-- @section Meta
280--- Create a new Meta object. It sets the metatable of the given table to
281--- `Meta`.
282-- @function Meta
283-- @tparam meta table table containing document meta information
284M.Meta = AstElement:make_subtype'Meta'
285function M.Meta:new (meta) return meta end
288------------------------------------------------------------------------
289-- MetaValue
290-- @section MetaValue
291M.MetaValue = AstElement:make_subtype('MetaValue')
293--- Meta blocks
294-- @function MetaBlocks
295-- @tparam {Block,...} blocks blocks
296M.MetaBlocks = M.MetaValue:create_constructor(
297 'MetaBlocks',
298 function (content) return ensureList(content) end
301--- Meta inlines
302-- @function MetaInlines
303-- @tparam {Inline,...} inlines inlines
304M.MetaInlines = M.MetaValue:create_constructor(
305 'MetaInlines',
306 function (content) return ensureInlineList(content) end
309--- Meta list
310-- @function MetaList
311-- @tparam {MetaValue,...} meta_values list of meta values
312M.MetaList = M.MetaValue:create_constructor(
313 'MetaList',
314 function (content)
315 if content.tag == 'MetaList' then
316 return content
317 end
318 return ensureList(content)
319 end
321for k, v in pairs(List) do
322 M.MetaList.behavior[k] = v
323end
325--- Meta map
326-- @function MetaMap
327-- @tparam table key_value_map a string-indexed map of meta values
328M.MetaMap = M.MetaValue:create_constructor(
329 "MetaMap",
330 function (mm) return mm end
333--- Creates string to be used in meta data.
334-- Does nothing, lua strings are meta strings.
335-- @function MetaString
336-- @tparam string str string value
337function M.MetaString(str)
338 return str
339end
341--- Creates boolean to be used in meta data.
342-- Does nothing, lua booleans are meta booleans.
343-- @function MetaBool
344-- @tparam boolean bool boolean value
345function M.MetaBool(bool)
346 return bool
347end
349------------------------------------------------------------------------
350-- Blocks
351-- @section Block
353--- Block elements
354M.Block = AstElement:make_subtype'Block'
356--- Creates a block quote element
357-- @function BlockQuote
358-- @tparam {Block,...} content block content
359-- @treturn Block block quote element
360M.BlockQuote = M.Block:create_constructor(
361 "BlockQuote",
362 function(content) return {c = ensureList(content)} end,
363 "content"
366--- Creates a bullet (i.e. unordered) list.
367-- @function BulletList
368-- @tparam {{Block,...},...} content list of items
369-- @treturn Block bullet list element
370M.BulletList = M.Block:create_constructor(
371 "BulletList",
372 function(content) return {c = ensureList(content)} end,
373 "content"
376--- Creates a code block element
377-- @function CodeBlock
378-- @tparam string text code string
379-- @tparam[opt] Attr attr element attributes
380-- @treturn Block code block element
381M.CodeBlock = M.Block:create_constructor(
382 "CodeBlock",
383 function(text, attr) return {c = {attr or M.Attr(), text}} end,
384 {{attr = {"identifier", "classes", "attributes"}}, "text"}
387--- Creates a definition list, containing terms and their explanation.
388-- @function DefinitionList
389-- @tparam {{{Inline,...},{Block,...}},...} content list of items
390-- @treturn Block definition list element
391M.DefinitionList = M.Block:create_constructor(
392 "DefinitionList",
393 function(content) return {c = ensureList(content)} end,
394 "content"
397--- Creates a div element
398-- @function Div
399-- @tparam {Block,...} content block content
400-- @tparam[opt] Attr attr element attributes
401-- @treturn Block div element
402M.Div = M.Block:create_constructor(
403 "Div",
404 function(content, attr)
405 return {c = {attr or M.Attr(), ensureList(content)}}
406 end,
407 {{attr = {"identifier", "classes", "attributes"}}, "content"}
410--- Creates a header element.
411-- @function Header
412-- @tparam int level header level
413-- @tparam {Inline,...} content inline content
414-- @tparam[opt] Attr attr element attributes
415-- @treturn Block header element
416M.Header = M.Block:create_constructor(
417 "Header",
418 function(level, content, attr)
419 return {c = {level, attr or M.Attr(), ensureInlineList(content)}}
420 end,
421 {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
424--- Creates a horizontal rule.
425-- @function HorizontalRule
426-- @treturn Block horizontal rule
427M.HorizontalRule = M.Block:create_constructor(
428 "HorizontalRule",
429 function() return {} end
432--- Creates a line block element.
433-- @function LineBlock
434-- @tparam {{Inline,...},...} content inline content
435-- @treturn Block line block element
436M.LineBlock = M.Block:create_constructor(
437 "LineBlock",
438 function(content) return {c = ensureList(content)} end,
439 "content"
442--- Creates a null element.
443-- @function Null
444-- @treturn Block null element
445M.Null = M.Block:create_constructor(
446 "Null",
447 function() return {} end
450--- Creates an ordered list.
451-- @function OrderedList
452-- @tparam {{Block,...},...} items list items
453-- @param[opt] listAttributes list parameters
454-- @treturn Block ordered list element
455M.OrderedList = M.Block:create_constructor(
456 "OrderedList",
457 function(items, listAttributes)
458 listAttributes = listAttributes or M.ListAttributes()
459 return {c = {listAttributes, ensureList(items)}}
460 end,
461 {{listAttributes = {"start", "style", "delimiter"}}, "content"}
464--- Creates a para element.
465-- @function Para
466-- @tparam {Inline,...} content inline content
467-- @treturn Block paragraph element
468M.Para = M.Block:create_constructor(
469 "Para",
470 function(content) return {c = ensureInlineList(content)} end,
471 "content"
474--- Creates a plain element.
475-- @function Plain
476-- @tparam {Inline,...} content inline content
477-- @treturn Block plain element
478M.Plain = M.Block:create_constructor(
479 "Plain",
480 function(content) return {c = ensureInlineList(content)} end,
481 "content"
484--- Creates a raw content block of the specified format.
485-- @function RawBlock
486-- @tparam string format format of content
487-- @tparam string text string content
488-- @treturn Block raw block element
489M.RawBlock = M.Block:create_constructor(
490 "RawBlock",
491 function(format, text) return {c = {format, text}} end,
492 {"format", "text"}
495--- Creates a table element.
496-- @function Table
497-- @tparam {Inline,...} caption table caption
498-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
499-- @tparam {int,...} widths column widths
500-- @tparam {Block,...} headers header row
501-- @tparam {{Block,...}} rows table rows
502-- @treturn Block table element
503M.Table = M.Block:create_constructor(
504 "Table",
505 function(caption, aligns, widths, headers, rows)
506 return {
507 c = {
508 ensureInlineList(caption),
509 List:new(aligns),
510 List:new(widths),
511 List:new(headers),
512 List:new(rows)
513 }
514 }
515 end,
516 {"caption", "aligns", "widths", "headers", "rows"}
520------------------------------------------------------------------------
521-- Inline
522-- @section Inline
524--- Inline element class
525M.Inline = AstElement:make_subtype'Inline'
527--- Creates a Cite inline element
528-- @function Cite
529-- @tparam {Inline,...} content List of inlines
530-- @tparam {Citation,...} citations List of citations
531-- @treturn Inline citations element
532M.Cite = M.Inline:create_constructor(
533 "Cite",
534 function(content, citations)
535 return {c = {ensureList(citations), ensureInlineList(content)}}
536 end,
537 {"citations", "content"}
540--- Creates a Code inline element
541-- @function Code
542-- @tparam string text code string
543-- @tparam[opt] Attr attr additional attributes
544-- @treturn Inline code element
545M.Code = M.Inline:create_constructor(
546 "Code",
547 function(text, attr) return {c = {attr or M.Attr(), text}} end,
548 {{attr = {"identifier", "classes", "attributes"}}, "text"}
551--- Creates an inline element representing emphasised text.
552-- @function Emph
553-- @tparam {Inline,..} content inline content
554-- @treturn Inline emphasis element
555M.Emph = M.Inline:create_constructor(
556 "Emph",
557 function(content) return {c = ensureInlineList(content)} end,
558 "content"
561--- Creates a Image inline element
562-- @function Image
563-- @tparam {Inline,..} caption text used to describe the image
564-- @tparam string src path to the image file
565-- @tparam[opt] string title brief image description
566-- @tparam[opt] Attr attr additional attributes
567-- @treturn Inline image element
568M.Image = M.Inline:create_constructor(
569 "Image",
570 function(caption, src, title, attr)
571 title = title or ""
572 attr = attr or M.Attr()
573 return {c = {attr, ensureInlineList(caption), {src, title}}}
574 end,
575 {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
578--- Create a LineBreak inline element
579-- @function LineBreak
580-- @treturn Inline linebreak element
581M.LineBreak = M.Inline:create_constructor(
582 "LineBreak",
583 function() return {} end
586--- Creates a link inline element, usually a hyperlink.
587-- @function Link
588-- @tparam {Inline,..} content text for this link
589-- @tparam string target the link target
590-- @tparam[opt] string title brief link description
591-- @tparam[opt] Attr attr additional attributes
592-- @treturn Inline image element
593M.Link = M.Inline:create_constructor(
594 "Link",
595 function(content, target, title, attr)
596 title = title or ""
597 attr = attr or M.Attr()
598 return {c = {attr, ensureInlineList(content), {target, title}}}
599 end,
600 {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
603--- Creates a Math element, either inline or displayed.
604-- @function Math
605-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
606-- @tparam string text Math content
607-- @treturn Inline Math element
608M.Math = M.Inline:create_constructor(
609 "Math",
610 function(mathtype, text)
611 return {c = {mathtype, text}}
612 end,
613 {"mathtype", "text"}
615--- Creates a DisplayMath element (DEPRECATED).
616-- @function DisplayMath
617-- @tparam string text Math content
618-- @treturn Inline Math element
619M.DisplayMath = M.Inline:create_constructor(
620 "DisplayMath",
621 function(text) return M.Math("DisplayMath", text) end,
622 {"mathtype", "text"}
624--- Creates an InlineMath inline element (DEPRECATED).
625-- @function InlineMath
626-- @tparam string text Math content
627-- @treturn Inline Math element
628M.InlineMath = M.Inline:create_constructor(
629 "InlineMath",
630 function(text) return M.Math("InlineMath", text) end,
631 {"mathtype", "text"}
634--- Creates a Note inline element
635-- @function Note
636-- @tparam {Block,...} content footnote block content
637M.Note = M.Inline:create_constructor(
638 "Note",
639 function(content) return {c = ensureList(content)} end,
640 "content"
643--- Creates a Quoted inline element given the quote type and quoted content.
644-- @function Quoted
645-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
646-- @tparam {Inline,..} content inline content
647-- @treturn Inline quoted element
648M.Quoted = M.Inline:create_constructor(
649 "Quoted",
650 function(quotetype, content) return {c = {quotetype, ensureInlineList(content)}} end,
651 {"quotetype", "content"}
653--- Creates a single-quoted inline element (DEPRECATED).
654-- @function SingleQuoted
655-- @tparam {Inline,..} content inline content
656-- @treturn Inline quoted element
657-- @see Quoted
658M.SingleQuoted = M.Inline:create_constructor(
659 "SingleQuoted",
660 function(content) return M.Quoted(M.SingleQuote, content) end,
661 {"quotetype", "content"}
663--- Creates a single-quoted inline element (DEPRECATED).
664-- @function DoubleQuoted
665-- @tparam {Inline,..} content inline content
666-- @treturn Inline quoted element
667-- @see Quoted
668M.DoubleQuoted = M.Inline:create_constructor(
669 "DoubleQuoted",
670 function(content) return M.Quoted("DoubleQuote", content) end,
671 {"quotetype", "content"}
674--- Creates a RawInline inline element
675-- @function RawInline
676-- @tparam string format format of the contents
677-- @tparam string text string content
678-- @treturn Inline raw inline element
679M.RawInline = M.Inline:create_constructor(
680 "RawInline",
681 function(format, text) return {c = {format, text}} end,
682 {"format", "text"}
685--- Creates text rendered in small caps
686-- @function SmallCaps
687-- @tparam {Inline,..} content inline content
688-- @treturn Inline smallcaps element
689M.SmallCaps = M.Inline:create_constructor(
690 "SmallCaps",
691 function(content) return {c = ensureInlineList(content)} end,
692 "content"
695--- Creates a SoftBreak inline element.
696-- @function SoftBreak
697-- @treturn Inline softbreak element
698M.SoftBreak = M.Inline:create_constructor(
699 "SoftBreak",
700 function() return {} end
703--- Create a Space inline element
704-- @function Space
705-- @treturn Inline space element
706M.Space = M.Inline:create_constructor(
707 "Space",
708 function() return {} end
711--- Creates a Span inline element
712-- @function Span
713-- @tparam {Inline,..} content inline content
714-- @tparam[opt] Attr attr additional attributes
715-- @treturn Inline span element
716M.Span = M.Inline:create_constructor(
717 "Span",
718 function(content, attr)
719 return {c = {attr or M.Attr(), ensureInlineList(content)}}
720 end,
721 {{attr = {"identifier", "classes", "attributes"}}, "content"}
724--- Creates a Str inline element
725-- @function Str
726-- @tparam string text content
727-- @treturn Inline string element
728M.Str = M.Inline:create_constructor(
729 "Str",
730 function(text) return {c = text} end,
731 "text"
734--- Creates text which is striked out.
735-- @function Strikeout
736-- @tparam {Inline,..} content inline content
737-- @treturn Inline strikeout element
738M.Strikeout = M.Inline:create_constructor(
739 "Strikeout",
740 function(content) return {c = ensureInlineList(content)} end,
741 "content"
744--- Creates a Strong element, whose text is usually displayed in a bold font.
745-- @function Strong
746-- @tparam {Inline,..} content inline content
747-- @treturn Inline strong element
748M.Strong = M.Inline:create_constructor(
749 "Strong",
750 function(content) return {c = ensureInlineList(content)} end,
751 "content"
754--- Creates a Subscript inline element
755-- @function Subscript
756-- @tparam {Inline,..} content inline content
757-- @treturn Inline subscript element
758M.Subscript = M.Inline:create_constructor(
759 "Subscript",
760 function(content) return {c = ensureInlineList(content)} end,
761 "content"
764--- Creates a Superscript inline element
765-- @function Superscript
766-- @tparam {Inline,..} content inline content
767-- @treturn Inline strong element
768M.Superscript = M.Inline:create_constructor(
769 "Superscript",
770 function(content) return {c = ensureInlineList(content)} end,
771 "content"
775------------------------------------------------------------------------
776-- Element components
777-- @section components
779--- Check if the first element of a pair matches the given value.
780-- @param x key value to be checked
781-- @return function returning true iff first element of its argument matches x
782-- @local
783local function assoc_key_equals (x)
784 return function (y) return y[1] == x end
785end
787--- Lookup a value in an associative list
788-- @function lookup
789-- @local
790-- @tparam {{key, value},...} alist associative list
791-- @param key key for which the associated value is to be looked up
792local function lookup(alist, key)
793 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
794end
796--- Return an iterator which returns key-value pairs of an associative list.
797-- @function apairs
798-- @local
799-- @tparam {{key, value},...} alist associative list
800local apairs = function (alist)
801 local i = 1
802 local cur
803 function nxt ()
804 cur = rawget(alist, i)
805 if cur then
806 i = i + 1
807 return cur[1], cur[2]
808 end
809 return nil
810 end
811 return nxt, nil, nil
812end
814--- AttributeList, a metatable to allow table-like access to attribute lists
815-- represented by associative lists.
816-- @local
817local AttributeList = {
818 __index = function (t, k)
819 if type(k) == "number" then
820 return rawget(t, k)
821 else
822 return lookup(t, k)
823 end
824 end,
826 __newindex = function (t, k, v)
827 local cur, idx = List.find_if(t, assoc_key_equals(k))
828 if v == nil then
829 table.remove(t, idx)
830 elseif cur then
831 cur[2] = v
832 elseif type(k) == "number" then
833 rawset(t, k, v)
834 else
835 rawset(t, #t + 1, {k, v})
836 end
837 end,
839 __pairs = apairs
842--- Convert a table to an associative list. The order of key-value pairs in the
843-- alist is undefined. The table should either contain no numeric keys or
844-- already be an associative list.
845-- @local
846-- @tparam table tbl associative list or table without numeric keys.
847-- @treturn table associative list
848local to_alist = function (tbl)
849 if #tbl ~= 0 or next(tbl) == nil then
850 -- probably already an alist
851 return tbl
852 end
853 local alist = {}
854 local i = 1
855 for k, v in pairs(tbl) do
856 alist[i] = {k, v}
857 i = i + 1
858 end
859 return alist
860end
862-- Attr
864--- Create a new set of attributes (Attr).
865-- @function Attr
866-- @tparam[opt] string identifier element identifier
867-- @tparam[opt] {string,...} classes element classes
868-- @tparam[opt] table attributes table containing string keys and values
869-- @return element attributes
870M.Attr = AstElement:make_subtype'Attr'
871function M.Attr:new (identifier, classes, attributes)
872 identifier = identifier or ''
873 classes = ensureList(classes or {})
874 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
875 return {identifier, classes, attributes}
876end
877M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
878M.Attr.behavior.__eq = utils.equals
879M.Attr.behavior.__index = function(t, k)
880 return rawget(t, getmetatable(t)._field_names[k]) or
881 getmetatable(t)[k]
882end
883M.Attr.behavior.__newindex = function(t, k, v)
884 if getmetatable(t)._field_names[k] then
885 rawset(t, getmetatable(t)._field_names[k], v)
886 else
887 rawset(t, k, v)
888 end
889end
890M.Attr.behavior.__pairs = function(t)
891 local field_names = M.Attr.behavior._field_names
892 local fields = {}
893 for name, i in pairs(field_names) do
894 fields[i] = name
895 end
896 return make_next_function(fields), t, nil
897end
899-- Citation
900M.Citation = AstElement:make_subtype'Citation'
902--- Creates a single citation.
903-- @function Citation
904-- @tparam string id citation identifier (like a bibtex key)
905-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
906-- @tparam[opt] {Inline,...} prefix citation prefix
907-- @tparam[opt] {Inline,...} suffix citation suffix
908-- @tparam[opt] int note_num note number
909-- @tparam[opt] int hash hash number
910function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
911 return {
912 id = id,
913 mode = mode,
914 prefix = ensureList(prefix or {}),
915 suffix = ensureList(suffix or {}),
916 note_num = note_num or 0,
917 hash = hash or 0,
918 }
919end
921-- ListAttributes
922M.ListAttributes = AstElement:make_subtype 'ListAttributes'
924--- Creates a set of list attributes.
925-- @function ListAttributes
926-- @tparam[opt] integer start number of the first list item
927-- @tparam[opt] string style style used for list numbering
928-- @tparam[opt] DefaultDelim|Period|OneParen|TwoParens delimiter delimiter of list numbers
929-- @treturn table list attributes table
930function M.ListAttributes:new (start, style, delimiter)
931 start = start or 1
932 style = style or 'DefaultStyle'
933 delimiter = delimiter or 'DefaultDelim'
934 return {start, style, delimiter}
935end
936M.ListAttributes.behavior._field_names = {start = 1, style = 2, delimiter = 3}
937M.ListAttributes.behavior.__eq = utils.equals
938M.ListAttributes.behavior.__index = function (t, k)
939 return rawget(t, getmetatable(t)._field_names[k]) or
940 getmetatable(t)[k]
941end
942M.ListAttributes.behavior.__newindex = function (t, k, v)
943 if getmetatable(t)._field_names[k] then
944 rawset(t, getmetatable(t)._field_names[k], v)
945 else
946 rawset(t, k, v)
947 end
948end
949M.ListAttributes.behavior.__pairs = function(t)
950 local field_names = M.ListAttributes.behavior._field_names
951 local fields = {}
952 for name, i in pairs(field_names) do
953 fields[i] = name
954 end
955 return make_next_function(fields), t, nil
956end
959------------------------------------------------------------------------
960-- Constants
961-- @section constants
963--- Author name is mentioned in the text.
964-- @see Citation
965-- @see Cite
966M.AuthorInText = "AuthorInText"
968--- Author name is suppressed.
969-- @see Citation
970-- @see Cite
971M.SuppressAuthor = "SuppressAuthor"
973--- Default citation style is used.
974-- @see Citation
975-- @see Cite
976M.NormalCitation = "NormalCitation"
978--- Table cells aligned left.
979-- @see Table
980M.AlignLeft = "AlignLeft"
982--- Table cells right-aligned.
983-- @see Table
984M.AlignRight = "AlignRight"
986--- Table cell content is centered.
987-- @see Table
988M.AlignCenter = "AlignCenter"
990--- Table cells are alignment is unaltered.
991-- @see Table
992M.AlignDefault = "AlignDefault"
994--- Default list number delimiters are used.
995-- @see OrderedList
996M.DefaultDelim = "DefaultDelim"
998--- List numbers are delimited by a period.
999-- @see OrderedList
1000M.Period = "Period"
1002--- List numbers are delimited by a single parenthesis.
1003-- @see OrderedList
1004M.OneParen = "OneParen"
1006--- List numbers are delimited by a double parentheses.
1007-- @see OrderedList
1008M.TwoParens = "TwoParens"
1010--- List are numbered in the default style
1011-- @see OrderedList
1012M.DefaultStyle = "DefaultStyle"
1014--- List items are numbered as examples.
1015-- @see OrderedList
1016M.Example = "Example"
1018--- List are numbered using decimal integers.
1019-- @see OrderedList
1020M.Decimal = "Decimal"
1022--- List are numbered using lower-case roman numerals.
1023-- @see OrderedList
1024M.LowerRoman = "LowerRoman"
1026--- List are numbered using upper-case roman numerals
1027-- @see OrderedList
1028M.UpperRoman = "UpperRoman"
1030--- List are numbered using lower-case alphabetic characters.
1031-- @see OrderedList
1032M.LowerAlpha = "LowerAlpha"
1034--- List are numbered using upper-case alphabetic characters.
1035-- @see OrderedList
1036M.UpperAlpha = "UpperAlpha"
1038------------------------------------------------------------------------
1039-- Functions which have moved to different modules
1040M.sha1 = utils.sha1
1042return M