git.iko.soy/typeable/pandoc
on 345bf8b help sign in
typeable/pandoc/data/pandoc.lua
815 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.2.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-- @return function that constructs a new element
67function Element:create_constructor(tag, fn, accessors)
68 local constr = self:make_subtype({tag = tag, getters = {}, setters = {}})
70 -- Add accessors to the metatable
71 if type(accessors) == "string" then
72 constr.getters[accessors] = function(elem)
73 return elem.c
74 end
75 constr.setters[accessors] = function(elem, v)
76 elem.c = v
77 end
78 else
79 for i = 1, #(accessors or {}) do
80 if type(accessors[i]) == "string" then
81 constr.getters[accessors[i]] = function(elem)
82 return elem.c[i]
83 end
84 constr.setters[accessors[i]] = function(elem, v)
85 elem.c[i] = v
86 end
87 else -- only two levels of nesting are supported
88 for k, v in ipairs(accessors[i]) do
89 constr.getters[v] = function(elem)
90 return elem.c[i][k]
91 end
92 constr.setters[v] = function(elem, v)
93 elem.c[i][k] = v
94 end
95 end
96 end
97 end
98 end
100 function constr:new(...)
101 local obj = fn(...)
102 setmetatable(obj, self)
103 self.__index = function(t, k)
104 if getmetatable(t).getters[k] then
105 return getmetatable(t).getters[k](t)
106 elseif k == "t" then
107 return getmetatable(t)["tag"]
108 else
109 return getmetatable(t)[k]
110 end
111 end
112 self.__newindex = function(t, k, v)
113 if getmetatable(t).setters[k] then
114 getmetatable(t).setters[k](t, v)
115 else
116 rawset(t, k, v)
117 end
118 end
119 return obj
120 end
121 self.constructor = self.constructor or {}
122 self.constructor[tag] = constr
123 return constr
124end
126--- Calls the constructor, creating a new element.
127-- @local
128function Element.__call(t, ...)
129 return t:new(...)
130end
132------------------------------------------------------------------------
133--- Pandoc Document
134-- @section document
136--- A complete pandoc document
137-- @function Doc
138-- @tparam {Block,...} blocks document content
139-- @tparam[opt] Meta meta document meta data
140function M.Doc(blocks, meta)
141 meta = meta or {}
142 return {
143 ["blocks"] = blocks,
144 ["meta"] = meta,
145 ["pandoc-api-version"] = {1,17,0,5},
146 }
147end
150------------------------------------------------------------------------
151-- MetaValue
152-- @section MetaValue
153M.MetaValue = Element:make_subtype{}
154M.MetaValue.__call = function(t, ...)
155 return t:new(...)
156end
157--- Meta blocks
158-- @function MetaBlocks
159-- @tparam {Block,...} blocks blocks
161--- Meta inlines
162-- @function MetaInlines
163-- @tparam {Inline,...} inlines inlines
165--- Meta list
166-- @function MetaList
167-- @tparam {MetaValue,...} meta_values list of meta values
169--- Meta map
170-- @function MetaMap
171-- @tparam table a string-index map of meta values
172M.meta_value_types = {
173 "MetaBlocks",
174 "MetaInlines",
175 "MetaList",
176 "MetaMap",
178for i = 1, #M.meta_value_types do
179 M[M.meta_value_types[i]] = M.MetaValue:create_constructor(
180 M.meta_value_types[i],
181 function(content)
182 return content
183 end
184 )
185end
187--- Creates string to be used in meta data.
188-- Does nothing, lua strings are meta strings.
189-- @function MetaString
190-- @tparam string str string value
191function M.MetaString(str)
192 return str
193end
195--- Creates boolean to be used in meta data.
196-- Does nothing, lua booleans are meta booleans.
197-- @function MetaBool
198-- @tparam boolean bool boolean value
199function M.MetaBool(bool)
200 return bool
201end
203------------------------------------------------------------------------
204-- Blocks
205-- @section Block
207--- Block elements
208M.Block = Element:make_subtype{}
209M.Block.__call = function (t, ...)
210 return t:new(...)
211end
213--- Creates a block quote element
214-- @function BlockQuote
215-- @tparam {Block,...} content block content
216-- @treturn Block block quote element
217M.BlockQuote = M.Block:create_constructor(
218 "BlockQuote",
219 function(content) return {c = content} end,
220 "content"
223--- Creates a bullet (i.e. unordered) list.
224-- @function BulletList
225-- @tparam {{Block,...},...} content list of items
226-- @treturn Block block quote element
227M.BulletList = M.Block:create_constructor(
228 "BulletList",
229 function(content) return {c = content} end,
230 "content"
233--- Creates a code block element
234-- @function CodeBlock
235-- @tparam string text code string
236-- @tparam[opt] Attr attr element attributes
237-- @treturn Block code block element
238M.CodeBlock = M.Block:create_constructor(
239 "CodeBlock",
240 function(text, attr) return {c = {attr or M.Attr(), text}} end,
241 {{"identifier", "classes", "attributes"}, "text"}
244--- Creates a definition list, containing terms and their explanation.
245-- @function DefinitionList
246-- @tparam {{{Inline,...},{Block,...}},...} content list of items
247-- @treturn Block block quote element
248M.DefinitionList = M.Block:create_constructor(
249 "DefinitionList",
250 function(content) return {c = content} end,
251 "content"
254--- Creates a div element
255-- @function Div
256-- @tparam {Block,...} content block content
257-- @tparam[opt] Attr attr element attributes
258-- @treturn Block code block element
259M.Div = M.Block:create_constructor(
260 "Div",
261 function(content, attr)
262 return {c = {attr or M.Attr(), content}}
263 end,
264 {{"identifier", "classes", "attributes"}, "content"}
267--- Creates a block quote element.
268-- @function Header
269-- @tparam int level header level
270-- @tparam {Inline,...} content inline content
271-- @tparam[opt] Attr attr element attributes
272-- @treturn Block header element
273M.Header = M.Block:create_constructor(
274 "Header",
275 function(level, content, attr)
276 return {c = {level, attr or M.Attr(), content}}
277 end,
278 {"level", {"identifier", "classes", "attributes"}, "content"}
281--- Creates a horizontal rule.
282-- @function HorizontalRule
283-- @treturn Block horizontal rule
284M.HorizontalRule = M.Block:create_constructor(
285 "HorizontalRule",
286 function() return {} end
289--- Creates a line block element.
290-- @function LineBlock
291-- @tparam {{Inline,...},...} content inline content
292-- @treturn Block block quote element
293M.LineBlock = M.Block:create_constructor(
294 "LineBlock",
295 function(content) return {c = content} end,
296 "content"
299--- Creates a null element.
300-- @function Null
301-- @treturn Block null element
302M.Null = M.Block:create_constructor(
303 "Null",
304 function() return {} end
307--- Creates an ordered list.
308-- @function OrderedList
309-- @tparam {{Block,...},...} items list items
310-- @param[opt] listAttributes list parameters
311-- @treturn Block
312M.OrderedList = M.Block:create_constructor(
313 "OrderedList",
314 function(items, listAttributes)
315 return {c = {listAttributes,items}}
316 end,
317 {{"start", "style", "delimiter"}, "content"}
320--- Creates a para element.
321-- @function Para
322-- @tparam {Inline,...} content inline content
323-- @treturn Block block quote element
324M.Para = M.Block:create_constructor(
325 "Para",
326 function(content) return {c = content} end,
327 "content"
330--- Creates a plain element.
331-- @function Plain
332-- @tparam {Inline,...} content inline content
333-- @treturn Block block quote element
334M.Plain = M.Block:create_constructor(
335 "Plain",
336 function(content) return {c = content} end,
337 "content"
340--- Creates a raw content block of the specified format.
341-- @function RawBlock
342-- @tparam string format format of content
343-- @tparam string text string content
344-- @treturn Block block quote element
345M.RawBlock = M.Block:create_constructor(
346 "RawBlock",
347 function(format, text) return {c = {format, text}} end,
348 {"format", "text"}
351--- Creates a table element.
352-- @function Table
353-- @tparam {Inline,...} caption table caption
354-- @tparam {AlignDefault|AlignLeft|AlignRight|AlignCenter,...} aligns alignments
355-- @tparam {int,...} widths column widths
356-- @tparam {Block,...} headers header row
357-- @tparam {{Block,...}} rows table rows
358-- @treturn Block block quote element
359M.Table = M.Block:create_constructor(
360 "Table",
361 function(caption, aligns, widths, headers, rows)
362 return {c = {caption, aligns, widths, headers, rows}}
363 end
367------------------------------------------------------------------------
368-- Inline
369-- @section Inline
371--- Inline element class
372M.Inline = Element:make_subtype{}
373M.Inline.__call = function (t, ...)
374 return t:new(...)
375end
377--- Creates a Cite inline element
378-- @function Cite
379-- @tparam {Inline,...} content List of inlines
380-- @tparam {Citation,...} citations List of citations
381-- @treturn Inline citations element
382M.Cite = M.Inline:create_constructor(
383 "Cite",
384 function(content, citations) return {c = {citations, content}} end,
385 {"citations", "content"}
388--- Creates a Code inline element
389-- @function Code
390-- @tparam string text brief image description
391-- @tparam[opt] Attr attr additional attributes
392-- @treturn Inline code element
393M.Code = M.Inline:create_constructor(
394 "Code",
395 function(text, attr) return {c = {attr or M.Attr(), text}} end,
396 {{"identifier", "classes", "attributes"}, "text"}
399--- Creates an inline element representing emphasised text.
400-- @function Emph
401-- @tparam {Inline,..} content inline content
402-- @treturn Inline emphasis element
403M.Emph = M.Inline:create_constructor(
404 "Emph",
405 function(content) return {c = content} end,
406 "content"
409--- Creates a Image inline element
410-- @function Image
411-- @tparam {Inline,..} caption text used to describe the image
412-- @tparam string src path to the image file
413-- @tparam[opt] string title brief image description
414-- @tparam[opt] Attr attr additional attributes
415-- @treturn Inline image element
416M.Image = M.Inline:create_constructor(
417 "Image",
418 function(caption, src, title, attr)
419 title = title or ""
420 attr = attr or M.Attr()
421 return {c = {attr, caption, {src, title}}}
422 end,
423 {"attributes", "caption", {"src", "title"}}
426--- Create a LineBreak inline element
427-- @function LineBreak
428-- @treturn Inline linebreak element
429M.LineBreak = M.Inline:create_constructor(
430 "LineBreak",
431 function() return {} end
434--- Creates a link inline element, usually a hyperlink.
435-- @function Link
436-- @tparam {Inline,..} content text for this link
437-- @tparam string target the link target
438-- @tparam[opt] string title brief link description
439-- @tparam[opt] Attr attr additional attributes
440-- @treturn Inline image element
441M.Link = M.Inline:create_constructor(
442 "Link",
443 function(content, target, title, attr)
444 title = title or ""
445 attr = attr or M.Attr()
446 return {c = {attr, content, {target, title}}}
447 end,
448 {"attributes", "content", {"target", "title"}}
451--- Creates a Math element, either inline or displayed. It is usually simpler to
452-- use one of the specialized functions @{InlineMath} or @{DisplayMath} instead.
453-- @function Math
454-- @tparam "InlineMath"|"DisplayMath" mathtype rendering specifier
455-- @tparam string text Math content
456-- @treturn Inline Math element
457M.Math = M.Inline:create_constructor(
458 "Math",
459 function(mathtype, text)
460 return {c = {mathtype, text}}
461 end,
462 {"mathtype", "text"}
464--- Creates a DisplayMath element.
465-- @function DisplayMath
466-- @tparam string text Math content
467-- @treturn Inline Math element
468M.DisplayMath = M.Inline:create_constructor(
469 "DisplayMath",
470 function(text) return M.Math("DisplayMath", text) end,
471 {"mathtype", "text"}
473--- Creates an InlineMath inline element.
474-- @function InlineMath
475-- @tparam string text Math content
476-- @treturn Inline Math element
477M.InlineMath = M.Inline:create_constructor(
478 "InlineMath",
479 function(text) return M.Math("InlineMath", text) end,
480 {"mathtype", "text"}
483--- Creates a Note inline element
484-- @function Note
485-- @tparam {Block,...} content footnote block content
486M.Note = M.Inline:create_constructor(
487 "Note",
488 function(content) return {c = content} end,
489 "content"
492--- Creates a Quoted inline element given the quote type and quoted content. It
493-- is usually simpler to use one of the specialized functions @{SingleQuoted} or
494-- @{DoubleQuoted} instead.
495-- @function Quoted
496-- @tparam "DoubleQuote"|"SingleQuote" quotetype type of quotes to be used
497-- @tparam {Inline,..} content inline content
498-- @treturn Inline quoted element
499M.Quoted = M.Inline:create_constructor(
500 "Quoted",
501 function(quotetype, content) return {c = {quotetype, content}} end,
502 {"quotetype", "content"}
504--- Creates a single-quoted inline element.
505-- @function SingleQuoted
506-- @tparam {Inline,..} content inline content
507-- @treturn Inline quoted element
508-- @see Quoted
509M.SingleQuoted = M.Inline:create_constructor(
510 "SingleQuoted",
511 function(content) return M.Quoted(M.SingleQuote, content) end,
512 {"quotetype", "content"}
514--- Creates a single-quoted inline element.
515-- @function DoubleQuoted
516-- @tparam {Inline,..} content inline content
517-- @treturn Inline quoted element
518-- @see Quoted
519M.DoubleQuoted = M.Inline:create_constructor(
520 "DoubleQuoted",
521 function(content) return M.Quoted("DoubleQuote", content) end,
522 {"quotetype", "content"}
525--- Creates a RawInline inline element
526-- @function RawInline
527-- @tparam string format format of the contents
528-- @tparam string text string content
529-- @treturn Inline raw inline element
530M.RawInline = M.Inline:create_constructor(
531 "RawInline",
532 function(format, text) return {c = {format, text}} end,
533 {"format", "text"}
536--- Creates text rendered in small caps
537-- @function SmallCaps
538-- @tparam {Inline,..} content inline content
539-- @treturn Inline smallcaps element
540M.SmallCaps = M.Inline:create_constructor(
541 "SmallCaps",
542 function(content) return {c = content} end,
543 "content"
546--- Creates a SoftBreak inline element.
547-- @function SoftBreak
548-- @treturn Inline softbreak element
549M.SoftBreak = M.Inline:create_constructor(
550 "SoftBreak",
551 function() return {} end
554--- Create a Space inline element
555-- @function Space
556-- @treturn Inline space element
557M.Space = M.Inline:create_constructor(
558 "Space",
559 function() return {} end
562--- Creates a Span inline element
563-- @function Span
564-- @tparam {Inline,..} content inline content
565-- @tparam[opt] Attr attr additional attributes
566-- @treturn Inline span element
567M.Span = M.Inline:create_constructor(
568 "Span",
569 function(content, attr) return {c = {attr or M.Attr(), content}} end,
570 {{"identifier", "classes", "attributes"}, "content"}
573--- Creates a Str inline element
574-- @function Str
575-- @tparam string text content
576-- @treturn Inline string element
577M.Str = M.Inline:create_constructor(
578 "Str",
579 function(text) return {c = text} end,
580 "text"
583--- Creates text which is striked out.
584-- @function Strikeout
585-- @tparam {Inline,..} content inline content
586-- @treturn Inline strikeout element
587M.Strikeout = M.Inline:create_constructor(
588 "Strikeout",
589 function(content) return {c = content} end,
590 "content"
593--- Creates a Strong element, whose text is usually displayed in a bold font.
594-- @function Strong
595-- @tparam {Inline,..} content inline content
596-- @treturn Inline strong element
597M.Strong = M.Inline:create_constructor(
598 "Strong",
599 function(content) return {c = content} end,
600 "content"
603--- Creates a Subscript inline element
604-- @function Subscript
605-- @tparam {Inline,..} content inline content
606-- @treturn Inline subscript element
607M.Subscript = M.Inline:create_constructor(
608 "Subscript",
609 function(content) return {c = content} end,
610 "content"
613--- Creates a Superscript inline element
614-- @function Superscript
615-- @tparam {Inline,..} content inline content
616-- @treturn Inline strong element
617M.Superscript = M.Inline:create_constructor(
618 "Superscript",
619 function(content) return {c = content} end,
620 "content"
624------------------------------------------------------------------------
625-- Helpers
626-- @section helpers
628-- Attr
629M.Attr = {}
630M.Attr._field_names = {identifier = 1, classes = 2, attributes = 3}
631--- Create a new set of attributes (Attr).
632-- @function Attr
633-- @tparam[opt] string identifier element identifier
634-- @tparam[opt] {string,...} classes element classes
635-- @tparam[opt] table attributes table containing string keys and values
636-- @return element attributes
637M.Attr.__call = function(t, identifier, classes, attributes)
638 identifier = identifier or ''
639 classes = classes or {}
640 attributes = attributes or {}
641 local attr = {identifier, classes, attributes}
642 setmetatable(attr, t)
643 return attr
644end
645M.Attr.__index = function(t, k)
646 return rawget(t, k) or
647 rawget(t, M.Attr._field_names[k]) or
648 rawget(getmetatable(t), k)
649end
650M.Attr.__newindex = function(t, k, v)
651 if M.Attr._field_names[k] then
652 rawset(t, M.Attr._field_names[k], v)
653 else
654 rawset(t, k, v)
655 end
656end
657setmetatable(M.Attr, M.Attr)
660--- Creates a single citation.
661-- @function Citation
662-- @tparam string id citation identifier (like a bibtex key)
663-- @tparam AuthorInText|SuppressAuthor|NormalCitation mode citation mode
664-- @tparam[opt] {Inline,...} prefix citation prefix
665-- @tparam[opt] {Inline,...} suffix citation suffix
666-- @tparam[opt] int note_num note number
667-- @tparam[opt] int note_num hash number
668M.Citation = function(id, mode, prefix, suffix, note_num, hash)
669 prefix = prefix or {}
670 suffix = suffix or {}
671 note_num = note_num or 0
672 hash = hash or 0
673 return {
674 citationId = id,
675 citationPrefix = prefix,
676 citationSuffix = suffix,
677 citationMode = mode,
678 citationNoteNum = note_num,
679 citationHash = hash,
680 }
681end
684------------------------------------------------------------------------
685-- Constants
686-- @section constants
688--- Author name is mentioned in the text.
689-- @see Citation
690-- @see Cite
691M.AuthorInText = "AuthorInText"
693--- Author name is suppressed.
694-- @see Citation
695-- @see Cite
696M.SuppressAuthor = "SuppressAuthor"
698--- Default citation style is used.
699-- @see Citation
700-- @see Cite
701M.NormalCitation = "NormalCitation"
703--- Table cells aligned left.
704-- @see Table
705M.AlignLeft = "AlignLeft"
707--- Table cells right-aligned.
708-- @see Table
709M.AlignRight = "AlignRight"
711--- Table cell content is centered.
712-- @see Table
713M.AlignCenter = "AlignCenter"
715--- Table cells are alignment is unaltered.
716-- @see Table
717M.AlignDefault = "AlignDefault"
719--- Default list number delimiters are used.
720-- @see OrderedList
721M.DefaultDelim = "DefaultDelim"
723--- List numbers are delimited by a period.
724-- @see OrderedList
725M.Period = "Period"
727--- List numbers are delimited by a single parenthesis.
728-- @see OrderedList
729M.OneParen = "OneParen"
731--- List numbers are delimited by a double parentheses.
732-- @see OrderedList
733M.TwoParens = "TwoParens"
735--- List are numbered in the default style
736-- @see OrderedList
737M.DefaultStyle = "DefaultStyle"
739--- List items are numbered as examples.
740-- @see OrderedList
741M.Example = "Example"
743--- List are numbered using decimal integers.
744-- @see OrderedList
745M.Decimal = "Decimal"
747--- List are numbered using lower-case roman numerals.
748-- @see OrderedList
749M.LowerRoman = "LowerRoman"
751--- List are numbered using upper-case roman numerals
752-- @see OrderedList
753M.UpperRoman = "UpperRoman"
755--- List are numbered using lower-case alphabetic characters.
756-- @see OrderedList
757M.LowerAlpha = "LowerAlpha"
759--- List are numbered using upper-case alphabetic characters.
760-- @see OrderedList
761M.UpperAlpha = "UpperAlpha"
764------------------------------------------------------------------------
765-- Helper Functions
766-- @section helpers
768--- Parse the given string into a Pandoc document.
769-- The method used to interpret input is specified by *format*. Acceptable
770-- values for this parameter are equal to those that can be given to the
771-- `--from` command line option.
772-- @tparam string markup the markup to be parsed
773-- @tparam[opt] string format format specification, defaults to "markdown".
774-- @return Doc pandoc document
775-- @usage
776-- local org_markup = "/emphasis/" -- Input to be read
777-- local document = pandoc.read(org_markup, "org")
778-- -- Get the first block of the document
779-- local block = document.blocks[1]
780-- -- The inline element in that block is an `Emph`
781-- assert(block.content[1].t == "Emph")
782function M.read(markup, format)
783 format = format or "markdown"
784 local pd = pandoc.__read(format, markup)
785 if type(pd) == "string" then
786 error(pd)
787 else
788 return pd
789 end
790end
792--- Use functions defined in the global namespace to create a pandoc filter.
793-- All globally defined functions which have names of pandoc elements are
794-- collected into a new table.
795-- @return A list of filter functions
796-- @usage
797-- -- within a file defining a pandoc filter:
798-- function Str(text)
799-- return pandoc.Str(utf8.upper(text))
800-- end
801--
802-- return {pandoc.global_filter()}
803-- -- the above is equivallent to
804-- -- return {{Str = Str}}
805function M.global_filter()
806 local res = {}
807 for k, v in pairs(_G) do
808 if M.Inline.constructor[k] or M.Block.constructor[k] or k == "Doc" then
809 res[k] = v
810 end
811 end
812 return res
813end
815return M