review 3.0.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby-win.yml +39 -0
- data/.github/workflows/ruby.yml +27 -0
- data/.rubocop.yml +50 -12
- data/.travis.yml +17 -8
- data/Dockerfile +21 -5
- data/NEWS.ja.md +358 -0
- data/NEWS.md +358 -1
- data/README.md +11 -8
- data/appveyor.yml +1 -3
- data/bin/review-catalog-converter +4 -4
- data/bin/review-check +8 -8
- data/bin/review-checkdep +1 -1
- data/bin/review-compile +12 -12
- data/bin/review-epubmaker +3 -35
- data/bin/review-idgxmlmaker +16 -0
- data/bin/review-index +2 -89
- data/bin/review-preproc +14 -19
- data/bin/review-validate +3 -3
- data/bin/review-vol +4 -78
- data/doc/LICENSE +1 -1
- data/doc/config.yml.sample +46 -12
- data/doc/config.yml.sample-simple +4 -2
- data/doc/format.ja.md +37 -13
- data/doc/format.md +35 -20
- data/doc/pdfmaker.ja.md +43 -1
- data/doc/pdfmaker.md +42 -1
- data/doc/quickstart.ja.md +46 -26
- data/doc/quickstart.md +38 -17
- data/lib/epubmaker/epubcommon.rb +10 -5
- data/lib/epubmaker/epubv2.rb +1 -1
- data/lib/epubmaker/epubv3.rb +1 -0
- data/lib/epubmaker/producer.rb +4 -2
- data/lib/review/book.rb +1 -1
- data/lib/review/book/base.rb +38 -79
- data/lib/review/book/chapter.rb +18 -3
- data/lib/review/book/compilable.rb +6 -5
- data/lib/review/book/index.rb +69 -101
- data/lib/review/book/index/item.rb +40 -0
- data/lib/review/book/page_metric.rb +7 -7
- data/lib/review/book/part.rb +28 -5
- data/lib/review/book/volume.rb +3 -4
- data/lib/review/builder.rb +105 -44
- data/lib/review/catalog.rb +13 -16
- data/lib/review/compiler.rb +84 -72
- data/lib/review/configure.rb +19 -8
- data/lib/review/epub2html.rb +37 -4
- data/lib/review/epubmaker.rb +62 -7
- data/lib/review/extentions/string.rb +0 -4
- data/lib/review/htmlbuilder.rb +102 -115
- data/lib/review/htmlutils.rb +2 -3
- data/lib/review/i18n.rb +2 -2
- data/lib/review/i18n.yml +9 -0
- data/lib/review/idgxmlbuilder.rb +153 -74
- data/lib/review/idgxmlmaker.rb +191 -0
- data/lib/review/init-web/finish.html +10 -0
- data/lib/review/init-web/index.html +190 -0
- data/lib/review/init-web/review-layout-design.js +691 -0
- data/lib/review/init.rb +125 -34
- data/lib/review/latexbuilder.rb +199 -88
- data/lib/review/lineinput.rb +1 -1
- data/lib/review/location.rb +32 -0
- data/lib/review/logger.rb +4 -8
- data/lib/review/makerhelper.rb +24 -5
- data/lib/review/markdownbuilder.rb +31 -37
- data/lib/review/md2inaobuilder.rb +3 -5
- data/lib/review/pdfmaker.rb +44 -22
- data/lib/review/plaintextbuilder.rb +106 -85
- data/lib/review/preprocessor.rb +32 -41
- data/lib/review/rstbuilder.rb +33 -33
- data/lib/review/textmaker.rb +19 -3
- data/lib/review/textutils.rb +76 -2
- data/lib/review/tocprinter.rb +231 -102
- data/lib/review/topbuilder.rb +114 -61
- data/lib/review/update.rb +19 -19
- data/lib/review/version.rb +1 -1
- data/lib/review/volumeprinter.rb +99 -0
- data/lib/review/webmaker.rb +11 -4
- data/lib/review/webtocprinter.rb +38 -35
- data/lib/review/yamlloader.rb +26 -16
- data/review.gemspec +6 -4
- data/samples/sample-book/README.md +7 -2
- data/samples/sample-book/src/.gitignore +154 -0
- data/samples/sample-book/src/config-ebook.yml +4 -0
- data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
- data/samples/sample-book/src/config-jlreq.yml +6 -0
- data/samples/sample-book/src/config.yml +2 -2
- data/samples/sample-book/src/lib/tasks/review.rake +29 -14
- data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +14 -8
- data/samples/syntax-book/ch01.re +4 -2
- data/samples/syntax-book/ch02.re +8 -16
- data/samples/syntax-book/ch03.re +3 -6
- data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
- data/samples/syntax-book/config-jlreq.yml +5 -0
- data/samples/syntax-book/config-print.yml +3 -0
- data/samples/syntax-book/config.yml +1 -1
- data/samples/syntax-book/lib/tasks/review.rake +30 -15
- data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +14 -8
- data/templates/latex/config.erb +16 -0
- data/templates/latex/layout.tex.erb +4 -0
- data/templates/latex/review-jlreq/review-base.sty +150 -61
- data/templates/latex/review-jlreq/review-jlreq.cls +74 -8
- data/templates/latex/review-jlreq/review-style.sty +4 -1
- data/templates/latex/review-jsbook/README.md +39 -0
- data/templates/latex/review-jsbook/review-base.sty +101 -23
- data/templates/latex/review-jsbook/review-jsbook.cls +28 -5
- data/templates/latex/review-jsbook/review-style.sty +5 -2
- data/templates/opf/epubv3.opf.erb +1 -0
- data/templates/web/html/layout-html5.html.erb +2 -2
- data/test/assets/test_template.tex +24 -3
- data/test/assets/test_template_backmatter.tex +24 -3
- data/test/test_book.rb +75 -21
- data/test/test_book_chapter.rb +4 -2
- data/test/test_book_part.rb +3 -3
- data/test/test_builder.rb +16 -0
- data/test/test_catalog.rb +24 -42
- data/test/test_catalog_converter_cmd.rb +1 -1
- data/test/test_epubmaker_cmd.rb +14 -7
- data/test/test_helper.rb +15 -7
- data/test/test_htmlbuilder.rb +909 -159
- data/test/test_i18n.rb +25 -25
- data/test/test_idgxmlbuilder.rb +395 -38
- data/test/test_idgxmlmaker_cmd.rb +46 -0
- data/test/test_image_finder.rb +52 -70
- data/test/test_index.rb +50 -10
- data/test/test_latexbuilder.rb +1194 -106
- data/test/test_latexbuilder_v2.rb +628 -97
- data/test/test_logger.rb +14 -1
- data/test/test_makerhelper.rb +3 -3
- data/test/test_markdownbuilder.rb +134 -16
- data/test/test_md2inaobuilder.rb +32 -9
- data/test/test_pdfmaker.rb +18 -1
- data/test/test_pdfmaker_cmd.rb +100 -6
- data/test/test_plaintextbuilder.rb +371 -25
- data/test/test_preprocessor.rb +2 -16
- data/test/test_rstbuilder.rb +249 -26
- data/test/test_textmaker_cmd.rb +54 -0
- data/test/test_textutils.rb +109 -2
- data/test/test_topbuilder.rb +546 -31
- data/test/test_update.rb +17 -8
- data/test/test_webtocprinter.rb +66 -34
- data/test/test_yamlloader.rb +13 -0
- data/vendor/jsclasses/LICENSE +1 -1
- data/vendor/jsclasses/jis/jsarticle.cls +53 -14
- data/vendor/jsclasses/jis/jsbook.cls +53 -14
- data/vendor/jsclasses/jis/jsclasses.dtx +84 -25
- data/vendor/jsclasses/jis/jslogo.dtx +4 -4
- data/vendor/jsclasses/jis/jslogo.sty +3 -3
- data/vendor/jsclasses/jis/jspf.cls +52 -13
- data/vendor/jsclasses/jis/jsreport.cls +53 -14
- data/vendor/jsclasses/jis/kiyou.cls +53 -14
- data/vendor/jsclasses/jis/okumacro.dtx +4 -5
- data/vendor/jsclasses/jis/okumacro.sty +3 -4
- data/vendor/jsclasses/jsarticle.cls +53 -14
- data/vendor/jsclasses/jsbook.cls +53 -14
- data/vendor/jsclasses/jsclasses.dtx +84 -25
- data/vendor/jsclasses/jsclasses.pdf +0 -0
- data/vendor/jsclasses/jslogo.dtx +4 -4
- data/vendor/jsclasses/jslogo.pdf +0 -0
- data/vendor/jsclasses/jslogo.sty +3 -3
- data/vendor/jsclasses/jspf.cls +52 -13
- data/vendor/jsclasses/jsreport.cls +53 -14
- data/vendor/jsclasses/kiyou.cls +53 -14
- data/vendor/jsclasses/okumacro.dtx +4 -5
- data/vendor/jsclasses/okumacro.pdf +0 -0
- data/vendor/jsclasses/okumacro.sty +3 -4
- metadata +55 -10
- data/lib/review/tocparser.rb +0 -271
- data/samples/syntax-book/review-ext.rb +0 -14
- data/test/test_tocparser.rb +0 -25
data/lib/review/epub2html.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#
|
2
|
-
# Copyright (c) 2018 Kenshi Muto
|
2
|
+
# Copyright (c) 2018-2019 Kenshi Muto
|
3
3
|
#
|
4
4
|
# This program is free software.
|
5
5
|
# You can distribute or modify this program under the terms of
|
@@ -9,6 +9,8 @@
|
|
9
9
|
require 'zip'
|
10
10
|
require 'rexml/document'
|
11
11
|
require 'cgi'
|
12
|
+
require 'optparse'
|
13
|
+
require 'review/version'
|
12
14
|
|
13
15
|
module ReVIEW
|
14
16
|
class Epub2Html
|
@@ -17,13 +19,26 @@ module ReVIEW
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def execute(*args)
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
opts = OptionParser.new
|
23
|
+
|
24
|
+
opts.banner = <<EOT
|
25
|
+
Usage: review-epub2html [options] EPUBfile [file_for_head_and_foot] > HTMLfile
|
23
26
|
file_for_head_and_foot: HTML file to extract header and footer area.
|
24
27
|
This file must be contained in the EPUB.
|
25
28
|
If omitted, the first found file is used.
|
29
|
+
|
26
30
|
EOT
|
31
|
+
opts.version = ReVIEW::VERSION
|
32
|
+
opts.on('--help', 'Prints this message and quit.') do
|
33
|
+
puts opts.help
|
34
|
+
exit 0
|
35
|
+
end
|
36
|
+
opts.on('--inline-footnote', 'Embed footnote blocks in paragraph.') { @inline_footnote = true }
|
37
|
+
|
38
|
+
opts.parse!(args)
|
39
|
+
|
40
|
+
if args[0].nil? || !File.exist?(args[0])
|
41
|
+
puts opts.help
|
27
42
|
exit 1
|
28
43
|
end
|
29
44
|
|
@@ -36,6 +51,7 @@ EOT
|
|
36
51
|
@htmls = {}
|
37
52
|
@head = nil
|
38
53
|
@tail = nil
|
54
|
+
@inline_footnote = nil
|
39
55
|
end
|
40
56
|
|
41
57
|
def parse_epub(epubname)
|
@@ -99,6 +115,23 @@ EOT
|
|
99
115
|
e.attributes['href'] = "##{anc}"
|
100
116
|
end
|
101
117
|
|
118
|
+
if @inline_footnote
|
119
|
+
# move footnotes to inline as same as LaTeX.
|
120
|
+
footnotes = {}
|
121
|
+
|
122
|
+
doc.each_element("//div[@class='footnote']") do |e|
|
123
|
+
e.name = 'span'
|
124
|
+
e.attributes.delete('epub:type')
|
125
|
+
footnotes[e.attributes['id']] = e
|
126
|
+
e.remove
|
127
|
+
end
|
128
|
+
|
129
|
+
doc.each_element("//a[@class='noteref']") do |e|
|
130
|
+
e.parent.insert_after(e, footnotes[e.attributes['href'].sub('#', '')])
|
131
|
+
e.remove
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
102
135
|
doc.to_s.
|
103
136
|
sub(/.*(<body.*?>)/m, %Q(<section id="#{sanitize(fname)}">)).
|
104
137
|
sub(%r{(</body>).*}m, '</section>')
|
data/lib/review/epubmaker.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2010-
|
1
|
+
# Copyright (c) 2010-2020 Kenshi Muto and Masayoshi Takahashi
|
2
2
|
#
|
3
3
|
# This program is free software.
|
4
4
|
# You can distribute or modify this program under the terms of
|
@@ -39,12 +39,12 @@ module ReVIEW
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def error(msg)
|
42
|
-
@logger.error
|
42
|
+
@logger.error msg
|
43
43
|
exit 1
|
44
44
|
end
|
45
45
|
|
46
46
|
def warn(msg)
|
47
|
-
@logger.warn
|
47
|
+
@logger.warn msg
|
48
48
|
end
|
49
49
|
|
50
50
|
def log(msg)
|
@@ -64,7 +64,47 @@ module ReVIEW
|
|
64
64
|
@producer.load(yamlfile)
|
65
65
|
@config = @producer.config
|
66
66
|
@config.maker = 'epubmaker'
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.execute(*args)
|
70
|
+
self.new.execute(*args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_opts(args)
|
74
|
+
cmd_config = {}
|
75
|
+
opts = OptionParser.new
|
76
|
+
@buildonly = nil
|
77
|
+
|
78
|
+
opts.banner = 'Usage: review-epubmaker [options] configfile [export_filename]'
|
79
|
+
opts.version = ReVIEW::VERSION
|
80
|
+
opts.on('--help', 'Prints this message and quit.') do
|
81
|
+
puts opts.help
|
82
|
+
exit 0
|
83
|
+
end
|
84
|
+
opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
|
85
|
+
opts.on('-y', '--only file1,file2,...', 'Build only specified files.') { |v| @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') } }
|
86
|
+
|
87
|
+
opts.parse!(args)
|
88
|
+
if args.size < 1 || args.size > 2
|
89
|
+
puts opts.help
|
90
|
+
exit 0
|
91
|
+
end
|
92
|
+
|
93
|
+
[cmd_config, args[0], args[1]]
|
94
|
+
end
|
95
|
+
|
96
|
+
def execute(*args)
|
97
|
+
@config = ReVIEW::Configure.values
|
98
|
+
@config.maker = 'epubmaker'
|
99
|
+
cmd_config, yamlfile, exportfile = parse_opts(args)
|
100
|
+
error "#{yamlfile} not found." unless File.exist?(yamlfile)
|
101
|
+
|
102
|
+
load_yaml(yamlfile)
|
103
|
+
@config.deep_merge!(cmd_config)
|
67
104
|
update_log_level
|
105
|
+
log("Loaded yaml file (#{yamlfile}).")
|
106
|
+
|
107
|
+
produce(yamlfile, exportfile)
|
68
108
|
end
|
69
109
|
|
70
110
|
def update_log_level
|
@@ -89,7 +129,6 @@ module ReVIEW
|
|
89
129
|
end
|
90
130
|
|
91
131
|
def produce(yamlfile, bookname = nil)
|
92
|
-
load_yaml(yamlfile)
|
93
132
|
I18n.setup(@config['language'])
|
94
133
|
bookname ||= @config['bookname']
|
95
134
|
booktmpname = "#{bookname}-epub"
|
@@ -99,7 +138,7 @@ module ReVIEW
|
|
99
138
|
rescue ReVIEW::ConfigError => e
|
100
139
|
warn e.message
|
101
140
|
end
|
102
|
-
log("
|
141
|
+
log("#{bookname}.epub will be created.")
|
103
142
|
|
104
143
|
FileUtils.rm_f("#{bookname}.epub")
|
105
144
|
if @config['debug']
|
@@ -127,7 +166,7 @@ module ReVIEW
|
|
127
166
|
copy_backmatter(basetmpdir)
|
128
167
|
|
129
168
|
math_dir = "./#{@config['imagedir']}/_review_math"
|
130
|
-
if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.
|
169
|
+
if @config['imgmath'] && File.exist?(File.join(math_dir, '__IMGMATH_BODY__.map'))
|
131
170
|
make_math_images(math_dir)
|
132
171
|
end
|
133
172
|
call_hook('hook_afterbackmatter', basetmpdir)
|
@@ -330,6 +369,8 @@ module ReVIEW
|
|
330
369
|
elsif chap.on_predef?
|
331
370
|
chaptype = 'pre'
|
332
371
|
elsif chap.on_appendix?
|
372
|
+
chaptype = 'appendix'
|
373
|
+
elsif chap.on_postdef?
|
333
374
|
chaptype = 'post'
|
334
375
|
end
|
335
376
|
|
@@ -355,6 +396,11 @@ module ReVIEW
|
|
355
396
|
end
|
356
397
|
end
|
357
398
|
|
399
|
+
if @buildonly && !@buildonly.include?(id)
|
400
|
+
warn "skip #{id}.re"
|
401
|
+
return
|
402
|
+
end
|
403
|
+
|
358
404
|
htmlfile = "#{id}.#{@config['htmlext']}"
|
359
405
|
write_buildlogtxt(basetmpdir, htmlfile, filename)
|
360
406
|
log("Create #{htmlfile} from #{filename}.")
|
@@ -406,6 +452,13 @@ module ReVIEW
|
|
406
452
|
path = File.join(basetmpdir, filename)
|
407
453
|
htmlio = File.new(path)
|
408
454
|
Document.parse_stream(htmlio, ReVIEWHeaderListener.new(headlines))
|
455
|
+
htmlio.close
|
456
|
+
|
457
|
+
if headlines.empty?
|
458
|
+
warn "#{filename} is discarded because there is no heading. Use `=[notoc]' or `=[nodisp]' to exclude headlines from the table of contents."
|
459
|
+
return
|
460
|
+
end
|
461
|
+
|
409
462
|
properties = detect_properties(path)
|
410
463
|
if properties.present?
|
411
464
|
prop_str = ',properties=' + properties.join(' ')
|
@@ -433,7 +486,6 @@ module ReVIEW
|
|
433
486
|
first = nil
|
434
487
|
end
|
435
488
|
end
|
436
|
-
htmlio.close
|
437
489
|
end
|
438
490
|
|
439
491
|
def push_contents(_basetmpdir)
|
@@ -461,6 +513,9 @@ module ReVIEW
|
|
461
513
|
def copy_stylesheet(basetmpdir)
|
462
514
|
return if @config['stylesheet'].empty?
|
463
515
|
@config['stylesheet'].each do |sfile|
|
516
|
+
unless File.exist?(sfile)
|
517
|
+
error "#{sfile} is not found."
|
518
|
+
end
|
464
519
|
FileUtils.cp(sfile, basetmpdir)
|
465
520
|
@producer.contents.push(Content.new('file' => sfile))
|
466
521
|
end
|
data/lib/review/htmlbuilder.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2008-
|
1
|
+
# Copyright (c) 2008-2020 Minero Aoki, Kenshi Muto, Masayoshi Takahashi,
|
2
2
|
# KADO Masanori
|
3
3
|
# 2002-2007 Minero Aoki
|
4
4
|
#
|
@@ -12,7 +12,6 @@ require 'review/htmlutils'
|
|
12
12
|
require 'review/template'
|
13
13
|
require 'review/textutils'
|
14
14
|
require 'review/webtocprinter'
|
15
|
-
require 'digest'
|
16
15
|
require 'tmpdir'
|
17
16
|
require 'open3'
|
18
17
|
|
@@ -287,15 +286,25 @@ module ReVIEW
|
|
287
286
|
end
|
288
287
|
|
289
288
|
def box(lines, caption = nil)
|
290
|
-
|
289
|
+
captionstr = nil
|
291
290
|
if caption.present?
|
292
|
-
|
291
|
+
captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
292
|
+
end
|
293
|
+
puts %Q(<div class="syntax">)
|
294
|
+
|
295
|
+
if caption_top?('list') && caption.present?
|
296
|
+
puts captionstr
|
293
297
|
end
|
298
|
+
|
294
299
|
print %Q(<pre class="syntax">)
|
295
300
|
lines.each do |line|
|
296
301
|
puts detab(line)
|
297
302
|
end
|
298
303
|
puts '</pre>'
|
304
|
+
|
305
|
+
if !caption_top?('list') && caption.present?
|
306
|
+
puts captionstr
|
307
|
+
end
|
299
308
|
puts '</div>'
|
300
309
|
end
|
301
310
|
|
@@ -308,7 +317,7 @@ module ReVIEW
|
|
308
317
|
end
|
309
318
|
|
310
319
|
def ul_item_begin(lines)
|
311
|
-
print "<li>#{lines
|
320
|
+
print "<li>#{join_lines_to_paragraph(lines)}"
|
312
321
|
end
|
313
322
|
|
314
323
|
def ul_item_end
|
@@ -329,7 +338,7 @@ module ReVIEW
|
|
329
338
|
end
|
330
339
|
|
331
340
|
def ol_item(lines, _num)
|
332
|
-
puts "<li>#{lines
|
341
|
+
puts "<li>#{join_lines_to_paragraph(lines)}</li>"
|
333
342
|
end
|
334
343
|
|
335
344
|
def ol_end
|
@@ -345,7 +354,7 @@ module ReVIEW
|
|
345
354
|
end
|
346
355
|
|
347
356
|
def dd(lines)
|
348
|
-
puts "<dd>#{lines
|
357
|
+
puts "<dd>#{join_lines_to_paragraph(lines)}</dd>"
|
349
358
|
end
|
350
359
|
|
351
360
|
def dl_end
|
@@ -354,10 +363,10 @@ module ReVIEW
|
|
354
363
|
|
355
364
|
def paragraph(lines)
|
356
365
|
if @noindent
|
357
|
-
puts %Q(<p class="noindent">#{lines
|
366
|
+
puts %Q(<p class="noindent">#{join_lines_to_paragraph(lines)}</p>)
|
358
367
|
@noindent = nil
|
359
368
|
else
|
360
|
-
puts "<p>#{lines
|
369
|
+
puts "<p>#{join_lines_to_paragraph(lines)}</p>"
|
361
370
|
end
|
362
371
|
end
|
363
372
|
|
@@ -374,12 +383,7 @@ module ReVIEW
|
|
374
383
|
|
375
384
|
def list(lines, id, caption, lang = nil)
|
376
385
|
puts %Q(<div id="#{normalize_id(id)}" class="caption-code">)
|
377
|
-
|
378
|
-
list_header id, caption, lang
|
379
|
-
rescue KeyError
|
380
|
-
error "no such list: #{id}"
|
381
|
-
end
|
382
|
-
list_body id, lines, lang
|
386
|
+
super(lines, id, caption, lang)
|
383
387
|
puts '</div>'
|
384
388
|
end
|
385
389
|
|
@@ -404,8 +408,7 @@ module ReVIEW
|
|
404
408
|
|
405
409
|
def source(lines, caption = nil, lang = nil)
|
406
410
|
puts %Q(<div class="source-code">)
|
407
|
-
|
408
|
-
source_body caption, lines, lang
|
411
|
+
super(lines, caption, lang)
|
409
412
|
puts '</div>'
|
410
413
|
end
|
411
414
|
|
@@ -415,7 +418,7 @@ module ReVIEW
|
|
415
418
|
end
|
416
419
|
end
|
417
420
|
|
418
|
-
def source_body(
|
421
|
+
def source_body(lines, lang)
|
419
422
|
print %Q(<pre class="source">)
|
420
423
|
body = lines.inject('') { |i, j| i + detab(j) + "\n" }
|
421
424
|
lexer = lang
|
@@ -425,30 +428,25 @@ module ReVIEW
|
|
425
428
|
|
426
429
|
def listnum(lines, id, caption, lang = nil)
|
427
430
|
puts %Q(<div id="#{normalize_id(id)}" class="code">)
|
428
|
-
|
429
|
-
list_header id, caption, lang
|
430
|
-
rescue KeyError
|
431
|
-
error "no such list: #{id}"
|
432
|
-
end
|
433
|
-
listnum_body lines, lang
|
431
|
+
super(lines, id, caption, lang)
|
434
432
|
puts '</div>'
|
435
433
|
end
|
436
434
|
|
437
435
|
def listnum_body(lines, lang)
|
436
|
+
body = lines.inject('') { |i, j| i + detab(j) + "\n" }
|
437
|
+
lexer = lang
|
438
|
+
first_line_number = line_num
|
439
|
+
hs = highlight(body: body, lexer: lexer, format: 'html', linenum: true,
|
440
|
+
options: { linenostart: first_line_number })
|
441
|
+
|
438
442
|
if highlight?
|
439
|
-
|
440
|
-
lexer = lang
|
441
|
-
first_line_number = line_num
|
442
|
-
puts highlight(body: body, lexer: lexer, format: 'html', linenum: true,
|
443
|
-
options: { linenostart: first_line_number })
|
443
|
+
puts hs
|
444
444
|
else
|
445
445
|
class_names = ['list']
|
446
446
|
class_names.push("language-#{lang}") unless lang.blank?
|
447
|
-
class_names.push('highlight') if highlight?
|
448
447
|
print %Q(<pre class="#{class_names.join(' ')}">)
|
449
|
-
|
450
|
-
|
451
|
-
puts detab((i + first_line_num).to_s.rjust(2) + ': ' + line)
|
448
|
+
hs.split("\n").each_with_index do |line, i|
|
449
|
+
puts detab((i + first_line_number).to_s.rjust(2) + ': ' + line)
|
452
450
|
end
|
453
451
|
puts '</pre>'
|
454
452
|
end
|
@@ -456,7 +454,7 @@ module ReVIEW
|
|
456
454
|
|
457
455
|
def emlist(lines, caption = nil, lang = nil)
|
458
456
|
puts %Q(<div class="emlist-code">)
|
459
|
-
if caption.present?
|
457
|
+
if caption_top?('list') && caption.present?
|
460
458
|
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
461
459
|
end
|
462
460
|
class_names = ['emlist']
|
@@ -467,46 +465,59 @@ module ReVIEW
|
|
467
465
|
lexer = lang
|
468
466
|
puts highlight(body: body, lexer: lexer, format: 'html')
|
469
467
|
puts '</pre>'
|
468
|
+
if !caption_top?('list') && caption.present?
|
469
|
+
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
470
|
+
end
|
470
471
|
puts '</div>'
|
471
472
|
end
|
472
473
|
|
473
474
|
def emlistnum(lines, caption = nil, lang = nil)
|
474
475
|
puts %Q(<div class="emlistnum-code">)
|
475
|
-
if caption.present?
|
476
|
+
if caption_top?('list') && caption.present?
|
476
477
|
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
477
478
|
end
|
478
479
|
|
480
|
+
body = lines.inject('') { |i, j| i + detab(j) + "\n" }
|
481
|
+
lexer = lang
|
482
|
+
first_line_number = line_num
|
483
|
+
hs = highlight(body: body, lexer: lexer, format: 'html', linenum: true,
|
484
|
+
options: { linenostart: first_line_number })
|
479
485
|
if highlight?
|
480
|
-
|
481
|
-
lexer = lang
|
482
|
-
first_line_number = line_num
|
483
|
-
puts highlight(body: body, lexer: lexer, format: 'html', linenum: true,
|
484
|
-
options: { linenostart: first_line_number })
|
486
|
+
puts hs
|
485
487
|
else
|
486
488
|
class_names = ['emlist']
|
487
489
|
class_names.push("language-#{lang}") unless lang.blank?
|
488
490
|
class_names.push('highlight') if highlight?
|
489
491
|
print %Q(<pre class="#{class_names.join(' ')}">)
|
490
|
-
|
491
|
-
|
492
|
-
puts detab((i + first_line_num).to_s.rjust(2) + ': ' + line)
|
492
|
+
hs.split("\n").each_with_index do |line, i|
|
493
|
+
puts detab((i + first_line_number).to_s.rjust(2) + ': ' + line)
|
493
494
|
end
|
494
495
|
puts '</pre>'
|
495
496
|
end
|
496
497
|
|
498
|
+
if !caption_top?('list') && caption.present?
|
499
|
+
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
500
|
+
end
|
501
|
+
|
497
502
|
puts '</div>'
|
498
503
|
end
|
499
504
|
|
500
505
|
def cmd(lines, caption = nil)
|
501
506
|
puts %Q(<div class="cmd-code">)
|
502
|
-
if caption.present?
|
507
|
+
if caption_top?('list') && caption.present?
|
503
508
|
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
504
509
|
end
|
510
|
+
|
505
511
|
print %Q(<pre class="cmd">)
|
506
512
|
body = lines.inject('') { |i, j| i + detab(j) + "\n" }
|
507
513
|
lexer = 'shell-session'
|
508
514
|
puts highlight(body: body, lexer: lexer, format: 'html')
|
509
515
|
puts '</pre>'
|
516
|
+
|
517
|
+
if !caption_top?('list') && caption.present?
|
518
|
+
puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
|
519
|
+
end
|
520
|
+
|
510
521
|
puts '</div>'
|
511
522
|
end
|
512
523
|
|
@@ -541,18 +552,19 @@ module ReVIEW
|
|
541
552
|
|
542
553
|
def texequation(lines, id = nil, caption = '')
|
543
554
|
if id
|
544
|
-
|
555
|
+
puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
|
556
|
+
texequation_header(id, caption) if caption_top?('equation')
|
545
557
|
end
|
546
558
|
|
547
559
|
texequation_body(lines)
|
548
560
|
|
549
561
|
if id
|
562
|
+
texequation_header(id, caption) unless caption_top?('equation')
|
550
563
|
puts '</div>'
|
551
564
|
end
|
552
565
|
end
|
553
566
|
|
554
567
|
def texequation_header(id, caption)
|
555
|
-
puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
|
556
568
|
if get_chap
|
557
569
|
puts %Q(<p class="caption">#{I18n.t('equation')}#{I18n.t('format_number_header', [get_chap, @chapter.equation(id).number])}#{I18n.t('caption_prefix')}#{compile_inline(caption)}</p>)
|
558
570
|
else
|
@@ -566,11 +578,11 @@ module ReVIEW
|
|
566
578
|
require 'math_ml'
|
567
579
|
require 'math_ml/symbol/character_reference'
|
568
580
|
p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
|
569
|
-
|
581
|
+
print p.parse(lines.join("\n") + "\n", true)
|
570
582
|
elsif @book.config['imgmath']
|
571
583
|
fontsize = @book.config['imgmath_options']['fontsize'].to_f
|
572
584
|
lineheight = @book.config['imgmath_options']['lineheight'].to_f
|
573
|
-
math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{
|
585
|
+
math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
|
574
586
|
key = Digest::SHA256.hexdigest(math_str)
|
575
587
|
math_dir = File.join(@book.config['imagedir'], '_review_math')
|
576
588
|
Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
|
@@ -615,20 +627,22 @@ module ReVIEW
|
|
615
627
|
def image_image(id, caption, metric)
|
616
628
|
metrics = parse_metric('html', metric)
|
617
629
|
puts %Q(<div id="#{normalize_id(id)}" class="image">)
|
630
|
+
image_header(id, caption) if caption_top?('image')
|
618
631
|
puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
|
619
|
-
image_header
|
632
|
+
image_header(id, caption) unless caption_top?('image')
|
620
633
|
puts '</div>'
|
621
634
|
end
|
622
635
|
|
623
636
|
def image_dummy(id, caption, lines)
|
624
637
|
warn "image not bound: #{id}"
|
625
638
|
puts %Q(<div id="#{normalize_id(id)}" class="image">)
|
639
|
+
image_header(id, caption) if caption_top?('image')
|
626
640
|
puts %Q(<pre class="dummyimage">)
|
627
641
|
lines.each do |line|
|
628
642
|
puts detab(line)
|
629
643
|
end
|
630
644
|
puts '</pre>'
|
631
|
-
image_header
|
645
|
+
image_header(id, caption) unless caption_top?('image')
|
632
646
|
puts '</div>'
|
633
647
|
end
|
634
648
|
|
@@ -643,47 +657,12 @@ module ReVIEW
|
|
643
657
|
end
|
644
658
|
|
645
659
|
def table(lines, id = nil, caption = nil)
|
646
|
-
rows = []
|
647
|
-
sepidx = nil
|
648
|
-
lines.each_with_index do |line, idx|
|
649
|
-
if /\A[\=\-]{12}/ =~ line
|
650
|
-
# just ignore
|
651
|
-
# error "too many table separator" if sepidx
|
652
|
-
sepidx ||= idx
|
653
|
-
next
|
654
|
-
end
|
655
|
-
rows.push(line.strip.split(/\t+/).map { |s| s.sub(/\A\./, '') })
|
656
|
-
end
|
657
|
-
rows = adjust_n_cols(rows)
|
658
|
-
|
659
660
|
if id
|
660
661
|
puts %Q(<div id="#{normalize_id(id)}" class="table">)
|
661
662
|
else
|
662
663
|
puts %Q(<div class="table">)
|
663
664
|
end
|
664
|
-
|
665
|
-
if caption.present?
|
666
|
-
table_header id, caption
|
667
|
-
end
|
668
|
-
rescue KeyError
|
669
|
-
error "no such table: #{id}"
|
670
|
-
end
|
671
|
-
table_begin rows.first.size
|
672
|
-
return if rows.empty?
|
673
|
-
if sepidx
|
674
|
-
sepidx.times do
|
675
|
-
tr(rows.shift.map { |s| th(s) })
|
676
|
-
end
|
677
|
-
rows.each do |cols|
|
678
|
-
tr(cols.map { |s| td(s) })
|
679
|
-
end
|
680
|
-
else
|
681
|
-
rows.each do |cols|
|
682
|
-
h, *cs = *cols
|
683
|
-
tr([th(h)] + cs.map { |s| td(s) })
|
684
|
-
end
|
685
|
-
end
|
686
|
-
table_end
|
665
|
+
super(lines, id, caption)
|
687
666
|
puts '</div>'
|
688
667
|
end
|
689
668
|
|
@@ -718,23 +697,27 @@ module ReVIEW
|
|
718
697
|
end
|
719
698
|
|
720
699
|
def imgtable(lines, id, caption = nil, metric = nil)
|
721
|
-
unless @chapter.
|
700
|
+
unless @chapter.image_bound?(id)
|
722
701
|
warn "image not bound: #{id}"
|
723
|
-
image_dummy
|
702
|
+
image_dummy(id, caption, lines)
|
724
703
|
return
|
725
704
|
end
|
726
705
|
|
727
706
|
puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
|
728
707
|
begin
|
729
|
-
if caption.present?
|
730
|
-
table_header
|
708
|
+
if caption_top?('table') && caption.present?
|
709
|
+
table_header(id, caption)
|
710
|
+
end
|
711
|
+
|
712
|
+
imgtable_image(id, caption, metric)
|
713
|
+
|
714
|
+
if !caption_top?('table') && caption.present?
|
715
|
+
table_header(id, caption)
|
731
716
|
end
|
732
717
|
rescue KeyError
|
733
718
|
error "no such table: #{id}"
|
734
719
|
end
|
735
720
|
|
736
|
-
imgtable_image(id, caption, metric)
|
737
|
-
|
738
721
|
puts '</div>'
|
739
722
|
end
|
740
723
|
|
@@ -748,16 +731,21 @@ module ReVIEW
|
|
748
731
|
end
|
749
732
|
|
750
733
|
def comment(lines, comment = nil)
|
751
|
-
lines ||= []
|
752
|
-
lines.unshift comment unless comment.blank?
|
753
734
|
return unless @book.config['draft']
|
735
|
+
lines ||= []
|
736
|
+
lines.unshift(escape(comment)) unless comment.blank?
|
754
737
|
str = lines.join('<br />')
|
755
|
-
puts %Q(<div class="draft-comment">#{
|
738
|
+
puts %Q(<div class="draft-comment">#{str}</div>)
|
756
739
|
end
|
757
740
|
|
758
741
|
def footnote(id, str)
|
759
742
|
if @book.config['epubversion'].to_i == 3
|
760
|
-
|
743
|
+
back = ''
|
744
|
+
if @book.config['epubmaker'] && @book.config['epubmaker']['back_footnote']
|
745
|
+
back = %Q(<a href="#fnb-#{normalize_id(id)}">#{I18n.t('html_footnote_backmark')}</a>)
|
746
|
+
end
|
747
|
+
# XXX: back link must be located at first of p for Kindle.
|
748
|
+
puts %Q(<div class="footnote" epub:type="footnote" id="fn-#{normalize_id(id)}"><p class="footnote">#{back}#{I18n.t('html_footnote_textmark', @chapter.footnote(id).number)}#{compile_inline(str)}</p></div>)
|
761
749
|
else
|
762
750
|
puts %Q(<div class="footnote" id="fn-#{normalize_id(id)}"><p class="footnote">[<a href="#fnb-#{normalize_id(id)}">*#{@chapter.footnote(id).number}</a>] #{compile_inline(str)}</p></div>)
|
763
751
|
end
|
@@ -766,7 +754,19 @@ module ReVIEW
|
|
766
754
|
def indepimage(lines, id, caption = '', metric = nil)
|
767
755
|
metrics = parse_metric('html', metric)
|
768
756
|
caption = '' unless caption.present?
|
757
|
+
caption_str = nil
|
758
|
+
if caption.present?
|
759
|
+
caption_str = <<-EOS
|
760
|
+
<p class="caption">
|
761
|
+
#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}
|
762
|
+
</p>
|
763
|
+
EOS
|
764
|
+
end
|
765
|
+
|
769
766
|
puts %Q(<div id="#{normalize_id(id)}" class="image">)
|
767
|
+
if caption_top?('image') && caption.present?
|
768
|
+
puts caption_str
|
769
|
+
end
|
770
770
|
begin
|
771
771
|
puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
|
772
772
|
rescue
|
@@ -780,10 +780,8 @@ module ReVIEW
|
|
780
780
|
end
|
781
781
|
end
|
782
782
|
|
783
|
-
if caption.present?
|
784
|
-
puts
|
785
|
-
puts %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)})
|
786
|
-
puts '</p>'
|
783
|
+
if !caption_top?('image') && caption.present?
|
784
|
+
puts caption_str
|
787
785
|
end
|
788
786
|
puts '</div>'
|
789
787
|
end
|
@@ -862,7 +860,7 @@ module ReVIEW
|
|
862
860
|
|
863
861
|
def inline_fn(id)
|
864
862
|
if @book.config['epubversion'].to_i == 3
|
865
|
-
%Q(<a id="fnb-#{normalize_id(id)}" href="#fn-#{normalize_id(id)}" class="noteref" epub:type="noteref"
|
863
|
+
%Q(<a id="fnb-#{normalize_id(id)}" href="#fn-#{normalize_id(id)}" class="noteref" epub:type="noteref">#{I18n.t('html_footnote_refmark', @chapter.footnote(id).number)}</a>)
|
866
864
|
else
|
867
865
|
%Q(<a id="fnb-#{normalize_id(id)}" href="#fn-#{normalize_id(id)}" class="noteref">*#{@chapter.footnote(id).number}</a>)
|
868
866
|
end
|
@@ -973,8 +971,8 @@ module ReVIEW
|
|
973
971
|
|
974
972
|
def bibpaper(lines, id, caption)
|
975
973
|
puts %Q(<div class="bibpaper">)
|
976
|
-
bibpaper_header
|
977
|
-
bibpaper_bibpaper
|
974
|
+
bibpaper_header(id, caption)
|
975
|
+
bibpaper_bibpaper(id, caption, lines) unless lines.empty?
|
978
976
|
puts '</div>'
|
979
977
|
end
|
980
978
|
|
@@ -997,7 +995,7 @@ module ReVIEW
|
|
997
995
|
|
998
996
|
def inline_hd_chap(chap, id)
|
999
997
|
n = chap.headline_index.number(id)
|
1000
|
-
if
|
998
|
+
if n.present? && chap.number && over_secnolevel?(n)
|
1001
999
|
str = I18n.t('hd_quote', [n, compile_inline(chap.headline(id).caption)])
|
1002
1000
|
else
|
1003
1001
|
str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
|
@@ -1214,17 +1212,6 @@ module ReVIEW
|
|
1214
1212
|
@ol_num = num.to_i
|
1215
1213
|
end
|
1216
1214
|
|
1217
|
-
def defer_math_image(str, path, key)
|
1218
|
-
# for Re:VIEW >3
|
1219
|
-
File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.tex'), 'a+') do |f|
|
1220
|
-
f.puts str
|
1221
|
-
f.puts '\\clearpage'
|
1222
|
-
end
|
1223
|
-
File.open(File.join(File.dirname(path), '__IMGMATH_BODY__.map'), 'a+') do |f|
|
1224
|
-
f.puts key
|
1225
|
-
end
|
1226
|
-
end
|
1227
|
-
|
1228
1215
|
def make_math_image(str, path, fontsize = 12)
|
1229
1216
|
# Re:VIEW 2 compatibility
|
1230
1217
|
fontsize2 = (fontsize * 1.2).round.to_i
|