pandoc2review 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/pandoc.yml +18 -0
- data/.gitignore +47 -0
- data/Gemfile +6 -0
- data/LICENSE +339 -0
- data/README.md +105 -0
- data/Rakefile +13 -0
- data/exe/pandoc2review +12 -0
- data/lib/pandoc2review.rb +99 -0
- data/lua/filters.lua +163 -0
- data/lua/review.lua +620 -0
- data/markdown-format.ja.md +721 -0
- data/pandoc2review.gemspec +29 -0
- data/samples/format.md +276 -0
- data/samples/reviewsample/.gitignore +154 -0
- data/samples/reviewsample/Gemfile +4 -0
- data/samples/reviewsample/Rakefile +3 -0
- data/samples/reviewsample/catalog.yml +10 -0
- data/samples/reviewsample/ch01.md +38 -0
- data/samples/reviewsample/ch02.re +3 -0
- data/samples/reviewsample/config-ebook.yml +6 -0
- data/samples/reviewsample/config.yml +20 -0
- data/samples/reviewsample/images/cover-a5.ai +5836 -16
- data/samples/reviewsample/images/cover.jpg +0 -0
- data/samples/reviewsample/images/pandoc2review.png +0 -0
- data/samples/reviewsample/lib/tasks/review.rake +128 -0
- data/samples/reviewsample/lib/tasks/z01_pandoc2review.rake +69 -0
- data/samples/reviewsample/sty/README.md +168 -0
- data/samples/reviewsample/sty/gentombow.sty +769 -0
- data/samples/reviewsample/sty/jsbook.cls +2072 -0
- data/samples/reviewsample/sty/jumoline.sty +310 -0
- data/samples/reviewsample/sty/plistings.sty +326 -0
- data/samples/reviewsample/sty/review-base.sty +530 -0
- data/samples/reviewsample/sty/review-custom.sty +1 -0
- data/samples/reviewsample/sty/review-jsbook.cls +503 -0
- data/samples/reviewsample/sty/review-style.sty +49 -0
- data/samples/reviewsample/sty/reviewmacro.sty +15 -0
- data/samples/reviewsample/style.css +494 -0
- metadata +128 -0
data/Rakefile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rake/testtask"
|
3
|
+
|
4
|
+
desc 'Run tests'
|
5
|
+
task :test, :target do |_, argv|
|
6
|
+
if argv[:target].nil?
|
7
|
+
ruby('test/run_test.rb')
|
8
|
+
else
|
9
|
+
ruby('test/run_test.rb', "--pattern=#{argv[:target]}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :test
|
data/exe/pandoc2review
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright 2020-2021 Kenshi Muto
|
4
|
+
|
5
|
+
require 'pathname'
|
6
|
+
bindir = Pathname.new(__FILE__).realpath.dirname
|
7
|
+
$LOAD_PATH.unshift((bindir + '../lib').realpath)
|
8
|
+
|
9
|
+
require 'pandoc2review'
|
10
|
+
|
11
|
+
p2r = Pandoc2ReVIEW.new
|
12
|
+
p2r.main
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright 2020-2021 Kenshi Muto
|
3
|
+
require 'optparse'
|
4
|
+
require 'unicode/eaw'
|
5
|
+
require 'pathname'
|
6
|
+
require 'open3'
|
7
|
+
|
8
|
+
class Pandoc2ReVIEW
|
9
|
+
def main
|
10
|
+
luadir = ((Pathname.new(__FILE__)).realpath.dirname + '../lua').realpath
|
11
|
+
parse_args
|
12
|
+
|
13
|
+
ARGV.each do |file|
|
14
|
+
unless File.exist?(file)
|
15
|
+
puts "#{file} not exist. skip."
|
16
|
+
next
|
17
|
+
end
|
18
|
+
args = ['pandoc', '-t', File.join(luadir, 'review.lua'), '--lua-filter', File.join(luadir, 'filters.lua')]
|
19
|
+
|
20
|
+
if file =~ /\.md$/i
|
21
|
+
args += ['-f', 'markdown-auto_identifiers-smart+east_asian_line_breaks']
|
22
|
+
|
23
|
+
if @disableeaw
|
24
|
+
args += ['-M', "softbreak:true"]
|
25
|
+
end
|
26
|
+
|
27
|
+
if @hideraw
|
28
|
+
args += ['-M', "hideraw:true"]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if @heading
|
33
|
+
args += ["--shift-heading-level-by=#{@heading}"]
|
34
|
+
end
|
35
|
+
|
36
|
+
args.push(file)
|
37
|
+
|
38
|
+
stdout, stderr, status = Open3.capture3(*args)
|
39
|
+
unless status.success?
|
40
|
+
STDERR.puts stderr
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
print modify_result(stdout)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_args
|
48
|
+
@heading = nil
|
49
|
+
@disableeaw = nil
|
50
|
+
@hideraw = nil
|
51
|
+
opts = OptionParser.new
|
52
|
+
opts.banner = 'Usage: pandoc2review [option] file [file ...]'
|
53
|
+
opts.version = '1.2'
|
54
|
+
|
55
|
+
opts.on('--help', 'Prints this message and quit.') do
|
56
|
+
puts opts.help
|
57
|
+
exit 0
|
58
|
+
end
|
59
|
+
opts.on('--shiftheading num', 'Add <num> to heading level.') do |v|
|
60
|
+
@heading = v
|
61
|
+
end
|
62
|
+
opts.on('--disable-eaw', "Disable compositing a paragraph with Ruby's EAW library.") do
|
63
|
+
@disableeaw = true
|
64
|
+
end
|
65
|
+
opts.on('--hideraw', "Hide raw inline/block with no review format specified.") do
|
66
|
+
@hideraw = true
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.parse!(ARGV)
|
70
|
+
if ARGV.size != 1
|
71
|
+
puts opts.help
|
72
|
+
exit 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def modify_result(s)
|
77
|
+
s.gsub('<P2RBR/>') do
|
78
|
+
tail = $`[-1]
|
79
|
+
head = $'[0]
|
80
|
+
return '' if tail.nil? || head.nil?
|
81
|
+
|
82
|
+
space = ' '
|
83
|
+
if %i[F W H].include?(Unicode::Eaw.property(tail)) &&
|
84
|
+
%i[F W H].include?(Unicode::Eaw.property(head)) &&
|
85
|
+
tail !~ /\p{Hangul}/ && head !~ /\p{Hangul}/
|
86
|
+
space = ''
|
87
|
+
end
|
88
|
+
|
89
|
+
if (%i[F W H].include?(Unicode::Eaw.property(tail)) &&
|
90
|
+
tail !~ /\p{Hangul}/) ||
|
91
|
+
(%i[F W H].include?(Unicode::Eaw.property(head)) &&
|
92
|
+
head !~ /\p{Hangul}/)
|
93
|
+
space = ''
|
94
|
+
end
|
95
|
+
|
96
|
+
space
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lua/filters.lua
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
local function review_inline(x)
|
2
|
+
return pandoc.RawInline("review", x)
|
3
|
+
end
|
4
|
+
|
5
|
+
local beginchild = {pandoc.Plain(review_inline("//beginchild"))}
|
6
|
+
local endchild = {pandoc.Plain(review_inline("//endchild"))}
|
7
|
+
|
8
|
+
local function markdown(text)
|
9
|
+
return(pandoc.read(text, "markdown").blocks[1].content)
|
10
|
+
end
|
11
|
+
|
12
|
+
local function support_blankline(constructor)
|
13
|
+
--[[
|
14
|
+
Returns a function that splits a block into blocks separated by a Div
|
15
|
+
element which defines blank lines.
|
16
|
+
The Re:VIEW Lua writer subsequently transforms the Div element into
|
17
|
+
`//blankline` commands.
|
18
|
+
]]
|
19
|
+
local construct = constructor or pandoc.Para
|
20
|
+
return function(x)
|
21
|
+
local blocks = {construct({})}
|
22
|
+
local i = 1
|
23
|
+
local n_break = 0
|
24
|
+
local content = blocks[i].content
|
25
|
+
|
26
|
+
for j, elem in ipairs(x.content) do
|
27
|
+
if elem.tag == "LineBreak" then
|
28
|
+
-- Count the repeated number of LineBreak
|
29
|
+
n_break = n_break + 1
|
30
|
+
elseif n_break == 1 then
|
31
|
+
-- Do nothing if LineBreak is not repeated
|
32
|
+
table.insert(content, pandoc.LineBreak())
|
33
|
+
table.insert(content, elem)
|
34
|
+
n_break = 0
|
35
|
+
elseif n_break > 1 then
|
36
|
+
-- Convert LineBreak's into //blankline commands
|
37
|
+
table.insert(blocks, pandoc.Div({}, {blankline = n_break - 1}))
|
38
|
+
table.insert(blocks, construct({elem}))
|
39
|
+
i = i + 2
|
40
|
+
content = blocks[i].content
|
41
|
+
n_break = 0
|
42
|
+
else
|
43
|
+
-- Do nothing on elements other than LineBreak
|
44
|
+
table.insert(content, elem)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
return blocks
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
local function nestablelist(elem)
|
53
|
+
--[[
|
54
|
+
Support items with multiple blocks in
|
55
|
+
BulletList, OrderedList, and DefinitionList.
|
56
|
+
]]
|
57
|
+
for _, block in ipairs(elem.content) do
|
58
|
+
local second = block[2]
|
59
|
+
if second then
|
60
|
+
if second.tag == "BulletList" then
|
61
|
+
table.insert(second.content, 1, beginchild)
|
62
|
+
elseif second.tag then
|
63
|
+
table.insert(block, 2, pandoc.BulletList(beginchild))
|
64
|
+
else
|
65
|
+
for _,definition in ipairs(second) do
|
66
|
+
if definition[2] then
|
67
|
+
table.insert(definition, 2, pandoc.BulletList(beginchild))
|
68
|
+
table.insert(definition, pandoc.BulletList(endchild))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
local last = block[#block]
|
74
|
+
if last.tag == "BulletList" then
|
75
|
+
table.insert(last.content, endchild)
|
76
|
+
elseif last.tag then
|
77
|
+
table.insert(block, pandoc.BulletList(endchild))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
return elem
|
82
|
+
end
|
83
|
+
|
84
|
+
local function support_strong(child)
|
85
|
+
--[[
|
86
|
+
Returns a function that converts `***text***` as Span with the strong class
|
87
|
+
(i.e., `[text]{.strong}`).
|
88
|
+
Pandoc treats `***` as Emph wrapped by Strong, but is not documented.
|
89
|
+
This filter also supports the inverse order just for sure.
|
90
|
+
|
91
|
+
The Lua writer, review.lua, further converts the text to `@strong{text}`
|
92
|
+
]]
|
93
|
+
return function(elem)
|
94
|
+
if (#elem.content == 1) and (elem.content[1].tag == child) then
|
95
|
+
return pandoc.Span(elem.content[1].content, {class = 'strong'})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
local function caption_div(div)
|
101
|
+
local class = div.classes[1]
|
102
|
+
local caption = div.attributes.caption
|
103
|
+
|
104
|
+
if ((#div.content == 1) and
|
105
|
+
(#div.content[1].content == 1) and
|
106
|
+
(div.content[1].content[1].tag == "Math") and
|
107
|
+
(div.identifier)) then
|
108
|
+
class = "texequation[" .. div.identifier .. "]"
|
109
|
+
local math_text = (div.content[1].content[1].text
|
110
|
+
):gsub("^\n+", ""):gsub("\n+$", "")
|
111
|
+
|
112
|
+
if caption == nil then
|
113
|
+
return pandoc.RawBlock(
|
114
|
+
"review",
|
115
|
+
"//" .. class .. "{\n" .. math_text .. "\n//}"
|
116
|
+
)
|
117
|
+
end
|
118
|
+
|
119
|
+
div.content = {pandoc.RawBlock("review", math_text)}
|
120
|
+
end
|
121
|
+
|
122
|
+
if class == nil then
|
123
|
+
return nil
|
124
|
+
end
|
125
|
+
|
126
|
+
if caption then
|
127
|
+
local begin = pandoc.Para(markdown(caption))
|
128
|
+
table.insert(begin.content, 1, review_inline("//" .. class .. "["))
|
129
|
+
table.insert(begin.content, review_inline("]{<P2RREMOVEBELOW/>"))
|
130
|
+
table.insert(div.content, 1, begin)
|
131
|
+
table.insert(div.content, pandoc.RawBlock("review", "<P2RREMOVEABOVE/>//}"))
|
132
|
+
div.classes = {"review-internal"}
|
133
|
+
return div
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
local function noindent(para)
|
138
|
+
first = para.content[1]
|
139
|
+
|
140
|
+
if ((first.tag == "RawInline") and
|
141
|
+
(first.format == "tex") and
|
142
|
+
(first.text:match("^\\noindent%s*"))) then
|
143
|
+
para.content[1] = review_inline("//noindent\n")
|
144
|
+
if para.content[2].tag == "SoftBreak" then
|
145
|
+
table.remove(para.content, 2)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
return para
|
150
|
+
end
|
151
|
+
|
152
|
+
return {
|
153
|
+
{Emph = support_strong("Strong")},
|
154
|
+
{Strong = support_strong("Emph")},
|
155
|
+
{Plain = support_blankline(pandoc.Plain)},
|
156
|
+
{Para = support_blankline(pandoc.Para)},
|
157
|
+
{Para = noindent},
|
158
|
+
-- blankline must be processed before lists
|
159
|
+
{BulletList = nestablelist},
|
160
|
+
{OrderedList = nestablelist},
|
161
|
+
{DefinitionList = nestablelist},
|
162
|
+
{Div = caption_div}
|
163
|
+
}
|
data/lua/review.lua
ADDED
@@ -0,0 +1,620 @@
|
|
1
|
+
-- -*- coding: utf-8 -*-
|
2
|
+
-- Re:VIEW Writer for Pandoc
|
3
|
+
-- Copyright 2020 Kenshi Muto
|
4
|
+
|
5
|
+
-- config
|
6
|
+
local config = {
|
7
|
+
use_header_id = "true",
|
8
|
+
use_hr = "true",
|
9
|
+
use_table_align = "true",
|
10
|
+
|
11
|
+
bold = "b",
|
12
|
+
italic = "i",
|
13
|
+
code = "tt",
|
14
|
+
strike = "del",
|
15
|
+
underline = "u",
|
16
|
+
lineblock = "source", --- XXX: Re:VIEW doesn't provide poem style by default
|
17
|
+
}
|
18
|
+
|
19
|
+
-- counter
|
20
|
+
local table_num = 0
|
21
|
+
local list_num = 0
|
22
|
+
local fig_num = 0
|
23
|
+
local note_num = 0
|
24
|
+
local footnotes = {}
|
25
|
+
|
26
|
+
-- internal
|
27
|
+
local metadata = nil
|
28
|
+
local stringify = (require "pandoc.utils").stringify
|
29
|
+
local inline_commands = {
|
30
|
+
-- processed if given as classes of Span elements
|
31
|
+
-- true if syntax is `@<command>{string}`
|
32
|
+
--- formats
|
33
|
+
kw = true,
|
34
|
+
bou = true,
|
35
|
+
ami = true,
|
36
|
+
u = true,
|
37
|
+
b = true,
|
38
|
+
i = true,
|
39
|
+
strong = true,
|
40
|
+
em = true,
|
41
|
+
tt = true,
|
42
|
+
tti = true,
|
43
|
+
ttb = true,
|
44
|
+
code = true,
|
45
|
+
tcy = true,
|
46
|
+
--- ref
|
47
|
+
chap = true,
|
48
|
+
title = true,
|
49
|
+
chapref = true,
|
50
|
+
list = true,
|
51
|
+
img = true,
|
52
|
+
table = true,
|
53
|
+
eq = true,
|
54
|
+
hd = true,
|
55
|
+
column = true,
|
56
|
+
--- others
|
57
|
+
ruby = false,
|
58
|
+
br = false,
|
59
|
+
uchar = true,
|
60
|
+
href = false,
|
61
|
+
icon = true,
|
62
|
+
m = true,
|
63
|
+
w = true,
|
64
|
+
wb = true,
|
65
|
+
raw = false,
|
66
|
+
embed = false,
|
67
|
+
idx = true,
|
68
|
+
hidx = true,
|
69
|
+
balloon = true,
|
70
|
+
}
|
71
|
+
|
72
|
+
local function try_catch(what)
|
73
|
+
-- ref: http://bushimichi.blogspot.com/2016/11/lua-try-catch.html
|
74
|
+
local status, result = pcall(what.try)
|
75
|
+
if not status then
|
76
|
+
what.catch(result)
|
77
|
+
end
|
78
|
+
return result
|
79
|
+
end
|
80
|
+
|
81
|
+
local function log(s)
|
82
|
+
io.stderr:write(s)
|
83
|
+
end
|
84
|
+
|
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
|
99
|
+
end
|
100
|
+
return "{" .. s .. "}"
|
101
|
+
end
|
102
|
+
|
103
|
+
local function format_inline(fmt, s)
|
104
|
+
return string.format("@<%s>%s", fmt, surround_inline(s))
|
105
|
+
end
|
106
|
+
|
107
|
+
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
|
117
|
+
end
|
118
|
+
|
119
|
+
function Blocksep()
|
120
|
+
return "\n\n"
|
121
|
+
end
|
122
|
+
|
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"))
|
131
|
+
end
|
132
|
+
return table.concat(buffer, "\n")
|
133
|
+
end
|
134
|
+
|
135
|
+
function Str(s)
|
136
|
+
return s
|
137
|
+
end
|
138
|
+
|
139
|
+
function Space()
|
140
|
+
return " "
|
141
|
+
end
|
142
|
+
|
143
|
+
function LineBreak()
|
144
|
+
return "@<br>{}"
|
145
|
+
end
|
146
|
+
|
147
|
+
function SoftBreak(s)
|
148
|
+
if (metadata.softbreak) then
|
149
|
+
return " "
|
150
|
+
else
|
151
|
+
return "<P2RBR/>"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
function Plain(s)
|
156
|
+
return s
|
157
|
+
end
|
158
|
+
|
159
|
+
function Para(s)
|
160
|
+
return s
|
161
|
+
end
|
162
|
+
|
163
|
+
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 ""
|
171
|
+
end
|
172
|
+
|
173
|
+
local function attr_classes(attr)
|
174
|
+
local classes = {}
|
175
|
+
|
176
|
+
for cls in attr_val(attr, "class"):gmatch("[^%s]+") do
|
177
|
+
classes[cls] = true
|
178
|
+
end
|
179
|
+
return classes
|
180
|
+
end
|
181
|
+
|
182
|
+
local function attr_scale(attr, key) -- a helper for CaptionedImage
|
183
|
+
scale = attr_val(attr, key)
|
184
|
+
if (scale == "") or (key == "scale") then
|
185
|
+
return scale
|
186
|
+
end
|
187
|
+
|
188
|
+
scale, count = scale:gsub("%%$", "")
|
189
|
+
if count == 0 then
|
190
|
+
log("WARNING: Units must be % for `" .. key .. "` of Image. Ignored.\n")
|
191
|
+
return ""
|
192
|
+
end
|
193
|
+
|
194
|
+
return tonumber(scale) / 100
|
195
|
+
end
|
196
|
+
|
197
|
+
function Header(level, s, attr)
|
198
|
+
local headmark = ""
|
199
|
+
for i = 1, level do
|
200
|
+
headmark = headmark .. "="
|
201
|
+
end
|
202
|
+
|
203
|
+
local classes = attr_classes(attr)
|
204
|
+
|
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
|
219
|
+
headmark = headmark .. "{" .. attr.id .. "}"
|
220
|
+
end
|
221
|
+
|
222
|
+
return headmark .. " " .. s
|
223
|
+
end
|
224
|
+
|
225
|
+
function HorizontalRule()
|
226
|
+
if (config.use_hr == "true") then
|
227
|
+
return "//hr"
|
228
|
+
else
|
229
|
+
return ""
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
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")
|
237
|
+
end
|
238
|
+
|
239
|
+
function BulletList(items)
|
240
|
+
local buffer = {}
|
241
|
+
for _, item in pairs(items) do
|
242
|
+
if (item == "//beginchild") or (item == "//endchild") then
|
243
|
+
table.insert(buffer, item)
|
244
|
+
else
|
245
|
+
table.insert(buffer, " * " .. item)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
return lint_list(table.concat(buffer, "\n"))
|
249
|
+
end
|
250
|
+
|
251
|
+
function OrderedList(items, start)
|
252
|
+
local buffer = {}
|
253
|
+
local n = start
|
254
|
+
for _, item in pairs(items) do
|
255
|
+
if (item == "//beginchild") or (item == "//endchild") then
|
256
|
+
table.insert(buffer, item)
|
257
|
+
else
|
258
|
+
table.insert(buffer, " " .. n .. ". " .. item)
|
259
|
+
n = n + 1
|
260
|
+
end
|
261
|
+
end
|
262
|
+
return lint_list(table.concat(buffer, "\n"))
|
263
|
+
end
|
264
|
+
|
265
|
+
function DefinitionList(items)
|
266
|
+
local buffer = {}
|
267
|
+
for _, item in pairs(items) do
|
268
|
+
for k, v in pairs(item) do
|
269
|
+
table.insert(buffer, " : " .. k .. "\n\t" .. table.concat(v, "\n"))
|
270
|
+
end
|
271
|
+
end
|
272
|
+
return lint_list(table.concat(buffer, "\n") .. "\n")
|
273
|
+
end
|
274
|
+
|
275
|
+
function BlockQuote(s)
|
276
|
+
return "//quote{\n" .. s .. "\n//}"
|
277
|
+
end
|
278
|
+
|
279
|
+
function CodeBlock(s, attr)
|
280
|
+
local classes = attr_classes(attr)
|
281
|
+
|
282
|
+
local command = nil
|
283
|
+
for k,v in pairs({cmd = "cmd", source = "source", quote = "source"}) do
|
284
|
+
if classes[k] then
|
285
|
+
command = v
|
286
|
+
break
|
287
|
+
end
|
288
|
+
end
|
289
|
+
command = command or "list"
|
290
|
+
|
291
|
+
is_list = command == "list"
|
292
|
+
|
293
|
+
|
294
|
+
local num = (is_list == false) and "" or (
|
295
|
+
(classes["numberLines"] or classes["number-lines"] or classes["num"]) and
|
296
|
+
"num" or ""
|
297
|
+
)
|
298
|
+
|
299
|
+
local firstlinenum = ""
|
300
|
+
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"
|
305
|
+
break
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
local lang = ""
|
311
|
+
local not_lang = {numberLines = true, num = true, em = true, source = true}
|
312
|
+
not_lang["number-lines"] = true
|
313
|
+
if is_list or (command == "source") then
|
314
|
+
for key,_ in pairs(classes) do
|
315
|
+
if not_lang[key] ~= true then
|
316
|
+
lang = "[" .. key .. "]"
|
317
|
+
break
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
local caption = (command == "cmd") and "" or attr_val(attr, "caption")
|
323
|
+
local identifier = ""
|
324
|
+
local em = is_list and classes["em"] and "em" or ""
|
325
|
+
if (caption ~= "") then
|
326
|
+
if is_list and (em == "") then
|
327
|
+
if (attr.id ~= "") then
|
328
|
+
identifier = "[" .. attr.id .. "]"
|
329
|
+
else
|
330
|
+
list_num = list_num + 1
|
331
|
+
identifier = "[list" .. list_num .. "]"
|
332
|
+
end
|
333
|
+
end
|
334
|
+
caption = "[" .. caption .. "]"
|
335
|
+
else
|
336
|
+
if is_list then
|
337
|
+
em = "em"
|
338
|
+
end
|
339
|
+
if lang ~= "" then
|
340
|
+
caption = "[" .. caption .. "]"
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
return (
|
345
|
+
firstlinenum ..
|
346
|
+
"//" .. em .. command .. num .. identifier .. caption .. lang ..
|
347
|
+
"{\n" .. s .. "\n//}"
|
348
|
+
)
|
349
|
+
end
|
350
|
+
|
351
|
+
function LineBlock(s)
|
352
|
+
-- | block
|
353
|
+
return "//" .. config.lineblock .. "{\n" .. table.concat(s, "\n") .. "\n//}"
|
354
|
+
end
|
355
|
+
|
356
|
+
function Link(s, src, tit)
|
357
|
+
if (src == s) then
|
358
|
+
return format_inline("href", src)
|
359
|
+
else
|
360
|
+
return format_inline("href", src .. "," .. s)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
function Code(s, attr)
|
365
|
+
-- ignore attr
|
366
|
+
return format_inline(config.code, s)
|
367
|
+
end
|
368
|
+
|
369
|
+
function Emph(s)
|
370
|
+
return format_inline(config.italic, s)
|
371
|
+
end
|
372
|
+
|
373
|
+
function Strong(s)
|
374
|
+
return format_inline(config.bold, s)
|
375
|
+
end
|
376
|
+
|
377
|
+
function Strikeout(s)
|
378
|
+
return format_inline(config.strike, s)
|
379
|
+
end
|
380
|
+
|
381
|
+
function Underline(s)
|
382
|
+
return format_inline(config.underline, s)
|
383
|
+
end
|
384
|
+
|
385
|
+
function Subscript(s)
|
386
|
+
return format_inline("sub", s)
|
387
|
+
end
|
388
|
+
|
389
|
+
function Superscript(s)
|
390
|
+
return format_inline("sup", s)
|
391
|
+
end
|
392
|
+
|
393
|
+
function InlineMath(s)
|
394
|
+
return format_inline("m", s)
|
395
|
+
end
|
396
|
+
|
397
|
+
function DisplayMath(s)
|
398
|
+
return format_inline("m", "\\displaystyle{}" .. s)
|
399
|
+
end
|
400
|
+
|
401
|
+
function Table(caption, aligns, widths, headers, rows)
|
402
|
+
local buffer = {}
|
403
|
+
local function add(s)
|
404
|
+
table.insert(buffer, s)
|
405
|
+
end
|
406
|
+
if caption ~= "" then
|
407
|
+
table_num = table_num + 1
|
408
|
+
add("//table[table" .. table_num .. "][" .. caption .. "]{")
|
409
|
+
else
|
410
|
+
add("//table{")
|
411
|
+
end
|
412
|
+
local tmp = {}
|
413
|
+
for i, h in pairs(headers) do
|
414
|
+
align = html_align(aligns[i])
|
415
|
+
if (config.use_table_align == "true") and (align ~= "") then
|
416
|
+
h = format_inline("dtp", "table align=" .. align) .. h
|
417
|
+
end
|
418
|
+
table.insert(tmp, h)
|
419
|
+
end
|
420
|
+
add(table.concat(tmp, "\t"))
|
421
|
+
add("--------------")
|
422
|
+
for _, row in pairs(rows) do
|
423
|
+
tmp = {}
|
424
|
+
for i, c in pairs(row) do
|
425
|
+
align = html_align(aligns[i])
|
426
|
+
if (config.use_table_align == "true") and (align ~= "") then
|
427
|
+
c = format_inline("dtp", "table align=" .. align) .. c
|
428
|
+
end
|
429
|
+
table.insert(tmp, c)
|
430
|
+
end
|
431
|
+
add(table.concat(tmp, "\t"))
|
432
|
+
end
|
433
|
+
add("//}")
|
434
|
+
|
435
|
+
return table.concat(buffer, "\n")
|
436
|
+
end
|
437
|
+
|
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
|
+
function CaptionedImage(s, src, tit, attr)
|
446
|
+
local path = "[" .. s:gsub("%.%w+$", ""):gsub("^images/", "") .. "]"
|
447
|
+
|
448
|
+
local comment = src:gsub("^fig:", ""):gsub("(.+)", "\n%1")
|
449
|
+
|
450
|
+
local scale = attr_scale(attr, "scale")
|
451
|
+
if scale == "" then
|
452
|
+
local width = attr_scale(attr, "width")
|
453
|
+
local height = attr_scale(attr, "height")
|
454
|
+
if (width ~= "") then
|
455
|
+
if (height ~= "") and (width ~= height) then
|
456
|
+
log("WARNING: Image width and height must be same. Using width.\n")
|
457
|
+
end
|
458
|
+
scale = width
|
459
|
+
else
|
460
|
+
scale = height
|
461
|
+
end
|
462
|
+
end
|
463
|
+
if scale ~= "" then
|
464
|
+
scale = "[scale=" .. scale .. "]"
|
465
|
+
end
|
466
|
+
|
467
|
+
local command = "//image"
|
468
|
+
local caption = ""
|
469
|
+
if (tit == "") then
|
470
|
+
command = "//indepimage"
|
471
|
+
else
|
472
|
+
caption = "[" .. tit .. "]"
|
473
|
+
end
|
474
|
+
|
475
|
+
return (
|
476
|
+
command .. path .. caption .. scale .. "{" .. comment .. "\n//}"
|
477
|
+
)
|
478
|
+
end
|
479
|
+
|
480
|
+
function Note(s)
|
481
|
+
note_num = note_num + 1
|
482
|
+
table.insert(footnotes, "//footnote[fn" .. note_num .. "][" .. s .. "]")
|
483
|
+
return format_inline("fn", "fn" .. note_num)
|
484
|
+
end
|
485
|
+
|
486
|
+
function Cite(s, cs)
|
487
|
+
-- use @ as is.
|
488
|
+
return s
|
489
|
+
end
|
490
|
+
|
491
|
+
function Quoted(quotetype, s)
|
492
|
+
if (quotetype == "SingleQuote") then
|
493
|
+
return SingleQuoted(s)
|
494
|
+
end
|
495
|
+
if (quotetype == "DoubleQuote") then
|
496
|
+
return DoubleQuoted(s)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
function SingleQuoted(s)
|
501
|
+
return "'" .. s .. "'"
|
502
|
+
end
|
503
|
+
|
504
|
+
function DoubleQuoted(s)
|
505
|
+
return '"' .. s .. '"'
|
506
|
+
end
|
507
|
+
|
508
|
+
function SmallCaps(s)
|
509
|
+
return "◆→SMALLCAPS:" .. s .. "←◆"
|
510
|
+
end
|
511
|
+
|
512
|
+
function Div(s, attr)
|
513
|
+
local blankline = attr_val(attr, "blankline")
|
514
|
+
if blankline ~= "" then
|
515
|
+
local buffer = {}
|
516
|
+
for i = 1, tonumber(blankline) do
|
517
|
+
table.insert(buffer, "//blankline")
|
518
|
+
end
|
519
|
+
return table.concat(buffer, "\n")
|
520
|
+
end
|
521
|
+
|
522
|
+
local classes = attr_classes(attr)
|
523
|
+
|
524
|
+
if next(classes) == nil then
|
525
|
+
return "//{\n" .. s .. "\n//}"
|
526
|
+
end
|
527
|
+
|
528
|
+
if classes["review-internal"] then
|
529
|
+
s, _ = s:gsub(
|
530
|
+
"%]{<P2RREMOVEBELOW/>\n", "]{"
|
531
|
+
):gsub(
|
532
|
+
"\n<P2RREMOVEABOVE/>//}", "//}"
|
533
|
+
)
|
534
|
+
return s
|
535
|
+
end
|
536
|
+
|
537
|
+
for cls,_ in pairs(classes) do
|
538
|
+
s = "//" .. cls .. "{\n" .. s .. "\n//}"
|
539
|
+
end
|
540
|
+
return s
|
541
|
+
end
|
542
|
+
|
543
|
+
function Span(s, attr)
|
544
|
+
-- ruby and kw with a supplement
|
545
|
+
local a = ""
|
546
|
+
for _, cmd in ipairs({"ruby", "kw"}) do
|
547
|
+
a = attr_val(attr, cmd)
|
548
|
+
if a ~= "" then
|
549
|
+
s = format_inline(cmd, s .. "," .. a)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
-- inline format
|
554
|
+
for cmd in attr_val(attr, "class"):gmatch("[^%s]+") do
|
555
|
+
if inline_commands[cmd] then
|
556
|
+
s = format_inline(cmd, s)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
|
560
|
+
return s
|
561
|
+
end
|
562
|
+
|
563
|
+
function RawInline(format, text)
|
564
|
+
if (format == "review") then
|
565
|
+
return text
|
566
|
+
end
|
567
|
+
|
568
|
+
if (metadata.hideraw) then
|
569
|
+
return ""
|
570
|
+
end
|
571
|
+
|
572
|
+
if (format == "tex") then
|
573
|
+
return format_inline("embed", "|latex|" .. text)
|
574
|
+
else
|
575
|
+
return format_inline("embed", "|" .. format .. "|", text)
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
function RawBlock(format, text)
|
580
|
+
if (format == "review") then
|
581
|
+
return text
|
582
|
+
end
|
583
|
+
|
584
|
+
if (metadata.hideraw) then
|
585
|
+
return ""
|
586
|
+
end
|
587
|
+
|
588
|
+
if (format == "tex") then
|
589
|
+
return "//embed[latex]{\n" .. text .. "\n//}"
|
590
|
+
else
|
591
|
+
return "//embed[" .. format .. "]{\n" .. text .. "\n//}"
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
try_catch {
|
596
|
+
try = function()
|
597
|
+
metadata = PANDOC_DOCUMENT.meta
|
598
|
+
end,
|
599
|
+
catch = function(error)
|
600
|
+
log("Due to your pandoc version is too old, config.yml loader is disabled.\n")
|
601
|
+
end
|
602
|
+
}
|
603
|
+
|
604
|
+
if (metadata) then
|
605
|
+
-- Load config from YAML
|
606
|
+
for k,v in pairs(config) do
|
607
|
+
if metadata[k] ~= nil then
|
608
|
+
config[k] = stringify(metadata[k])
|
609
|
+
end
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
local meta = {}
|
614
|
+
meta.__index =
|
615
|
+
function(_, key)
|
616
|
+
log(string.format("WARNING: Undefined function '%s'\n", key))
|
617
|
+
return function() return "" end
|
618
|
+
end
|
619
|
+
|
620
|
+
setmetatable(_G, meta)
|