review 5.0.0 → 5.1.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-tex.yml +31 -0
- data/.github/workflows/ruby-win.yml +3 -3
- data/.github/workflows/ruby.yml +1 -1
- data/.rubocop.yml +15 -7
- data/NEWS.ja.md +108 -0
- data/NEWS.md +108 -0
- data/README.md +7 -6
- data/Rakefile +7 -2
- data/bin/review +2 -4
- data/bin/review-catalog-converter +3 -3
- data/bin/review-check +6 -8
- data/bin/review-checkdep +1 -4
- data/bin/review-compile +2 -5
- data/bin/review-epub2html +1 -4
- data/bin/review-epubmaker +3 -4
- data/bin/review-idgxmlmaker +1 -3
- data/bin/review-index +11 -5
- data/bin/review-init +1 -4
- data/bin/review-pdfmaker +1 -3
- data/bin/review-preproc +2 -4
- data/bin/review-textmaker +1 -3
- data/bin/review-update +1 -4
- data/bin/review-validate +3 -3
- data/bin/review-vol +1 -4
- data/bin/review-webmaker +1 -3
- data/doc/config.yml.sample +21 -5
- data/doc/config.yml.sample-simple +1 -1
- data/doc/format.ja.md +21 -10
- data/doc/format.md +21 -10
- data/doc/quickstart.ja.md +11 -1
- data/doc/quickstart.md +11 -2
- data/lib/review.rb +1 -1
- data/lib/review/book/base.rb +4 -0
- data/lib/review/book/book_unit.rb +3 -0
- data/lib/review/book/chapter.rb +3 -0
- data/lib/review/book/index.rb +1 -0
- data/lib/review/book/volume.rb +1 -0
- data/lib/review/builder.rb +8 -1
- data/lib/review/call_hook.rb +20 -0
- data/lib/review/catalog.rb +1 -0
- data/lib/review/compiler.rb +27 -10
- data/lib/review/configure.rb +64 -7
- data/lib/review/epubmaker.rb +93 -96
- data/lib/review/epubmaker/content.rb +113 -0
- data/lib/review/epubmaker/epubcommon.rb +372 -0
- data/lib/review/epubmaker/epubv2.rb +178 -0
- data/lib/review/epubmaker/epubv3.rb +231 -0
- data/lib/review/epubmaker/producer.rb +168 -0
- data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
- data/lib/review/epubmaker/zip_exporter.rb +84 -0
- data/lib/review/exception.rb +6 -0
- data/lib/review/htmlbuilder.rb +36 -49
- data/lib/review/htmlutils.rb +1 -1
- data/lib/review/i18n.rb +1 -0
- data/lib/review/idgxmlbuilder.rb +33 -30
- data/lib/review/idgxmlmaker.rb +3 -1
- data/lib/review/img_math.rb +245 -0
- data/lib/review/index_builder.rb +1 -0
- data/lib/review/init.rb +4 -4
- data/lib/review/latexbox.rb +58 -0
- data/lib/review/latexbuilder.rb +30 -19
- data/lib/review/latexutils.rb +9 -1
- data/lib/review/lineinput.rb +112 -2
- data/lib/review/logger.rb +41 -2
- data/lib/review/makerhelper.rb +2 -205
- data/lib/review/markdownbuilder.rb +32 -1
- data/lib/review/pdfmaker.rb +31 -29
- data/lib/review/plaintextbuilder.rb +9 -1
- data/lib/review/preprocessor.rb +12 -6
- data/lib/review/rstbuilder.rb +1 -1
- data/lib/review/sec_counter.rb +1 -0
- data/lib/review/template.rb +6 -0
- data/lib/review/textmaker.rb +11 -7
- data/lib/review/textutils.rb +2 -10
- data/lib/review/tocprinter.rb +85 -68
- data/lib/review/topbuilder.rb +18 -11
- data/lib/review/update.rb +5 -6
- data/lib/review/version.rb +1 -1
- data/lib/review/volumeprinter.rb +4 -5
- data/lib/review/webmaker.rb +18 -13
- data/lib/review/webtocprinter.rb +10 -9
- data/lib/review/yamlloader.rb +2 -1
- data/review.gemspec +5 -3
- data/samples/sample-book/src/config-epub2.yml +1 -1
- data/samples/sample-book/src/config.yml +1 -1
- data/samples/sample-book/src/lib/tasks/review.rake +17 -1
- data/samples/syntax-book/ch01.re +1 -1
- data/samples/syntax-book/ch02.re +21 -6
- data/samples/syntax-book/ch03.re +1 -1
- data/samples/syntax-book/images/img3-2.png +0 -0
- data/templates/html/_colophon.html.erb +23 -0
- data/templates/html/_colophon_history.html.erb +9 -0
- data/templates/html/_cover.html.erb +10 -0
- data/templates/html/_part_body.html.erb +6 -0
- data/templates/html/_titlepage.html.erb +20 -0
- data/templates/html/layout-html5.html.erb +6 -0
- data/templates/html/layout-xhtml1.html.erb +6 -0
- data/templates/latex/config.erb +8 -0
- data/templates/latex/review-jlreq/review-base.sty +4 -5
- data/templates/latex/review-jlreq/review-jlreq.cls +10 -2
- data/templates/latex/review-jlreq/review-style.sty +6 -1
- data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
- data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
- data/templates/latex/review-jsbook/review-base.sty +5 -7
- data/templates/latex/review-jsbook/review-jsbook.cls +10 -2
- data/templates/latex/review-jsbook/review-style.sty +6 -1
- data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
- data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
- data/templates/opf/epubv2.opf.erb +7 -7
- data/templates/opf/epubv3.opf.erb +7 -7
- data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
- data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
- data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
- data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
- data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
- data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
- data/templates/web/html/layout-html5.html.erb +6 -5
- data/templates/web/html/layout-xhtml1.html.erb +6 -0
- data/test/assets/header_listener.html +35 -0
- data/test/assets/img_math/img1.png +0 -0
- data/test/assets/img_math/img2.png +0 -0
- data/test/assets/img_math/img3.png +0 -0
- data/test/assets/syntax_book_index_detail.txt +58 -0
- data/test/assets/test_template.tex +4 -1
- data/test/assets/test_template_backmatter.tex +4 -1
- data/test/run_test.rb +1 -1
- data/test/test_book_chapter.rb +2 -2
- data/test/test_catalog_converter_cmd.rb +1 -1
- data/test/test_epub3maker.rb +168 -124
- data/test/test_epubmaker.rb +243 -131
- data/test/test_epubmaker_cmd.rb +2 -2
- data/test/test_helper.rb +5 -4
- data/test/test_htmlbuilder.rb +64 -6
- data/test/test_idgxmlbuilder.rb +13 -0
- data/test/test_idgxmlmaker_cmd.rb +7 -3
- data/test/test_img_math.rb +111 -0
- data/test/test_indexbuilder.rb +5 -5
- data/test/test_latexbuilder.rb +107 -4
- data/test/test_lineinput.rb +20 -93
- data/test/test_markdownbuilder.rb +29 -0
- data/test/test_pdfmaker.rb +71 -0
- data/test/test_pdfmaker_cmd.rb +2 -2
- data/test/test_plaintextbuilder.rb +10 -18
- data/test/test_reviewheaderlistener.rb +49 -0
- data/test/test_template.rb +12 -2
- data/test/test_textmaker_cmd.rb +5 -1
- data/test/test_tocprinter.rb +46 -0
- data/test/test_topbuilder.rb +6 -1
- data/test/test_update.rb +34 -34
- data/test/test_zip_exporter.rb +5 -6
- metadata +91 -17
- data/lib/epubmaker.rb +0 -23
- data/lib/epubmaker/content.rb +0 -111
- data/lib/epubmaker/epubcommon.rb +0 -449
- data/lib/epubmaker/epubv2.rb +0 -142
- data/lib/epubmaker/epubv3.rb +0 -235
- data/lib/epubmaker/producer.rb +0 -375
- data/lib/epubmaker/zip_exporter.rb +0 -81
- data/lib/lineinput.rb +0 -155
data/lib/review/exception.rb
CHANGED
@@ -10,10 +10,16 @@
|
|
10
10
|
|
11
11
|
module ReVIEW
|
12
12
|
class Error < ::StandardError; end
|
13
|
+
|
13
14
|
class ApplicationError < Error; end
|
15
|
+
|
14
16
|
class ConfigError < ApplicationError; end
|
17
|
+
|
15
18
|
class CompileError < ApplicationError; end
|
19
|
+
|
16
20
|
class SyntaxError < CompileError; end
|
21
|
+
|
17
22
|
class FileNotFound < ApplicationError; end
|
23
|
+
|
18
24
|
class KeyError < CompileError; end
|
19
25
|
end
|
data/lib/review/htmlbuilder.rb
CHANGED
@@ -53,6 +53,7 @@ module ReVIEW
|
|
53
53
|
@first_line_num = nil
|
54
54
|
@body_ext = nil
|
55
55
|
@toc = nil
|
56
|
+
@javascripts = []
|
56
57
|
end
|
57
58
|
private :builder_init_file
|
58
59
|
|
@@ -74,6 +75,7 @@ module ReVIEW
|
|
74
75
|
if !File.exist?(layout_file) && File.exist?(File.join(@book.basedir, 'layouts', 'layout.erb'))
|
75
76
|
raise ReVIEW::ConfigError, 'layout.erb is obsoleted. Please use layout.html.erb.'
|
76
77
|
end
|
78
|
+
|
77
79
|
if File.exist?(layout_file)
|
78
80
|
if ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
|
79
81
|
warn %Q(user's layout is prohibited in safe mode. ignored.)
|
@@ -100,6 +102,11 @@ module ReVIEW
|
|
100
102
|
@toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
|
101
103
|
end
|
102
104
|
|
105
|
+
if @book.config['math_format'] == 'mathjax'
|
106
|
+
@javascripts.push(%Q(<script>MathJax = { tex: { inlineMath: [['\\\\(', '\\\\)']] }, svg: { fontCache: 'global' } };</script>))
|
107
|
+
@javascripts.push(%Q(<script type="text/javascript" id="MathJax-script" async="true" src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>))
|
108
|
+
end
|
109
|
+
|
103
110
|
ReVIEW::Template.load(layoutfile).result(binding)
|
104
111
|
end
|
105
112
|
|
@@ -149,6 +156,7 @@ module ReVIEW
|
|
149
156
|
@nonum_counter += 1
|
150
157
|
puts if level > 1
|
151
158
|
return unless caption.present?
|
159
|
+
|
152
160
|
if label
|
153
161
|
puts %Q(<h#{level} id="#{normalize_id(label)}">#{compile_inline(caption)}</h#{level}>)
|
154
162
|
else
|
@@ -164,6 +172,7 @@ module ReVIEW
|
|
164
172
|
@nonum_counter += 1
|
165
173
|
puts if level > 1
|
166
174
|
return unless caption.present?
|
175
|
+
|
167
176
|
if label
|
168
177
|
puts %Q(<h#{level} id="#{normalize_id(label)}" notoc="true">#{compile_inline(caption)}</h#{level}>)
|
169
178
|
else
|
@@ -179,6 +188,7 @@ module ReVIEW
|
|
179
188
|
@nonum_counter += 1
|
180
189
|
puts '' if level > 1
|
181
190
|
return unless caption.present?
|
191
|
+
|
182
192
|
if label
|
183
193
|
puts %Q(<a id="#{normalize_id(label)}" /><h#{level} id="#{normalize_id(label)}" hidden="true">#{compile_inline(caption)}</h#{level}>)
|
184
194
|
else
|
@@ -603,24 +613,27 @@ module ReVIEW
|
|
603
613
|
|
604
614
|
def texequation_body(lines)
|
605
615
|
puts %Q(<div class="equation">)
|
606
|
-
if @book.config['mathml'
|
607
|
-
|
608
|
-
|
616
|
+
if @book.config['math_format'] == 'mathml'
|
617
|
+
begin
|
618
|
+
require 'math_ml'
|
619
|
+
require 'math_ml/symbol/character_reference'
|
620
|
+
rescue LoadError
|
621
|
+
error 'not found math_ml'
|
622
|
+
end
|
609
623
|
p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
|
610
624
|
print p.parse(lines.join("\n") + "\n", true)
|
611
|
-
elsif @book.config['
|
625
|
+
elsif @book.config['math_format'] == 'mathjax'
|
626
|
+
puts "$$#{lines.join("\n")}$$"
|
627
|
+
elsif @book.config['math_format'] == 'imgmath'
|
612
628
|
fontsize = @book.config['imgmath_options']['fontsize'].to_f
|
613
629
|
lineheight = @book.config['imgmath_options']['lineheight'].to_f
|
614
630
|
math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
|
615
631
|
key = Digest::SHA256.hexdigest(math_str)
|
616
|
-
math_dir = File.join(@book.config['imagedir'], '_review_math')
|
617
|
-
Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
|
618
|
-
img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
|
619
632
|
if @book.config.check_version('2', exception: false)
|
620
|
-
make_math_image(math_str,
|
633
|
+
img_path = @img_math.make_math_image(math_str, key)
|
621
634
|
puts %Q(<img src="#{img_path}" />)
|
622
635
|
else
|
623
|
-
defer_math_image(math_str,
|
636
|
+
img_path = @img_math.defer_math_image(math_str, key)
|
624
637
|
puts %Q(<img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(lines.join(' '))}" />)
|
625
638
|
end
|
626
639
|
else
|
@@ -761,6 +774,7 @@ module ReVIEW
|
|
761
774
|
|
762
775
|
def comment(lines, comment = nil)
|
763
776
|
return unless @book.config['draft']
|
777
|
+
|
764
778
|
lines ||= []
|
765
779
|
lines.unshift(escape(comment)) unless comment.blank?
|
766
780
|
str = lines.join('<br />')
|
@@ -971,22 +985,25 @@ EOS
|
|
971
985
|
end
|
972
986
|
|
973
987
|
def inline_m(str)
|
974
|
-
if @book.config['mathml'
|
975
|
-
|
976
|
-
|
988
|
+
if @book.config['math_format'] == 'mathml'
|
989
|
+
begin
|
990
|
+
require 'math_ml'
|
991
|
+
require 'math_ml/symbol/character_reference'
|
992
|
+
rescue LoadError
|
993
|
+
error 'not found math_ml'
|
994
|
+
end
|
977
995
|
parser = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
|
978
996
|
%Q(<span class="equation">#{parser.parse(str, nil)}</span>)
|
979
|
-
elsif @book.config['
|
997
|
+
elsif @book.config['math_format'] == 'mathjax'
|
998
|
+
%Q(<span class="equation">\\( #{str} \\)</span>)
|
999
|
+
elsif @book.config['math_format'] == 'imgmath'
|
980
1000
|
math_str = '$' + str + '$'
|
981
1001
|
key = Digest::SHA256.hexdigest(str)
|
982
|
-
math_dir = File.join(@book.config['imagedir'], '_review_math')
|
983
|
-
Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
|
984
|
-
img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
|
985
1002
|
if @book.config.check_version('2', exception: false)
|
986
|
-
make_math_image(math_str,
|
1003
|
+
img_path = @img_math.make_math_image(math_str, key)
|
987
1004
|
%Q(<span class="equation"><img src="#{img_path}" /></span>)
|
988
1005
|
else
|
989
|
-
defer_math_image(math_str,
|
1006
|
+
img_path = @img_math.defer_math_image(math_str, key)
|
990
1007
|
%Q(<span class="equation"><img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(str)}" /></span>)
|
991
1008
|
end
|
992
1009
|
else
|
@@ -1030,7 +1047,7 @@ EOS
|
|
1030
1047
|
str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
|
1031
1048
|
end
|
1032
1049
|
if @book.config['chapterlink']
|
1033
|
-
anchor = 'h' + n.
|
1050
|
+
anchor = 'h' + n.tr('.', '-')
|
1034
1051
|
%Q(<a href="#{chap.id}#{extname}##{anchor}">#{str}</a>)
|
1035
1052
|
else
|
1036
1053
|
str
|
@@ -1240,35 +1257,5 @@ EOS
|
|
1240
1257
|
def olnum(num)
|
1241
1258
|
@ol_num = num.to_i
|
1242
1259
|
end
|
1243
|
-
|
1244
|
-
def make_math_image(str, path, fontsize = 12)
|
1245
|
-
# Re:VIEW 2 compatibility
|
1246
|
-
fontsize2 = (fontsize * 1.2).round.to_i
|
1247
|
-
texsrc = <<-EOB
|
1248
|
-
\\documentclass[12pt]{article}
|
1249
|
-
\\usepackage[utf8]{inputenc}
|
1250
|
-
\\usepackage{amsmath}
|
1251
|
-
\\usepackage{amsthm}
|
1252
|
-
\\usepackage{amssymb}
|
1253
|
-
\\usepackage{amsfonts}
|
1254
|
-
\\usepackage{anyfontsize}
|
1255
|
-
\\usepackage{bm}
|
1256
|
-
\\pagestyle{empty}
|
1257
|
-
|
1258
|
-
\\begin{document}
|
1259
|
-
\\fontsize{#{fontsize}}{#{fontsize2}}\\selectfont #{str}
|
1260
|
-
\\end{document}
|
1261
|
-
EOB
|
1262
|
-
Dir.mktmpdir do |tmpdir|
|
1263
|
-
tex_path = File.join(tmpdir, 'tmpmath.tex')
|
1264
|
-
dvi_path = File.join(tmpdir, 'tmpmath.dvi')
|
1265
|
-
File.write(tex_path, texsrc)
|
1266
|
-
cmd = "latex --interaction=nonstopmode --output-directory=#{tmpdir} #{tex_path} && dvipng -T tight -z9 -o #{path} #{dvi_path}"
|
1267
|
-
out, status = Open3.capture2e(cmd)
|
1268
|
-
unless status.success?
|
1269
|
-
error "latex compile error\n\nError log:\n" + out
|
1270
|
-
end
|
1271
|
-
end
|
1272
|
-
end
|
1273
1260
|
end
|
1274
1261
|
end # module ReVIEW
|
data/lib/review/htmlutils.rb
CHANGED
@@ -134,7 +134,7 @@ module ReVIEW
|
|
134
134
|
elsif id =~ /\A[0-9_.-][a-z0-9_.-]*\Z/i
|
135
135
|
"id_#{id}" # dummy prefix
|
136
136
|
else
|
137
|
-
"id_#{CGI.escape(id.gsub('_', '__')).
|
137
|
+
"id_#{CGI.escape(id.gsub('_', '__')).tr('%', '_').tr('+', '-')}" # escape all
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
data/lib/review/i18n.rb
CHANGED
data/lib/review/idgxmlbuilder.rb
CHANGED
@@ -103,15 +103,9 @@ module ReVIEW
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def headline(level, label, caption)
|
106
|
+
output_close_sect_tags(level)
|
106
107
|
case level
|
107
108
|
when 1
|
108
|
-
if @secttags
|
109
|
-
print '</sect4>' if @subsubsubsection > 0
|
110
|
-
print '</sect3>' if @subsubsection > 0
|
111
|
-
print '</sect2>' if @subsection > 0
|
112
|
-
print '</sect>' if @section > 0
|
113
|
-
end
|
114
|
-
|
115
109
|
print %Q(<chapter id="chap:#{@chapter.number}">) if @secttags
|
116
110
|
|
117
111
|
@section = 0
|
@@ -119,12 +113,6 @@ module ReVIEW
|
|
119
113
|
@subsubsection = 0
|
120
114
|
@subsubsubsection = 0
|
121
115
|
when 2
|
122
|
-
if @secttags
|
123
|
-
print '</sect4>' if @subsubsubsection > 0
|
124
|
-
print '</sect3>' if @subsubsection > 0
|
125
|
-
print '</sect2>' if @subsection > 0
|
126
|
-
print '</sect>' if @section > 0
|
127
|
-
end
|
128
116
|
@section += 1
|
129
117
|
print %Q(<sect id="sect:#{@chapter.number}.#{@section}">) if @secttags
|
130
118
|
|
@@ -132,30 +120,17 @@ module ReVIEW
|
|
132
120
|
@subsubsection = 0
|
133
121
|
@subsubsubsection = 0
|
134
122
|
when 3
|
135
|
-
if @secttags
|
136
|
-
print '</sect4>' if @subsubsubsection > 0
|
137
|
-
print '</sect3>' if @subsubsection > 0
|
138
|
-
print '</sect2>' if @subsection > 0
|
139
|
-
end
|
140
|
-
|
141
123
|
@subsection += 1
|
142
124
|
print %Q(<sect2 id="sect:#{@chapter.number}.#{@section}.#{@subsection}">) if @secttags
|
143
125
|
|
144
126
|
@subsubsection = 0
|
145
127
|
@subsubsubsection = 0
|
146
128
|
when 4
|
147
|
-
if @secttags
|
148
|
-
print '</sect4>' if @subsubsubsection > 0
|
149
|
-
print '</sect3>' if @subsubsection > 0
|
150
|
-
end
|
151
|
-
|
152
129
|
@subsubsection += 1
|
153
130
|
print %Q(<sect3 id="sect:#{@chapter.number}.#{@section}.#{@subsection}.#{@subsubsection}">) if @secttags
|
154
131
|
|
155
132
|
@subsubsubsection = 0
|
156
133
|
when 5
|
157
|
-
print '</sect4>' if @secttags && @subsubsubsection > 0
|
158
|
-
|
159
134
|
@subsubsubsection += 1
|
160
135
|
print %Q(<sect4 id="sect:#{@chapter.number}.#{@section}.#{@subsection}.#{@subsubsection}.#{@subsubsubsection}">) if @secttags
|
161
136
|
when 6 # rubocop:disable Lint/EmptyWhen
|
@@ -170,6 +145,23 @@ module ReVIEW
|
|
170
145
|
puts %Q(<title#{label} aid:pstyle="h#{level}">#{prefix}#{compile_inline(caption)}</title><?dtp level="#{level}" section="#{prefix}#{toccaption}"?>)
|
171
146
|
end
|
172
147
|
|
148
|
+
def output_close_sect_tags(level)
|
149
|
+
if @secttags
|
150
|
+
if level <= 5 && @subsubsubsection > 0
|
151
|
+
print '</sect4>'
|
152
|
+
end
|
153
|
+
if level <= 4 && @subsubsection > 0
|
154
|
+
print '</sect3>'
|
155
|
+
end
|
156
|
+
if level <= 3 && @subsection > 0
|
157
|
+
print '</sect2>'
|
158
|
+
end
|
159
|
+
if level <= 2 && @section > 0
|
160
|
+
print '</sect>'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
173
165
|
def ul_begin
|
174
166
|
level = block_given? ? yield : ''
|
175
167
|
level = nil if level == 1
|
@@ -282,6 +274,7 @@ module ReVIEW
|
|
282
274
|
|
283
275
|
def list_header(id, caption, _lang)
|
284
276
|
return true unless caption.present?
|
277
|
+
|
285
278
|
if get_chap.nil?
|
286
279
|
puts %Q(<caption>#{I18n.t('list')}#{I18n.t('format_number_without_chapter', [@chapter.list(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
|
287
280
|
else
|
@@ -448,6 +441,7 @@ module ReVIEW
|
|
448
441
|
|
449
442
|
def image_header(id, caption)
|
450
443
|
return true unless caption.present?
|
444
|
+
|
451
445
|
if get_chap.nil?
|
452
446
|
puts %Q(<caption>#{I18n.t('image')}#{I18n.t('format_number_without_chapter', [@chapter.image(id).number])}#{I18n.t('caption_prefix_idgxml')}#{compile_inline(caption)}</caption>)
|
453
447
|
else
|
@@ -640,6 +634,7 @@ module ReVIEW
|
|
640
634
|
|
641
635
|
def comment(lines, comment = nil)
|
642
636
|
return unless @book.config['draft']
|
637
|
+
|
643
638
|
lines ||= []
|
644
639
|
lines.unshift(escape(comment)) unless comment.blank?
|
645
640
|
str = lines.join("\n")
|
@@ -674,7 +669,7 @@ module ReVIEW
|
|
674
669
|
then escape("#{word}(#{alt.strip})")
|
675
670
|
else escape(word)
|
676
671
|
end +
|
677
|
-
|
672
|
+
'</keyword>' +
|
678
673
|
%Q(<index value="#{escape(word)}" />) +
|
679
674
|
if alt
|
680
675
|
alt.split(/\s*,\s*/).collect! { |e| %Q(<index value="#{escape(e.strip)}" />) }.join
|
@@ -773,6 +768,14 @@ module ReVIEW
|
|
773
768
|
%Q(<underline>#{escape(str)}</underline>)
|
774
769
|
end
|
775
770
|
|
771
|
+
def inline_ins(str)
|
772
|
+
%Q(<ins>#{escape(str)}</ins>)
|
773
|
+
end
|
774
|
+
|
775
|
+
def inline_del(str)
|
776
|
+
%Q(<del>#{escape(str)}</del>)
|
777
|
+
end
|
778
|
+
|
776
779
|
def inline_icon(id)
|
777
780
|
begin
|
778
781
|
%Q(<Image href="file://#{@chapter.image(id).path.sub(%r{\A\./}, '')}" type="inline" />)
|
@@ -1182,10 +1185,10 @@ module ReVIEW
|
|
1182
1185
|
chs = ['', '「', '」']
|
1183
1186
|
if @book.config['chapref']
|
1184
1187
|
chs2 = @book.config['chapref'].split(',')
|
1185
|
-
if chs2.size
|
1186
|
-
error '--chapsplitter must have exactly 3 parameters with comma.'
|
1187
|
-
else
|
1188
|
+
if chs2.size == 3
|
1188
1189
|
chs = chs2
|
1190
|
+
else
|
1191
|
+
error '--chapsplitter must have exactly 3 parameters with comma.'
|
1189
1192
|
end
|
1190
1193
|
end
|
1191
1194
|
s = "#{chs[0]}#{@book.chapter_index.number(id)}#{chs[1]}#{@book.chapter_index.title(id)}#{chs[2]}"
|
data/lib/review/idgxmlmaker.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2019 Kenshi Muto
|
1
|
+
# Copyright (c) 2019-2021 Kenshi Muto
|
2
2
|
#
|
3
3
|
# This program is free software.
|
4
4
|
# You can distribute or modify this program under the terms of
|
@@ -86,8 +86,10 @@ module ReVIEW
|
|
86
86
|
I18n.setup(@config['language'])
|
87
87
|
begin
|
88
88
|
generate_idgxml_files(yamlfile)
|
89
|
+
@logger.success("built #{build_path}")
|
89
90
|
rescue ApplicationError => e
|
90
91
|
raise if @config['debug']
|
92
|
+
|
91
93
|
error(e.message)
|
92
94
|
end
|
93
95
|
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module ReVIEW
|
5
|
+
class ImgMath
|
6
|
+
def initialize(config, path_name: '_review_math')
|
7
|
+
@config = config
|
8
|
+
@logger = ReVIEW.logger
|
9
|
+
@math_dir = File.join(@config['imagedir'], path_name)
|
10
|
+
@math_maps = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def cleanup_mathimg
|
14
|
+
if @config['math_format'] == 'imgmath' && Dir.exist?(@math_dir)
|
15
|
+
FileUtils.rm_rf(@math_dir)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def defer_math_image(str, key)
|
20
|
+
# for Re:VIEW >3
|
21
|
+
@math_maps[key] = str
|
22
|
+
File.join(@math_dir, "_gen_#{key}.#{@config['imgmath_options']['format']}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def make_math_image(str, key, fontsize = 12)
|
26
|
+
# Re:VIEW 2 compatibility
|
27
|
+
|
28
|
+
img_path = File.join(@math_dir, "_gen_#{key}.#{@config['imgmath_options']['format']}")
|
29
|
+
Dir.mkdir(@math_dir) unless Dir.exist?(@math_dir)
|
30
|
+
fontsize2 = (fontsize * 1.2).round.to_i
|
31
|
+
texsrc = <<-EOB
|
32
|
+
\\documentclass[12pt]{article}
|
33
|
+
\\usepackage[utf8]{inputenc}
|
34
|
+
\\usepackage{amsmath}
|
35
|
+
\\usepackage{amsthm}
|
36
|
+
\\usepackage{amssymb}
|
37
|
+
\\usepackage{amsfonts}
|
38
|
+
\\usepackage{anyfontsize}
|
39
|
+
\\usepackage{bm}
|
40
|
+
\\pagestyle{empty}
|
41
|
+
|
42
|
+
\\begin{document}
|
43
|
+
\\fontsize{#{fontsize}}{#{fontsize2}}\\selectfont #{str}
|
44
|
+
\\end{document}
|
45
|
+
EOB
|
46
|
+
Dir.mktmpdir do |tmpdir|
|
47
|
+
tex_path = File.join(tmpdir, 'tmpmath.tex')
|
48
|
+
dvi_path = File.join(tmpdir, 'tmpmath.dvi')
|
49
|
+
File.write(tex_path, texsrc)
|
50
|
+
cmd = "latex --interaction=nonstopmode --output-directory=#{tmpdir} #{tex_path} && dvipng -T tight -z9 -o #{img_path} #{dvi_path}"
|
51
|
+
out, status = Open3.capture2e(cmd)
|
52
|
+
unless status.success?
|
53
|
+
raise ApplicationError, "latex compile error\n\nError log:\n" + out
|
54
|
+
end
|
55
|
+
|
56
|
+
img_path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def make_math_images
|
61
|
+
return if @math_maps.empty?
|
62
|
+
|
63
|
+
Dir.mkdir(@math_dir) unless Dir.exist?(@math_dir)
|
64
|
+
fontsize = @config['imgmath_options']['fontsize'].to_f
|
65
|
+
lineheight = @config['imgmath_options']['lineheight'].to_f
|
66
|
+
|
67
|
+
texsrc = default_imgmath_preamble
|
68
|
+
if @config['imgmath_options']['preamble_file'] && File.readable?(@config['imgmath_options']['preamble_file'])
|
69
|
+
texsrc = File.read(@config['imgmath_options']['preamble_file'])
|
70
|
+
end
|
71
|
+
|
72
|
+
texsrc << <<-EOB
|
73
|
+
\\begin{document}
|
74
|
+
\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont
|
75
|
+
\\input{__IMGMATH_BODY__}
|
76
|
+
\\end{document}
|
77
|
+
EOB
|
78
|
+
|
79
|
+
math_real_dir = File.realpath(@math_dir)
|
80
|
+
Dir.mktmpdir do |tmpdir|
|
81
|
+
File.open(File.join(tmpdir, '__IMGMATH_BODY__.tex'), 'w') do |f|
|
82
|
+
@math_maps.keys.sort.each do |key|
|
83
|
+
f.puts "% #{key}"
|
84
|
+
f.puts @math_maps[key]
|
85
|
+
f.puts '\\clearpage'
|
86
|
+
f.puts
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
tex_path = File.join(tmpdir, '__IMGMATH__.tex')
|
91
|
+
File.write(tex_path, texsrc)
|
92
|
+
|
93
|
+
begin
|
94
|
+
case @config['imgmath_options']['converter']
|
95
|
+
when 'pdfcrop'
|
96
|
+
make_math_images_pdfcrop(tmpdir, tex_path, math_real_dir)
|
97
|
+
when 'dvipng'
|
98
|
+
make_math_images_dvipng(tmpdir, tex_path, math_real_dir)
|
99
|
+
else
|
100
|
+
error "unknown math converter error. imgmath_options/converter parameter should be 'pdfcrop' or 'dvipng'."
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
rescue CompileError
|
104
|
+
FileUtils.cp([tex_path,
|
105
|
+
File.join(File.dirname(tex_path), '__IMGMATH__.log')],
|
106
|
+
math_real_dir)
|
107
|
+
error "LaTeX math compile error. See #{math_real_dir}/__IMGMATH__.log for details."
|
108
|
+
exit 1
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@math_maps.clear
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def error(msg)
|
117
|
+
@logger.error msg
|
118
|
+
end
|
119
|
+
|
120
|
+
def warn(msg)
|
121
|
+
@logger.warn msg
|
122
|
+
end
|
123
|
+
|
124
|
+
def default_imgmath_preamble
|
125
|
+
<<-EOB
|
126
|
+
\\documentclass[uplatex,a3paper,landscape]{jsarticle}
|
127
|
+
\\usepackage[deluxe,uplatex]{otf}
|
128
|
+
\\usepackage[T1]{fontenc}
|
129
|
+
\\usepackage{textcomp}
|
130
|
+
\\usepackage{lmodern}
|
131
|
+
\\usepackage[dvipdfmx]{graphicx}
|
132
|
+
\\usepackage[dvipdfmx,table]{xcolor}
|
133
|
+
\\usepackage[utf8]{inputenc}
|
134
|
+
\\usepackage{ascmac}
|
135
|
+
\\usepackage{float}
|
136
|
+
\\usepackage{alltt}
|
137
|
+
\\usepackage{amsmath}
|
138
|
+
\\usepackage{amssymb}
|
139
|
+
\\usepackage{amsfonts}
|
140
|
+
\\usepackage{anyfontsize}
|
141
|
+
\\usepackage{bm}
|
142
|
+
\\pagestyle{empty}
|
143
|
+
% \\setpaperwidth{1000mm}
|
144
|
+
EOB
|
145
|
+
end
|
146
|
+
|
147
|
+
def make_math_images_pdfcrop(dir, tex_path, math_real_dir)
|
148
|
+
Dir.chdir(dir) do
|
149
|
+
dvi_path = '__IMGMATH__.dvi'
|
150
|
+
pdf_path = '__IMGMATH__.pdf'
|
151
|
+
out, status = Open3.capture2e(*[@config['texcommand'], @config['texoptions'].shellsplit, tex_path].flatten.compact)
|
152
|
+
if !status.success? || (!File.exist?(dvi_path) && !File.exist?(pdf_path))
|
153
|
+
raise CompileError
|
154
|
+
end
|
155
|
+
|
156
|
+
if File.exist?(dvi_path)
|
157
|
+
out, status = Open3.capture2e(*[@config['dvicommand'], @config['dvioptions'].shellsplit, dvi_path].flatten.compact)
|
158
|
+
if !status.success? || !File.exist?(pdf_path)
|
159
|
+
warn "error in #{@config['dvicommand']}. Error log:\n#{out}"
|
160
|
+
raise CompileError
|
161
|
+
end
|
162
|
+
end
|
163
|
+
args = @config['imgmath_options']['pdfcrop_cmd'].shellsplit
|
164
|
+
args.map! do |m|
|
165
|
+
m.sub('%i', pdf_path).
|
166
|
+
sub('%o', '__IMGMATH__pdfcrop.pdf')
|
167
|
+
end
|
168
|
+
out, status = Open3.capture2e(*args)
|
169
|
+
unless status.success?
|
170
|
+
warn "error in pdfcrop. Error log:\n#{out}"
|
171
|
+
raise CompileError
|
172
|
+
end
|
173
|
+
pdf_path = '__IMGMATH__pdfcrop.pdf'
|
174
|
+
pdf_path2 = pdf_path
|
175
|
+
|
176
|
+
@math_maps.keys.sort.each_with_index do |key, idx|
|
177
|
+
page = idx + 1
|
178
|
+
if File.exist?(File.join(math_real_dir, "_gen_#{key}.#{@config['imgmath_options']['format']}"))
|
179
|
+
# made already
|
180
|
+
next
|
181
|
+
end
|
182
|
+
|
183
|
+
if @config['imgmath_options']['extract_singlepage']
|
184
|
+
# if extract_singlepage = true, split each page
|
185
|
+
args = @config['imgmath_options']['pdfextract_cmd'].shellsplit
|
186
|
+
|
187
|
+
args.map! do |m|
|
188
|
+
m.sub('%i', pdf_path).
|
189
|
+
sub('%o', "__IMGMATH__pdfcrop_p#{page}.pdf").
|
190
|
+
sub('%O', "__IMGMATH__pdfcrop_p#{page}").
|
191
|
+
sub('%p', page.to_s)
|
192
|
+
end
|
193
|
+
out, status = Open3.capture2e(*args)
|
194
|
+
unless status.success?
|
195
|
+
warn "error in pdf extracting. Error log:\n#{out}"
|
196
|
+
raise CompileError
|
197
|
+
end
|
198
|
+
|
199
|
+
pdf_path2 = "__IMGMATH__pdfcrop_p#{page}.pdf"
|
200
|
+
end
|
201
|
+
|
202
|
+
args = @config['imgmath_options']['pdfcrop_pixelize_cmd'].shellsplit
|
203
|
+
args.map! do |m|
|
204
|
+
m.sub('%i', pdf_path2).
|
205
|
+
sub('%t', @config['imgmath_options']['format']).
|
206
|
+
sub('%o', File.join(math_real_dir, "_gen_#{key}.#{@config['imgmath_options']['format']}")).
|
207
|
+
sub('%O', File.join(math_real_dir, "_gen_#{key}")).
|
208
|
+
sub('%p', page.to_s)
|
209
|
+
end
|
210
|
+
out, status = Open3.capture2e(*args)
|
211
|
+
unless status.success?
|
212
|
+
warn "error in pdf pixelizing. Error log:\n#{out}"
|
213
|
+
raise CompileError
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def make_math_images_dvipng(dir, tex_path, math_real_dir)
|
220
|
+
Dir.chdir(dir) do
|
221
|
+
dvi_path = '__IMGMATH__.dvi'
|
222
|
+
out, status = Open3.capture2e(*[@config['texcommand'], @config['texoptions'].shellsplit, tex_path].flatten.compact)
|
223
|
+
if !status.success? || !File.exist?(dvi_path)
|
224
|
+
raise CompileError
|
225
|
+
end
|
226
|
+
|
227
|
+
@math_maps.keys.sort.each_with_index do |key, idx|
|
228
|
+
page = idx + 1
|
229
|
+
args = @config['imgmath_options']['dvipng_cmd'].shellsplit
|
230
|
+
args.map! do |m|
|
231
|
+
m.sub('%i', dvi_path).
|
232
|
+
sub('%o', File.join(math_real_dir, "_gen_#{key}.#{@config['imgmath_options']['format']}")).
|
233
|
+
sub('%O', File.join(math_real_dir, "_gen_#{key}")).
|
234
|
+
sub('%p', page.to_s)
|
235
|
+
end
|
236
|
+
out, status = Open3.capture2e(*args)
|
237
|
+
unless status.success?
|
238
|
+
warn "error in dvipng. Error log:\n#{out}"
|
239
|
+
raise CompileError
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|