pandoc2review 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +14 -0
- data/.github/workflows/pandoc.yml +1 -1
- data/.rubocop.yml +305 -0
- data/Gemfile +0 -2
- data/README.md +10 -1
- data/Rakefile +13 -3
- data/exe/pandoc2review +1 -2
- data/lib/pandoc2review.rb +17 -10
- data/lua/filters.lua +32 -69
- data/lua/review.lua +301 -170
- data/pandoc2review.gemspec +23 -16
- data/stylua.toml +3 -0
- metadata +62 -2
data/lua/review.lua
CHANGED
@@ -25,7 +25,7 @@ local footnotes = {}
|
|
25
25
|
|
26
26
|
-- internal
|
27
27
|
local metadata = nil
|
28
|
-
local stringify = (require
|
28
|
+
local stringify = (require("pandoc.utils")).stringify
|
29
29
|
local inline_commands = {
|
30
30
|
-- processed if given as classes of Span elements
|
31
31
|
-- true if syntax is `@<command>{string}`
|
@@ -48,7 +48,7 @@ local inline_commands = {
|
|
48
48
|
title = true,
|
49
49
|
chapref = true,
|
50
50
|
list = true,
|
51
|
-
img =
|
51
|
+
img = true,
|
52
52
|
table = true,
|
53
53
|
eq = true,
|
54
54
|
hd = true,
|
@@ -83,21 +83,19 @@ local function log(s)
|
|
83
83
|
end
|
84
84
|
|
85
85
|
local function surround_inline(s)
|
86
|
-
if
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
else
|
92
|
-
-- surround by ||
|
93
|
-
return "|" .. s .. "|"
|
94
|
-
end
|
95
|
-
else
|
96
|
-
-- surround by $$
|
97
|
-
return "$" .. s .. "$"
|
98
|
-
end
|
86
|
+
if not s:match("[{}]") then
|
87
|
+
return "{" .. s .. "}"
|
88
|
+
end
|
89
|
+
if not s:match("%$") then
|
90
|
+
return "$" .. s .. "$"
|
99
91
|
end
|
100
|
-
|
92
|
+
|
93
|
+
-- use % for regexp escape
|
94
|
+
if s:match("|") then
|
95
|
+
-- give up. escape } by \}
|
96
|
+
return "{" .. s:gsub("}", "\\}") .. "}"
|
97
|
+
end
|
98
|
+
return "|" .. s .. "|"
|
101
99
|
end
|
102
100
|
|
103
101
|
local function format_inline(fmt, s)
|
@@ -105,31 +103,18 @@ local function format_inline(fmt, s)
|
|
105
103
|
end
|
106
104
|
|
107
105
|
local function html_align(align)
|
108
|
-
|
109
|
-
return ""
|
110
|
-
elseif align == "AlignRight" then
|
111
|
-
return "right"
|
112
|
-
elseif align == "AlignCenter" then
|
113
|
-
return "center"
|
114
|
-
else
|
115
|
-
return ""
|
116
|
-
end
|
106
|
+
return ({ AlignRight = "right", AlignCenter = "center" })[align] or ""
|
117
107
|
end
|
118
108
|
|
119
109
|
function Blocksep()
|
120
110
|
return "\n\n"
|
121
111
|
end
|
122
112
|
|
123
|
-
function Doc(body,
|
124
|
-
|
125
|
-
|
126
|
-
table.insert(buffer, s)
|
127
|
-
end
|
128
|
-
add(body)
|
129
|
-
if (#footnotes > 0) then
|
130
|
-
add("\n" .. table.concat(footnotes, "\n"))
|
113
|
+
function Doc(body, meta, variables)
|
114
|
+
if #footnotes == 0 then
|
115
|
+
return body
|
131
116
|
end
|
132
|
-
return table.concat(
|
117
|
+
return table.concat({ body, "", table.concat(footnotes, "\n") }, "\n")
|
133
118
|
end
|
134
119
|
|
135
120
|
function Str(s)
|
@@ -145,11 +130,7 @@ function LineBreak()
|
|
145
130
|
end
|
146
131
|
|
147
132
|
function SoftBreak(s)
|
148
|
-
|
149
|
-
return " "
|
150
|
-
else
|
151
|
-
return "<P2RBR/>"
|
152
|
-
end
|
133
|
+
return metadata.softbreak and " " or "<P2RBR/>"
|
153
134
|
end
|
154
135
|
|
155
136
|
function Plain(s)
|
@@ -161,13 +142,7 @@ function Para(s)
|
|
161
142
|
end
|
162
143
|
|
163
144
|
local function attr_val(attr, key)
|
164
|
-
|
165
|
-
for k, v in pairs(attr) do
|
166
|
-
if (k == key and v and v ~= "") then
|
167
|
-
return v
|
168
|
-
end
|
169
|
-
end
|
170
|
-
return ""
|
145
|
+
return attr[key] or ""
|
171
146
|
end
|
172
147
|
|
173
148
|
local function attr_classes(attr)
|
@@ -180,7 +155,7 @@ local function attr_classes(attr)
|
|
180
155
|
end
|
181
156
|
|
182
157
|
local function attr_scale(attr, key) -- a helper for CaptionedImage
|
183
|
-
scale = attr_val(attr, key)
|
158
|
+
local scale, count = attr_val(attr, key), 0
|
184
159
|
if (scale == "") or (key == "scale") then
|
185
160
|
return scale
|
186
161
|
end
|
@@ -194,28 +169,27 @@ local function attr_scale(attr, key) -- a helper for CaptionedImage
|
|
194
169
|
return tonumber(scale) / 100
|
195
170
|
end
|
196
171
|
|
197
|
-
function
|
198
|
-
|
199
|
-
for
|
200
|
-
|
172
|
+
local function class_header(classes)
|
173
|
+
-- Re:VIEW's behavior
|
174
|
+
for _, cls in pairs({ "column", "nonum", "nodisp", "notoc" }) do
|
175
|
+
if classes[cls] then
|
176
|
+
return string.format("[%s]", cls)
|
177
|
+
end
|
201
178
|
end
|
202
179
|
|
203
|
-
|
180
|
+
-- Pandoc's behavior
|
181
|
+
if classes.unnumbered then
|
182
|
+
return classes.unlisted and "[notoc]" or "[nonum]"
|
183
|
+
end
|
204
184
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
classes["unlisted"] and "[notoc]" or "[nonum]") or (
|
214
|
-
-- None
|
215
|
-
"")))))
|
216
|
-
)
|
217
|
-
|
218
|
-
if ((config.use_header_id == "true") and attr.id ~= "" and attr.id ~= s) then
|
185
|
+
-- None
|
186
|
+
return ""
|
187
|
+
end
|
188
|
+
|
189
|
+
function Header(level, s, attr)
|
190
|
+
local headmark = string.rep("=", level) .. class_header(attr_classes(attr))
|
191
|
+
|
192
|
+
if (config.use_header_id == "true") and attr.id ~= "" and attr.id ~= s then
|
219
193
|
headmark = headmark .. "{" .. attr.id .. "}"
|
220
194
|
end
|
221
195
|
|
@@ -223,17 +197,13 @@ function Header(level, s, attr)
|
|
223
197
|
end
|
224
198
|
|
225
199
|
function HorizontalRule()
|
226
|
-
|
227
|
-
return "//hr"
|
228
|
-
else
|
229
|
-
return ""
|
230
|
-
end
|
200
|
+
return config.use_hr == "true" and "//hr" or ""
|
231
201
|
end
|
232
202
|
|
233
203
|
local function lint_list(s)
|
234
|
-
return s:gsub("\n+(//beginchild)\n+",
|
235
|
-
|
236
|
-
|
204
|
+
return s:gsub("\n+(//beginchild)\n+", "\n\n%1\n\n")
|
205
|
+
:gsub("\n+(//endchild)\n+", "\n\n%1\n\n")
|
206
|
+
:gsub("\n+(//endchild)\n*$", "\n\n%1")
|
237
207
|
end
|
238
208
|
|
239
209
|
function BulletList(items)
|
@@ -279,39 +249,33 @@ end
|
|
279
249
|
function CodeBlock(s, attr)
|
280
250
|
local classes = attr_classes(attr)
|
281
251
|
|
282
|
-
local command =
|
283
|
-
for k,v in pairs({cmd = "cmd", source = "source", quote = "source"}) do
|
252
|
+
local command = "list" -- default
|
253
|
+
for k, v in pairs({ cmd = "cmd", source = "source", quote = "source" }) do
|
284
254
|
if classes[k] then
|
285
255
|
command = v
|
286
256
|
break
|
287
257
|
end
|
288
258
|
end
|
289
|
-
command = command or "list"
|
290
|
-
|
291
|
-
is_list = command == "list"
|
292
259
|
|
260
|
+
local is_list = command == "list"
|
293
261
|
|
294
|
-
local num = (is_list
|
295
|
-
(classes["numberLines"] or classes["number-lines"] or classes["num"]) and
|
296
|
-
"num" or ""
|
297
|
-
)
|
262
|
+
local num = (is_list and (classes["numberLines"] or classes["number-lines"] or classes["num"])) and "num" or ""
|
298
263
|
|
299
264
|
local firstlinenum = ""
|
300
265
|
if is_list and (num == "num") then
|
301
|
-
for _, key in ipairs({"startFrom", "start-from", "firstlinenum"}) do
|
302
|
-
|
303
|
-
|
304
|
-
firstlinenum = "//firstlinenum[" .. firstlinenum .. "]\n"
|
266
|
+
for _, key in ipairs({ "startFrom", "start-from", "firstlinenum" }) do
|
267
|
+
if attr[key] then
|
268
|
+
firstlinenum = "//firstlinenum[" .. attr[key] .. "]\n"
|
305
269
|
break
|
306
270
|
end
|
307
271
|
end
|
308
272
|
end
|
309
273
|
|
310
274
|
local lang = ""
|
311
|
-
local not_lang = {numberLines = true, num = true, em = true, source = true}
|
275
|
+
local not_lang = { numberLines = true, num = true, em = true, source = true }
|
312
276
|
not_lang["number-lines"] = true
|
313
277
|
if is_list or (command == "source") then
|
314
|
-
for key,_ in pairs(classes) do
|
278
|
+
for key, _ in pairs(classes) do
|
315
279
|
if not_lang[key] ~= true then
|
316
280
|
lang = "[" .. key .. "]"
|
317
281
|
break
|
@@ -322,9 +286,9 @@ function CodeBlock(s, attr)
|
|
322
286
|
local caption = (command == "cmd") and "" or attr_val(attr, "caption")
|
323
287
|
local identifier = ""
|
324
288
|
local em = is_list and classes["em"] and "em" or ""
|
325
|
-
if
|
289
|
+
if caption ~= "" then
|
326
290
|
if is_list and (em == "") then
|
327
|
-
if
|
291
|
+
if attr.id ~= "" then
|
328
292
|
identifier = "[" .. attr.id .. "]"
|
329
293
|
else
|
330
294
|
list_num = list_num + 1
|
@@ -341,11 +305,7 @@ function CodeBlock(s, attr)
|
|
341
305
|
end
|
342
306
|
end
|
343
307
|
|
344
|
-
return (
|
345
|
-
firstlinenum ..
|
346
|
-
"//" .. em .. command .. num .. identifier .. caption .. lang ..
|
347
|
-
"{\n" .. s .. "\n//}"
|
348
|
-
)
|
308
|
+
return (firstlinenum .. "//" .. em .. command .. num .. identifier .. caption .. lang .. "{\n" .. s .. "\n//}")
|
349
309
|
end
|
350
310
|
|
351
311
|
function LineBlock(s)
|
@@ -354,7 +314,7 @@ function LineBlock(s)
|
|
354
314
|
end
|
355
315
|
|
356
316
|
function Link(s, src, tit)
|
357
|
-
if
|
317
|
+
if src == s then
|
358
318
|
return format_inline("href", src)
|
359
319
|
else
|
360
320
|
return format_inline("href", src .. "," .. s)
|
@@ -411,7 +371,7 @@ function Table(caption, aligns, widths, headers, rows)
|
|
411
371
|
end
|
412
372
|
local tmp = {}
|
413
373
|
for i, h in pairs(headers) do
|
414
|
-
align = html_align(aligns[i])
|
374
|
+
local align = html_align(aligns[i])
|
415
375
|
if (config.use_table_align == "true") and (align ~= "") then
|
416
376
|
h = format_inline("dtp", "table align=" .. align) .. h
|
417
377
|
end
|
@@ -421,8 +381,8 @@ function Table(caption, aligns, widths, headers, rows)
|
|
421
381
|
add("--------------")
|
422
382
|
for _, row in pairs(rows) do
|
423
383
|
tmp = {}
|
424
|
-
|
425
|
-
align = html_align(aligns[i])
|
384
|
+
for i, c in pairs(row) do
|
385
|
+
local align = html_align(aligns[i])
|
426
386
|
if (config.use_table_align == "true") and (align ~= "") then
|
427
387
|
c = format_inline("dtp", "table align=" .. align) .. c
|
428
388
|
end
|
@@ -435,13 +395,6 @@ function Table(caption, aligns, widths, headers, rows)
|
|
435
395
|
return table.concat(buffer, "\n")
|
436
396
|
end
|
437
397
|
|
438
|
-
function Image(s, src, tit)
|
439
|
-
-- Re:VIEW @<icon> ignores caption and title
|
440
|
-
local id = string.gsub(src, "%.%w+$", "")
|
441
|
-
id = string.gsub(id, "^images/", "")
|
442
|
-
return format_inline("icon", id)
|
443
|
-
end
|
444
|
-
|
445
398
|
function CaptionedImage(s, src, tit, attr)
|
446
399
|
local path = "[" .. s:gsub("%.%w+$", ""):gsub("^images/", "") .. "]"
|
447
400
|
|
@@ -451,7 +404,7 @@ function CaptionedImage(s, src, tit, attr)
|
|
451
404
|
if scale == "" then
|
452
405
|
local width = attr_scale(attr, "width")
|
453
406
|
local height = attr_scale(attr, "height")
|
454
|
-
if
|
407
|
+
if width ~= "" then
|
455
408
|
if (height ~= "") and (width ~= height) then
|
456
409
|
log("WARNING: Image width and height must be same. Using width.\n")
|
457
410
|
end
|
@@ -464,26 +417,15 @@ function CaptionedImage(s, src, tit, attr)
|
|
464
417
|
scale = "[scale=" .. scale .. "]"
|
465
418
|
end
|
466
419
|
|
467
|
-
local command = "//image"
|
468
|
-
local caption = ""
|
469
|
-
if (tit == "") then
|
470
|
-
command = "//indepimage"
|
471
|
-
else
|
472
|
-
caption = "[" .. tit .. "]"
|
473
|
-
end
|
420
|
+
local command = tit == "" and "//indepimage" or "//image"
|
421
|
+
local caption = tit == "" and "" or ("[" .. tit .. "]")
|
474
422
|
|
475
|
-
return (
|
476
|
-
command .. path .. caption .. scale .. "{" .. comment .. "\n//}"
|
477
|
-
)
|
423
|
+
return (command .. path .. caption .. scale .. "{" .. comment .. "\n//}")
|
478
424
|
end
|
479
425
|
|
480
426
|
function Image(s, src, tit, attr)
|
481
427
|
-- Re:VIEW @<icon> ignores caption and title
|
482
|
-
|
483
|
-
return CaptionedImage(src, s, tit, attr)
|
484
|
-
end
|
485
|
-
local id = string.gsub(src, "%.%w+$", "")
|
486
|
-
id = string.gsub(id, "^images/", "")
|
428
|
+
local id = src:gsub("%.%w+$", ""):gsub("^images/", "")
|
487
429
|
return format_inline("icon", id)
|
488
430
|
end
|
489
431
|
|
@@ -499,12 +441,7 @@ function Cite(s, cs)
|
|
499
441
|
end
|
500
442
|
|
501
443
|
function Quoted(quotetype, s)
|
502
|
-
|
503
|
-
return SingleQuoted(s)
|
504
|
-
end
|
505
|
-
if (quotetype == "DoubleQuote") then
|
506
|
-
return DoubleQuoted(s)
|
507
|
-
end
|
444
|
+
return _G[quotetype](s)
|
508
445
|
end
|
509
446
|
|
510
447
|
function SingleQuoted(s)
|
@@ -520,13 +457,9 @@ function SmallCaps(s)
|
|
520
457
|
end
|
521
458
|
|
522
459
|
function Div(s, attr)
|
523
|
-
local blankline =
|
524
|
-
if blankline
|
525
|
-
|
526
|
-
for i = 1, tonumber(blankline) do
|
527
|
-
table.insert(buffer, "//blankline")
|
528
|
-
end
|
529
|
-
return table.concat(buffer, "\n")
|
460
|
+
local blankline = tonumber(attr.blankline)
|
461
|
+
if blankline then
|
462
|
+
return string.rep("//blankline\n", blankline):gsub("\n$", "")
|
530
463
|
end
|
531
464
|
|
532
465
|
local classes = attr_classes(attr)
|
@@ -540,15 +473,11 @@ function Div(s, attr)
|
|
540
473
|
end
|
541
474
|
|
542
475
|
if classes["review-internal"] then
|
543
|
-
s, _ = s:gsub(
|
544
|
-
"%]{<P2RREMOVEBELOW/>\n", "]{"
|
545
|
-
):gsub(
|
546
|
-
"\n<P2RREMOVEABOVE/>//}", "//}"
|
547
|
-
)
|
476
|
+
s, _ = s:gsub("%]{<P2RREMOVEBELOW/>\n", "]{"):gsub("\n<P2RREMOVEABOVE/>//}", "//}")
|
548
477
|
return s
|
549
478
|
end
|
550
479
|
|
551
|
-
for cls,_ in pairs(classes) do
|
480
|
+
for cls, _ in pairs(classes) do
|
552
481
|
s = "//" .. cls .. "{\n" .. s .. "\n//}"
|
553
482
|
end
|
554
483
|
return s
|
@@ -557,7 +486,7 @@ end
|
|
557
486
|
function Span(s, attr)
|
558
487
|
-- ruby and kw with a supplement
|
559
488
|
local a = ""
|
560
|
-
for _, cmd in ipairs({"ruby", "kw"}) do
|
489
|
+
for _, cmd in ipairs({ "ruby", "kw" }) do
|
561
490
|
a = attr_val(attr, cmd)
|
562
491
|
if a ~= "" then
|
563
492
|
s = format_inline(cmd, s .. "," .. a)
|
@@ -575,31 +504,31 @@ function Span(s, attr)
|
|
575
504
|
end
|
576
505
|
|
577
506
|
function RawInline(format, text)
|
578
|
-
if
|
507
|
+
if format == "review" then
|
579
508
|
return text
|
580
509
|
end
|
581
510
|
|
582
|
-
if
|
511
|
+
if metadata.hideraw then
|
583
512
|
return ""
|
584
513
|
end
|
585
514
|
|
586
|
-
if
|
515
|
+
if format == "tex" then
|
587
516
|
return format_inline("embed", "|latex|" .. text)
|
588
517
|
else
|
589
|
-
return format_inline("embed", "|" .. format .. "|"
|
518
|
+
return format_inline("embed", "|" .. format .. "|" .. text)
|
590
519
|
end
|
591
520
|
end
|
592
521
|
|
593
522
|
function RawBlock(format, text)
|
594
|
-
if
|
523
|
+
if format == "review" then
|
595
524
|
return text
|
596
525
|
end
|
597
526
|
|
598
|
-
if
|
527
|
+
if metadata.hideraw then
|
599
528
|
return ""
|
600
529
|
end
|
601
530
|
|
602
|
-
if
|
531
|
+
if format == "tex" then
|
603
532
|
return "//embed[latex]{\n" .. text .. "\n//}"
|
604
533
|
else
|
605
534
|
return "//embed[" .. format .. "]{\n" .. text .. "\n//}"
|
@@ -607,18 +536,18 @@ function RawBlock(format, text)
|
|
607
536
|
end
|
608
537
|
|
609
538
|
local function configure()
|
610
|
-
try_catch
|
539
|
+
try_catch({
|
611
540
|
try = function()
|
612
541
|
metadata = PANDOC_DOCUMENT.meta
|
613
542
|
end,
|
614
543
|
catch = function(error)
|
615
544
|
log("Due to your pandoc version is too old, config.yml loader is disabled.\n")
|
616
|
-
end
|
617
|
-
}
|
545
|
+
end,
|
546
|
+
})
|
618
547
|
|
619
|
-
if
|
548
|
+
if metadata then
|
620
549
|
-- Load config from YAML
|
621
|
-
for k,
|
550
|
+
for k, _ in pairs(config) do
|
622
551
|
if metadata[k] ~= nil then
|
623
552
|
config[k] = stringify(metadata[k])
|
624
553
|
end
|
@@ -626,23 +555,225 @@ local function configure()
|
|
626
555
|
end
|
627
556
|
end
|
628
557
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
558
|
+
setmetatable(_G, {
|
559
|
+
__index = function(_, key)
|
560
|
+
log(string.format("WARNING: Undefined function '%s'\n", key))
|
561
|
+
return function()
|
562
|
+
return ""
|
563
|
+
end
|
564
|
+
end,
|
565
|
+
})
|
566
|
+
|
567
|
+
if PANDOC_VERSION < "3.0.0" then
|
638
568
|
configure()
|
569
|
+
return
|
639
570
|
end
|
640
571
|
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
572
|
+
Blocks = setmetatable({}, {
|
573
|
+
__index = function(_, key)
|
574
|
+
error("NotImplementedError: Blocks.%" .. tostring(key))
|
575
|
+
end,
|
576
|
+
})
|
577
|
+
|
578
|
+
Inlines = setmetatable({}, {
|
579
|
+
__index = function(_, key)
|
580
|
+
error("NotImplementedError: Inlines.%" .. tostring(key))
|
581
|
+
end,
|
582
|
+
})
|
583
|
+
|
584
|
+
local tidy_attr = function(el)
|
585
|
+
local ret = {}
|
586
|
+
for k, v in pairs(el.attr.attributes) do
|
587
|
+
ret[k] = v
|
588
|
+
end
|
589
|
+
ret.id = el.identifier or ""
|
590
|
+
ret.class = el.classes and table.concat(el.classes, " ")
|
591
|
+
return ret
|
592
|
+
end
|
593
|
+
|
594
|
+
local concat = pandoc.layout.concat
|
595
|
+
|
596
|
+
local function render(...)
|
597
|
+
local x = pandoc.layout.render(...):gsub("\n+$", "")
|
598
|
+
return x
|
599
|
+
end
|
600
|
+
|
601
|
+
local function inlines(els)
|
602
|
+
local buff = {}
|
603
|
+
for _, el in ipairs(els) do
|
604
|
+
table.insert(buff, Inlines[el.tag](el))
|
605
|
+
end
|
606
|
+
return concat(buff)
|
607
|
+
end
|
608
|
+
|
609
|
+
local function blocks(els, sep)
|
610
|
+
local buff = {}
|
611
|
+
for _, el in ipairs(els) do
|
612
|
+
table.insert(buff, Blocks[el.tag](el))
|
646
613
|
end
|
614
|
+
return concat(buff, sep)
|
615
|
+
end
|
616
|
+
|
617
|
+
Inlines.Str = function(el)
|
618
|
+
return Str(el.text)
|
619
|
+
end
|
647
620
|
|
648
|
-
|
621
|
+
for _, v in pairs({ "Space", "LineBreak", "SoftBreak" }) do
|
622
|
+
Inlines[v] = _G[v]
|
623
|
+
end
|
624
|
+
|
625
|
+
Blocks.HorizontalRule = function(_)
|
626
|
+
return HorizontalRule() .. "\n"
|
627
|
+
end
|
628
|
+
|
629
|
+
Blocks.Plain = function(el)
|
630
|
+
return inlines(el.content) .. "\n"
|
631
|
+
end
|
632
|
+
|
633
|
+
Blocks.Para = function(el)
|
634
|
+
if #el.content == 1 and el.content[1].tag == "Image" then
|
635
|
+
local img = el.content[1]
|
636
|
+
return CaptionedImage(img.src, img.title, render(inlines(img.caption)), tidy_attr(img)) .. "\n"
|
637
|
+
end
|
638
|
+
return inlines(el.content) .. "\n"
|
639
|
+
end
|
640
|
+
|
641
|
+
Blocks.Header = function(el)
|
642
|
+
return Header(el.level, render(inlines(el.content)), tidy_attr(el)) .. "\n"
|
643
|
+
end
|
644
|
+
|
645
|
+
local function render_blocks(blks, sep)
|
646
|
+
local ret = {}
|
647
|
+
for _, v in pairs(blks) do
|
648
|
+
table.insert(ret, render(blocks(v, sep or "\n")))
|
649
|
+
end
|
650
|
+
return ret
|
651
|
+
end
|
652
|
+
|
653
|
+
Blocks.BulletList = function(el)
|
654
|
+
return BulletList(render_blocks(el.content)) .. "\n"
|
655
|
+
end
|
656
|
+
|
657
|
+
Blocks.OrderedList = function(el)
|
658
|
+
return OrderedList(render_blocks(el.content), el.start) .. "\n"
|
659
|
+
end
|
660
|
+
|
661
|
+
Blocks.DefinitionList = function(el)
|
662
|
+
local items = {}
|
663
|
+
for _, v in pairs(el.content) do
|
664
|
+
local term = render(inlines(v[1]))
|
665
|
+
table.insert(items, { [term] = render_blocks(v[2]) })
|
666
|
+
end
|
667
|
+
return DefinitionList(items) .. "\n"
|
668
|
+
end
|
669
|
+
|
670
|
+
Blocks.BlockQuote = function(el)
|
671
|
+
return BlockQuote(render(blocks(el.content, "\n"))) .. "\n"
|
672
|
+
end
|
673
|
+
|
674
|
+
Blocks.CodeBlock = function(el)
|
675
|
+
return CodeBlock(el.text, tidy_attr(el)) .. "\n"
|
676
|
+
end
|
677
|
+
|
678
|
+
Blocks.LineBlock = function(el)
|
679
|
+
local lines = {}
|
680
|
+
for _, v in pairs(el.content) do
|
681
|
+
table.insert(lines, render(inlines(v)))
|
682
|
+
end
|
683
|
+
return LineBlock(lines) .. "\n"
|
684
|
+
end
|
685
|
+
|
686
|
+
Inlines.Link = function(el)
|
687
|
+
return Link(render(inlines(el.content)), el.target, el.title)
|
688
|
+
end
|
689
|
+
|
690
|
+
Inlines.Code = function(el)
|
691
|
+
return Code(el.text, tidy_attr(el))
|
692
|
+
end
|
693
|
+
|
694
|
+
for _, k in pairs({ "Emph", "Strong", "Strikeout", "Underline", "Subscript", "Superscript", "SmallCaps" }) do
|
695
|
+
Inlines[k] = function(el)
|
696
|
+
return _G[k](render(inlines(el.content)))
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
Inlines.Math = function(el)
|
701
|
+
return _G[el.mathtype](el.text)
|
702
|
+
end
|
703
|
+
|
704
|
+
Blocks.Table = function(el)
|
705
|
+
local tbl = pandoc.utils.to_simple_table(el)
|
706
|
+
local headers = render_blocks(tbl.headers)
|
707
|
+
local rows = {}
|
708
|
+
for _, row in pairs(tbl.rows) do
|
709
|
+
table.insert(rows, render_blocks(row, ""))
|
710
|
+
end
|
711
|
+
return Table(render(inlines(tbl.caption)), tbl.aligns, tbl.widths, headers, rows) .. "\n"
|
712
|
+
end
|
713
|
+
|
714
|
+
Inlines.Image = function(el)
|
715
|
+
return Image(render(inlines(el.caption)), el.src, el.title, tidy_attr(el))
|
716
|
+
end
|
717
|
+
|
718
|
+
Inlines.Note = function(el)
|
719
|
+
return Note(render(blocks(el.content, "\n")))
|
720
|
+
end
|
721
|
+
|
722
|
+
Inlines.Cite = function(el)
|
723
|
+
return Cite(render(inlines(el.content)))
|
724
|
+
end
|
725
|
+
|
726
|
+
Inlines.Quoted = function(el)
|
727
|
+
return Quoted(el.quotetype, render(inlines(el.content)))
|
728
|
+
end
|
729
|
+
|
730
|
+
Blocks.Div = function(el)
|
731
|
+
return Div(render(blocks(el.content, "\n")), tidy_attr(el)) .. "\n"
|
732
|
+
end
|
733
|
+
|
734
|
+
Inlines.Span = function(el)
|
735
|
+
return Span(render(inlines(el.content)), tidy_attr(el))
|
736
|
+
end
|
737
|
+
|
738
|
+
Inlines.RawInline = function(el)
|
739
|
+
return RawInline(el.format, el.text)
|
740
|
+
end
|
741
|
+
|
742
|
+
Blocks.RawBlock = function(el)
|
743
|
+
return RawBlock(el.format, el.text) .. "\n"
|
744
|
+
end
|
745
|
+
|
746
|
+
Blocks.Figure = function(el)
|
747
|
+
if #el.content > 1 or #el.content[1].content > 1 or el.content[1].content[1].tag ~= "Image" then
|
748
|
+
error("NotImplementedError: current implementation assumes Figure contains only a single image.")
|
749
|
+
-- because Pandoc 3.1.4 does not support Pandoc's markdown cotaining Figure with multiple images...
|
750
|
+
end
|
751
|
+
|
752
|
+
local img = el.content[1].content[1]
|
753
|
+
|
754
|
+
return CaptionedImage(img.src, img.title, render(inlines(img.caption)), tidy_attr(img)) .. "\n"
|
755
|
+
end
|
756
|
+
|
757
|
+
function Writer(doc, opts)
|
758
|
+
PANDOC_DOCUMENT = doc
|
759
|
+
PANDOC_WRITER_OPTIONS = opts
|
760
|
+
configure()
|
761
|
+
|
762
|
+
if metadata.classicwriter then
|
763
|
+
if pandoc.write_classic then
|
764
|
+
return pandoc.write_classic(
|
765
|
+
doc:walk({
|
766
|
+
Figure = function(el)
|
767
|
+
return pandoc.RawBlock("review", render(Blocks.Figure(el)))
|
768
|
+
end,
|
769
|
+
}),
|
770
|
+
opts
|
771
|
+
)
|
772
|
+
end
|
773
|
+
log("WARNING: pandoc.write_classic is defunct. Using modern writer")
|
774
|
+
end
|
775
|
+
|
776
|
+
-- body should keep trailing new lines but remove one if there are footnotes for the backward-compatibility
|
777
|
+
local body = pandoc.layout.render(pandoc.layout.concat({ blocks(doc.blocks, "\n") }))
|
778
|
+
return Doc(#footnotes == 0 and body or body:gsub("\n$", ""))
|
779
|
+
end
|