git.iko.soy/typeable/pandoc
on 2.13 help sign in
typeable/pandoc/data/pandoc.lua
1169 lines 35 kB history raw
1--[[
2pandoc.lua
4Copyright © 2017–2019 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–2019 Albert Krewinkel
24-- @license MIT
25local M = {}
27-- Re-export bundled modules
28M.List = require 'pandoc.List'
29M.mediabag = require 'pandoc.mediabag'
30M.system = require 'pandoc.system'
31M.types = require 'pandoc.types'
32M.utils = require 'pandoc.utils'
33M.text = require 'text'
35-- Local names for modules which this module depends on.
36local List = M.List
37local utils = M.utils
40------------------------------------------------------------------------
41-- Accessor objects
42--
43-- Create metatables which allow to access numerical indices via accessor
44-- methods.
45-- @section
46-- @local
48--- Create a new indexing function.
49-- @param template function template
50-- @param indices list of indices, starting with the most deeply nested
51-- @return newly created function
52-- @local
53function make_indexing_function(template, ...)
54 local indices = {...}
55 local loadstring = loadstring or load
56 local bracketed = {}
57 for i = 1, #indices do
58 local idx = indices[#indices - i + 1]
59 bracketed[i] = type(idx) == 'number'
60 and string.format('[%d]', idx)
61 or string.format('.%s', idx)
62 end
63 local fnstr = string.format('return ' .. template, table.concat(bracketed))
64 return assert(loadstring(fnstr))()
65end
67--- Create accessor functions using a function template.
68-- @param fn_template function template in which '%s' is replacd with indices
69-- @param accessors list of accessors
70-- @return mapping from accessor names to accessor functions
71-- @local
72local function create_accessor_functions (fn_template, accessors)
73 local res = {}
74 function add_accessors(acc, ...)
75 if type(acc) == 'string' then
76 res[acc] = make_indexing_function(fn_template, ...)
77 elseif type(acc) == 'table' and #acc == 0 and next(acc) then
78 -- Named substructure: the given names are accessed via the substructure,
79 -- but the accessors are also added to the result table, enabling direct
80 -- access from the parent element. Mainly used for `attr`.
81 local name, substructure = next(acc)
82 res[name] = make_indexing_function(fn_template, ...)
83 for _, subname in ipairs(substructure) do
84 res[subname] = make_indexing_function(fn_template, subname, ...)
85 end
86 else
87 for i = 1, #(acc or {}) do
88 add_accessors(acc[i], i, ...)
89 end
90 end
91 end
92 add_accessors(accessors)
93 return res
94end
96--- Get list of top-level fields from field descriptor table.
97-- E.g.: `top_level_fields{'foo', {bar='baz'}, {'qux', 'quux'}}`
98-- gives {'foo, 'bar', 'qux', 'quux'}
99-- @local
100local function top_level_fields (fields)
101 local result = List:new{}
102 for _, v in ipairs(fields) do
103 if type(v) == 'string' then
104 table.insert(result, v)
105 elseif type(v) == 'table' and #v == 0 and next(v) then
106 table.insert(result, (next(v)))
107 else
108 result:extend(top_level_fields(v))
109 end
110 end
111 return result
112end
114--- Creates a function which behaves like next, but respects field names.
115-- @local
116local function make_next_function (fields)
117 local field_indices = {}
118 for i, f in ipairs(fields) do
119 field_indices[f] = i
120 end
122 return function (t, field)
123 local raw_idx = field == nil and 0 or field_indices[field]
124 local next_field = fields[raw_idx + 1]
125 return next_field, t[next_field]
126 end
127end
129--- Create a new table which allows to access numerical indices via accessor
130-- functions.
131-- @local
132local function create_accessor_behavior (tag, accessors)
133 local behavior = {tag = tag}
134 behavior.getters = create_accessor_functions(
135 'function (x) return x.c%s end',
136 accessors
137 )
138 behavior.setters = create_accessor_functions(
139 'function (x, v) x.c%s = v end',
140 accessors
141 )
142 behavior.__eq = utils.equals
143 behavior.__index = function(t, k)
144 if getmetatable(t).getters[k] then
145 return getmetatable(t).getters[k](t)
146 elseif k == "t" then
147 return getmetatable(t)["tag"]
148 else
149 return getmetatable(t)[k]
150 end
151 end
152 behavior.__newindex = function(t, k, v)
153 if getmetatable(t).setters[k] then
154 getmetatable(t).setters[k](t, v)
155 else
156 rawset(t, k, v)
157 end
158 end
159 behavior.__pairs = function (t)
160 if accessors == nil then
161 return next, t
162 end
163 local iterable_fields = type(accessors) == 'string'
164 and {accessors}
165 or top_level_fields(accessors)
166 return make_next_function(iterable_fields), t
167 end
168 return behavior
169end
172------------------------------------------------------------------------
173-- The base class for types
174-- @type Type
175-- @local
176local Type = {}
177Type.name = 'Type'
178Type.__index = Type
179Type.behavior = {
180 __type = Type,
181 new = function (obj)
182 obj = obj or {}
183 setmetatable(obj, self)
184 return obj
185 end
187Type.behavior.__index = Type.behavior
189--- Set a new behavior for the type, inheriting that of the parent type if none
190--- is specified explicitly
191-- @param behavior the behavior object for this type.
192-- @local
193function Type:set_behavior (behavior)
194 behavior = behavior or {}
195 behavior.__index = rawget(behavior, '__index') or behavior
196 behavior.__type = self
197 if not getmetatable(behavior) and getmetatable(self) then
198 setmetatable(behavior, getmetatable(self).behavior)
199 end
200 self.behavior = behavior
201end
203--- Create a new subtype, using the given table as base.
204-- @param name name of the new type
205-- @param[opt] behavior behavioral object for the new type.
206-- @return a new type
207-- @local
208function Type:make_subtype(name, behavior)
209 local newtype = setmetatable({}, self)
210 newtype.name = name
211 newtype.__index = newtype
212 newtype:set_behavior(behavior)
213 return newtype
214end
217------------------------------------------------------------------------
218-- The base class for pandoc's AST elements.
219-- @type AstElement
220-- @local
221local AstElement = Type:make_subtype 'AstElement'
222AstElement.__call = function(t, ...)
223 local success, ret = pcall(t.new, t, ...)
224 if success then
225 return setmetatable(ret, t.behavior)
226 else
227 error(string.format('Constructor for %s failed: %s\n', t.name, ret))
228 end
229end
231--- Make a new subtype which constructs a new value when called.
232-- @local
233function AstElement:make_subtype(...)
234 local newtype = Type.make_subtype(self, ...)
235 newtype.__call = self.__call
236 return newtype
237end
239--- Create a new constructor
240-- @local
241-- @param tag Tag used to identify the constructor
242-- @param fn Function to be called when constructing a new element
243-- @param accessors names to use as accessors for numerical fields
244-- @return function that constructs a new element
245function AstElement:create_constructor(tag, fn, accessors)
246 local constr = self:make_subtype(tag, create_accessor_behavior(tag, accessors))
247 function constr:new(...)
248 return setmetatable(fn(...), self.behavior)
249 end
250 self.constructor = self.constructor or {}
251 self.constructor[tag] = constr
252 return constr
253end
255--- Convert AstElement input into a list if necessary.
256-- @local
257local function ensureList (x)
258 if x.tag then
259 -- Lists are not tagged, but all elements are
260 return List:new{x}
261 else
262 return List:new(x)
263 end
264end
266--- Ensure a given object is an Inline element, or convert it into one.
267-- @local
268local function ensureInlineList (x)
269 if type(x) == 'string' then
270 return List:new{M.Str(x)}
271 else
272 return ensureList(x)
273 end
274end
276--- Ensure that the given object is a definition pair, convert if necessary.
277-- @local
278local function ensureDefinitionPairs (pair)
279 local inlines = ensureInlineList(pair[1] or {})
280 local blocks = ensureList(pair[2] or {}):map(ensureList)
281 return {inlines, blocks}
282end
284--- Split a string into it's words, using whitespace as separators.
285local function words (str)
286 local ws = {}
287 for w in str:gmatch("([^%s]+)") do ws[#ws + 1] = w end
288 return ws
289end
291--- Try hard to turn the arguments into an Attr object.
292local function ensureAttr(attr)
293 if type(attr) == 'table' then
294 if #attr > 0 then return M.Attr(table.unpack(attr)) end
296 -- assume HTML-like key-value pairs
297 local ident = attr.id or ''
298 local classes = words(attr.class or '')
299 local attributes = attr
300 attributes.id = nil
301 attributes.class = nil
302 return M.Attr(ident, classes, attributes)
303 elseif attr == nil then
304 return M.Attr()
305 elseif type(attr) == 'string' then
306 -- treat argument as ID
307 return M.Attr(attr)
308 end
309 -- print(arg, ...)
310 error('Could not convert to Attr')
311end
313------------------------------------------------------------------------
314--- Pandoc Document
315-- @section document
317--- A complete pandoc document
318-- @function Pandoc
319-- @tparam {Block,...} blocks document content
320-- @tparam[opt] Meta meta document meta data
321M.Pandoc = AstElement:make_subtype'Pandoc'
322M.Pandoc.behavior.clone = M.types.clone.Pandoc
323function M.Pandoc:new (blocks, meta)
324 return {
325 blocks = ensureList(blocks),
326 meta = meta or {},
327 }
328end
330-- DEPRECATED synonym:
331M.Doc = M.Pandoc
333------------------------------------------------------------------------
334-- Meta
335-- @section Meta
337--- Create a new Meta object. It sets the metatable of the given table to
338--- `Meta`.
339-- @function Meta
340-- @tparam meta table table containing document meta information
341M.Meta = AstElement:make_subtype'Meta'
342M.Meta.behavior.clone = M.types.clone.Meta
343function M.Meta:new (meta) return meta end
346------------------------------------------------------------------------
347-- MetaValue
348-- @section MetaValue
349M.MetaValue = AstElement:make_subtype('MetaValue')
350M.MetaValue.behavior.clone = M.types.clone.MetaValue
352--- Meta blocks
353-- @function MetaBlocks
354-- @tparam {Block,...} blocks blocks
355M.MetaBlocks = M.MetaValue:create_constructor(
356 'MetaBlocks',
357 function (content) return ensureList(content) end
360--- Meta inlines
361-- @function MetaInlines
362-- @tparam {Inline,...} inlines inlines
363M.MetaInlines = M.MetaValue:create_constructor(
364 'MetaInlines',
365 function (content) return ensureInlineList(content) end
368--- Meta list
369-- @function MetaList
370-- @tparam {MetaValue,...} meta_values list of meta values
371M.MetaList = M.MetaValue:create_constructor(
372 'MetaList',
373 function (content)
374 if content.tag == 'MetaList' then
375 return content
376 end
377 return ensureList(content)
378 end
380for k, v in pairs(List) do
381 M.MetaList.behavior[k] = v
382end
384--- Meta map
385-- @function MetaMap
386-- @tparam table key_value_map a string-indexed map of meta values
387M.MetaMap = M.MetaValue:create_constructor(
388 "MetaMap",
389 function (mm) return mm end
392--- Creates string to be used in meta data.
393-- Does nothing, lua strings are meta strings.
394-- @function MetaString
395-- @tparam string str string value
396function M.MetaString(str)
397 return str
398end
400--- Creates boolean to be used in meta data.
401-- Does nothing, lua booleans are meta booleans.
402-- @function MetaBool
403-- @tparam boolean bool boolean value
404function M.MetaBool(bool)
405 return bool
406end
408------------------------------------------------------------------------
409-- Blocks
410-- @section Block
412--- Block elements
413M.Block = AstElement:make_subtype'Block'
414M.Block.behavior.clone = M.types.clone.Block
416--- Creates a block quote element
417-- @function BlockQuote
418-- @tparam {Block,...} content block content
419-- @treturn Block block quote element
420M.BlockQuote = M.Block:create_constructor(
421 "BlockQuote",
422 function(content) return {c = ensureList(content)} end,
423 "content"
426--- Creates a bullet (i.e. unordered) list.
427-- @function BulletList
428-- @tparam {{Block,...},...} content list of items
429-- @treturn Block bullet list element
430M.BulletList = M.Block:create_constructor(
431 "BulletList",
432 function(content) return {c = ensureList(content):map(ensureList)} end,
433 "content"
436--- Creates a code block element
437-- @function CodeBlock
438-- @tparam string text code string
439-- @tparam[opt] Attr attr element attributes
440-- @treturn Block code block element
441M.CodeBlock = M.Block:create_constructor(
442 "CodeBlock",
443 function(text, attr) return {c = {ensureAttr(attr), text}} end,
444 {{attr = {"identifier", "classes", "attributes"}}, "text"}
447--- Creates a definition list, containing terms and their explanation.
448-- @function DefinitionList
449-- @tparam {{{Inline,...},{{Block,...}}},...} content list of items
450-- @treturn Block definition list element
451M.DefinitionList = M.Block:create_constructor(
452 "DefinitionList",
453 function(content)
454 return {c = ensureList(content):map(ensureDefinitionPairs)}
455 end,
456 "content"
459--- Creates a div element
460-- @function Div
461-- @tparam {Block,...} content block content
462-- @tparam[opt] Attr attr element attributes
463-- @treturn Block div element
464M.Div = M.Block:create_constructor(
465 "Div",
466 function(content, attr)
467 return {c = {ensureAttr(attr), ensureList(content)}}
468 end,
469 {{attr = {"identifier", "classes", "attributes"}}, "content"}
472--- Creates a header element.
473-- @function Header
474-- @tparam int level header level
475-- @tparam {Inline,...} content inline content
476-- @tparam[opt] Attr attr element attributes
477-- @treturn Block header element
478M.Header = M.Block:create_constructor(
479 "Header",
480 function(level, content, attr)
481 return {c = {level, ensureAttr(attr), ensureInlineList(content)}}
482 end,
483 {"level", {attr = {"identifier", "classes", "attributes"}}, "content"}
486--- Creates a horizontal rule.
487-- @function HorizontalRule
488-- @treturn Block horizontal rule
489M.HorizontalRule = M.Block:create_constructor(
490 "HorizontalRule",
491 function() return {} end
494--- Creates a line block element.
495-- @function LineBlock
496-- @tparam {{Inline,...},...} content inline content
497-- @treturn Block line block element
498M.LineBlock = M.Block:create_constructor(
499 "LineBlock",
500 function(content) return {c = ensureList(content):map(ensureInlineList)} end,
501 "content"
504--- Creates a null element.
505-- @function Null
506-- @treturn Block null element
507M.Null = M.Block:create_constructor(
508 "Null",
509 function() return {} end
512--- Creates an ordered list.
513-- @function OrderedList
514-- @tparam {{Block,...},...} items list items
515-- @param[opt] listAttributes list parameters
516-- @treturn Block ordered list element
517M.OrderedList = M.Block:create_constructor(
518 "OrderedList",
519 function(items, listAttributes)
520 listAttributes = listAttributes or M.ListAttributes()
521 return {c = {listAttributes, ensureList(items):map(ensureList)}}
522 end,
523 {{listAttributes = {"start", "style", "delimiter"}}, "content"}
526--- Creates a para element.
527-- @function Para
528-- @tparam {Inline,...} content inline content
529-- @treturn Block paragraph element
530M.Para = M.Block:create_constructor(
531 "Para",
532 function(content) return {c = ensureInlineList(content)} end,
533 "content"
536--- Creates a plain element.
537-- @function Plain
538-- @tparam {Inline,...} content inline content
539-- @treturn Block plain element
540M.Plain = M.Block:create_constructor(
541 "Plain",
542 function(content) return {c = ensureInlineList(content)} end,
543 "content"
546--- Creates a raw content block of the specified format.
547-- @function RawBlock
548-- @tparam string format format of content
549-- @tparam string text string content
550-- @treturn Block raw block element
551M.RawBlock = M.Block:create_constructor(
552 "RawBlock",
553 function(format, text) return {c = {format, text}} end,
554 {"format", "text"}
557--- Creates a table element.
558-- @function Table
559-- @tparam Caption caption table caption
560-- @tparam {ColSpec,...} colspecs column alignments and widths
561-- @tparam TableHead head table head
562-- @tparam {TableBody,..} bodies table bodies
563-- @treturn TableFoot foot table foot
564-- @tparam[opt] Attr attr attributes
565M.Table = M.Block:create_constructor(
566 "Table",
567 function(caption, colspecs, head, bodies, foot, attr)
568 return {
569 c = {
570 ensureAttr(attr),
571 caption,
572 List:new(colspecs),
573 head,
574 List:new(bodies),
575 foot
576 }
577 }
578 end,
579 {"attr", "caption", "colspecs", "head", "bodies", "foot"}
583------------------------------------------------------------------------
584-- Inline
585-- @section Inline
587--- Inline element class
588M.Inline = AstElement:make_subtype'Inline'
589M.Inline.behavior.clone = M.types.clone.Inline
591--- Creates a Cite inline element
592-- @function Cite
593-- @tparam {Inline,...} content List of inlines
594-- @tparam {Citation,...} citations List of citations
595-- @treturn Inline citations element
596M.Cite = M.Inline:create_constructor(
597 "Cite",
598 function(content, citations)
599 return {c = {ensureList(citations), ensureInlineList(content)}}
600 end,
601 {"citations", "content"}
604--- Creates a Code inline element
605-- @function Code
606-- @tparam string text code string
607-- @tparam[opt] Attr attr additional attributes
608-- @treturn Inline code element
609M.Code = M.Inline:create_constructor(
610 "Code",
611 function(text, attr) return {c = {ensureAttr(attr), text}} end,
612 {{attr = {"identifier", "classes", "attributes"}}, "text"}
615--- Creates an inline element representing emphasised text.
616-- @function Emph
617-- @tparam {Inline,..} content inline content
618-- @treturn Inline emphasis element
619M.Emph = M.Inline:create_constructor(
620 "Emph",
621 function(content) return {c = ensureInlineList(content)} end,
622 "content"
625--- Creates a Image inline element
626-- @function Image
627-- @tparam {Inline,..} caption text used to describe the image
628-- @tparam string src path to the image file
629-- @tparam[opt] string title brief image description
630-- @tparam[opt] Attr attr additional attributes
631-- @treturn Inline image element
632M.Image = M.Inline:create_constructor(
633 "Image",
634 function(caption, src, title, attr)
635 title = title or ""
636 return {c = {ensureAttr(attr), ensureInlineList(caption), {src, title}}}
637 end,
638 {{attr = {"identifier", "classes", "attributes"}}, "caption", {"src", "title"}}
641--- Create a LineBreak inline element
642-- @function LineBreak
643-- @treturn Inline linebreak element
644M.LineBreak = M.Inline:create_constructor(
645 "LineBreak",
646 function() return {} end
649--- Creates a link inline element, usually a hyperlink.
650-- @function Link
651-- @tparam {Inline,..} content text for this link
652-- @tparam string target the link target
653-- @tparam[opt] string title brief link description
654-- @tparam[opt] Attr attr additional attributes
655-- @treturn Inline image element
656M.Link = M.Inline:create_constructor(
657 "Link",
658 function(content, target, title, attr)
659 title = title or ""
660 attr = ensureAttr(attr)
661 return {c = {attr, ensureInlineList(content), {target, title}}}
662 end,
663 {{attr = {"identifier", "classes", "attributes"}}, "content", {"target", "title"}}
666--- Creates a Math element, either inline or displayed.
667-- @function Math
668-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
669-- @tparam string text Math content
670-- @treturn Inline Math element
671M.Math = M.Inline:create_constructor(
672 "Math",
673 function(mathtype, text)
674 return {c = {mathtype, text}}
675 end,
676 {"mathtype", "text"}
678--- Creates a DisplayMath element (DEPRECATED).
679-- @function DisplayMath
680-- @tparam string text Math content
681-- @treturn Inline Math element
682M.DisplayMath = M.Inline:create_constructor(
683 "DisplayMath",
684 function(text) return M.Math("DisplayMath", text) end,
685 {"mathtype", "text"}
687--- Creates an InlineMath inline element (DEPRECATED).
688-- @function InlineMath
689-- @tparam string text Math content
690-- @treturn Inline Math element
691M.InlineMath = M.Inline:create_constructor(
692 "InlineMath",
693 function(text) return M.Math("InlineMath", text) end,
694 {"mathtype", "text"}
697--- Creates a Note inline element
698-- @function Note
699-- @tparam {Block,...} content footnote block content
700M.Note = M.Inline:create_constructor(
701 "Note",
702 function(content) return {c = ensureList(content)} end,
703 "content"
706--- Creates a Quoted inline element given the quote type and quoted content.
707-- @function Quoted
708-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
709-- @tparam {Inline,..} content inline content
710-- @treturn Inline quoted element
711M.Quoted = M.Inline:create_constructor(
712 "Quoted",
713 function(quotetype, content)
714 return {c = {quotetype, ensureInlineList(content)}}
715 end,
716 {"quotetype", "content"}
718--- Creates a single-quoted inline element (DEPRECATED).
719-- @function SingleQuoted
720-- @tparam {Inline,..} content inline content
721-- @treturn Inline quoted element
722-- @see Quoted
723M.SingleQuoted = M.Inline:create_constructor(
724 "SingleQuoted",
725 function(content) return M.Quoted(M.SingleQuote, content) end,
726 {"quotetype", "content"}
728--- Creates a single-quoted inline element (DEPRECATED).
729-- @function DoubleQuoted
730-- @tparam {Inline,..} content inline content
731-- @treturn Inline quoted element
732-- @see Quoted
733M.DoubleQuoted = M.Inline:create_constructor(
734 "DoubleQuoted",
735 function(content) return M.Quoted("DoubleQuote", content) end,
736 {"quotetype", "content"}
739--- Creates a RawInline inline element
740-- @function RawInline
741-- @tparam string format format of the contents
742-- @tparam string text string content
743-- @treturn Inline raw inline element
744M.RawInline = M.Inline:create_constructor(
745 "RawInline",
746 function(format, text) return {c = {format, text}} end,
747 {"format", "text"}
750--- Creates text rendered in small caps
751-- @function SmallCaps
752-- @tparam {Inline,..} content inline content
753-- @treturn Inline smallcaps element
754M.SmallCaps = M.Inline:create_constructor(
755 "SmallCaps",
756 function(content) return {c = ensureInlineList(content)} end,
757 "content"
760--- Creates a SoftBreak inline element.
761-- @function SoftBreak
762-- @treturn Inline softbreak element
763M.SoftBreak = M.Inline:create_constructor(
764 "SoftBreak",
765 function() return {} end
768--- Create a Space inline element
769-- @function Space
770-- @treturn Inline space element
771M.Space = M.Inline:create_constructor(
772 "Space",
773 function() return {} end
776--- Creates a Span inline element
777-- @function Span
778-- @tparam {Inline,..} content inline content
779-- @tparam[opt] Attr attr additional attributes
780-- @treturn Inline span element
781M.Span = M.Inline:create_constructor(
782 "Span",
783 function(content, attr)
784 return {c = {ensureAttr(attr), ensureInlineList(content)}}
785 end,
786 {{attr = {"identifier", "classes", "attributes"}}, "content"}
789--- Creates a Str inline element
790-- @function Str
791-- @tparam string text content
792-- @treturn Inline string element
793M.Str = M.Inline:create_constructor(
794 "Str",
795 function(text) return {c = text} end,
796 "text"
799--- Creates text which is striked out.
800-- @function Strikeout
801-- @tparam {Inline,..} content inline content
802-- @treturn Inline strikeout element
803M.Strikeout = M.Inline:create_constructor(
804 "Strikeout",
805 function(content) return {c = ensureInlineList(content)} end,
806 "content"
809--- Creates a Strong element, whose text is usually displayed in a bold font.
810-- @function Strong
811-- @tparam {Inline,..} content inline content
812-- @treturn Inline strong element
813M.Strong = M.Inline:create_constructor(
814 "Strong",
815 function(content) return {c = ensureInlineList(content)} end,
816 "content"
819--- Creates a Subscript inline element
820-- @function Subscript
821-- @tparam {Inline,..} content inline content
822-- @treturn Inline subscript element
823M.Subscript = M.Inline:create_constructor(
824 "Subscript",
825 function(content) return {c = ensureInlineList(content)} end,
826 "content"
829--- Creates a Superscript inline element
830-- @function Superscript
831-- @tparam {Inline,..} content inline content
832-- @treturn Inline superscript element
833M.Superscript = M.Inline:create_constructor(
834 "Superscript",
835 function(content) return {c = ensureInlineList(content)} end,
836 "content"
839--- Creates an Underline inline element
840-- @function Underline
841-- @tparam {Inline,..} content inline content
842-- @treturn Inline underline element
843M.Underline = M.Inline:create_constructor(
844 "Underline",
845 function(content) return {c = ensureInlineList(content)} end,
846 "content"
850------------------------------------------------------------------------
851-- Element components
852-- @section components
854--- Check if the first element of a pair matches the given value.
855-- @param x key value to be checked
856-- @return function returning true iff first element of its argument matches x
857-- @local
858local function assoc_key_equals (x)
859 return function (y) return y[1] == x end
860end
862--- Lookup a value in an associative list
863-- @function lookup
864-- @local
865-- @tparam {{key, value},...} alist associative list
866-- @param key key for which the associated value is to be looked up
867local function lookup(alist, key)
868 return (List.find_if(alist, assoc_key_equals(key)) or {})[2]
869end
871--- Return an iterator which returns key-value pairs of an associative list.
872-- @function apairs
873-- @local
874-- @tparam {{key, value},...} alist associative list
875local apairs = function (alist)
876 local i = 1
877 local cur
878 function nxt ()
879 cur = rawget(alist, i)
880 if cur then
881 i = i + 1
882 return cur[1], cur[2]
883 end
884 return nil
885 end
886 return nxt, nil, nil
887end
889--- AttributeList, a metatable to allow table-like access to attribute lists
890-- represented by associative lists.
891-- @local
892local AttributeList = {
893 __index = function (t, k)
894 if type(k) == "number" then
895 return rawget(t, k)
896 else
897 return lookup(t, k)
898 end
899 end,
901 __newindex = function (t, k, v)
902 local cur, idx = List.find_if(t, assoc_key_equals(k))
903 if v == nil and not cur then
904 -- deleted key does not exists in list
905 return
906 elseif v == nil then
907 table.remove(t, idx)
908 elseif cur then
909 cur[2] = v
910 elseif type(k) == "number" then
911 rawset(t, k, v)
912 else
913 rawset(t, #t + 1, {k, v})
914 end
915 end,
917 __pairs = apairs
920--- Convert a table to an associative list. The order of key-value pairs in the
921-- alist is undefined. The table should either contain no numeric keys or
922-- already be an associative list.
923-- @local
924-- @tparam table tbl associative list or table without numeric keys.
925-- @treturn table associative list
926local to_alist = function (tbl)
927 if #tbl ~= 0 or next(tbl) == nil then
928 -- probably already an alist
929 return tbl
930 end
931 local alist = {}
932 local i = 1
933 for k, v in pairs(tbl) do
934 alist[i] = {k, v}
935 i = i + 1
936 end
937 return alist
938end
940-- Attr
942--- Create a new set of attributes (Attr).
943-- @function Attr
944-- @tparam[opt] string identifier element identifier
945-- @tparam[opt] {string,...} classes element classes
946-- @tparam[opt] table attributes table containing string keys and values
947-- @return element attributes
948M.Attr = AstElement:make_subtype'Attr'
949function M.Attr:new (identifier, classes, attributes)
950 identifier = identifier or ''
951 classes = ensureList(classes or {})
952 attributes = setmetatable(to_alist(attributes or {}), AttributeList)
953 return setmetatable({identifier, classes, attributes}, self.behavior)
954end
955M.Attr.behavior.clone = M.types.clone.Attr
956M.Attr.behavior.tag = 'Attr'
957M.Attr.behavior._field_names = {identifier = 1, classes = 2, attributes = 3}
958M.Attr.behavior.__eq = utils.equals
959M.Attr.behavior.__index = function(t, k)
960 return (k == 't' and t.tag) or
961 rawget(t, getmetatable(t)._field_names[k]) or
962 getmetatable(t)[k]
963end
964M.Attr.behavior.__newindex = function(t, k, v)
965 if k == 'attributes' then
966 rawset(t, 3, setmetatable(to_alist(v or {}), AttributeList))
967 elseif getmetatable(t)._field_names[k] then
968 rawset(t, getmetatable(t)._field_names[k], v)
969 else
970 rawset(t, k, v)
971 end
972end
973M.Attr.behavior.__pairs = function(t)
974 local field_names = M.Attr.behavior._field_names
975 local fields = {}
976 for name, i in pairs(field_names) do
977 fields[i] = name
978 end
979 return make_next_function(fields), t, nil
980end
982-- Monkey-patch setters for `attr` fields to be more forgiving in the input that
983-- results in a valid Attr value.
984function augment_attr_setter (setters)
985 if setters.attr then
986 local orig = setters.attr
987 setters.attr = function(k, v)
988 orig(k, ensureAttr(v))
989 end
990 end
991end
992for _, blk in pairs(M.Block.constructor) do
993 augment_attr_setter(blk.behavior.setters)
994end
995for _, inln in pairs(M.Inline.constructor) do
996 augment_attr_setter(inln.behavior.setters)
997end
1000-- Citation
1001M.Citation = AstElement:make_subtype'Citation'
1002M.Citation.behavior.clone = M.types.clone.Citation
1004--- Creates a single citation.
1005-- @function Citation
1006-- @tparam string id citation identifier (like a bibtex key)
1007-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
1008-- @tparam[opt] {Inline,...} prefix citation prefix
1009-- @tparam[opt] {Inline,...} suffix citation suffix
1010-- @tparam[opt] int note_num note number
1011-- @tparam[opt] int hash hash number
1012function M.Citation:new (id, mode, prefix, suffix, note_num, hash)
1013 return {
1014 id = id,
1015 mode = mode,
1016 prefix = ensureList(prefix or {}),
1017 suffix = ensureList(suffix or {}),
1018 note_num = note_num or 0,
1019 hash = hash or 0,
1021end
1023-- ListAttributes
1024M.ListAttributes = AstElement:make_subtype 'ListAttributes'
1025M.ListAttributes.behavior.clone = M.types.clone.ListAttributes
1027--- Creates a set of list attributes.
1028-- @function ListAttributes
1029-- @tparam[opt] integer start number of the first list item
1030-- @tparam[opt] string style style used for list numbering
1031-- @tparam[opt] DefaultDelim|Period|OneParen|TwoParens delimiter delimiter of list numbers
1032-- @treturn table list attributes table
1033function M.ListAttributes:new (start, style, delimiter)
1034 start = start or 1
1035 style = style or 'DefaultStyle'
1036 delimiter = delimiter or 'DefaultDelim'
1037 return {start, style, delimiter}
1038end
1039M.ListAttributes.behavior._field_names = {start = 1, style = 2, delimiter = 3}
1040M.ListAttributes.behavior.__eq = utils.equals
1041M.ListAttributes.behavior.__index = function (t, k)
1042 return rawget(t, getmetatable(t)._field_names[k]) or
1043 getmetatable(t)[k]
1044end
1045M.ListAttributes.behavior.__newindex = function (t, k, v)
1046 if getmetatable(t)._field_names[k] then
1047 rawset(t, getmetatable(t)._field_names[k], v)
1048 else
1049 rawset(t, k, v)
1050 end
1051end
1052M.ListAttributes.behavior.__pairs = function(t)
1053 local field_names = M.ListAttributes.behavior._field_names
1054 local fields = {}
1055 for name, i in pairs(field_names) do
1056 fields[i] = name
1057 end
1058 return make_next_function(fields), t, nil
1059end
1062-- Legacy and compatibility types
1065--- Creates a simple (old style) table element.
1066-- @function SimpleTable
1067-- @tparam {Inline,...} caption table caption
1068-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
1069-- @tparam {int,...} widths column widths
1070-- @tparam {Block,...} headers header row
1071-- @tparam {{Block,...}} rows table rows
1072-- @treturn Block table element
1073M.SimpleTable = function(caption, aligns, widths, headers, rows)
1074 return {
1075 caption = ensureInlineList(caption),
1076 aligns = List:new(aligns),
1077 widths = List:new(widths),
1078 headers = List:new(headers),
1079 rows = List:new(rows),
1080 tag = "SimpleTable",
1081 t = "SimpleTable",
1083end
1086------------------------------------------------------------------------
1087-- Constants
1088-- @section constants
1090--- Author name is mentioned in the text.
1091-- @see Citation
1092-- @see Cite
1093M.AuthorInText = "AuthorInText"
1095--- Author name is suppressed.
1096-- @see Citation
1097-- @see Cite
1098M.SuppressAuthor = "SuppressAuthor"
1100--- Default citation style is used.
1101-- @see Citation
1102-- @see Cite
1103M.NormalCitation = "NormalCitation"
1105--- Table cells aligned left.
1106-- @see Table
1107M.AlignLeft = "AlignLeft"
1109--- Table cells right-aligned.
1110-- @see Table
1111M.AlignRight = "AlignRight"
1113--- Table cell content is centered.
1114-- @see Table
1115M.AlignCenter = "AlignCenter"
1117--- Table cells are alignment is unaltered.
1118-- @see Table
1119M.AlignDefault = "AlignDefault"
1121--- Default list number delimiters are used.
1122-- @see OrderedList
1123M.DefaultDelim = "DefaultDelim"
1125--- List numbers are delimited by a period.
1126-- @see OrderedList
1127M.Period = "Period"
1129--- List numbers are delimited by a single parenthesis.
1130-- @see OrderedList
1131M.OneParen = "OneParen"
1133--- List numbers are delimited by a double parentheses.
1134-- @see OrderedList
1135M.TwoParens = "TwoParens"
1137--- List are numbered in the default style
1138-- @see OrderedList
1139M.DefaultStyle = "DefaultStyle"
1141--- List items are numbered as examples.
1142-- @see OrderedList
1143M.Example = "Example"
1145--- List are numbered using decimal integers.
1146-- @see OrderedList
1147M.Decimal = "Decimal"
1149--- List are numbered using lower-case roman numerals.
1150-- @see OrderedList
1151M.LowerRoman = "LowerRoman"
1153--- List are numbered using upper-case roman numerals
1154-- @see OrderedList
1155M.UpperRoman = "UpperRoman"
1157--- List are numbered using lower-case alphabetic characters.
1158-- @see OrderedList
1159M.LowerAlpha = "LowerAlpha"
1161--- List are numbered using upper-case alphabetic characters.
1162-- @see OrderedList
1163M.UpperAlpha = "UpperAlpha"
1165------------------------------------------------------------------------
1166-- Functions which have moved to different modules
1167M.sha1 = utils.sha1
1169return M