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.
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 "pandoc.utils").stringify
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 = true,
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 (string.match(s, "{") or string.match(s, "}")) then
87
- if (string.match(s, "%$")) then -- use % for regexp escape
88
- if (string.match(s, "|")) then
89
- -- give up. escape } by \}
90
- return "{" .. string.gsub(s, "}", "\\}") .. "}"
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
- return "{" .. s .. "}"
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
- if align == "AlignLeft" then
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, metadata, variables)
124
- local buffer = {}
125
- local function add(s)
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(buffer, "\n")
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
- if (metadata.softbreak) then
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
- local attr_table = {}
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 Header(level, s, attr)
198
- local headmark = ""
199
- for i = 1, level do
200
- headmark = headmark .. "="
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
- local classes = attr_classes(attr)
180
+ -- Pandoc's behavior
181
+ if classes.unnumbered then
182
+ return classes.unlisted and "[notoc]" or "[nonum]"
183
+ end
204
184
 
205
- headmark = headmark .. (
206
- -- Re:VIEW's behavior
207
- classes["column"] and "[column]" or (
208
- classes["nonum"] and "[nonum]" or (
209
- classes["nodisp"] and "[nodisp]" or (
210
- classes["notoc"] and "[notoc]" or (
211
- -- Pandoc's behavior
212
- classes["unnumbered"] and (
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
- if (config.use_hr == "true") then
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+", '\n\n%1\n\n'
235
- ):gsub("\n+(//endchild)\n+", '\n\n%1\n\n'
236
- ):gsub("\n+(//endchild)\n*$", "\n\n%1")
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 = nil
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 == false) and "" or (
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
- firstlinenum = attr_val(attr, key)
303
- if firstlinenum ~= "" then
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 (caption ~= "") then
289
+ if caption ~= "" then
326
290
  if is_list and (em == "") then
327
- if (attr.id ~= "") then
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 (src == s) then
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
- for i, c in pairs(row) do
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 (width ~= "") then
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
- if attr.is_figure then
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
- if (quotetype == "SingleQuote") then
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 = attr_val(attr, "blankline")
524
- if blankline ~= "" then
525
- local buffer = {}
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 (format == "review") then
507
+ if format == "review" then
579
508
  return text
580
509
  end
581
510
 
582
- if (metadata.hideraw) then
511
+ if metadata.hideraw then
583
512
  return ""
584
513
  end
585
514
 
586
- if (format == "tex") then
515
+ if format == "tex" then
587
516
  return format_inline("embed", "|latex|" .. text)
588
517
  else
589
- return format_inline("embed", "|" .. format .. "|", text)
518
+ return format_inline("embed", "|" .. format .. "|" .. text)
590
519
  end
591
520
  end
592
521
 
593
522
  function RawBlock(format, text)
594
- if (format == "review") then
523
+ if format == "review" then
595
524
  return text
596
525
  end
597
526
 
598
- if (metadata.hideraw) then
527
+ if metadata.hideraw then
599
528
  return ""
600
529
  end
601
530
 
602
- if (format == "tex") then
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 (metadata) then
548
+ if metadata then
620
549
  -- Load config from YAML
621
- for k,v in pairs(config) do
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
- if PANDOC_VERSION >= "3.0.0" then
630
- -- NOTE: A wrapper to support Pandoc >= 3.0 https://pandoc.org/custom-writers.html#changes-in-pandoc-3.0
631
- function Writer (doc, opts)
632
- PANDOC_DOCUMENT = doc
633
- PANDOC_WRITER_OPTIONS = opts
634
- configure()
635
- return pandoc.write_classic(doc, opts)
636
- end
637
- else
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
- local meta = {}
642
- meta.__index =
643
- function(_, key)
644
- log(string.format("WARNING: Undefined function '%s'\n", key))
645
- return function() return "" end
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
- setmetatable(_G, meta)
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