git.iko.soy/typeable/pandoc
on 896c288 help sign in
typeable/pandoc/data/pandoc.lua
822 lines 24 kB history raw
1--[[
2pandoc.lua
4Copyright © 2017 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 Albert Krewinkel
24-- @license MIT
25local M = {
26 _VERSION = "0.3.0"
29------------------------------------------------------------------------
30-- The base class for pandoc's AST elements.
31-- @type Element
32-- @local
33local Element = {}
35--- Create a new element subtype
36-- @local
37function Element:make_subtype(o)
38 o = o or {}
39 setmetatable(o, self)
40 self.__index = self
41 return o
42end
44--- Create a new element given its tag and arguments
45-- @local
46function Element:new(tag, ...)
47 local element = { t = tag }
48 local content = {...}
49 -- special case for unary constructors
50 if #content == 1 then
51 element.c = content[1]
52 -- Don't set 'c' field if no further arguments were given. This is important
53 -- for nullary constructors like `Space` and `HorizontalRule`.
54 elseif #content > 0 then
55 element.c = content
56 end
57 setmetatable(element, self)
58 self.__index = self
59 return element
60end
62--- Create a new constructor
63-- @local
64-- @param tag Tag used to identify the constructor
65-- @param fn Function to be called when constructing a new element
66-- @param accessors names to use as accessors for numerical fields
67-- @return function that constructs a new element
68function Element:create_constructor(tag, fn, accessors)
69 local constr = self:make_subtype({tag = tag, getters = {}, setters = {}})
71 -- Add accessors to the metatable
72 if type(accessors) == "string" then
73 constr.getters[accessors] = function(elem)
74 return elem.c
75 end
76 constr.setters[accessors] = function(elem, v)
77 elem.c = v
78 end
79 else
80 for i = 1, #(accessors or {}) do
81 if type(accessors[i]) == "string" then
82 constr.getters[accessors[i]] = function(elem)
83 return elem.c[i]
84 end
85 constr.setters[accessors[i]] = function(elem, v)
86 elem.c[i] = v
87 end
88 else -- only two levels of nesting are supported
89 for k, v in ipairs(accessors[i]) do
90 constr.getters[v] = function(elem)
91 return elem.c[i][k]
92 end
93 constr.setters[v] = function(elem, v)
94 elem.c[i][k] = v
95 end
96 end
97 end
98 end
99 end
101 function constr:new(...)
102 local obj = fn(...)
103 setmetatable(obj, self)
104 self.__index = function(t, k)
105 if getmetatable(t).getters[k] then
106 return getmetatable(t).getters[k](t)
107 elseif k == "t" then
108 return getmetatable(t)["tag"]
109 else
110 return getmetatable(t)[k]
111 end
112 end
113 self.__newindex = function(t, k, v)
114 if getmetatable(t).setters[k] then
115 getmetatable(t).setters[k](t, v)
116 else
117 rawset(t, k, v)
118 end
119 end
120 return obj
121 end
122 self.constructor = self.constructor or {}
123 self.constructor[tag] = constr
124 return constr
125end
127--- Calls the constructor, creating a new element.
128-- @local
129function Element.__call(t, ...)
130 return t:new(...)
131end
133------------------------------------------------------------------------
134--- Pandoc Document
135-- @section document
137--- A complete pandoc document
138-- @function Pandoc
139-- @tparam {Block,...} blocks document content
140-- @tparam[opt] Meta meta document meta data
141function M.Pandoc(blocks, meta)
142 meta = meta or {}
143 return {
144 ["blocks"] = blocks,
145 ["meta"] = meta,
146 ["pandoc-api-version"] = {1,17,0,5},
147 }
148end
150-- DEPRECATED synonym:
151M.Doc = M.Pandoc
153------------------------------------------------------------------------
154-- MetaValue
155-- @section MetaValue
156M.MetaValue = Element:make_subtype{}
157M.MetaValue.__call = function(t, ...)
158 return t:new(...)
159end
160--- Meta blocks
161-- @function MetaBlocks
162-- @tparam {Block,...} blocks blocks
164--- Meta inlines
165-- @function MetaInlines
166-- @tparam {Inline,...} inlines inlines
168--- Meta list
169-- @function MetaList
170-- @tparam {MetaValue,...} meta_values list of meta values
172--- Meta map
173-- @function MetaMap
174-- @tparam table key_value_map a string-indexed map of meta values
175M.meta_value_types = {
176 "MetaBlocks",
177 "MetaInlines",
178 "MetaList",
179 "MetaMap",
181for i = 1, #M.meta_value_types do
182 M[M.meta_value_types[i]] = M.MetaValue:create_constructor(
183 M.meta_value_types[i],
184 function(content)
185 return content
186 end
187 )
188end
190--- Creates string to be used in meta data.
191-- Does nothing, lua strings are meta strings.
192-- @function MetaString
193-- @tparam string str string value
194function M.MetaString(str)
195 return str
196end
198--- Creates boolean to be used in meta data.
199-- Does nothing, lua booleans are meta booleans.
200-- @function MetaBool
201-- @tparam boolean bool boolean value
202function M.MetaBool(bool)
203 return bool
204end
206------------------------------------------------------------------------
207-- Blocks
208-- @section Block
210--- Block elements
211M.Block = Element:make_subtype{}
212M.Block.__call = function (t, ...)
213 return t:new(...)
214end
216--- Creates a block quote element
217-- @function BlockQuote
218-- @tparam {Block,...} content block content
219-- @treturn Block block quote element
220M.BlockQuote = M.Block:create_constructor(
221 "BlockQuote",
222 function(content) return {c = content} end,
223 "content"
226--- Creates a bullet (i.e. unordered) list.
227-- @function BulletList
228-- @tparam {{Block,...},...} content list of items
229-- @treturn Block block quote element
230M.BulletList = M.Block:create_constructor(
231 "BulletList",
232 function(content) return {c = content} end,
233 "content"
236--- Creates a code block element
237-- @function CodeBlock
238-- @tparam string text code string
239-- @tparam[opt] Attr attr element attributes
240-- @treturn Block code block element
241M.CodeBlock = M.Block:create_constructor(
242 "CodeBlock",
243 function(text, attr) return {c = {attr or M.Attr(), text}} end,
244 {{"identifier", "classes", "attributes"}, "text"}
247--- Creates a definition list, containing terms and their explanation.
248-- @function DefinitionList
249-- @tparam {{{Inline,...},{Block,...}},...} content list of items
250-- @treturn Block block quote element
251M.DefinitionList = M.Block:create_constructor(
252 "DefinitionList",
253 function(content) return {c = content} end,
254 "content"
257--- Creates a div element
258-- @function Div
259-- @tparam {Block,...} content block content
260-- @tparam[opt] Attr attr element attributes
261-- @treturn Block code block element
262M.Div = M.Block:create_constructor(
263 "Div",
264 function(content, attr)
265 return {c = {attr or M.Attr(), content}}
266 end,
267 {{"identifier", "classes", "attributes"}, "content"}
270--- Creates a block quote element.
271-- @function Header
272-- @tparam int level header level
273-- @tparam {Inline,...} content inline content
274-- @tparam[opt] Attr attr element attributes
275-- @treturn Block header element
276M.Header = M.Block:create_constructor(
277 "Header",
278 function(level, content, attr)
279 return {c = {level, attr or M.Attr(), content}}
280 end,
281 {"level", {"identifier", "classes", "attributes"}, "content"}
284--- Creates a horizontal rule.
285-- @function HorizontalRule
286-- @treturn Block horizontal rule
287M.HorizontalRule = M.Block:create_constructor(
288 "HorizontalRule",
289 function() return {} end
292--- Creates a line block element.
293-- @function LineBlock
294-- @tparam {{Inline,...},...} content inline content
295-- @treturn Block block quote element
296M.LineBlock = M.Block:create_constructor(
297 "LineBlock",
298 function(content) return {c = content} end,
299 "content"
302--- Creates a null element.
303-- @function Null
304-- @treturn Block null element
305M.Null = M.Block:create_constructor(
306 "Null",
307 function() return {} end
310--- Creates an ordered list.
311-- @function OrderedList
312-- @tparam {{Block,...},...} items list items
313-- @param[opt] listAttributes list parameters
314-- @treturn Block
315M.OrderedList = M.Block:create_constructor(
316 "OrderedList",
317 function(items, listAttributes)
318 return {c = {listAttributes,items}}
319 end,
320 {{"start", "style", "delimiter"}, "content"}
323--- Creates a para element.
324-- @function Para
325-- @tparam {Inline,...} content inline content
326-- @treturn Block block quote element
327M.Para = M.Block:create_constructor(
328 "Para",
329 function(content) return {c = content} end,
330 "content"
333--- Creates a plain element.
334-- @function Plain
335-- @tparam {Inline,...} content inline content
336-- @treturn Block block quote element
337M.Plain = M.Block:create_constructor(
338 "Plain",
339 function(content) return {c = content} end,
340 "content"
343--- Creates a raw content block of the specified format.
344-- @function RawBlock
345-- @tparam string format format of content
346-- @tparam string text string content
347-- @treturn Block block quote element
348M.RawBlock = M.Block:create_constructor(
349 "RawBlock",
350 function(format, text) return {c = {format, text}} end,
351 {"format", "text"}
354--- Creates a table element.
355-- @function Table
356-- @tparam {Inline,...} caption table caption
357-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
358-- @tparam {int,...} widths column widths
359-- @tparam {Block,...} headers header row
360-- @tparam {{Block,...}} rows table rows
361-- @treturn Block block quote element
362M.Table = M.Block:create_constructor(
363 "Table",
364 function(caption, aligns, widths, headers, rows)
365 return {c = {caption, aligns, widths, headers, rows}}
366 end,
367 {"caption", "aligns", "widths", "headers", "rows"}
371------------------------------------------------------------------------
372-- Inline
373-- @section Inline
375--- Inline element class
376M.Inline = Element:make_subtype{}
377M.Inline.__call = function (t, ...)
378 return t:new(...)
379end
381--- Creates a Cite inline element
382-- @function Cite
383-- @tparam {Inline,...} content List of inlines
384-- @tparam {Citation,...} citations List of citations
385-- @treturn Inline citations element
386M.Cite = M.Inline:create_constructor(
387 "Cite",
388 function(content, citations) return {c = {citations, content}} end,
389 {"citations", "content"}
392--- Creates a Code inline element
393-- @function Code
394-- @tparam string text brief image description
395-- @tparam[opt] Attr attr additional attributes
396-- @treturn Inline code element
397M.Code = M.Inline:create_constructor(
398 "Code",
399 function(text, attr) return {c = {attr or M.Attr(), text}} end,
400 {{"identifier", "classes", "attributes"}, "text"}
403--- Creates an inline element representing emphasised text.
404-- @function Emph
405-- @tparam {Inline,..} content inline content
406-- @treturn Inline emphasis element
407M.Emph = M.Inline:create_constructor(
408 "Emph",
409 function(content) return {c = content} end,
410 "content"
413--- Creates a Image inline element
414-- @function Image
415-- @tparam {Inline,..} caption text used to describe the image
416-- @tparam string src path to the image file
417-- @tparam[opt] string title brief image description
418-- @tparam[opt] Attr attr additional attributes
419-- @treturn Inline image element
420M.Image = M.Inline:create_constructor(
421 "Image",
422 function(caption, src, title, attr)
423 title = title or ""
424 attr = attr or M.Attr()
425 return {c = {attr, caption, {src, title}}}
426 end,
427 {"attributes", "caption", {"src", "title"}}
430--- Create a LineBreak inline element
431-- @function LineBreak
432-- @treturn Inline linebreak element
433M.LineBreak = M.Inline:create_constructor(
434 "LineBreak",
435 function() return {} end
438--- Creates a link inline element, usually a hyperlink.
439-- @function Link
440-- @tparam {Inline,..} content text for this link
441-- @tparam string target the link target
442-- @tparam[opt] string title brief link description
443-- @tparam[opt] Attr attr additional attributes
444-- @treturn Inline image element
445M.Link = M.Inline:create_constructor(
446 "Link",
447 function(content, target, title, attr)
448 title = title or ""
449 attr = attr or M.Attr()
450 return {c = {attr, content, {target, title}}}
451 end,
452 {"attributes", "content", {"target", "title"}}
455--- Creates a Math element, either inline or displayed.
456-- @function Math
457-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
458-- @tparam string text Math content
459-- @treturn Inline Math element
460M.Math = M.Inline:create_constructor(
461 "Math",
462 function(mathtype, text)
463 return {c = {mathtype, text}}
464 end,
465 {"mathtype", "text"}
467--- Creates a DisplayMath element (DEPRECATED).
468-- @function DisplayMath
469-- @tparam string text Math content
470-- @treturn Inline Math element
471M.DisplayMath = M.Inline:create_constructor(
472 "DisplayMath",
473 function(text) return M.Math("DisplayMath", text) end,
474 {"mathtype", "text"}
476--- Creates an InlineMath inline element (DEPRECATED).
477-- @function InlineMath
478-- @tparam string text Math content
479-- @treturn Inline Math element
480M.InlineMath = M.Inline:create_constructor(
481 "InlineMath",
482 function(text) return M.Math("InlineMath", text) end,
483 {"mathtype", "text"}
486--- Creates a Note inline element
487-- @function Note
488-- @tparam {Block,...} content footnote block content
489M.Note = M.Inline:create_constructor(
490 "Note",
491 function(content) return {c = content} end,
492 "content"
495--- Creates a Quoted inline element given the quote type and quoted content.
496-- @function Quoted
497-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
498-- @tparam {Inline,..} content inline content
499-- @treturn Inline quoted element
500M.Quoted = M.Inline:create_constructor(
501 "Quoted",
502 function(quotetype, content) return {c = {quotetype, content}} end,
503 {"quotetype", "content"}
505--- Creates a single-quoted inline element (DEPRECATED).
506-- @function SingleQuoted
507-- @tparam {Inline,..} content inline content
508-- @treturn Inline quoted element
509-- @see Quoted
510M.SingleQuoted = M.Inline:create_constructor(
511 "SingleQuoted",
512 function(content) return M.Quoted(M.SingleQuote, content) end,
513 {"quotetype", "content"}
515--- Creates a single-quoted inline element (DEPRECATED).
516-- @function DoubleQuoted
517-- @tparam {Inline,..} content inline content
518-- @treturn Inline quoted element
519-- @see Quoted
520M.DoubleQuoted = M.Inline:create_constructor(
521 "DoubleQuoted",
522 function(content) return M.Quoted("DoubleQuote", content) end,
523 {"quotetype", "content"}
526--- Creates a RawInline inline element
527-- @function RawInline
528-- @tparam string format format of the contents
529-- @tparam string text string content
530-- @treturn Inline raw inline element
531M.RawInline = M.Inline:create_constructor(
532 "RawInline",
533 function(format, text) return {c = {format, text}} end,
534 {"format", "text"}
537--- Creates text rendered in small caps
538-- @function SmallCaps
539-- @tparam {Inline,..} content inline content
540-- @treturn Inline smallcaps element
541M.SmallCaps = M.Inline:create_constructor(
542 "SmallCaps",
543 function(content) return {c = content} end,
544 "content"
547--- Creates a SoftBreak inline element.
548-- @function SoftBreak
549-- @treturn Inline softbreak element
550M.SoftBreak = M.Inline:create_constructor(
551 "SoftBreak",
552 function() return {} end
555--- Create a Space inline element
556-- @function Space
557-- @treturn Inline space element
558M.Space = M.Inline:create_constructor(
559 "Space",
560 function() return {} end
563--- Creates a Span inline element
564-- @function Span
565-- @tparam {Inline,..} content inline content
566-- @tparam[opt] Attr attr additional attributes
567-- @treturn Inline span element
568M.Span = M.Inline:create_constructor(
569 "Span",
570 function(content, attr) return {c = {attr or M.Attr(), content}} end,
571 {{"identifier", "classes", "attributes"}, "content"}
574--- Creates a Str inline element
575-- @function Str
576-- @tparam string text content
577-- @treturn Inline string element
578M.Str = M.Inline:create_constructor(
579 "Str",
580 function(text) return {c = text} end,
581 "text"
584--- Creates text which is striked out.
585-- @function Strikeout
586-- @tparam {Inline,..} content inline content
587-- @treturn Inline strikeout element
588M.Strikeout = M.Inline:create_constructor(
589 "Strikeout",
590 function(content) return {c = content} end,
591 "content"
594--- Creates a Strong element, whose text is usually displayed in a bold font.
595-- @function Strong
596-- @tparam {Inline,..} content inline content
597-- @treturn Inline strong element
598M.Strong = M.Inline:create_constructor(
599 "Strong",
600 function(content) return {c = content} end,
601 "content"
604--- Creates a Subscript inline element
605-- @function Subscript
606-- @tparam {Inline,..} content inline content
607-- @treturn Inline subscript element
608M.Subscript = M.Inline:create_constructor(
609 "Subscript",
610 function(content) return {c = content} end,
611 "content"
614--- Creates a Superscript inline element
615-- @function Superscript
616-- @tparam {Inline,..} content inline content
617-- @treturn Inline strong element
618M.Superscript = M.Inline:create_constructor(
619 "Superscript",
620 function(content) return {c = content} end,
621 "content"
625------------------------------------------------------------------------
626-- Helpers
627-- @section helpers
629-- Attr
630M.Attr = {}
631M.Attr._field_names = {identifier = 1, classes = 2, attributes = 3}
632--- Create a new set of attributes (Attr).
633-- @function Attr
634-- @tparam[opt] string identifier element identifier
635-- @tparam[opt] {string,...} classes element classes
636-- @tparam[opt] table attributes table containing string keys and values
637-- @return element attributes
638M.Attr.__call = function(t, identifier, classes, attributes)
639 identifier = identifier or ''
640 classes = classes or {}
641 attributes = attributes or {}
642 local attr = {identifier, classes, attributes}
643 setmetatable(attr, t)
644 return attr
645end
646M.Attr.__index = function(t, k)
647 return rawget(t, k) or
648 rawget(t, M.Attr._field_names[k]) or
649 rawget(getmetatable(t), k)
650end
651M.Attr.__newindex = function(t, k, v)
652 if M.Attr._field_names[k] then
653 rawset(t, M.Attr._field_names[k], v)
654 else
655 rawset(t, k, v)
656 end
657end
658setmetatable(M.Attr, M.Attr)
661--- Creates a single citation.
662-- @function Citation
663-- @tparam string id citation identifier (like a bibtex key)
664-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
665-- @tparam[opt] {Inline,...} prefix citation prefix
666-- @tparam[opt] {Inline,...} suffix citation suffix
667-- @tparam[opt] int note_num note number
668-- @tparam[opt] int hash hash number
669M.Citation = function(id, mode, prefix, suffix, note_num, hash)
670 prefix = prefix or {}
671 suffix = suffix or {}
672 note_num = note_num or 0
673 hash = hash or 0
674 return {
675 citationId = id,
676 citationPrefix = prefix,
677 citationSuffix = suffix,
678 citationMode = mode,
679 citationNoteNum = note_num,
680 citationHash = hash,
681 }
682end
685------------------------------------------------------------------------
686-- Constants
687-- @section constants
689--- Author name is mentioned in the text.
690-- @see Citation
691-- @see Cite
692M.AuthorInText = "AuthorInText"
694--- Author name is suppressed.
695-- @see Citation
696-- @see Cite
697M.SuppressAuthor = "SuppressAuthor"
699--- Default citation style is used.
700-- @see Citation
701-- @see Cite
702M.NormalCitation = "NormalCitation"
704--- Table cells aligned left.
705-- @see Table
706M.AlignLeft = "AlignLeft"
708--- Table cells right-aligned.
709-- @see Table
710M.AlignRight = "AlignRight"
712--- Table cell content is centered.
713-- @see Table
714M.AlignCenter = "AlignCenter"
716--- Table cells are alignment is unaltered.
717-- @see Table
718M.AlignDefault = "AlignDefault"
720--- Default list number delimiters are used.
721-- @see OrderedList
722M.DefaultDelim = "DefaultDelim"
724--- List numbers are delimited by a period.
725-- @see OrderedList
726M.Period = "Period"
728--- List numbers are delimited by a single parenthesis.
729-- @see OrderedList
730M.OneParen = "OneParen"
732--- List numbers are delimited by a double parentheses.
733-- @see OrderedList
734M.TwoParens = "TwoParens"
736--- List are numbered in the default style
737-- @see OrderedList
738M.DefaultStyle = "DefaultStyle"
740--- List items are numbered as examples.
741-- @see OrderedList
742M.Example = "Example"
744--- List are numbered using decimal integers.
745-- @see OrderedList
746M.Decimal = "Decimal"
748--- List are numbered using lower-case roman numerals.
749-- @see OrderedList
750M.LowerRoman = "LowerRoman"
752--- List are numbered using upper-case roman numerals
753-- @see OrderedList
754M.UpperRoman = "UpperRoman"
756--- List are numbered using lower-case alphabetic characters.
757-- @see OrderedList
758M.LowerAlpha = "LowerAlpha"
760--- List are numbered using upper-case alphabetic characters.
761-- @see OrderedList
762M.UpperAlpha = "UpperAlpha"
765------------------------------------------------------------------------
766-- Helper Functions
767-- @section helpers
769--- Parse the given string into a Pandoc document.
770-- The method used to interpret input is specified by *format*. Acceptable
771-- values for this parameter are equal to those that can be given to the
772-- `--from` command line option.
773-- @tparam string markup the markup to be parsed
774-- @tparam[opt] string format format specification, defaults to "markdown".
775-- @treturn Pandoc pandoc document
776-- @usage
777-- local org_markup = "/emphasis/" -- Input to be read
778-- local document = pandoc.read(org_markup, "org")
779-- -- Get the first block of the document
780-- local block = document.blocks[1]
781-- -- The inline element in that block is an `Emph`
782-- assert(block.content[1].t == "Emph")
783function M.read(markup, format)
784 format = format or "markdown"
785 local pd = pandoc.__read(format, markup)
786 if type(pd) == "string" then
787 error(pd)
788 else
789 return pd
790 end
791end
793--- Use functions defined in the global namespace to create a pandoc filter.
794-- All globally defined functions which have names of pandoc elements are
795-- collected into a new table.
796-- @return A list of filter functions
797-- @usage
798-- -- within a file defining a pandoc filter:
799-- function Str(text)
800-- return pandoc.Str(utf8.upper(text))
801-- end
802--
803-- return {pandoc.global_filter()}
804-- -- the above is equivallent to
805-- -- return {{Str = Str}}
806function M.global_filter()
807 local res = {}
808 function is_filter_function(k)
809 return M.Inline.constructor[k] or
810 M.Block.constructor[k] or
811 k == "Meta" or k == "Doc" or k == "Pandoc" or
812 k == "Block" or k == "Inline"
813 end
814 for k, v in pairs(_G) do
815 if is_filter_function(k) then
816 res[k] = v
817 end
818 end
819 return res
820end
822return M