review-retrovert 0.9.7 → 0.9.8
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/.dockerignore +9 -0
- data/.editorconfig +3 -0
- data/.github/workflows/retrovert.yml +20 -5
- data/.gitignore +1 -0
- data/.vscode/launch.json +48 -0
- data/Gemfile.lock +13 -4
- data/Makefile +24 -0
- data/docker/review.Dockerfile +10 -0
- data/lib/review/retrovert/converter.rb +374 -111
- data/lib/review/retrovert/reviewcompat.rb +57 -0
- data/lib/review/retrovert/reviewdef.rb +70 -0
- data/lib/review/retrovert/sty/{ird.sty → ird.sty.erb} +9 -1
- data/lib/review/retrovert/sty/review-retrovert-custom.sty.erb +6 -0
- data/lib/review/retrovert/utils.rb +35 -0
- data/lib/review/retrovert/version.rb +1 -1
- data/lib/review/retrovert/yamlconfig.rb +0 -1
- data/package-lock.json +6 -0
- data/package.json +1 -0
- data/review-retrovert.gemspec +5 -1
- data/testdata/mybook/.gitignore +3 -1
- data/testdata/mybook/.textlintrc +11 -0
- data/testdata/mybook/Rakefile +8 -0
- data/testdata/mybook/catalog.yml +36 -10
- data/testdata/mybook/config-starter.yml +134 -9
- data/testdata/mybook/config.yml +44 -15
- data/testdata/mybook/contents/00-preface.re +48 -2
- data/testdata/mybook/contents/01-install.re +38 -5
- data/testdata/mybook/contents/02-tutorial.re +333 -113
- data/testdata/mybook/contents/03-syntax.re +2370 -373
- data/testdata/mybook/contents/04-customize.re +424 -88
- data/testdata/mybook/contents/05-faq.re +288 -10
- data/testdata/mybook/contents/06-bestpractice.re +431 -59
- data/testdata/mybook/contents/91-compare.re +402 -2
- data/testdata/mybook/contents/92-filelist.re +14 -8
- data/testdata/mybook/contents/93-background.re +10 -10
- data/testdata/mybook/contents/99-postface.re +2 -1
- data/testdata/mybook/contents/r0-root.re +1 -1
- data/testdata/mybook/css/webstyle.css +180 -2
- data/testdata/mybook/data/terms.txt +3 -0
- data/testdata/mybook/data/words.txt +15 -0
- data/testdata/mybook/images/03-syntax/index-page.png +0 -0
- data/testdata/mybook/images/03-syntax/order-detail.png +0 -0
- data/testdata/mybook/images/04-customize/section_decoration_samples.png +0 -0
- data/testdata/mybook/images/05-faq/dummy-image.png +0 -0
- data/testdata/mybook/images/06-bestpractice/section_title_wlines.png +0 -0
- data/testdata/mybook/images/avatar-b.png +0 -0
- data/testdata/mybook/images/avatar-g.png +0 -0
- data/testdata/mybook/images/avatar-r.png +0 -0
- data/testdata/mybook/images/caution-icon.png +0 -0
- data/testdata/mybook/images/info-icon.png +0 -0
- data/testdata/mybook/images/warning-icon.png +0 -0
- data/testdata/mybook/layouts/layout.html5.erb +3 -1
- data/testdata/mybook/layouts/layout.tex.erb +265 -379
- data/testdata/mybook/layouts/layout.tex.erb.orig +386 -0
- data/testdata/mybook/lib/ruby/review-book.rb +64 -0
- data/testdata/mybook/lib/ruby/review-builder.rb +902 -63
- data/testdata/mybook/lib/ruby/review-compiler.rb +675 -22
- data/testdata/mybook/lib/ruby/review-epubbuilder.rb +33 -0
- data/testdata/mybook/lib/ruby/review-epubmaker.rb +10 -7
- data/testdata/mybook/lib/ruby/review-htmlbuilder.rb +354 -66
- data/testdata/mybook/lib/ruby/review-latexbuilder.rb +429 -146
- data/testdata/mybook/lib/ruby/review-maker.rb +117 -6
- data/testdata/mybook/lib/ruby/review-markdownbuilder.rb +945 -0
- data/testdata/mybook/lib/ruby/review-markdownmaker.rb +91 -0
- data/testdata/mybook/lib/ruby/review-monkeypatch.rb +2 -0
- data/testdata/mybook/lib/ruby/review-pdfmaker.rb +160 -82
- data/testdata/mybook/lib/ruby/review-webmaker.rb +20 -5
- data/testdata/mybook/lib/tasks/review.rake +14 -0
- data/testdata/mybook/lib/tasks/starter.rake +148 -4
- data/testdata/mybook/sty/indexstyle.ist +25 -0
- data/testdata/mybook/sty/mytextsize.sty +29 -0
- data/testdata/mybook/sty/mytitlepage.sty +34 -11
- data/testdata/mybook/sty/review-base.sty +276 -0
- data/testdata/mybook/sty/starter-codeblock.sty +237 -106
- data/testdata/mybook/sty/starter-color.sty +72 -17
- data/testdata/mybook/sty/starter-heading.sty +60 -13
- data/testdata/mybook/sty/starter-misc.sty +894 -0
- data/testdata/mybook/sty/starter-note.sty +67 -14
- data/testdata/mybook/sty/starter-talklist.sty +105 -0
- data/testdata/mybook/sty/starter-util.sty +35 -0
- data/testdata/mybook/sty/starter.sty +8 -526
- metadata +80 -4
|
@@ -14,13 +14,19 @@ module ReVIEW
|
|
|
14
14
|
|
|
15
15
|
class LATEXBuilder
|
|
16
16
|
|
|
17
|
+
public :print, :puts
|
|
18
|
+
|
|
19
|
+
def target_name
|
|
20
|
+
"latex"
|
|
21
|
+
end
|
|
22
|
+
|
|
17
23
|
## 章や節や項や目のタイトル
|
|
18
24
|
def headline(level, label, caption)
|
|
19
25
|
with_context(:headline) do
|
|
20
26
|
_, anchor = headline_prefix(level)
|
|
21
27
|
headname = _headline_name(level) # 'chapter', 'section', 'subsection', ...
|
|
22
28
|
headstar = _headline_star(level) # '*' or nil
|
|
23
|
-
blank unless @output.pos == 0
|
|
29
|
+
blank() unless @output.pos == 0
|
|
24
30
|
with_context(:caption) do
|
|
25
31
|
print macro("#{headname}#{headstar}", compile_inline(caption))
|
|
26
32
|
print "\n" unless level >= 5 # \paragraphと\subpararaphでは改行しない
|
|
@@ -31,7 +37,12 @@ module ReVIEW
|
|
|
31
37
|
puts "\\ifx\\Chapter\\undefined{\\addcontentsline{toc}{#{headname}}{#{compile_inline(caption)}}}\\fi"
|
|
32
38
|
end
|
|
33
39
|
if _headline_chapter?(level)
|
|
34
|
-
|
|
40
|
+
## \Chapter直後の\addvspaceが効くように、
|
|
41
|
+
## \lastskipをいったん保存し、\labelのあとで復元する。
|
|
42
|
+
puts "\\keeplastskip{"
|
|
43
|
+
puts " \\label{#{chapter_label()}}"
|
|
44
|
+
puts " \\par\\nobreak"
|
|
45
|
+
puts "}"
|
|
35
46
|
elsif level >= 5 # 段(Paragraph)と小段(Subparagraph)では
|
|
36
47
|
nil # 何もしない、\labelもつけない
|
|
37
48
|
else
|
|
@@ -72,7 +83,7 @@ module ReVIEW
|
|
|
72
83
|
public
|
|
73
84
|
|
|
74
85
|
def nonum_begin(level, _label, caption)
|
|
75
|
-
blank unless @output.pos == 0
|
|
86
|
+
blank() unless @output.pos == 0
|
|
76
87
|
with_context(:headline) do
|
|
77
88
|
with_context(:caption) do
|
|
78
89
|
puts macro(HEADLINE[level] + '*', compile_inline(caption))
|
|
@@ -84,7 +95,7 @@ module ReVIEW
|
|
|
84
95
|
end
|
|
85
96
|
|
|
86
97
|
def notoc_begin(level, _label, caption)
|
|
87
|
-
blank unless @output.pos == 0
|
|
98
|
+
blank() unless @output.pos == 0
|
|
88
99
|
with_context(:headline) do
|
|
89
100
|
with_context(:caption) do
|
|
90
101
|
puts "\\ifx\\Chapter\\undefined"
|
|
@@ -96,18 +107,51 @@ module ReVIEW
|
|
|
96
107
|
end
|
|
97
108
|
end
|
|
98
109
|
|
|
99
|
-
##
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
110
|
+
## テーブル
|
|
111
|
+
def table(lines, id=nil, caption=nil, option=nil)
|
|
112
|
+
super
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def table_header(id, caption, options)
|
|
116
|
+
if id.present? || caption.present?
|
|
103
117
|
@table_caption = true
|
|
118
|
+
pos = options[:pos] || 'h'
|
|
104
119
|
star = id.present? ? '' : '*'
|
|
105
|
-
s = with_context(:caption) { compile_inline(caption) }
|
|
106
|
-
puts "\\begin{table}[
|
|
120
|
+
s = with_context(:caption) { compile_inline(caption || '') }
|
|
121
|
+
puts "\\begin{table}[#{pos}]%%#{id}"
|
|
107
122
|
puts "\\centering%"
|
|
108
123
|
puts macro("reviewtablecaption#{star}", s)
|
|
109
124
|
end
|
|
110
|
-
|
|
125
|
+
begin
|
|
126
|
+
puts macro('label', table_label(id)) if id.present?
|
|
127
|
+
rescue KeyError
|
|
128
|
+
error "no such table: #{id}"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
alias __original_table_begin table_begin
|
|
133
|
+
|
|
134
|
+
def table_begin(ncols, fontsize: nil)
|
|
135
|
+
if fontsize
|
|
136
|
+
font = FONTSIZES[fontsize]
|
|
137
|
+
puts "\\def\\startertablefont{\\#{font}}" if font
|
|
138
|
+
end
|
|
139
|
+
__original_table_begin(ncols)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
## CSVテーブル
|
|
143
|
+
def _table_hline()
|
|
144
|
+
"\\hline"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def _table_bottom(hline: false)
|
|
148
|
+
puts "\\hline" if hline
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def _table_tr(cells, hline: false)
|
|
152
|
+
s = "#{cells.join(' & ')} \\\\"
|
|
153
|
+
s << " \\hline" if hline
|
|
154
|
+
return s
|
|
111
155
|
end
|
|
112
156
|
|
|
113
157
|
## 改行命令「\\」のあとに改行文字「\n」を置かない。
|
|
@@ -131,18 +175,10 @@ module ReVIEW
|
|
|
131
175
|
"\\\\[0pt]" # これなら後続行の先頭に1/4空白が入らない
|
|
132
176
|
end
|
|
133
177
|
|
|
178
|
+
protected
|
|
134
179
|
|
|
135
|
-
## コードブロック(//program, //terminal)
|
|
136
|
-
|
|
137
|
-
def program(lines, id=nil, caption=nil, optionstr=nil)
|
|
138
|
-
_codeblock('program', lines, id, caption, optionstr)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def terminal(lines, id=nil, caption=nil, optionstr=nil)
|
|
142
|
-
_codeblock('terminal', lines, id, caption, optionstr)
|
|
143
|
-
end
|
|
144
180
|
|
|
145
|
-
|
|
181
|
+
## コードブロック(//program, //terminal, //output)
|
|
146
182
|
|
|
147
183
|
FONTSIZES = {
|
|
148
184
|
"small" => "small",
|
|
@@ -151,125 +187,226 @@ module ReVIEW
|
|
|
151
187
|
"large" => "large",
|
|
152
188
|
"x-large" => "Large",
|
|
153
189
|
"xx-large" => "LARGE",
|
|
190
|
+
"medium" => "normalsize",
|
|
154
191
|
}
|
|
155
192
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
def _codeblock_eolmark()
|
|
194
|
+
"{\\startereolmark}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def _codeblock_indentmark()
|
|
198
|
+
"{\\starterindentchar}"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
LATEX_ESCAPE_TABLE = {
|
|
202
|
+
'{' => '\{',
|
|
203
|
+
'}' => '\}',
|
|
204
|
+
'%' => '\%',
|
|
205
|
+
'$' => '\$',
|
|
206
|
+
'#' => '\#',
|
|
207
|
+
'&' => '\&',
|
|
208
|
+
'_' => '\_',
|
|
209
|
+
'\\' => '{\textbackslash}',
|
|
210
|
+
'^' => '{\textasciicircum}',
|
|
211
|
+
'~' => '{\textasciitilde}',
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
def _render_codeblock(blockname, lines, id, caption_str, opts)
|
|
164
215
|
if opts['eolmark']
|
|
165
|
-
|
|
216
|
+
eolmark = _codeblock_eolmark() # ex: '{\startereolmark}'
|
|
166
217
|
else
|
|
167
|
-
|
|
218
|
+
eolmark = nil
|
|
168
219
|
end
|
|
169
220
|
#
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
line.sub(/\A( +)/) {
|
|
175
|
-
m, n = ($1.length - 1).divmod indent_w
|
|
176
|
-
" " << indent_str * m << " " * n
|
|
177
|
-
}
|
|
221
|
+
eol = eolmark ? "#{eolmark}\\par\n" : "\\par\n"
|
|
222
|
+
lines = lines.map {|line|
|
|
223
|
+
line = _parse_inline(line) {|text|
|
|
224
|
+
_convert_and_escape_str(text)
|
|
178
225
|
}
|
|
179
|
-
|
|
226
|
+
if line =~ /\A\n/
|
|
227
|
+
"\\mbox{}#{eol}\n"
|
|
228
|
+
else
|
|
229
|
+
line.gsub(/(?:\\-)?\n/, eol)
|
|
230
|
+
end
|
|
231
|
+
}
|
|
180
232
|
#
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
caption_str = nil
|
|
233
|
+
indent_width = opts['indent']
|
|
234
|
+
if indent_width && indent_width > 0
|
|
235
|
+
lines = _add_indent_mark(lines, indent_width)
|
|
185
236
|
end
|
|
186
237
|
#
|
|
238
|
+
default_opts = _codeblock_default_options(blockname)
|
|
239
|
+
opts2 = {}
|
|
240
|
+
opts.each do |k, v|
|
|
241
|
+
opts2[k] = v unless v == default_opts[k]
|
|
242
|
+
end
|
|
187
243
|
fontsize = FONTSIZES[opts['fontsize']]
|
|
188
|
-
print "\\def\\startercodeblockfontsize{#{fontsize}}\n"
|
|
189
244
|
#
|
|
190
245
|
environ = "starter#{blockname}"
|
|
246
|
+
puts "\\begingroup"
|
|
247
|
+
puts " \\makeatletter" if fontsize
|
|
248
|
+
puts " \\def\\starter@#{blockname}@fontsize{#{fontsize}}" if fontsize
|
|
249
|
+
puts " \\makeatother" if fontsize
|
|
250
|
+
puts " \\makeatletter" unless opts2.empty?
|
|
251
|
+
opts2.each do |k, v|
|
|
252
|
+
x = k.gsub(/[^a-zA-Z]/, '_')
|
|
253
|
+
v = v == true ? 'Y' : v == false ? '' : v #escape(v.to_s)
|
|
254
|
+
puts " \\edef\\starter@#{blockname}@#{x}{#{v}}"
|
|
255
|
+
#puts " \\edef\\starter@codeblock@#{x}{#{v}}"
|
|
256
|
+
end
|
|
257
|
+
puts " \\makeatother" unless opts2.empty?
|
|
191
258
|
print "\\begin{#{environ}}[#{id}]{#{caption_str}}"
|
|
192
259
|
print "\\startersetfoldmark{}" unless opts['foldmark']
|
|
193
|
-
if opts['eolmark']
|
|
194
|
-
print "\\startereolmarkdark{}" if blockname == 'terminal'
|
|
195
|
-
print "\\startereolmarklight{}" if blockname != 'terminal'
|
|
196
|
-
end
|
|
197
260
|
if opts['lineno']
|
|
198
261
|
gen = LineNumberGenerator.new(opts['lineno'])
|
|
199
|
-
width = opts['linenowidth']
|
|
262
|
+
width = opts['linenowidth'] || -1
|
|
200
263
|
if width && width >= 0
|
|
201
264
|
if width == 0
|
|
202
265
|
last_lineno = gen.each.take(lines.length).compact.last
|
|
203
266
|
width = last_lineno.to_s.length
|
|
204
267
|
end
|
|
205
268
|
print "\\startersetfoldindentwidth{#{'9'*(width+2)}}"
|
|
206
|
-
format = "\\
|
|
269
|
+
format = "\\starterinnerlineno{%#{width}s:} "
|
|
207
270
|
else
|
|
208
|
-
format = "\\
|
|
271
|
+
format = "\\starterouterlineno{%s}"
|
|
209
272
|
end
|
|
210
273
|
buf = []
|
|
211
|
-
opt_fold = opts['fold']
|
|
212
274
|
lines.zip(gen).each do |x, n|
|
|
213
|
-
buf << (
|
|
214
|
-
? "#{format % n.to_s}\\seqsplit{#{x}}" \
|
|
215
|
-
: "#{format % n.to_s}#{x}" )
|
|
275
|
+
buf << "#{(format % n.to_s).gsub(' ', '~')}#{x}"
|
|
216
276
|
end
|
|
217
|
-
print buf.join(
|
|
277
|
+
print buf.join()
|
|
218
278
|
else
|
|
219
|
-
print
|
|
220
|
-
print lines.join("\n")
|
|
221
|
-
print "}" if opts['fold']
|
|
279
|
+
print lines.join()
|
|
222
280
|
end
|
|
223
281
|
puts "\\end{#{environ}}"
|
|
282
|
+
puts "\\endgroup"
|
|
224
283
|
nil
|
|
225
284
|
end
|
|
226
285
|
|
|
286
|
+
def _convert_and_escape_str(str)
|
|
287
|
+
#str.gsub(/[\{\}\\\%\^\_\$\&\~]/, LATEX_ESCAPE_TABLE)
|
|
288
|
+
rexp = /[\{\}\\\#\%\^\_\$\&\~]/
|
|
289
|
+
cs = []
|
|
290
|
+
zenkaku_rexp = ZENKAKU_CHAR_REXP
|
|
291
|
+
str.each_char do |c|
|
|
292
|
+
cs << (
|
|
293
|
+
case c
|
|
294
|
+
when / / ; '~'
|
|
295
|
+
when /\n/ ; "\n"
|
|
296
|
+
when rexp ; LATEX_ESCAPE_TABLE[c]
|
|
297
|
+
when zenkaku_rexp ; "\\ZC{#{c}}" # 全角文字
|
|
298
|
+
else ; c # 半角文字
|
|
299
|
+
end
|
|
300
|
+
)
|
|
301
|
+
end
|
|
302
|
+
cs << "" unless cs[-1] == "\n"
|
|
303
|
+
return cs.join('\\-')
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
ZENKAKU_CHAR_REXP = /\A[^\000-\177]\z/
|
|
307
|
+
|
|
308
|
+
def _add_indent_mark(lines, indent_width)
|
|
309
|
+
space = "~\\-"
|
|
310
|
+
rexp = /\A((?:~\\-)+)/
|
|
311
|
+
#
|
|
312
|
+
width = indent_width
|
|
313
|
+
mark = _codeblock_indentmark() # ex: '{\starterindentmark}'
|
|
314
|
+
indent = space * (width - 1) + mark
|
|
315
|
+
nchar = space.length
|
|
316
|
+
return lines.map {|line|
|
|
317
|
+
line.sub(rexp) {
|
|
318
|
+
m, n = ($1.length / nchar - 1).divmod width
|
|
319
|
+
"#{space}#{indent * m}#{space * n}"
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
end
|
|
323
|
+
|
|
227
324
|
public
|
|
228
325
|
|
|
229
326
|
## ・\caption{} のかわりに \reviewimagecaption{} を使うよう修正
|
|
230
327
|
## ・「scale=X」に加えて「pos=X」も受け付けるように拡張
|
|
231
|
-
def
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
case
|
|
235
|
-
when
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
pos = v # detect 'pos=H' or 'pos=h'
|
|
239
|
-
when 'border', 'draft'
|
|
240
|
-
case v
|
|
241
|
-
when nil ; flag = true
|
|
242
|
-
when 'on' ; flag = true
|
|
243
|
-
when 'off'; flag = false
|
|
244
|
-
else
|
|
245
|
-
raise "//image[][][#{k}=#{v}]: expected '#{k}=on' or '#{k}=off'"
|
|
246
|
-
end
|
|
247
|
-
border = flag if k == 'border'
|
|
248
|
-
arr << "draft=#{flag}" if k == 'draft'
|
|
328
|
+
def _render_image(id, image_filepath, caption, opts)
|
|
329
|
+
width = "\\maxwidth"
|
|
330
|
+
if opts[:scale]
|
|
331
|
+
case (scale = opts[:scale])
|
|
332
|
+
when /\A\d+\z/, /\A\d\.\d*\z/, /\A\.\d+\z/
|
|
333
|
+
when /\A\d+(\.\d+)?%\z/
|
|
334
|
+
scale = scale.sub(/%\z/, '').to_f / 100.0
|
|
249
335
|
else
|
|
250
|
-
|
|
336
|
+
error "scale=#{scale}: invalid scale value."
|
|
251
337
|
end
|
|
338
|
+
width = "#{scale}\\maxwidth" # not '\textwidth'
|
|
252
339
|
end
|
|
253
340
|
#
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
341
|
+
if opts[:width]
|
|
342
|
+
case opts[:width]
|
|
343
|
+
when /\A\d+\z/, /\A\d\.\d*\z/, /\A\.\d+\z/
|
|
344
|
+
width = "#{opts[:width]}\\textwidth" # not '\maxwidth'
|
|
345
|
+
when /\A(\d+(\.\d+)?)%\z/
|
|
346
|
+
width = "#{$1.to_f/100.0}\\textwidth" # not '\maxwidth'
|
|
347
|
+
when /\A(\d+(?:\.\d*)?)(mm|cm)\z/
|
|
348
|
+
width = "#{$1}true#{$2}" # 'mm'->'truemm', 'cm'->'truecm'
|
|
349
|
+
else
|
|
350
|
+
width = opts[:width]
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
#
|
|
354
|
+
metrics = ["width=#{width}"]
|
|
355
|
+
metrics << "draft=#{opts[:draft]}" if opts[:draft] != nil
|
|
356
|
+
#
|
|
357
|
+
pos = opts[:pos] || config_starter()['image_position']
|
|
358
|
+
puts "\\begin{reviewimage}[#{pos}]%%#{id}"
|
|
359
|
+
puts "\\starterimageframe{%" if opts[:border]
|
|
360
|
+
puts "\\includegraphics[#{metrics.join(',')}]{#{image_filepath}}%"
|
|
361
|
+
puts "}%" if opts[:border]
|
|
261
362
|
with_context(:caption) do
|
|
262
363
|
#puts macro('caption', compile_inline(caption)) if caption.present? # original
|
|
263
|
-
puts
|
|
364
|
+
puts "\\reviewimagecaption{#{compile_inline(caption)}}" if caption.present?
|
|
264
365
|
end
|
|
265
|
-
puts
|
|
366
|
+
puts "\\label{#{image_label(id)}}"
|
|
266
367
|
puts "\\end{reviewimage}"
|
|
267
368
|
end
|
|
268
369
|
|
|
370
|
+
## //imgtable
|
|
371
|
+
def imgtable(lines, id, caption=nil, option=nil)
|
|
372
|
+
super
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def _render_imgtable(id, caption, opts)
|
|
376
|
+
pos = opts['pos'] || 'h'
|
|
377
|
+
puts "\\begin{table}[#{pos}]%%#{id}"
|
|
378
|
+
puts "\\centering"
|
|
379
|
+
yield
|
|
380
|
+
puts "\\end{table}"
|
|
381
|
+
blank()
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def _render_imgtable_caption(caption)
|
|
385
|
+
puts macro('reviewimgtablecaption', compile_inline(caption))
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def _render_imgtable_label(id)
|
|
389
|
+
puts macro('label', table_label(id))
|
|
390
|
+
rescue ReVIEW::KeyError
|
|
391
|
+
error "no such table: #{id}"
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def imgtable_image(id, _caption, metric)
|
|
395
|
+
metrics = parse_metric('latex', metric)
|
|
396
|
+
# image is always bound here
|
|
397
|
+
#puts "\\begin{reviewimage}%%#{id}" #-
|
|
398
|
+
metrics = "width=\\maxwidth" unless metrics.present?
|
|
399
|
+
imagefile = @chapter.image(id).path
|
|
400
|
+
puts "\\includegraphics[#{metrics}]{#{imagefile}}"
|
|
401
|
+
#puts '\end{reviewimage}' #-
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
##
|
|
405
|
+
|
|
269
406
|
def _build_secref(chap, num, title, parent_title)
|
|
270
407
|
s = ""
|
|
271
408
|
## 親セクションのタイトルがあれば使う
|
|
272
|
-
if parent_title &&
|
|
409
|
+
if parent_title && self.config_starter['secref_parenttitle']
|
|
273
410
|
s << "「%s」内の" % parent_title # TODO: I18n化
|
|
274
411
|
end
|
|
275
412
|
## 対象セクションへのリンクを作成する
|
|
@@ -294,17 +431,17 @@ module ReVIEW
|
|
|
294
431
|
public
|
|
295
432
|
|
|
296
433
|
def ul_begin
|
|
297
|
-
blank
|
|
434
|
+
blank()
|
|
298
435
|
puts '\begin{starteritemize}' # instead of 'itemize'
|
|
299
436
|
end
|
|
300
437
|
|
|
301
438
|
def ul_end
|
|
302
439
|
puts '\end{starteritemize}' # instead of 'itemize'
|
|
303
|
-
blank
|
|
440
|
+
blank()
|
|
304
441
|
end
|
|
305
442
|
|
|
306
443
|
def ol_begin(start_num=nil)
|
|
307
|
-
blank
|
|
444
|
+
blank()
|
|
308
445
|
puts '\begin{starterenumerate}' # instead of 'enumerate'
|
|
309
446
|
if start_num.nil?
|
|
310
447
|
return true unless @ol_num
|
|
@@ -315,7 +452,7 @@ module ReVIEW
|
|
|
315
452
|
|
|
316
453
|
def ol_end
|
|
317
454
|
puts '\end{starterenumerate}' # instead of 'enumerate'
|
|
318
|
-
blank
|
|
455
|
+
blank()
|
|
319
456
|
end
|
|
320
457
|
|
|
321
458
|
def ol_item_begin(lines, num)
|
|
@@ -327,10 +464,20 @@ module ReVIEW
|
|
|
327
464
|
def ol_item_end()
|
|
328
465
|
end
|
|
329
466
|
|
|
467
|
+
def dt(str)
|
|
468
|
+
puts "\\starterdt{#{str}}%"
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def dl_dd_begin()
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def dl_dd_end()
|
|
475
|
+
end
|
|
476
|
+
|
|
330
477
|
## コラム
|
|
331
478
|
|
|
332
479
|
def column_begin(level, label, caption)
|
|
333
|
-
blank
|
|
480
|
+
blank()
|
|
334
481
|
@doc_status[:column] = true
|
|
335
482
|
puts "\\begin{reviewcolumn}\n"
|
|
336
483
|
puts "\\phantomsection % for hyperref" #+
|
|
@@ -367,12 +514,85 @@ module ReVIEW
|
|
|
367
514
|
## (導入文 //lead{ ... //} と似ているが、導入文では詩や物語を
|
|
368
515
|
## 引用するのが普通らしく、概要 (abstract) とは違うみたいなので、
|
|
369
516
|
## 概要を表すブロックを用意した。)
|
|
370
|
-
def
|
|
517
|
+
def on_abstract_block()
|
|
371
518
|
puts '\begin{starterabstract}'
|
|
372
|
-
|
|
519
|
+
yield
|
|
373
520
|
puts '\end{starterabstract}'
|
|
374
521
|
end
|
|
375
522
|
|
|
523
|
+
## 章 (Chapter) の著者
|
|
524
|
+
def on_chapterauthor_block(name)
|
|
525
|
+
puts "\\starterchapterauthor{#{escape(name)}}"
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
## 会話リスト
|
|
529
|
+
def _render_talklist(opts, &b)
|
|
530
|
+
puts '\begingroup'
|
|
531
|
+
puts ' \makeatletter' unless opts.empty?
|
|
532
|
+
opts.each do |k, v|
|
|
533
|
+
puts " \\def\\starter@talklist@#{k}{#{v}}"
|
|
534
|
+
end
|
|
535
|
+
puts ' \makeatother' unless opts.empty?
|
|
536
|
+
puts '\begin{startertalklist}'
|
|
537
|
+
yield
|
|
538
|
+
puts '\end{startertalklist}'
|
|
539
|
+
puts '\endgroup'
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
## 会話項目
|
|
543
|
+
def _render_talk(image_filepath=nil, name=nil, &b)
|
|
544
|
+
s = name ? compile_inline(name) : nil
|
|
545
|
+
print "\\startertalk{#{image_filepath}}{#{s}}{%"
|
|
546
|
+
yield
|
|
547
|
+
@blank_needed = false
|
|
548
|
+
puts "}"
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
## キーと説明文のリスト
|
|
552
|
+
def _render_desclist(opts, &b)
|
|
553
|
+
bkup = @_desclist_opts
|
|
554
|
+
@_desclist_opts = opts
|
|
555
|
+
star = opts[:compact] ? '*' : ''
|
|
556
|
+
puts "\\begingroup"
|
|
557
|
+
puts " \\makeatletter" unless opts.empty?
|
|
558
|
+
opts.each do |k, v|
|
|
559
|
+
k_ = k.to_s.gsub('_', '@')
|
|
560
|
+
v_ = v == true ? 'Y' : v == false ? '' : escape(v.to_s)
|
|
561
|
+
puts " \\def\\starter@desclist@#{k_}{#{v_}}"
|
|
562
|
+
end
|
|
563
|
+
puts " \\makeatother" unless opts.empty?
|
|
564
|
+
puts "\\begin{starterdesclist}"
|
|
565
|
+
yield
|
|
566
|
+
puts "\\end{starterdesclist}"
|
|
567
|
+
puts "\\endgroup"
|
|
568
|
+
@_desclist_opts = bkup
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
## キーと説明文
|
|
572
|
+
def on_desc_block(key, text=nil, &b)
|
|
573
|
+
text = "\n" + text if text
|
|
574
|
+
super(key, text, &b)
|
|
575
|
+
end
|
|
576
|
+
def _render_desc(key, &b)
|
|
577
|
+
opts = @_desclist_opts
|
|
578
|
+
s = compile_inline(key)
|
|
579
|
+
#print "\\begin{starterdesc}{#{s}}"
|
|
580
|
+
#print "\\begin{starterdesc}{#{s}}%"
|
|
581
|
+
print "\\begin{starterdesc}{#{s}}\\ignorespaces "
|
|
582
|
+
yield
|
|
583
|
+
@blank_needed = false
|
|
584
|
+
puts "\\end{starterdesc}"
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
## 縦方向の空きを入れる
|
|
588
|
+
def _render_vspace(size)
|
|
589
|
+
puts "\\vspace{#{size}}"
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
def _render_addvspace(size)
|
|
593
|
+
puts "\\addvspace{#{size}}"
|
|
594
|
+
end
|
|
595
|
+
|
|
376
596
|
## 章タイトルを独立したページに
|
|
377
597
|
def makechaptitlepage(option=nil)
|
|
378
598
|
case option
|
|
@@ -387,10 +607,8 @@ module ReVIEW
|
|
|
387
607
|
end
|
|
388
608
|
|
|
389
609
|
## 縦方向のスペースがなければ改ページ
|
|
390
|
-
def
|
|
391
|
-
|
|
392
|
-
puts "\\needvspace{#{height}}"
|
|
393
|
-
end
|
|
610
|
+
def _render_needvspace(height)
|
|
611
|
+
puts "\\needvspace{#{height}}"
|
|
394
612
|
end
|
|
395
613
|
|
|
396
614
|
## 段(Paragraph)の終わりにスペースを入れる
|
|
@@ -428,11 +646,13 @@ module ReVIEW
|
|
|
428
646
|
## ノート(//note[caption]{ ... //})
|
|
429
647
|
## (入れ子対応なので、中に箇条書きや別のブロックを入れられる)
|
|
430
648
|
def on_note_block(label=nil, caption=nil)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
649
|
+
with_context(:minicolumn) do
|
|
650
|
+
caption, label = label, nil if caption.nil?
|
|
651
|
+
s = compile_inline(caption || "")
|
|
652
|
+
puts "\\begin{starternote}[#{label}]{#{s}}"
|
|
653
|
+
yield
|
|
654
|
+
puts "\\end{starternote}"
|
|
655
|
+
end
|
|
436
656
|
end
|
|
437
657
|
def note(lines, label=nil, caption=nil)
|
|
438
658
|
on_note_block(label, caption) do
|
|
@@ -476,7 +696,7 @@ module ReVIEW
|
|
|
476
696
|
arr = []
|
|
477
697
|
arr << lang if lang
|
|
478
698
|
if lineno_flag
|
|
479
|
-
first_line_num = line_num
|
|
699
|
+
first_line_num = line_num()
|
|
480
700
|
arr << "lineno=#{first_line_num}"
|
|
481
701
|
arr << "linenowidth=0"
|
|
482
702
|
end
|
|
@@ -484,24 +704,12 @@ module ReVIEW
|
|
|
484
704
|
end
|
|
485
705
|
private :_codeblock_optstr
|
|
486
706
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
def on_minicolumn(type, caption, &b)
|
|
491
|
-
s = with_context(:caption) { compile_inline(caption) }
|
|
492
|
-
puts "\\begin{starter#{type}}{#{s}}"
|
|
493
|
-
yield
|
|
494
|
-
puts "\\end{starter#{type}}\n"
|
|
495
|
-
end
|
|
496
|
-
protected :on_minicolumn
|
|
497
|
-
|
|
498
|
-
def on_sideimage_block(imagefile, imagewidth, option_str=nil, &b)
|
|
499
|
-
imagefile, imagewidth, opts = validate_sideimage_args(imagefile, imagewidth, option_str)
|
|
500
|
-
filepath = find_image_filepath(imagefile)
|
|
501
|
-
side = opts['side'] || 'L'
|
|
707
|
+
## 画像横に文章
|
|
708
|
+
def _render_sideimage(filepath, imagewidth, opts, &b)
|
|
709
|
+
side = opts['side'] || 'L'
|
|
502
710
|
normalize = proc {|s|
|
|
503
|
-
|
|
504
|
-
if
|
|
711
|
+
rexp = /\A(\d+(?:\.\d+)?)(%|mm|cm)\z/
|
|
712
|
+
if s !~ rexp ; s
|
|
505
713
|
elsif $2 == '%' ; "#{$1.to_f/100.0}\\textwidth"
|
|
506
714
|
else ; "#{$1}true#{$2}"
|
|
507
715
|
end
|
|
@@ -517,6 +725,20 @@ module ReVIEW
|
|
|
517
725
|
puts "}\n"
|
|
518
726
|
end
|
|
519
727
|
|
|
728
|
+
## 入れ子可能なブロック命令
|
|
729
|
+
|
|
730
|
+
def on_minicolumn(type, caption=nil, &b)
|
|
731
|
+
with_context(:minicolumn) do
|
|
732
|
+
s = caption ? with_context(:caption) { compile_inline(caption) } : nil
|
|
733
|
+
puts "\\begin{starter#{type}}{#{s}}"
|
|
734
|
+
yield
|
|
735
|
+
puts "\\end{starter#{type}}\n"
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
protected :on_minicolumn
|
|
739
|
+
|
|
740
|
+
## 数式
|
|
741
|
+
|
|
520
742
|
def texequation(lines, label=nil, caption=nil)
|
|
521
743
|
blank()
|
|
522
744
|
#
|
|
@@ -561,6 +783,11 @@ module ReVIEW
|
|
|
561
783
|
|
|
562
784
|
#### インライン命令
|
|
563
785
|
|
|
786
|
+
## 改段落(箇条書き内では空行を入れられないため)
|
|
787
|
+
def inline_par(arg)
|
|
788
|
+
"\\starterpar{#{arg}}"
|
|
789
|
+
end
|
|
790
|
+
|
|
564
791
|
## ファイル名
|
|
565
792
|
def inline_file(str)
|
|
566
793
|
on_inline_file { escape(str) }
|
|
@@ -574,11 +801,11 @@ module ReVIEW
|
|
|
574
801
|
on_inline_userinput { escape(str) }
|
|
575
802
|
end
|
|
576
803
|
def on_inline_userinput
|
|
577
|
-
if within_codeblock?()
|
|
578
|
-
|
|
579
|
-
else
|
|
804
|
+
#if within_codeblock?()
|
|
805
|
+
# "{\\starteruserinput{\\seqsplit{#{yield}}}}"
|
|
806
|
+
#else
|
|
580
807
|
"\\starteruserinput{#{yield}}"
|
|
581
|
-
end
|
|
808
|
+
#end
|
|
582
809
|
end
|
|
583
810
|
|
|
584
811
|
## 引数をそのまま表示
|
|
@@ -597,11 +824,11 @@ module ReVIEW
|
|
|
597
824
|
on_inline_weak { escape(str) }
|
|
598
825
|
end
|
|
599
826
|
def on_inline_weak
|
|
600
|
-
if within_codeblock?()
|
|
601
|
-
|
|
602
|
-
else
|
|
827
|
+
#if within_codeblock?()
|
|
828
|
+
# "{\\starterweak{\\seqsplit{#{yield}}}}"
|
|
829
|
+
#else
|
|
603
830
|
"\\starterweak{#{yield}}"
|
|
604
|
-
end
|
|
831
|
+
#end
|
|
605
832
|
end
|
|
606
833
|
|
|
607
834
|
## 文字を小さくする
|
|
@@ -672,19 +899,17 @@ module ReVIEW
|
|
|
672
899
|
def on_inline_balloon(); "{\\reviewballoon{#{yield}}}" ; end
|
|
673
900
|
|
|
674
901
|
def on_inline_tt()
|
|
675
|
-
|
|
676
|
-
## その問題を回避するために、' ' を '\ ' にする。
|
|
677
|
-
s = yield
|
|
678
|
-
s = s.gsub(/([!?:.]) /, '\\1\\ ')
|
|
679
|
-
return "{\\reviewtt{#{s}}}"
|
|
902
|
+
return "{\\reviewtt{#{yield}}}"
|
|
680
903
|
end
|
|
681
904
|
|
|
682
905
|
def on_inline_code()
|
|
683
906
|
with_context(:inline_code) {
|
|
684
|
-
##
|
|
685
|
-
## その問題を回避するために、' ' を '\ ' にする。
|
|
907
|
+
## 連続した空白が1つの空白として扱われるのを防ぐ
|
|
686
908
|
s = yield
|
|
687
|
-
s = s.gsub(/
|
|
909
|
+
s = s.gsub(/ /, '{\\starterspacechar}')
|
|
910
|
+
## 連続した「`」や「'」はエスケープする必要がある
|
|
911
|
+
s = s.gsub(/\'\'/, "{'}{'}")
|
|
912
|
+
s = s.gsub(/\`\`/, '{`}{`}')
|
|
688
913
|
## コンテキストによって、背景色をつけないことがある
|
|
689
914
|
if false
|
|
690
915
|
elsif within_context?(:headline) # 章タイトルや節タイトルでは
|
|
@@ -719,35 +944,43 @@ module ReVIEW
|
|
|
719
944
|
if within_codeblock?()
|
|
720
945
|
#"\\reviewstrike{#{yield}}" # \seqsplit{} 内でエラーになる
|
|
721
946
|
#"{\\reviewstrike{#{yield}}}" # \seqsplit{} 内でもエラーにならないが折り返しされない
|
|
722
|
-
"{\\reviewstrike{\\seqsplit{#{yield}}}}" # エラーにならないし、折り返しもされる
|
|
947
|
+
#"{\\reviewstrike{\\seqsplit{#{yield}}}}" # エラーにならないし、折り返しもされる
|
|
948
|
+
"{\\reviewstrike{#{yield}}}"
|
|
723
949
|
else
|
|
724
950
|
macro('reviewstrike', yield)
|
|
725
951
|
end
|
|
726
952
|
end
|
|
727
953
|
|
|
728
954
|
def build_inline_href(url, escaped_label) # compile_href()をベースに改造
|
|
729
|
-
flag_footnote =
|
|
955
|
+
flag_footnote = self.config_starter['linkurl_footnote']
|
|
730
956
|
return _inline_hyperlink(url, escaped_label, flag_footnote)
|
|
731
957
|
end
|
|
732
958
|
|
|
733
959
|
## @<href>{} の代わり
|
|
734
960
|
def inline_hlink(str)
|
|
735
961
|
url, label = str.split(/, /, 2)
|
|
736
|
-
flag_footnote =
|
|
737
|
-
|
|
962
|
+
flag_footnote = self.config_starter['hyperlink_footnote']
|
|
963
|
+
label_ = label.present? ? escape(label) : nil
|
|
964
|
+
return _inline_hyperlink(url, label_, flag_footnote)
|
|
738
965
|
end
|
|
739
966
|
|
|
740
967
|
def _inline_hyperlink(url, escaped_label, flag_footnote)
|
|
741
968
|
if /\A[a-z]+:/ !~ url
|
|
742
969
|
"\\ref{#{url}}"
|
|
743
970
|
elsif ! escaped_label.present?
|
|
744
|
-
"\\url{#{escape_url(url)}}"
|
|
971
|
+
#"\\url{#{escape_url(url)}}"
|
|
972
|
+
"\\starterurl{#{escape_url(url)}}{#{escape(url)}}"
|
|
745
973
|
elsif ! flag_footnote
|
|
746
974
|
"\\href{#{escape_url(url)}}{#{escaped_label}}"
|
|
747
975
|
elsif within_context?(:footnote)
|
|
748
|
-
"#{escaped_label}(\\url{#{escape_url(url)}})"
|
|
976
|
+
#"#{escaped_label}(\\url{#{escape_url(url)}})"
|
|
977
|
+
"#{escaped_label}(\\starterurl{#{escape_url(url)}}{#{escape(url)}})"
|
|
749
978
|
else
|
|
750
|
-
"#{escaped_label}\\footnote{\\url{#{escape_url(url)}}}"
|
|
979
|
+
#"#{escaped_label}\\footnote{\\url{#{escape_url(url)}}}"
|
|
980
|
+
#"#{escaped_label}\\footnote{\\starterurl{#{escape_url(url)}}{#{escape(url)}}}"
|
|
981
|
+
url1 = escape_url(url)
|
|
982
|
+
url2 = escape(url)
|
|
983
|
+
"\\href{#{url1}}{#{escaped_label}}\\footnote{\\starterurl{#{url1}}{#{url2}}}"
|
|
751
984
|
end
|
|
752
985
|
end
|
|
753
986
|
private :_inline_hyperlink
|
|
@@ -776,6 +1009,56 @@ module ReVIEW
|
|
|
776
1009
|
escape("#{I18n.t('equation')}#{chapter.number}.#{number}")
|
|
777
1010
|
end
|
|
778
1011
|
|
|
1012
|
+
public
|
|
1013
|
+
|
|
1014
|
+
## 数式を $...$ から \(...\) に変更する。
|
|
1015
|
+
## これで //list の中でも @<m>$...$ が使えるようになる。
|
|
1016
|
+
## ただし '^' や '_' がエスケープされるので、実用性はイマイチ。
|
|
1017
|
+
def inline_m(str)
|
|
1018
|
+
#" $#{str}$ " # original
|
|
1019
|
+
"\\(#{str}\\)"
|
|
1020
|
+
end
|
|
1021
|
+
|
|
1022
|
+
## 「``」と「''」で囲む
|
|
1023
|
+
def on_inline_qq()
|
|
1024
|
+
"``#{yield}''"
|
|
1025
|
+
end
|
|
1026
|
+
|
|
1027
|
+
## 索引に載せる語句 (@<idx>{}, @<term>{})
|
|
1028
|
+
def inline_idx(str)
|
|
1029
|
+
s1, s2 = _compile_term(str)
|
|
1030
|
+
"#{s1}\\index{#{s2}}"
|
|
1031
|
+
end
|
|
1032
|
+
def inline_hidx(str)
|
|
1033
|
+
_, s2 = _compile_term(str)
|
|
1034
|
+
"\\index{#{s2}}"
|
|
1035
|
+
end
|
|
1036
|
+
def inline_term(str)
|
|
1037
|
+
s1, s2 = _compile_term(str)
|
|
1038
|
+
"\\starterterm{#{s1}}\\index{#{s2}}"
|
|
1039
|
+
end
|
|
1040
|
+
def on_inline_termnoidx()
|
|
1041
|
+
"\\starterterm{#{yield}}"
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
def _compile_term(str)
|
|
1045
|
+
arr = []
|
|
1046
|
+
placeholder = "\\starterindexplaceholder{}"
|
|
1047
|
+
display_str, see = parse_term(str, placeholder) do |term, term_e, yomi|
|
|
1048
|
+
if yomi
|
|
1049
|
+
arr << "#{escape_index(escape_latex(yomi))}@#{term_e}"
|
|
1050
|
+
elsif escape_index(term) != term_e
|
|
1051
|
+
arr << "#{escape_index(term)}@#{term_e}"
|
|
1052
|
+
else
|
|
1053
|
+
arr << term_e
|
|
1054
|
+
end
|
|
1055
|
+
end
|
|
1056
|
+
argstr = arr.join('!')
|
|
1057
|
+
argstr += "|see{#{escape_latex(see)}}" if see
|
|
1058
|
+
return display_str, argstr
|
|
1059
|
+
end
|
|
1060
|
+
private :_compile_term
|
|
1061
|
+
|
|
779
1062
|
end
|
|
780
1063
|
|
|
781
1064
|
|