diff options
Diffstat (limited to 'lua')
-rw-r--r-- | lua/allwords.lua | 17 | ||||
-rw-r--r-- | lua/jttm.lua | 193 | ||||
-rw-r--r-- | lua/river.lua | 226 | ||||
-rw-r--r-- | lua/sample.lua | 324 | ||||
-rw-r--r-- | lua/test.lua | 304 |
5 files changed, 1064 insertions, 0 deletions
diff --git a/lua/allwords.lua b/lua/allwords.lua new file mode 100644 index 0000000..b87f08a --- /dev/null +++ b/lua/allwords.lua | |||
@@ -0,0 +1,17 @@ | |||
1 | function allwords () | ||
2 | local line = io.read() | ||
3 | local pos = 1 | ||
4 | return function () | ||
5 | while line do | ||
6 | local s, e = string.find(line, "%w+", pos) | ||
7 | if s then | ||
8 | pos = e + 1 | ||
9 | return string.sub(line, s, e) | ||
10 | else | ||
11 | line = io.read() | ||
12 | pos = 1 | ||
13 | end | ||
14 | end | ||
15 | return nil | ||
16 | end | ||
17 | end | ||
diff --git a/lua/jttm.lua b/lua/jttm.lua new file mode 100644 index 0000000..2ba101a --- /dev/null +++ b/lua/jttm.lua | |||
@@ -0,0 +1,193 @@ | |||
1 | -- Pandoc "Just the text, Ma'am" | ||
2 | -- (JTTM): a custom writer that | ||
3 | -- strips everything except for | ||
4 | -- the TEXT from a pandoc source | ||
5 | -- vim: fdm=marker | ||
6 | -- invoke with: pandoc -t jttm/jttm.lua | ||
7 | |||
8 | -- Table to store footnotes so they are at the END of the document | ||
9 | local notes = {} | ||
10 | |||
11 | -- This function is called once for the whole document. Parameters: | ||
12 | -- body is a string, metadata is a table, variables is a table. | ||
13 | -- One could use some kind of templating | ||
14 | -- system here; this just gives you a simple standalone HTML file. | ||
15 | function Doc(body, metadata, variables) | ||
16 | local buffer = {} | ||
17 | local function add(s) | ||
18 | table.insert(buffer, s) | ||
19 | end | ||
20 | if metadata['title'] and metadata['title'] ~= "" then | ||
21 | add(string.upper(metadata['title'])) | ||
22 | end | ||
23 | if metadata['subtitle'] and metadata['subtitle'] ~= "" then | ||
24 | add(": " .. metadata['subtitle']) | ||
25 | end | ||
26 | add("\n") | ||
27 | -- TODO: epigraph.content, epigraph.attrib, dedication, other metadata? | ||
28 | add(body) | ||
29 | -- TODO: add notes at the end. | ||
30 | return table.concat(buffer, '\n') | ||
31 | end | ||
32 | |||
33 | -- TODOs {{{ | ||
34 | function align(align) | ||
35 | -- TODO: is this necessary? | ||
36 | end | ||
37 | |||
38 | function Note(s) | ||
39 | -- TODO | ||
40 | end | ||
41 | |||
42 | -- convert Tables to csv? or tab-separated? | ||
43 | function Table(caption, aligns, widths, headers, rows) | ||
44 | local buffer = {} | ||
45 | local function add(s) | ||
46 | table.insert(buffer, s) | ||
47 | end | ||
48 | add("\n\n") | ||
49 | if caption ~= "" then | ||
50 | add("[" .. caption .. "]") | ||
51 | end | ||
52 | -- TODO: finish | ||
53 | end | ||
54 | |||
55 | -- }}} | ||
56 | -- Remove all formatting {{{ | ||
57 | function Blocksep() | ||
58 | return "\n\n" | ||
59 | end | ||
60 | function Emph(s) | ||
61 | return s | ||
62 | end | ||
63 | |||
64 | function Strong(s) | ||
65 | return s | ||
66 | end | ||
67 | |||
68 | function Subscript(s) | ||
69 | return s | ||
70 | end | ||
71 | |||
72 | function Superscript(s) | ||
73 | return s | ||
74 | end | ||
75 | |||
76 | function SmallCaps(s) | ||
77 | return s | ||
78 | end | ||
79 | |||
80 | function Strikeout(s) | ||
81 | return s | ||
82 | end | ||
83 | |||
84 | function Code(s, attr) | ||
85 | return s | ||
86 | end | ||
87 | |||
88 | function CodeBlock(s, attr) | ||
89 | return s | ||
90 | end | ||
91 | |||
92 | function InlineMath(s) | ||
93 | return s | ||
94 | end | ||
95 | |||
96 | function DisplayMath(s) | ||
97 | return s | ||
98 | end | ||
99 | |||
100 | function Span(s, attr) | ||
101 | return s | ||
102 | end | ||
103 | |||
104 | function Cite(s) | ||
105 | return s | ||
106 | end | ||
107 | |||
108 | function Plain(s) | ||
109 | return s | ||
110 | end | ||
111 | |||
112 | -- Links only include the link text | ||
113 | function Link(s, src, tit) | ||
114 | return s | ||
115 | end | ||
116 | |||
117 | -- Images have nothing to give us | ||
118 | -- (but add a space just in case) | ||
119 | function Image(s, src, tit) | ||
120 | return " " | ||
121 | end | ||
122 | |||
123 | function Str(s) | ||
124 | return s | ||
125 | end | ||
126 | |||
127 | function Div(s, attr) | ||
128 | return s | ||
129 | end | ||
130 | |||
131 | function Space(s) | ||
132 | return " " | ||
133 | end | ||
134 | |||
135 | function LineBreak() | ||
136 | return "\n" | ||
137 | end | ||
138 | |||
139 | function Para(s) | ||
140 | -- add paragraphing | ||
141 | return s .. "\n\n" | ||
142 | end | ||
143 | -- }}} | ||
144 | -- Leave just a little formatting {{{ | ||
145 | function Header(lev, s, attr) | ||
146 | if lev == 1 then | ||
147 | return "\n\n " .. string.upper(s) .. "\n\n" | ||
148 | elseif lev == 2 then | ||
149 | return "\n " .. string.upper(s) .. "\n" | ||
150 | else | ||
151 | return s | ||
152 | end | ||
153 | end | ||
154 | |||
155 | function Blockquote(s) | ||
156 | return "\n\n" .. string.gsub(s, "*\n", " %0") | ||
157 | end | ||
158 | |||
159 | function HorizontalRule(s) | ||
160 | return "\n\n\n" | ||
161 | end | ||
162 | |||
163 | function BulletList(items) | ||
164 | local buffer = {} | ||
165 | for _, item in pairs(items) do | ||
166 | table.insert(buffer, "- " .. item .. "\n") | ||
167 | end | ||
168 | return "\n\n" .. table.concat(buffer, "\n") .. "\n\n" | ||
169 | end | ||
170 | |||
171 | function DefinitionList(items) | ||
172 | local buffer = {} | ||
173 | for _, item in pairs(items) do | ||
174 | for k, v in pairs(item) do | ||
175 | table.insert(buffer, "\n" .. k .. ":\n " .. | ||
176 | table.concat(v, "\n ")) | ||
177 | end | ||
178 | end | ||
179 | return "\n\n" .. table.concat(buffer, "\n") .. "\n\n" | ||
180 | end | ||
181 | -- }}} | ||
182 | |||
183 | -- The following code will produce runtime warnings when you haven't defined | ||
184 | -- all of the functions you need for the custom writer, so it's useful | ||
185 | -- to include when you're working on a writer. | ||
186 | local meta = {} | ||
187 | meta.__index = | ||
188 | function(_, key) | ||
189 | io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) | ||
190 | return function() return "" end | ||
191 | end | ||
192 | setmetatable(_G, meta) | ||
193 | |||
diff --git a/lua/river.lua b/lua/river.lua new file mode 100644 index 0000000..d060ba9 --- /dev/null +++ b/lua/river.lua | |||
@@ -0,0 +1,226 @@ | |||
1 | -- Pandoc River writer | ||
2 | -- it takes out all formatting, leaving only a river of text | ||
3 | -- running down the page: one word per line | ||
4 | -- vim: fdm=marker | ||
5 | -- invoke with: pandoc -t river.lua | ||
6 | |||
7 | local function flow(s) | ||
8 | return s:gsub("%s+", "\n") | ||
9 | end | ||
10 | |||
11 | local function nude(s) | ||
12 | -- Expand contractions | ||
13 | s = s:gsub("'%a+%s", function (x) | ||
14 | if x == "'ll" then | ||
15 | return " will " | ||
16 | elseif x == "'ve" then | ||
17 | return " have " | ||
18 | elseif x == "'re" then | ||
19 | return " are " | ||
20 | else | ||
21 | return x | ||
22 | end | ||
23 | end) | ||
24 | -- Get rid of quotes around words | ||
25 | s = s:gsub('"', ' ') | ||
26 | s = s:gsub("%s+'", ' ') | ||
27 | s = s:gsub("'%s+", ' ') | ||
28 | -- Remove HTML entities | ||
29 | s = s:gsub('&.-;', ' ') | ||
30 | s = s:gsub('%b<>', ' ') | ||
31 | -- Remove end-of-line backslashes | ||
32 | s = s:gsub('%s+\\$', ' ') | ||
33 | -- Remove dashes (not hyphens) | ||
34 | s = s:gsub('%-%-+', ' ') | ||
35 | s = s:gsub('%-%s', ' ') | ||
36 | -- Remove general punctuation | ||
37 | s = s:gsub('[%.!%?:;,%[%]%(%)<>]', ' ') | ||
38 | -- Remove extra spaces | ||
39 | s = s:gsub('%s+', ' ') | ||
40 | return s:lower() | ||
41 | end | ||
42 | |||
43 | -- This function is called once for the whole document. Parameters: | ||
44 | -- body is a string, metadata is a table, variables is a table. | ||
45 | -- One could use some kind of templating | ||
46 | -- system here; this just gives you a simple standalone HTML file. | ||
47 | function Doc(body, metadata, variables) | ||
48 | local buffer = "" | ||
49 | local function add(s) | ||
50 | buffer = buffer .. nude(s) .. "\n" | ||
51 | end | ||
52 | if metadata['title'] then | ||
53 | add(metadata['title']) | ||
54 | end | ||
55 | if metadata['subtitle'] then | ||
56 | add(metadata['subtitle']) | ||
57 | end | ||
58 | -- TODO: epigraph.content, epigraph.attrib, dedication, other metadata? | ||
59 | add(body) | ||
60 | return flow(buffer) | ||
61 | end | ||
62 | |||
63 | -- Remove all formatting {{{ | ||
64 | function Note(s) | ||
65 | return nude(s) | ||
66 | end | ||
67 | |||
68 | function Blocksep() | ||
69 | return "\n" | ||
70 | end | ||
71 | function Emph(s) | ||
72 | return nude(s) | ||
73 | end | ||
74 | |||
75 | function Strong(s) | ||
76 | return nude(s) | ||
77 | end | ||
78 | |||
79 | function Subscript(s) | ||
80 | return nude(s) | ||
81 | end | ||
82 | |||
83 | function Superscript(s) | ||
84 | return nude(s) | ||
85 | end | ||
86 | |||
87 | function SmallCaps(s) | ||
88 | return nude(s) | ||
89 | end | ||
90 | |||
91 | function Strikeout(s) | ||
92 | return nude(s) | ||
93 | end | ||
94 | |||
95 | function Code(s, attr) | ||
96 | return nude(s) | ||
97 | end | ||
98 | |||
99 | function CodeBlock(s, attr) | ||
100 | return nude(s) | ||
101 | end | ||
102 | |||
103 | function InlineMath(s) | ||
104 | return nude(s) | ||
105 | end | ||
106 | |||
107 | function DisplayMath(s) | ||
108 | return nude(s) | ||
109 | end | ||
110 | |||
111 | function Span(s, attr) | ||
112 | return nude(s) | ||
113 | end | ||
114 | |||
115 | function Cite(s) | ||
116 | return nude(s) | ||
117 | end | ||
118 | |||
119 | function Plain(s) | ||
120 | return nude(s) | ||
121 | end | ||
122 | |||
123 | -- Links only include the link text | ||
124 | function Link(s, src, tit) | ||
125 | return nude(s) | ||
126 | end | ||
127 | |||
128 | -- Images have nothing to give us | ||
129 | -- (but add a space just in case) | ||
130 | function Image(s, src, tit) | ||
131 | return "\n" | ||
132 | end | ||
133 | |||
134 | function CaptionedImage(s, src, tit) | ||
135 | return "\n" | ||
136 | end | ||
137 | |||
138 | function Str(s) | ||
139 | return nude(s) | ||
140 | end | ||
141 | |||
142 | function Div(s, attr) | ||
143 | return nude(s) | ||
144 | end | ||
145 | |||
146 | function Space(s) | ||
147 | return "\n" | ||
148 | end | ||
149 | |||
150 | function LineBreak() | ||
151 | return "\n" | ||
152 | end | ||
153 | |||
154 | function Para(s) | ||
155 | return nude(s) | ||
156 | end | ||
157 | |||
158 | function Header(lev, s, attr) | ||
159 | return nude(s) | ||
160 | end | ||
161 | |||
162 | function BlockQuote(s) | ||
163 | return nude(s) | ||
164 | end | ||
165 | |||
166 | function HorizontalRule() | ||
167 | return "\n" | ||
168 | end | ||
169 | |||
170 | function BulletList(items) | ||
171 | local buffer = "" | ||
172 | for _, item in pairs(items) do | ||
173 | buffer = buffer .. nude(item) .. "\n" | ||
174 | end | ||
175 | return buffer .. "\n" | ||
176 | end | ||
177 | |||
178 | function OrderedList(items) | ||
179 | local buffer = "" | ||
180 | for _, item in pairs(items) do | ||
181 | buffer = buffer .. nude(item) .. "\n" | ||
182 | end | ||
183 | return buffer .. "\n" | ||
184 | end | ||
185 | |||
186 | function DefinitionList(items) | ||
187 | local buffer = "" | ||
188 | for _, item in pairs(items) do | ||
189 | for k, v in pairs(item) do | ||
190 | buffer = buffer .. nude(k) .. "\n" .. nude(v) .. "\n" | ||
191 | end | ||
192 | end | ||
193 | return buffer .. "\n" | ||
194 | end | ||
195 | |||
196 | function Table(caption, aligns, widths, headers, rows) | ||
197 | local buffer = "" | ||
198 | local function add(s) | ||
199 | buffer = buffer .. nude(s) .. "\n" | ||
200 | end | ||
201 | if caption ~= "" then | ||
202 | add(caption) | ||
203 | end | ||
204 | for _,h in pairs(headers) do | ||
205 | add(h) | ||
206 | end | ||
207 | for _, row in pairs(rows) do | ||
208 | for _, cell in pairs(row) do | ||
209 | add(cell) | ||
210 | end | ||
211 | end | ||
212 | return buffer | ||
213 | end | ||
214 | -- }}} | ||
215 | |||
216 | -- The following code will produce runtime warnings when you haven't defined | ||
217 | -- all of the functions you need for the custom writer, so it's useful | ||
218 | -- to include when you're working on a writer. | ||
219 | local meta = {} | ||
220 | meta.__index = | ||
221 | function(_, key) | ||
222 | io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) | ||
223 | return function() return "" end | ||
224 | end | ||
225 | setmetatable(_G, meta) | ||
226 | |||
diff --git a/lua/sample.lua b/lua/sample.lua new file mode 100644 index 0000000..a0c3c29 --- /dev/null +++ b/lua/sample.lua | |||
@@ -0,0 +1,324 @@ | |||
1 | -- This is a sample custom writer for pandoc. It produces output | ||
2 | -- that is very similar to that of pandoc's HTML writer. | ||
3 | -- There is one new feature: code blocks marked with class 'dot' | ||
4 | -- are piped through graphviz and images are included in the HTML | ||
5 | -- output using 'data:' URLs. | ||
6 | -- | ||
7 | -- Invoke with: pandoc -t sample.lua | ||
8 | -- | ||
9 | -- Note: you need not have lua installed on your system to use this | ||
10 | -- custom writer. However, if you do have lua installed, you can | ||
11 | -- use it to test changes to the script. 'lua sample.lua' will | ||
12 | -- produce informative error messages if your code contains | ||
13 | -- syntax errors. | ||
14 | |||
15 | -- Character escaping | ||
16 | local function escape(s, in_attribute) | ||
17 | return s:gsub("[<>&\"']", | ||
18 | function(x) | ||
19 | if x == '<' then | ||
20 | return '<' | ||
21 | elseif x == '>' then | ||
22 | return '>' | ||
23 | elseif x == '&' then | ||
24 | return '&' | ||
25 | elseif x == '"' then | ||
26 | return '"' | ||
27 | elseif x == "'" then | ||
28 | return ''' | ||
29 | else | ||
30 | return x | ||
31 | end | ||
32 | end) | ||
33 | end | ||
34 | |||
35 | -- Helper function to convert an attributes table into | ||
36 | -- a string that can be put into HTML tags. | ||
37 | local function attributes(attr) | ||
38 | local attr_table = {} | ||
39 | for x,y in pairs(attr) do | ||
40 | if y and y ~= "" then | ||
41 | table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"') | ||
42 | end | ||
43 | end | ||
44 | return table.concat(attr_table) | ||
45 | end | ||
46 | |||
47 | -- Run cmd on a temporary file containing inp and return result. | ||
48 | local function pipe(cmd, inp) | ||
49 | local tmp = os.tmpname() | ||
50 | local tmph = io.open(tmp, "w") | ||
51 | tmph:write(inp) | ||
52 | tmph:close() | ||
53 | local outh = io.popen(cmd .. " " .. tmp,"r") | ||
54 | local result = outh:read("*all") | ||
55 | outh:close() | ||
56 | os.remove(tmp) | ||
57 | return result | ||
58 | end | ||
59 | |||
60 | -- Table to store footnotes, so they can be included at the end. | ||
61 | local notes = {} | ||
62 | |||
63 | -- Blocksep is used to separate block elements. | ||
64 | function Blocksep() | ||
65 | return "\n\n" | ||
66 | end | ||
67 | |||
68 | -- This function is called once for the whole document. Parameters: | ||
69 | -- body is a string, metadata is a table, variables is a table. | ||
70 | -- One could use some kind of templating | ||
71 | -- system here; this just gives you a simple standalone HTML file. | ||
72 | function Doc(body, metadata, variables) | ||
73 | local buffer = {} | ||
74 | local function add(s) | ||
75 | table.insert(buffer, s) | ||
76 | end | ||
77 | add('<!DOCTYPE html>') | ||
78 | add('<html>') | ||
79 | add('<head>') | ||
80 | add('<title>' .. (metadata['title'] or '') .. '</title>') | ||
81 | add('</head>') | ||
82 | add('<body>') | ||
83 | if metadata['title'] and metadata['title'] ~= "" then | ||
84 | add('<h1 class="title">' .. metadata['title'] .. '</h1>') | ||
85 | end | ||
86 | for _, author in pairs(metadata['author'] or {}) do | ||
87 | add('<h2 class="author">' .. author .. '</h2>') | ||
88 | end | ||
89 | if metadata['date'] and metadata['date'] ~= "" then | ||
90 | add('<h3 class="date">' .. metadata.date .. '</h3>') | ||
91 | end | ||
92 | add(body) | ||
93 | if #notes > 0 then | ||
94 | add('<ol class="footnotes">') | ||
95 | for _,note in pairs(notes) do | ||
96 | add(note) | ||
97 | end | ||
98 | add('</ol>') | ||
99 | end | ||
100 | add('</body>') | ||
101 | add('</html>') | ||
102 | return table.concat(buffer,'\n') | ||
103 | end | ||
104 | |||
105 | -- The functions that follow render corresponding pandoc elements. | ||
106 | -- s is always a string, attr is always a table of attributes, and | ||
107 | -- items is always an array of strings (the items in a list). | ||
108 | -- Comments indicate the types of other variables. | ||
109 | |||
110 | function Str(s) | ||
111 | return escape(s) | ||
112 | end | ||
113 | |||
114 | function Space() | ||
115 | return " " | ||
116 | end | ||
117 | |||
118 | function LineBreak() | ||
119 | return "<br/>" | ||
120 | end | ||
121 | |||
122 | function Emph(s) | ||
123 | return "<em>" .. s .. "</em>" | ||
124 | end | ||
125 | |||
126 | function Strong(s) | ||
127 | return "<strong>" .. s .. "</strong>" | ||
128 | end | ||
129 | |||
130 | function Subscript(s) | ||
131 | return "<sub>" .. s .. "</sub>" | ||
132 | end | ||
133 | |||
134 | function Superscript(s) | ||
135 | return "<sup>" .. s .. "</sup>" | ||
136 | end | ||
137 | |||
138 | function SmallCaps(s) | ||
139 | return '<span style="font-variant: small-caps;">' .. s .. '</span>' | ||
140 | end | ||
141 | |||
142 | function Strikeout(s) | ||
143 | return '<del>' .. s .. '</del>' | ||
144 | end | ||
145 | |||
146 | function Link(s, src, tit) | ||
147 | return "<a href='" .. escape(src,true) .. "' title='" .. | ||
148 | escape(tit,true) .. "'>" .. s .. "</a>" | ||
149 | end | ||
150 | |||
151 | function Image(s, src, tit) | ||
152 | return "<img src='" .. escape(src,true) .. "' title='" .. | ||
153 | escape(tit,true) .. "'/>" | ||
154 | end | ||
155 | |||
156 | function Code(s, attr) | ||
157 | return "<code" .. attributes(attr) .. ">" .. escape(s) .. "</code>" | ||
158 | end | ||
159 | |||
160 | function InlineMath(s) | ||
161 | return "\\(" .. escape(s) .. "\\)" | ||
162 | end | ||
163 | |||
164 | function DisplayMath(s) | ||
165 | return "\\[" .. escape(s) .. "\\]" | ||
166 | end | ||
167 | |||
168 | function Note(s) | ||
169 | local num = #notes + 1 | ||
170 | -- insert the back reference right before the final closing tag. | ||
171 | s = string.gsub(s, | ||
172 | '(.*)</', '%1 <a href="#fnref' .. num .. '">↩</a></') | ||
173 | -- add a list item with the note to the note table. | ||
174 | table.insert(notes, '<li id="fn' .. num .. '">' .. s .. '</li>') | ||
175 | -- return the footnote reference, linked to the note. | ||
176 | return '<a id="fnref' .. num .. '" href="#fn' .. num .. | ||
177 | '"><sup>' .. num .. '</sup></a>' | ||
178 | end | ||
179 | |||
180 | function Span(s, attr) | ||
181 | return "<span" .. attributes(attr) .. ">" .. s .. "</span>" | ||
182 | end | ||
183 | |||
184 | function Cite(s) | ||
185 | return "<span class=\"cite\">" .. s .. "</span>" | ||
186 | end | ||
187 | |||
188 | function Plain(s) | ||
189 | return s | ||
190 | end | ||
191 | |||
192 | function Para(s) | ||
193 | return "<p>" .. s .. "</p>" | ||
194 | end | ||
195 | |||
196 | -- lev is an integer, the header level. | ||
197 | function Header(lev, s, attr) | ||
198 | return "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">" | ||
199 | end | ||
200 | |||
201 | function BlockQuote(s) | ||
202 | return "<blockquote>\n" .. s .. "\n</blockquote>" | ||
203 | end | ||
204 | |||
205 | function HorizontalRule() | ||
206 | return "<hr/>" | ||
207 | end | ||
208 | |||
209 | function CodeBlock(s, attr) | ||
210 | -- If code block has class 'dot', pipe the contents through dot | ||
211 | -- and base64, and include the base64-encoded png as a data: URL. | ||
212 | if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then | ||
213 | local png = pipe("base64", pipe("dot -Tpng", s)) | ||
214 | return '<img src="data:image/png;base64,' .. png .. '"/>' | ||
215 | -- otherwise treat as code (one could pipe through a highlighter) | ||
216 | else | ||
217 | return "<pre><code" .. attributes(attr) .. ">" .. escape(s) .. | ||
218 | "</code></pre>" | ||
219 | end | ||
220 | end | ||
221 | |||
222 | function BulletList(items) | ||
223 | local buffer = {} | ||
224 | for _, item in pairs(items) do | ||
225 | table.insert(buffer, "<li>" .. item .. "</li>") | ||
226 | end | ||
227 | return "<ul>\n" .. table.concat(buffer, "\n") .. "\n</ul>" | ||
228 | end | ||
229 | |||
230 | function OrderedList(items) | ||
231 | local buffer = {} | ||
232 | for _, item in pairs(items) do | ||
233 | table.insert(buffer, "<li>" .. item .. "</li>") | ||
234 | end | ||
235 | return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>" | ||
236 | end | ||
237 | |||
238 | -- Revisit association list STackValue instance. | ||
239 | function DefinitionList(items) | ||
240 | local buffer = {} | ||
241 | for _,item in pairs(items) do | ||
242 | for k, v in pairs(item) do | ||
243 | table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" .. | ||
244 | table.concat(v,"</dd>\n<dd>") .. "</dd>") | ||
245 | end | ||
246 | end | ||
247 | return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>" | ||
248 | end | ||
249 | |||
250 | -- Convert pandoc alignment to something HTML can use. | ||
251 | -- align is AlignLeft, AlignRight, AlignCenter, or AlignDefault. | ||
252 | function html_align(align) | ||
253 | if align == 'AlignLeft' then | ||
254 | return 'left' | ||
255 | elseif align == 'AlignRight' then | ||
256 | return 'right' | ||
257 | elseif align == 'AlignCenter' then | ||
258 | return 'center' | ||
259 | else | ||
260 | return 'left' | ||
261 | end | ||
262 | end | ||
263 | |||
264 | -- Caption is a string, aligns is an array of strings, | ||
265 | -- widths is an array of floats, headers is an array of | ||
266 | -- strings, rows is an array of arrays of strings. | ||
267 | function Table(caption, aligns, widths, headers, rows) | ||
268 | local buffer = {} | ||
269 | local function add(s) | ||
270 | table.insert(buffer, s) | ||
271 | end | ||
272 | add("<table>") | ||
273 | if caption ~= "" then | ||
274 | add("<caption>" .. caption .. "</caption>") | ||
275 | end | ||
276 | if widths and widths[1] ~= 0 then | ||
277 | for _, w in pairs(widths) do | ||
278 | add('<col width="' .. string.format("%d%%", w * 100) .. '" />') | ||
279 | end | ||
280 | end | ||
281 | local header_row = {} | ||
282 | local empty_header = true | ||
283 | for i, h in pairs(headers) do | ||
284 | local align = html_align(aligns[i]) | ||
285 | table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>') | ||
286 | empty_header = empty_header and h == "" | ||
287 | end | ||
288 | if empty_header then | ||
289 | head = "" | ||
290 | else | ||
291 | add('<tr class="header">') | ||
292 | for _,h in pairs(header_row) do | ||
293 | add(h) | ||
294 | end | ||
295 | add('</tr>') | ||
296 | end | ||
297 | local class = "even" | ||
298 | for _, row in pairs(rows) do | ||
299 | class = (class == "even" and "odd") or "even" | ||
300 | add('<tr class="' .. class .. '">') | ||
301 | for i,c in pairs(row) do | ||
302 | add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>') | ||
303 | end | ||
304 | add('</tr>') | ||
305 | end | ||
306 | add('</table') | ||
307 | return table.concat(buffer,'\n') | ||
308 | end | ||
309 | |||
310 | function Div(s, attr) | ||
311 | return "<div" .. attributes(attr) .. ">\n" .. s .. "</div>" | ||
312 | end | ||
313 | |||
314 | -- The following code will produce runtime warnings when you haven't defined | ||
315 | -- all of the functions you need for the custom writer, so it's useful | ||
316 | -- to include when you're working on a writer. | ||
317 | local meta = {} | ||
318 | meta.__index = | ||
319 | function(_, key) | ||
320 | io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) | ||
321 | return function() return "" end | ||
322 | end | ||
323 | setmetatable(_G, meta) | ||
324 | |||
diff --git a/lua/test.lua b/lua/test.lua new file mode 100644 index 0000000..bfbafc2 --- /dev/null +++ b/lua/test.lua | |||
@@ -0,0 +1,304 @@ | |||
1 | -- This is a sample custom writer for pandoc. It produces output | ||
2 | -- that is very similar to that of pandoc's HTML writer. | ||
3 | -- There is one new feature: code blocks marked with class 'dot' | ||
4 | -- are piped through graphviz and images are included in the HTML | ||
5 | -- output using 'data:' URLs. | ||
6 | -- | ||
7 | -- Invoke with: pandoc -t sample.lua | ||
8 | -- | ||
9 | -- Note: you need not have lua installed on your system to use this | ||
10 | -- custom writer. However, if you do have lua installed, you can | ||
11 | -- use it to test changes to the script. 'lua sample.lua' will | ||
12 | -- produce informative error messages if your code contains | ||
13 | -- syntax errors. | ||
14 | |||
15 | -- Character escaping | ||
16 | local function escape(s, in_attribute) | ||
17 | return s:gsub("[<>&\"']", | ||
18 | function(x) | ||
19 | if x == '<' then | ||
20 | return '<' | ||
21 | elseif x == '>' then | ||
22 | return '>' | ||
23 | elseif x == '&' then | ||
24 | return '&' | ||
25 | elseif x == '"' then | ||
26 | return '"' | ||
27 | elseif x == "'" then | ||
28 | return ''' | ||
29 | else | ||
30 | return x | ||
31 | end | ||
32 | end) | ||
33 | end | ||
34 | |||
35 | -- Helper function to convert an attributes table into | ||
36 | -- a string that can be put into HTML tags. | ||
37 | local function attributes(attr) | ||
38 | local attr_table = {} | ||
39 | for x,y in pairs(attr) do | ||
40 | if y and y ~= "" then | ||
41 | table.insert(attr_table, ' ' .. x .. '="' .. escape(y,true) .. '"') | ||
42 | end | ||
43 | end | ||
44 | return table.concat(attr_table) | ||
45 | end | ||
46 | |||
47 | -- Run cmd on a temporary file containing inp and return result. | ||
48 | local function pipe(cmd, inp) | ||
49 | local tmp = os.tmpname() | ||
50 | local tmph = io.open(tmp, "w") | ||
51 | tmph:write(inp) | ||
52 | tmph:close() | ||
53 | local outh = io.popen(cmd .. " " .. tmp,"r") | ||
54 | local result = outh:read("*all") | ||
55 | outh:close() | ||
56 | os.remove(tmp) | ||
57 | return result | ||
58 | end | ||
59 | |||
60 | -- Table to store footnotes, so they can be included at the end. | ||
61 | local notes = {} | ||
62 | |||
63 | -- Blocksep is used to separate block elements. | ||
64 | function Blocksep() | ||
65 | return "\n\n" | ||
66 | end | ||
67 | |||
68 | -- This function is called once for the whole document. Parameters: | ||
69 | -- body is a string, metadata is a table, variables is a table. | ||
70 | -- One could use some kind of templating | ||
71 | -- system here; this just gives you a simple standalone HTML file. | ||
72 | function Doc(body, metadata, variables) | ||
73 | local buffer = {} | ||
74 | for k, v in pairs(metadata) do | ||
75 | if type(v) == "string" then | ||
76 | table.insert(buffer, string.upper(k) .. ': ' .. v) | ||
77 | else | ||
78 | table.insert(buffer, string.upper(k) .. ': ' .. table.concat(v)) | ||
79 | end | ||
80 | end | ||
81 | return table.concat(buffer, "\n") | ||
82 | end | ||
83 | |||
84 | -- The functions that follow render corresponding pandoc elements. | ||
85 | -- s is always a string, attr is always a table of attributes, and | ||
86 | -- items is always an array of strings (the items in a list). | ||
87 | -- Comments indicate the types of other variables. | ||
88 | |||
89 | function Str(s) | ||
90 | return escape(s) | ||
91 | end | ||
92 | |||
93 | function Space() | ||
94 | return " " | ||
95 | end | ||
96 | |||
97 | function LineBreak() | ||
98 | return "<br/>" | ||
99 | end | ||
100 | |||
101 | function Emph(s) | ||
102 | return "<em>" .. s .. "</em>" | ||
103 | end | ||
104 | |||
105 | function Strong(s) | ||
106 | return "<strong>" .. s .. "</strong>" | ||
107 | end | ||
108 | |||
109 | function Subscript(s) | ||
110 | return "<sub>" .. s .. "</sub>" | ||
111 | end | ||
112 | |||
113 | function Superscript(s) | ||
114 | return "<sup>" .. s .. "</sup>" | ||
115 | end | ||
116 | |||
117 | function SmallCaps(s) | ||
118 | return '<span style="font-variant: small-caps;">' .. s .. '</span>' | ||
119 | end | ||
120 | |||
121 | function Strikeout(s) | ||
122 | return '<del>' .. s .. '</del>' | ||
123 | end | ||
124 | |||
125 | function Link(s, src, tit) | ||
126 | return "<a href='" .. escape(src,true) .. "' title='" .. | ||
127 | escape(tit,true) .. "'>" .. s .. "</a>" | ||
128 | end | ||
129 | |||
130 | function Image(s, src, tit) | ||
131 | return "<img src='" .. escape(src,true) .. "' title='" .. | ||
132 | escape(tit,true) .. "'/>" | ||
133 | end | ||
134 | |||
135 | function Code(s, attr) | ||
136 | return "<code" .. attributes(attr) .. ">" .. escape(s) .. "</code>" | ||
137 | end | ||
138 | |||
139 | function InlineMath(s) | ||
140 | return "\\(" .. escape(s) .. "\\)" | ||
141 | end | ||
142 | |||
143 | function DisplayMath(s) | ||
144 | return "\\[" .. escape(s) .. "\\]" | ||
145 | end | ||
146 | |||
147 | function Note(s) | ||
148 | local num = #notes + 1 | ||
149 | -- insert the back reference right before the final closing tag. | ||
150 | s = string.gsub(s, | ||
151 | '(.*)</', '%1 <a href="#fnref' .. num .. '">↩</a></') | ||
152 | -- add a list item with the note to the note table. | ||
153 | table.insert(notes, '<li id="fn' .. num .. '">' .. s .. '</li>') | ||
154 | -- return the footnote reference, linked to the note. | ||
155 | return '<a id="fnref' .. num .. '" href="#fn' .. num .. | ||
156 | '"><sup>' .. num .. '</sup></a>' | ||
157 | end | ||
158 | |||
159 | function Span(s, attr) | ||
160 | return "<span" .. attributes(attr) .. ">" .. s .. "</span>" | ||
161 | end | ||
162 | |||
163 | function Cite(s) | ||
164 | return "<span class=\"cite\">" .. s .. "</span>" | ||
165 | end | ||
166 | |||
167 | function Plain(s) | ||
168 | return s | ||
169 | end | ||
170 | |||
171 | function Para(s) | ||
172 | return "<p>" .. s .. "</p>" | ||
173 | end | ||
174 | |||
175 | -- lev is an integer, the header level. | ||
176 | function Header(lev, s, attr) | ||
177 | return "<h" .. lev .. attributes(attr) .. ">" .. s .. "</h" .. lev .. ">" | ||
178 | end | ||
179 | |||
180 | function BlockQuote(s) | ||
181 | return "<blockquote>\n" .. s .. "\n</blockquote>" | ||
182 | end | ||
183 | |||
184 | function HorizontalRule() | ||
185 | return "<hr/>" | ||
186 | end | ||
187 | |||
188 | function CodeBlock(s, attr) | ||
189 | -- If code block has class 'dot', pipe the contents through dot | ||
190 | -- and base64, and include the base64-encoded png as a data: URL. | ||
191 | if attr.class and string.match(' ' .. attr.class .. ' ',' dot ') then | ||
192 | local png = pipe("base64", pipe("dot -Tpng", s)) | ||
193 | return '<img src="data:image/png;base64,' .. png .. '"/>' | ||
194 | -- otherwise treat as code (one could pipe through a highlighter) | ||
195 | else | ||
196 | return "<pre><code" .. attributes(attr) .. ">" .. escape(s) .. | ||
197 | "</code></pre>" | ||
198 | end | ||
199 | end | ||
200 | |||
201 | function BulletList(items) | ||
202 | local buffer = {} | ||
203 | for _, item in pairs(items) do | ||
204 | table.insert(buffer, "<li>" .. item .. "</li>") | ||
205 | end | ||
206 | return "<ul>\n" .. table.concat(buffer, "\n") .. "\n</ul>" | ||
207 | end | ||
208 | |||
209 | function OrderedList(items) | ||
210 | local buffer = {} | ||
211 | for _, item in pairs(items) do | ||
212 | table.insert(buffer, "<li>" .. item .. "</li>") | ||
213 | end | ||
214 | return "<ol>\n" .. table.concat(buffer, "\n") .. "\n</ol>" | ||
215 | end | ||
216 | |||
217 | -- Revisit association list STackValue instance. | ||
218 | function DefinitionList(items) | ||
219 | local buffer = {} | ||
220 | for _,item in pairs(items) do | ||
221 | for k, v in pairs(item) do | ||
222 | table.insert(buffer,"<dt>" .. k .. "</dt>\n<dd>" .. | ||
223 | table.concat(v,"</dd>\n<dd>") .. "</dd>") | ||
224 | end | ||
225 | end | ||
226 | return "<dl>\n" .. table.concat(buffer, "\n") .. "\n</dl>" | ||
227 | end | ||
228 | |||
229 | -- Convert pandoc alignment to something HTML can use. | ||
230 | -- align is AlignLeft, AlignRight, AlignCenter, or AlignDefault. | ||
231 | function html_align(align) | ||
232 | if align == 'AlignLeft' then | ||
233 | return 'left' | ||
234 | elseif align == 'AlignRight' then | ||
235 | return 'right' | ||
236 | elseif align == 'AlignCenter' then | ||
237 | return 'center' | ||
238 | else | ||
239 | return 'left' | ||
240 | end | ||
241 | end | ||
242 | |||
243 | -- Caption is a string, aligns is an array of strings, | ||
244 | -- widths is an array of floats, headers is an array of | ||
245 | -- strings, rows is an array of arrays of strings. | ||
246 | function Table(caption, aligns, widths, headers, rows) | ||
247 | local buffer = {} | ||
248 | local function add(s) | ||
249 | table.insert(buffer, s) | ||
250 | end | ||
251 | add("<table>") | ||
252 | if caption ~= "" then | ||
253 | add("<caption>" .. caption .. "</caption>") | ||
254 | end | ||
255 | if widths and widths[1] ~= 0 then | ||
256 | for _, w in pairs(widths) do | ||
257 | add('<col width="' .. string.format("%d%%", w * 100) .. '" />') | ||
258 | end | ||
259 | end | ||
260 | local header_row = {} | ||
261 | local empty_header = true | ||
262 | for i, h in pairs(headers) do | ||
263 | local align = html_align(aligns[i]) | ||
264 | table.insert(header_row,'<th align="' .. align .. '">' .. h .. '</th>') | ||
265 | empty_header = empty_header and h == "" | ||
266 | end | ||
267 | if empty_header then | ||
268 | head = "" | ||
269 | else | ||
270 | add('<tr class="header">') | ||
271 | for _,h in pairs(header_row) do | ||
272 | add(h) | ||
273 | end | ||
274 | add('</tr>') | ||
275 | end | ||
276 | local class = "even" | ||
277 | for _, row in pairs(rows) do | ||
278 | class = (class == "even" and "odd") or "even" | ||
279 | add('<tr class="' .. class .. '">') | ||
280 | for i,c in pairs(row) do | ||
281 | add('<td align="' .. html_align(aligns[i]) .. '">' .. c .. '</td>') | ||
282 | end | ||
283 | add('</tr>') | ||
284 | end | ||
285 | add('</table') | ||
286 | return table.concat(buffer,'\n') | ||
287 | end | ||
288 | |||
289 | function Div(s, attr) | ||
290 | return "<div" .. attributes(attr) .. ">\n" .. s .. "</div>" | ||
291 | end | ||
292 | |||
293 | -- The following code will produce runtime warnings when you haven't defined | ||
294 | -- all of the functions you need for the custom writer, so it's useful | ||
295 | -- to include when you're working on a writer. | ||
296 | local meta = {} | ||
297 | meta.__index = | ||
298 | function(_, key) | ||
299 | io.stderr:write(string.format("WARNING: Undefined function '%s'\n",key)) | ||
300 | return function() return "" end | ||
301 | end | ||
302 | setmetatable(_G, meta) | ||
303 | |||
304 | |||