@@ -1,7 +1,7 @@
11--[[
22pandoc.lua
33
4−Copyright (c) 2017 Albert Krewinkel
4+Copyright © 2017 Albert Krewinkel
55
66Permission to use, copy, modify, and/or distribute this software for any purpose
77with or without fee is hereby granted, provided that the above copyright notice
@@ -16,25 +16,87 @@ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
1616THIS SOFTWARE.
1717]]
1818
19−--- The module
19+---
20+-- Lua functions for pandoc scripts.
21+--
22+-- @author Albert Krewinkel
23+-- @copyright © 2017 Albert Krewinkel
24+-- @license MIT
2025local M = {
21− _version = "0.1.0"
26+ _VERSION = "0.2.0"
2227}
2328
29+--- Attributes
30+-- @type Attributes
31+M.Attributes = {}
32+setmetatable(M.Attributes, M.Attributes)
33+
34+M.Attributes.__index = function(t, k)
35+ if k == "id" then
36+ return t[1]
37+ elseif k == "class" then
38+ return table.concat(t[2], ' ')
39+ else
40+ return t.kv[k]
41+ end
42+end
43+
2444--- Create a new set of attributes (Attr).
25−function M.Attributes(id, classes, key_values)
26− return {id, classes, key_values}
45+-- @function Attributes
46+M.Attributes.__call = function(t, key_values, id, classes)
47+ local kv = {}
48+ for i = 1, #key_values do
49+ kv[key_values[i][1]] = key_values[i][2]
50+ end
51+ id = id or ''
52+ classes = classes or {}
53+ local attr = {id, classes, key_values, kv = kv}
54+ setmetatable(attr, t)
55+ return attr
2756end
57+M.Attributes.empty = M.Attributes('', {}, {})
58+
2859
60+--- Creates a single citation.
61+-- @function Citation
62+-- @tparam string id citation identifier (like a bibtex key)
63+-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
64+-- @tparam[opt] {Inline,...} prefix citation prefix
65+-- @tparam[opt] {Inline,...} suffix citation suffix
66+-- @tparam[opt] int note_num note number
67+-- @tparam[opt] int note_num hash number
68+M.Citation = function(id, mode, prefix, suffix, note_num, hash)
69+ prefix = prefix or {}
70+ suffix = suffix or {}
71+ note_num = note_num or 0
72+ hash = hash or 0
73+ return {
74+ citationId = id,
75+ citationPrefix = prefix,
76+ citationSuffix = suffix,
77+ citationMode = mode,
78+ citationNoteNum = note_num,
79+ citationHash = hash,
80+ }
81+end
82+
83+------------------------------------------------------------------------
84+-- The base class for pandoc's AST elements.
85+-- @type Element
86+-- @local
2987local Element = {}
88+
3089--- Create a new element subtype
90+-- @local
3191function Element:make_subtype(o)
3292 o = o or {}
3393 setmetatable(o, self)
3494 self.__index = self
3595 return o
3696end
97+
3798--- Create a new element given its tag and arguments
99+-- @local
38100function Element:new(tag, ...)
39101 local element = { t = tag }
40102 local content = {...}
@@ -51,7 +113,48 @@ function Element:new(tag, ...)
51113 return element
52114end
53115
54−local function Doc(blocks, meta)
116+--- Create a new constructor
117+-- @local
118+-- @param tag Tag used to identify the constructor
119+-- @param fn Function to be called when constructing a new element
120+-- @return function that constructs a new element
121+function Element:create_constructor(tag, fn)
122+ local constr = self:make_subtype({tag = tag})
123+ function constr:new(...)
124+ local obj = fn(...)
125+ setmetatable(obj, self)
126+ self.__index = function(t, k)
127+ if k == "c" then
128+ return t["content"]
129+ elseif k == "t" then
130+ return getmetatable(t)["tag"]
131+ else
132+ return getmetatable(t)[k]
133+ end
134+ end
135+ return obj
136+ end
137+ self.constructor = self.constructor or {}
138+ self.constructor[tag] = constr
139+ return constr
140+end
141+
142+--- Calls the constructor, creating a new element.
143+-- @local
144+function Element.__call(t, ...)
145+ return t:new(...)
146+end
147+
148+------------------------------------------------------------------------
149+--- Pandoc Document
150+-- @section document
151+
152+--- A complete pandoc document
153+-- @function Doc
154+-- @tparam {Block,...} blocks document content
155+-- @tparam[opt] Meta meta document meta data
156+function M.Doc(blocks, meta)
157+ meta = meta or {}
55158 return {
56159 ["blocks"] = blocks,
57160 ["meta"] = meta,
@@ -59,82 +162,545 @@ local function Doc(blocks, meta)
59162 }
60163end
61164
62−local Inline = Element:make_subtype{}
63−local Block = Element:make_subtype{}
64165
65−M.block_types = {
166+------------------------------------------------------------------------
167+-- MetaValue
168+-- @section MetaValue
169+M.MetaValue = Element:make_subtype{}
170+M.MetaValue.__call = function(t, ...)
171+ return t:new(...)
172+end
173+--- Meta blocks
174+-- @function MetaBlocks
175+-- @tparam {Block,...} blocks blocks
176+
177+--- Meta inlines
178+-- @function MetaInlines
179+-- @tparam {Inline,...} inlines inlines
180+
181+--- Meta list
182+-- @function MetaList
183+-- @tparam {MetaValue,...} meta_values list of meta values
184+
185+--- Meta boolean
186+-- @function MetaBool
187+-- @tparam boolean bool boolean value
188+
189+--- Meta map
190+-- @function MetaMap
191+-- @tparam table a string-index map of meta values
192+
193+--- Meta string
194+-- @function MetaString
195+-- @tparam string str string value
196+M.meta_value_types = {
197+ "MetaBlocks",
198+ "MetaBool",
199+ "MetaInlines",
200+ "MetaList",
201+ "MetaMap",
202+ "MetaString"
203+}
204+for i = 1, #M.meta_value_types do
205+ M[M.meta_value_types[i]] = M.MetaValue:create_constructor(
206+ M.meta_value_types[i],
207+ function(content)
208+ return {c = content}
209+ end
210+ )
211+end
212+
213+------------------------------------------------------------------------
214+-- Block
215+-- @section Block
216+
217+M.Block = Element:make_subtype{}
218+M.Block.__call = function (t, ...)
219+ return t:new(...)
220+end
221+
222+--- Creates a block quote element
223+-- @function BlockQuote
224+-- @tparam {Block,...} content block content
225+-- @treturn Block block quote element
226+M.BlockQuote = M.Block:create_constructor(
66227 "BlockQuote",
228+ function(content) return {c = content} end
229+)
230+
231+--- Creates a bullet (i.e. unordered) list.
232+-- @function BulletList
233+-- @tparam {{Block,...},...} content list of items
234+-- @treturn Block block quote element
235+M.BulletList = M.Block:create_constructor(
67236 "BulletList",
237+ function(content) return {c = content} end
238+)
239+
240+--- Creates a code block element
241+-- @function CodeBlock
242+-- @tparam string code code string
243+-- @tparam[opt] Attributes attributes element attributes
244+-- @treturn Block code block element
245+M.CodeBlock = M.Block:create_constructor(
68246 "CodeBlock",
247+ function(code, attributes) return {c = {attributes, code}} end
248+)
249+
250+--- Creates a definition list, containing terms and their explanation.
251+-- @function DefinitionList
252+-- @tparam {{{Inline,...},{Block,...}},...} content list of items
253+-- @treturn Block block quote element
254+M.DefinitionList = M.Block:create_constructor(
69255 "DefinitionList",
256+ function(content) return {c = content} end
257+)
258+
259+--- Creates a div element
260+-- @function Div
261+-- @tparam {Block,...} content block content
262+-- @tparam[opt] Attributes attributes element attributes
263+-- @treturn Block code block element
264+M.Div = M.Block:create_constructor(
70265 "Div",
266+ function(content, attributes) return {c = {attributes, content}} end
267+)
268+
269+--- Creates a block quote element.
270+-- @function Header
271+-- @tparam int level header level
272+-- @tparam Attributes attributes element attributes
273+-- @tparam {Inline,...} content inline content
274+-- @treturn Block header element
275+M.Header = M.Block:create_constructor(
71276 "Header",
277+ function(level, attributes, content)
278+ return {c = {level, attributes, content}}
279+ end
280+)
281+
282+--- Creates a horizontal rule.
283+-- @function HorizontalRule
284+-- @treturn Block horizontal rule
285+M.HorizontalRule = M.Block:create_constructor(
72286 "HorizontalRule",
73− "HorizontalRule",
287+ function() return {} end
288+)
289+
290+--- Creates a line block element.
291+-- @function LineBlock
292+-- @tparam {{Inline,...},...} content inline content
293+-- @treturn Block block quote element
294+M.LineBlock = M.Block:create_constructor(
74295 "LineBlock",
296+ function(content) return {c = content} end
297+)
298+
299+--- Creates a null element.
300+-- @function Null
301+-- @treturn Block null element
302+M.Null = M.Block:create_constructor(
75303 "Null",
304+ function() return {} end
305+)
306+
307+--- Creates an ordered list.
308+-- @function OrderedList
309+-- @tparam {{Block,...},...} items list items
310+-- @param[opt] listAttributes list parameters
311+-- @treturn Block
312+M.OrderedList = M.Block:create_constructor(
76313 "OrderedList",
314+ function(items, listAttributes)
315+ return {c = {listAttributes,items}}
316+ end
317+)
318+
319+--- Creates a para element.
320+-- @function Para
321+-- @tparam {Inline,...} content inline content
322+-- @treturn Block block quote element
323+M.Para = M.Block:create_constructor(
77324 "Para",
325+ function(content) return {c = content} end
326+)
327+
328+--- Creates a plain element.
329+-- @function Plain
330+-- @tparam {Inline,...} content inline content
331+-- @treturn Block block quote element
332+M.Plain = M.Block:create_constructor(
78333 "Plain",
334+ function(content) return {c = content} end
335+)
336+
337+--- Creates a raw content block of the specified format.
338+-- @function RawBlock
339+-- @tparam string format format of content
340+-- @tparam string content string content
341+-- @treturn Block block quote element
342+M.RawBlock = M.Block:create_constructor(
79343 "RawBlock",
344+ function(format, content) return {c = {format, content}} end
345+)
346+
347+--- Creates a table element.
348+-- @function Table
349+-- @tparam {Inline,...} caption table caption
350+-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
351+-- @tparam {int,...} widths column widths
352+-- @tparam {Block,...} headers header row
353+-- @tparam {{Block,...}} rows table rows
354+-- @treturn Block block quote element
355+M.Table = M.Block:create_constructor(
80356 "Table",
81−}
357+ function(caption, aligns, widths, headers, rows)
358+ return {c = {caption, aligns, widths, headers, rows}}
359+ end
360+)
361+
362+
363+------------------------------------------------------------------------
364+-- Inline
365+-- @section Inline
82366
83−M.inline_types = {
367+--- Inline element class
368+M.Inline = Element:make_subtype{}
369+M.Inline.__call = function (t, ...)
370+ return t:new(...)
371+end
372+
373+--- Creates a Cite inline element
374+-- @function Cite
375+-- @tparam {Inline,...} content List of inlines
376+-- @tparam {Citation,...} citations List of citations
377+-- @treturn Inline citations element
378+M.Cite = M.Inline:create_constructor(
84379 "Cite",
380+ function(content, citations) return {c = {citations, content}} end
381+)
382+
383+--- Creates a Code inline element
384+-- @function Code
385+-- @tparam string code brief image description
386+-- @tparam[opt] Attributes attributes additional attributes
387+-- @treturn Inline code element
388+M.Code = M.Inline:create_constructor(
85389 "Code",
390+ function(code, attributes) return {c = {attributes, code}} end
391+)
392+
393+--- Creates an inline element representing emphasised text.
394+-- @function Emph
395+-- @tparam {Inline,..} content inline content
396+-- @treturn Inline emphasis element
397+M.Emph = M.Inline:create_constructor(
86398 "Emph",
399+ function(content) return {c = content} end
400+)
401+
402+--- Creates a Image inline element
403+-- @function Image
404+-- @tparam {Inline,..} caption text used to describe the image
405+-- @tparam string src path to the image file
406+-- @tparam[opt] string title brief image description
407+-- @tparam[opt] Attributes attributes additional attributes
408+-- @treturn Inline image element
409+M.Image = M.Inline:create_constructor(
87410 "Image",
411+ function(caption, src, title, attributes)
412+ title = title or ""
413+ attributes = attributes or Attribute.empty
414+ return {c = {attributes, caption, {src, title}}}
415+ end
416+)
417+
418+--- Create a LineBreak inline element
419+-- @function LineBreak
420+-- @treturn Inline linebreak element
421+M.LineBreak = M.Inline:create_constructor(
88422 "LineBreak",
423+ function() return {} end
424+)
425+
426+--- Creates a link inline element, usually a hyperlink.
427+-- @function Link
428+-- @tparam {Inline,..} content text for this link
429+-- @tparam string target the link target
430+-- @tparam[opt] string title brief link description
431+-- @tparam[opt] Attributes attributes additional attributes
432+-- @treturn Inline image element
433+M.Link = M.Inline:create_constructor(
89434 "Link",
435+ function(content, target, title, attributes)
436+ title = title or ""
437+ attributes = attributes or Attribute.empty
438+ return {c = {attributes, content, {target, title}}}
439+ end
440+)
441+
442+--- Creates a Math inline element
443+-- @function Math
444+-- @tparam InlineMath|DisplayMath mathtype Display specifier
445+-- @tparam string text Math content
446+-- @treturn Inline Math element
447+M.Math = M.Inline:create_constructor(
90448 "Math",
449+ function(mathtype, text)
450+ return {c = {mathtype, text}}
451+ end
452+)
453+
454+--- Creates a Note inline element
455+-- @function Note
456+-- @tparam {Block,...} content footnote block content
457+M.Note = M.Inline:create_constructor(
91458 "Note",
459+ function(contents) return {c = contents} end
460+)
461+
462+--- Creates a Quoted inline element
463+-- @function Quoted
464+-- @tparam DoubleQuote|SingleQuote quotetype type of quotes to be used
465+-- @tparam {Inline,..} content inline content
466+-- @treturn Inline quoted element
467+M.Quoted = M.Inline:create_constructor(
92468 "Quoted",
469+ function(quotetype, content) return {c = {quotetype, content}} end
470+)
471+--- Creates a RawInline inline element
472+-- @function RawInline
473+-- @tparam string format format of the contents
474+-- @tparam string text string content
475+-- @treturn Inline raw inline element
476+M.RawInline = M.Inline:create_constructor(
93477 "RawInline",
478+ function(format, text) return {c = {format, text}} end
479+)
480+
481+--- Creates text rendered in small caps
482+-- @function SmallCaps
483+-- @tparam {Inline,..} content inline content
484+-- @treturn Inline smallcaps element
485+M.SmallCaps = M.Inline:create_constructor(
94486 "SmallCaps",
487+ function(content) return {c = content} end
488+)
489+
490+--- Creates a SoftBreak inline element.
491+-- @function SoftBreak
492+-- @treturn Inline softbreak element
493+M.SoftBreak = M.Inline:create_constructor(
95494 "SoftBreak",
495+ function() return {} end
496+)
497+
498+--- Create a Space inline element
499+-- @function Space
500+-- @treturn Inline space element
501+M.Space = M.Inline:create_constructor(
96502 "Space",
503+ function() return {} end
504+)
505+
506+--- Creates a Span inline element
507+-- @function Span
508+-- @tparam {Inline,..} content inline content
509+-- @tparam[opt] Attributes attributes additional attributes
510+-- @treturn Inline span element
511+M.Span = M.Inline:create_constructor(
97512 "Span",
513+ function(content, attributes) return {c = {attributes, content}} end
514+)
515+
516+--- Creates a Str inline element
517+-- @function Str
518+-- @tparam string text content
519+-- @treturn Inline string element
520+M.Str = M.Inline:create_constructor(
98521 "Str",
522+ function(text) return {c = text} end
523+)
524+
525+--- Creates text which is striked out.
526+-- @function Strikeout
527+-- @tparam {Inline,..} content inline content
528+-- @treturn Inline strikeout element
529+M.Strikeout = M.Inline:create_constructor(
99530 "Strikeout",
531+ function(content) return {c = content} end
532+)
533+
534+--- Creates a Strong element, whose text is usually displayed in a bold font.
535+-- @function Strong
536+-- @tparam {Inline,..} content inline content
537+-- @treturn Inline strong element
538+M.Strong = M.Inline:create_constructor(
100539 "Strong",
540+ function(content) return {c = content} end
541+)
542+
543+--- Creates a Subscript inline element
544+-- @function Subscript
545+-- @tparam {Inline,..} content inline content
546+-- @treturn Inline subscript element
547+M.Subscript = M.Inline:create_constructor(
101548 "Subscript",
102− "Superscript"
103−}
549+ function(content) return {c = content} end
550+)
104551
105−for _, block_type in pairs(M.block_types) do
106− M[block_type] = function(...)
107− return Block:new(block_type, ...)
108− end
109−end
552+--- Creates a Superscript inline element
553+-- @function Superscript
554+-- @tparam {Inline,..} content inline content
555+-- @treturn Inline strong element
556+M.Superscript = M.Inline:create_constructor(
557+ "Superscript",
558+ function(content) return {c = content} end
559+)
110560
111−for _, inline_type in pairs(M.inline_types) do
112− M[inline_type] = function(...)
113− return Inline:new(inline_type, ...)
114− end
115−end
116561
117−--- Arrays to provide fast lookup of element types
118−local set_of_inline_types = {}
119−local set_of_block_types = {}
562+------------------------------------------------------------------------
563+-- Constants
564+-- @section constants
120565
121−for i = 1, #M.inline_types do
122− set_of_inline_types[M.inline_types[i]] = true
123−end
124−for i = 1, #M.block_types do
125− set_of_block_types[M.block_types[i]] = true
126−end
566+--- Math content is to be displayed on a separate line.
567+-- @see Math
568+M.DisplayMath = {}
569+M.DisplayMath.t = "DisplayMath"
570+--- Math content is to be displayed inline within the paragraph
571+-- @see Math
572+M.InlineMath = {}
573+M.InlineMath.t = "InlineMath"
574+
575+--- Double quoted content.
576+-- @see Quoted
577+M.DoubleQuote = {}
578+M.DoubleQuote.t = "DoubleQuote"
579+
580+--- Single quoted content.
581+-- @see Quoted
582+M.SingleQuote = {}
583+M.SingleQuote.t = "SingleQuote"
584+
585+--- Author name is mentioned in the text.
586+-- @see Citation
587+-- @see Cite
588+M.AuthorInText = {}
589+M.AuthorInText.t = "AuthorInText"
590+
591+--- Author name is suppressed.
592+-- @see Citation
593+-- @see Cite
594+M.SuppressAuthor = {}
595+M.SuppressAuthor.t = "SuppressAuthor"
596+
597+--- Default citation style is used.
598+-- @see Citation
599+-- @see Cite
600+M.NormalCitation = {}
601+M.NormalCitation.t = "NormalCitation"
602+
603+--- Table cells aligned left.
604+-- @see Table
605+M.AlignLeft = {}
606+M.AlignLeft.t = "AlignLeft"
607+
608+--- Table cells right-aligned.
609+-- @see Table
610+M.AlignRight = {}
611+M.AlignRight.t = "AlignRight"
612+
613+--- Table cell content is centered.
614+-- @see Table
615+M.AlignCenter = {}
616+M.AlignCenter.t = "AlignCenter"
617+
618+--- Table cells are alignment is unaltered.
619+-- @see Table
620+M.AlignDefault = {}
621+M.AlignDefault.t = "AlignDefault"
622+
623+--- Default list number delimiters are used.
624+-- @see OrderedList
625+M.DefaultDelim = {}
626+M.DefaultDelim.t = "DefaultDelim"
627+
628+--- List numbers are delimited by a period.
629+-- @see OrderedList
630+M.Period = {}
631+M.Period.t = "Period"
127632
633+--- List numbers are delimited by a single parenthesis.
634+-- @see OrderedList
635+M.OneParen = {}
636+M.OneParen.t = "OneParen"
637+
638+--- List numbers are delimited by a double parentheses.
639+-- @see OrderedList
640+M.TwoParens = {}
641+M.TwoParens.t = "TwoParens"
642+
643+--- List are numbered in the default style
644+-- @see OrderedList
645+M.DefaultStyle = {}
646+M.DefaultStyle.t = "DefaultStyle"
647+
648+--- List items are numbered as examples.
649+-- @see OrderedList
650+M.Example = {}
651+M.Example.t = "Example"
652+
653+--- List are numbered using decimal integers.
654+-- @see OrderedList
655+M.Decimal = {}
656+M.Decimal.t = "Decimal"
657+
658+--- List are numbered using lower-case roman numerals.
659+-- @see OrderedList
660+M.LowerRoman = {}
661+M.LowerRoman.t = "LowerRoman"
662+
663+--- List are numbered using upper-case roman numerals
664+-- @see OrderedList
665+M.UpperRoman = {}
666+M.UpperRoman.t = "UpperRoman"
667+
668+--- List are numbered using lower-case alphabetic characters.
669+-- @see OrderedList
670+M.LowerAlpha = {}
671+M.LowerAlpha.t = "LowerAlpha"
672+
673+--- List are numbered using upper-case alphabetic characters.
674+-- @see OrderedList
675+M.UpperAlpha = {}
676+M.UpperAlpha.t = "UpperAlpha"
677+
678+
679+------------------------------------------------------------------------
680+-- Helper Functions
681+-- @section helpers
682+
683+--- Use functions defined in the global namespace to create a pandoc filter.
684+-- All globally defined functions which have names of pandoc elements are
685+-- collected into a new table.
686+-- @return A list of filter functions
687+-- @usage
688+-- -- within a file defining a pandoc filter:
689+-- function Str(text)
690+-- return pandoc.Str(utf8.upper(text))
691+-- end
692+--
693+-- return {pandoc.global_filter()}
694+-- -- the above is equivallent to
695+-- -- return {{Str = Str}}
128696function M.global_filter()
129697 local res = {}
130698 for k, v in pairs(_G) do
131− if set_of_inline_types[k] or set_of_block_types[k] or k == "Doc" then
699+ if M.Inline.constructor[k] or M.Block.constructor[k] or M.Block.constructors[k] or k == "Doc" then
132700 res[k] = v
133701 end
134702 end
135703 return res
136704end
137705
138−M["Doc"] = Doc
139−
140706return M