pandoc2review 1.6.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 +5 -0
- data/Rakefile +13 -3
- data/exe/pandoc2review +1 -2
- data/lib/pandoc2review.rb +17 -10
- data/lua/filters.lua +30 -67
- data/lua/review.lua +295 -155
- 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)
|
@@ -188,25 +169,27 @@ local function attr_scale(attr, key) -- a helper for CaptionedImage
|
|
188
169
|
return tonumber(scale) / 100
|
189
170
|
end
|
190
171
|
|
191
|
-
function
|
192
|
-
|
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
|
178
|
+
end
|
193
179
|
|
194
|
-
|
180
|
+
-- Pandoc's behavior
|
181
|
+
if classes.unnumbered then
|
182
|
+
return classes.unlisted and "[notoc]" or "[nonum]"
|
183
|
+
end
|
184
|
+
|
185
|
+
-- None
|
186
|
+
return ""
|
187
|
+
end
|
195
188
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
classes["nodisp"] and "[nodisp]" or (
|
201
|
-
classes["notoc"] and "[notoc]" or (
|
202
|
-
-- Pandoc's behavior
|
203
|
-
classes["unnumbered"] and (
|
204
|
-
classes["unlisted"] and "[notoc]" or "[nonum]") or (
|
205
|
-
-- None
|
206
|
-
"")))))
|
207
|
-
)
|
208
|
-
|
209
|
-
if ((config.use_header_id == "true") and attr.id ~= "" and attr.id ~= s) then
|
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
|
210
193
|
headmark = headmark .. "{" .. attr.id .. "}"
|
211
194
|
end
|
212
195
|
|
@@ -214,17 +197,13 @@ function Header(level, s, attr)
|
|
214
197
|
end
|
215
198
|
|
216
199
|
function HorizontalRule()
|
217
|
-
|
218
|
-
return "//hr"
|
219
|
-
else
|
220
|
-
return ""
|
221
|
-
end
|
200
|
+
return config.use_hr == "true" and "//hr" or ""
|
222
201
|
end
|
223
202
|
|
224
203
|
local function lint_list(s)
|
225
|
-
return s:gsub("\n+(//beginchild)\n+",
|
226
|
-
|
227
|
-
|
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")
|
228
207
|
end
|
229
208
|
|
230
209
|
function BulletList(items)
|
@@ -270,39 +249,33 @@ end
|
|
270
249
|
function CodeBlock(s, attr)
|
271
250
|
local classes = attr_classes(attr)
|
272
251
|
|
273
|
-
local command =
|
274
|
-
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
|
275
254
|
if classes[k] then
|
276
255
|
command = v
|
277
256
|
break
|
278
257
|
end
|
279
258
|
end
|
280
|
-
command = command or "list"
|
281
259
|
|
282
260
|
local is_list = command == "list"
|
283
261
|
|
284
|
-
|
285
|
-
local num = (is_list == false) and "" or (
|
286
|
-
(classes["numberLines"] or classes["number-lines"] or classes["num"]) and
|
287
|
-
"num" or ""
|
288
|
-
)
|
262
|
+
local num = (is_list and (classes["numberLines"] or classes["number-lines"] or classes["num"])) and "num" or ""
|
289
263
|
|
290
264
|
local firstlinenum = ""
|
291
265
|
if is_list and (num == "num") then
|
292
|
-
for _, key in ipairs({"startFrom", "start-from", "firstlinenum"}) do
|
293
|
-
|
294
|
-
|
295
|
-
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"
|
296
269
|
break
|
297
270
|
end
|
298
271
|
end
|
299
272
|
end
|
300
273
|
|
301
274
|
local lang = ""
|
302
|
-
local not_lang = {numberLines = true, num = true, em = true, source = true}
|
275
|
+
local not_lang = { numberLines = true, num = true, em = true, source = true }
|
303
276
|
not_lang["number-lines"] = true
|
304
277
|
if is_list or (command == "source") then
|
305
|
-
for key,_ in pairs(classes) do
|
278
|
+
for key, _ in pairs(classes) do
|
306
279
|
if not_lang[key] ~= true then
|
307
280
|
lang = "[" .. key .. "]"
|
308
281
|
break
|
@@ -313,9 +286,9 @@ function CodeBlock(s, attr)
|
|
313
286
|
local caption = (command == "cmd") and "" or attr_val(attr, "caption")
|
314
287
|
local identifier = ""
|
315
288
|
local em = is_list and classes["em"] and "em" or ""
|
316
|
-
if
|
289
|
+
if caption ~= "" then
|
317
290
|
if is_list and (em == "") then
|
318
|
-
if
|
291
|
+
if attr.id ~= "" then
|
319
292
|
identifier = "[" .. attr.id .. "]"
|
320
293
|
else
|
321
294
|
list_num = list_num + 1
|
@@ -332,11 +305,7 @@ function CodeBlock(s, attr)
|
|
332
305
|
end
|
333
306
|
end
|
334
307
|
|
335
|
-
return (
|
336
|
-
firstlinenum ..
|
337
|
-
"//" .. em .. command .. num .. identifier .. caption .. lang ..
|
338
|
-
"{\n" .. s .. "\n//}"
|
339
|
-
)
|
308
|
+
return (firstlinenum .. "//" .. em .. command .. num .. identifier .. caption .. lang .. "{\n" .. s .. "\n//}")
|
340
309
|
end
|
341
310
|
|
342
311
|
function LineBlock(s)
|
@@ -345,7 +314,7 @@ function LineBlock(s)
|
|
345
314
|
end
|
346
315
|
|
347
316
|
function Link(s, src, tit)
|
348
|
-
if
|
317
|
+
if src == s then
|
349
318
|
return format_inline("href", src)
|
350
319
|
else
|
351
320
|
return format_inline("href", src .. "," .. s)
|
@@ -412,7 +381,7 @@ function Table(caption, aligns, widths, headers, rows)
|
|
412
381
|
add("--------------")
|
413
382
|
for _, row in pairs(rows) do
|
414
383
|
tmp = {}
|
415
|
-
|
384
|
+
for i, c in pairs(row) do
|
416
385
|
local align = html_align(aligns[i])
|
417
386
|
if (config.use_table_align == "true") and (align ~= "") then
|
418
387
|
c = format_inline("dtp", "table align=" .. align) .. c
|
@@ -426,13 +395,6 @@ function Table(caption, aligns, widths, headers, rows)
|
|
426
395
|
return table.concat(buffer, "\n")
|
427
396
|
end
|
428
397
|
|
429
|
-
function Image(s, src, tit)
|
430
|
-
-- Re:VIEW @<icon> ignores caption and title
|
431
|
-
local id = string.gsub(src, "%.%w+$", "")
|
432
|
-
id = string.gsub(id, "^images/", "")
|
433
|
-
return format_inline("icon", id)
|
434
|
-
end
|
435
|
-
|
436
398
|
function CaptionedImage(s, src, tit, attr)
|
437
399
|
local path = "[" .. s:gsub("%.%w+$", ""):gsub("^images/", "") .. "]"
|
438
400
|
|
@@ -442,7 +404,7 @@ function CaptionedImage(s, src, tit, attr)
|
|
442
404
|
if scale == "" then
|
443
405
|
local width = attr_scale(attr, "width")
|
444
406
|
local height = attr_scale(attr, "height")
|
445
|
-
if
|
407
|
+
if width ~= "" then
|
446
408
|
if (height ~= "") and (width ~= height) then
|
447
409
|
log("WARNING: Image width and height must be same. Using width.\n")
|
448
410
|
end
|
@@ -455,26 +417,15 @@ function CaptionedImage(s, src, tit, attr)
|
|
455
417
|
scale = "[scale=" .. scale .. "]"
|
456
418
|
end
|
457
419
|
|
458
|
-
local command = "//image"
|
459
|
-
local caption = ""
|
460
|
-
if (tit == "") then
|
461
|
-
command = "//indepimage"
|
462
|
-
else
|
463
|
-
caption = "[" .. tit .. "]"
|
464
|
-
end
|
420
|
+
local command = tit == "" and "//indepimage" or "//image"
|
421
|
+
local caption = tit == "" and "" or ("[" .. tit .. "]")
|
465
422
|
|
466
|
-
return (
|
467
|
-
command .. path .. caption .. scale .. "{" .. comment .. "\n//}"
|
468
|
-
)
|
423
|
+
return (command .. path .. caption .. scale .. "{" .. comment .. "\n//}")
|
469
424
|
end
|
470
425
|
|
471
426
|
function Image(s, src, tit, attr)
|
472
427
|
-- Re:VIEW @<icon> ignores caption and title
|
473
|
-
|
474
|
-
return CaptionedImage(src, s, tit, attr)
|
475
|
-
end
|
476
|
-
local id = string.gsub(src, "%.%w+$", "")
|
477
|
-
id = string.gsub(id, "^images/", "")
|
428
|
+
local id = src:gsub("%.%w+$", ""):gsub("^images/", "")
|
478
429
|
return format_inline("icon", id)
|
479
430
|
end
|
480
431
|
|
@@ -490,12 +441,7 @@ function Cite(s, cs)
|
|
490
441
|
end
|
491
442
|
|
492
443
|
function Quoted(quotetype, s)
|
493
|
-
|
494
|
-
return SingleQuoted(s)
|
495
|
-
end
|
496
|
-
if (quotetype == "DoubleQuote") then
|
497
|
-
return DoubleQuoted(s)
|
498
|
-
end
|
444
|
+
return _G[quotetype](s)
|
499
445
|
end
|
500
446
|
|
501
447
|
function SingleQuoted(s)
|
@@ -511,13 +457,9 @@ function SmallCaps(s)
|
|
511
457
|
end
|
512
458
|
|
513
459
|
function Div(s, attr)
|
514
|
-
local blankline =
|
515
|
-
if blankline
|
516
|
-
|
517
|
-
for _ = 1, tonumber(blankline) do
|
518
|
-
table.insert(buffer, "//blankline")
|
519
|
-
end
|
520
|
-
return table.concat(buffer, "\n")
|
460
|
+
local blankline = tonumber(attr.blankline)
|
461
|
+
if blankline then
|
462
|
+
return string.rep("//blankline\n", blankline):gsub("\n$", "")
|
521
463
|
end
|
522
464
|
|
523
465
|
local classes = attr_classes(attr)
|
@@ -531,15 +473,11 @@ function Div(s, attr)
|
|
531
473
|
end
|
532
474
|
|
533
475
|
if classes["review-internal"] then
|
534
|
-
s, _ = s:gsub(
|
535
|
-
"%]{<P2RREMOVEBELOW/>\n", "]{"
|
536
|
-
):gsub(
|
537
|
-
"\n<P2RREMOVEABOVE/>//}", "//}"
|
538
|
-
)
|
476
|
+
s, _ = s:gsub("%]{<P2RREMOVEBELOW/>\n", "]{"):gsub("\n<P2RREMOVEABOVE/>//}", "//}")
|
539
477
|
return s
|
540
478
|
end
|
541
479
|
|
542
|
-
for cls,_ in pairs(classes) do
|
480
|
+
for cls, _ in pairs(classes) do
|
543
481
|
s = "//" .. cls .. "{\n" .. s .. "\n//}"
|
544
482
|
end
|
545
483
|
return s
|
@@ -548,7 +486,7 @@ end
|
|
548
486
|
function Span(s, attr)
|
549
487
|
-- ruby and kw with a supplement
|
550
488
|
local a = ""
|
551
|
-
for _, cmd in ipairs({"ruby", "kw"}) do
|
489
|
+
for _, cmd in ipairs({ "ruby", "kw" }) do
|
552
490
|
a = attr_val(attr, cmd)
|
553
491
|
if a ~= "" then
|
554
492
|
s = format_inline(cmd, s .. "," .. a)
|
@@ -566,15 +504,15 @@ function Span(s, attr)
|
|
566
504
|
end
|
567
505
|
|
568
506
|
function RawInline(format, text)
|
569
|
-
if
|
507
|
+
if format == "review" then
|
570
508
|
return text
|
571
509
|
end
|
572
510
|
|
573
|
-
if
|
511
|
+
if metadata.hideraw then
|
574
512
|
return ""
|
575
513
|
end
|
576
514
|
|
577
|
-
if
|
515
|
+
if format == "tex" then
|
578
516
|
return format_inline("embed", "|latex|" .. text)
|
579
517
|
else
|
580
518
|
return format_inline("embed", "|" .. format .. "|" .. text)
|
@@ -582,15 +520,15 @@ function RawInline(format, text)
|
|
582
520
|
end
|
583
521
|
|
584
522
|
function RawBlock(format, text)
|
585
|
-
if
|
523
|
+
if format == "review" then
|
586
524
|
return text
|
587
525
|
end
|
588
526
|
|
589
|
-
if
|
527
|
+
if metadata.hideraw then
|
590
528
|
return ""
|
591
529
|
end
|
592
530
|
|
593
|
-
if
|
531
|
+
if format == "tex" then
|
594
532
|
return "//embed[latex]{\n" .. text .. "\n//}"
|
595
533
|
else
|
596
534
|
return "//embed[" .. format .. "]{\n" .. text .. "\n//}"
|
@@ -598,16 +536,16 @@ function RawBlock(format, text)
|
|
598
536
|
end
|
599
537
|
|
600
538
|
local function configure()
|
601
|
-
try_catch
|
539
|
+
try_catch({
|
602
540
|
try = function()
|
603
541
|
metadata = PANDOC_DOCUMENT.meta
|
604
542
|
end,
|
605
543
|
catch = function(error)
|
606
544
|
log("Due to your pandoc version is too old, config.yml loader is disabled.\n")
|
607
|
-
end
|
608
|
-
}
|
545
|
+
end,
|
546
|
+
})
|
609
547
|
|
610
|
-
if
|
548
|
+
if metadata then
|
611
549
|
-- Load config from YAML
|
612
550
|
for k, _ in pairs(config) do
|
613
551
|
if metadata[k] ~= nil then
|
@@ -617,23 +555,225 @@ local function configure()
|
|
617
555
|
end
|
618
556
|
end
|
619
557
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
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
|
629
568
|
configure()
|
569
|
+
return
|
630
570
|
end
|
631
571
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
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))
|
613
|
+
end
|
614
|
+
return concat(buff, sep)
|
615
|
+
end
|
616
|
+
|
617
|
+
Inlines.Str = function(el)
|
618
|
+
return Str(el.text)
|
619
|
+
end
|
620
|
+
|
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
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
|
638
699
|
|
639
|
-
|
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
|