review 4.1.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +35 -0
  3. data/.github/workflows/ruby-win.yml +19 -9
  4. data/.github/workflows/ruby.yml +7 -3
  5. data/.rubocop.yml +138 -34
  6. data/NEWS.ja.md +285 -0
  7. data/NEWS.md +285 -1
  8. data/README.md +7 -6
  9. data/Rakefile +7 -2
  10. data/bin/review +2 -4
  11. data/bin/review-catalog-converter +4 -4
  12. data/bin/review-check +8 -12
  13. data/bin/review-checkdep +2 -5
  14. data/bin/review-compile +18 -34
  15. data/bin/review-epub2html +1 -4
  16. data/bin/review-epubmaker +3 -4
  17. data/bin/review-idgxmlmaker +1 -3
  18. data/bin/review-index +5 -86
  19. data/bin/review-init +1 -4
  20. data/bin/review-pdfmaker +1 -3
  21. data/bin/review-preproc +30 -38
  22. data/bin/review-textmaker +1 -3
  23. data/bin/review-update +1 -4
  24. data/bin/review-validate +4 -4
  25. data/bin/review-vol +5 -82
  26. data/bin/review-webmaker +1 -3
  27. data/doc/config.yml.sample +45 -11
  28. data/doc/config.yml.sample-simple +3 -3
  29. data/doc/format.ja.md +103 -13
  30. data/doc/format.md +104 -16
  31. data/doc/makeindex.ja.md +2 -2
  32. data/doc/pdfmaker.ja.md +42 -0
  33. data/doc/pdfmaker.md +41 -0
  34. data/doc/quickstart.ja.md +19 -6
  35. data/doc/quickstart.md +18 -6
  36. data/doc/writing_vertical.ja.md +6 -0
  37. data/lib/review.rb +1 -1
  38. data/lib/review/book.rb +2 -2
  39. data/lib/review/book/base.rb +67 -29
  40. data/lib/review/book/bib.rb +21 -0
  41. data/lib/review/book/book_unit.rb +158 -0
  42. data/lib/review/book/chapter.rb +33 -26
  43. data/lib/review/book/index.rb +24 -185
  44. data/lib/review/book/index/item.rb +7 -1
  45. data/lib/review/book/page_metric.rb +7 -7
  46. data/lib/review/book/part.rb +26 -11
  47. data/lib/review/book/volume.rb +5 -5
  48. data/lib/review/builder.rb +121 -52
  49. data/lib/review/call_hook.rb +20 -0
  50. data/lib/review/catalog.rb +3 -2
  51. data/lib/review/compiler.rb +230 -111
  52. data/lib/review/configure.rb +91 -7
  53. data/lib/review/converter.rb +1 -1
  54. data/lib/review/epub2html.rb +6 -1
  55. data/lib/review/epubmaker.rb +124 -152
  56. data/lib/review/epubmaker/content.rb +113 -0
  57. data/lib/review/epubmaker/epubcommon.rb +372 -0
  58. data/lib/review/epubmaker/epubv2.rb +178 -0
  59. data/lib/review/epubmaker/epubv3.rb +231 -0
  60. data/lib/review/epubmaker/producer.rb +167 -0
  61. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  62. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  63. data/lib/review/exception.rb +13 -0
  64. data/lib/review/htmlbuilder.rb +176 -89
  65. data/lib/review/htmlutils.rb +8 -11
  66. data/lib/review/i18n.rb +2 -1
  67. data/lib/review/idgxmlbuilder.rb +165 -75
  68. data/lib/review/idgxmlmaker.rb +24 -28
  69. data/lib/review/img_math.rb +238 -0
  70. data/lib/review/index_builder.rb +645 -0
  71. data/lib/review/init.rb +9 -17
  72. data/lib/review/latexbox.rb +58 -0
  73. data/lib/review/latexbuilder.rb +193 -75
  74. data/lib/review/latexutils.rb +9 -1
  75. data/lib/review/lineinput.rb +112 -2
  76. data/lib/review/loggable.rb +27 -0
  77. data/lib/review/logger.rb +90 -3
  78. data/lib/review/makerhelper.rb +17 -188
  79. data/lib/review/markdownbuilder.rb +54 -4
  80. data/lib/review/pdfmaker.rb +76 -84
  81. data/lib/review/plaintextbuilder.rb +106 -22
  82. data/lib/review/preprocessor.rb +107 -303
  83. data/lib/review/preprocessor/directive.rb +35 -0
  84. data/lib/review/preprocessor/line.rb +34 -0
  85. data/lib/review/preprocessor/repository.rb +177 -0
  86. data/lib/review/rstbuilder.rb +27 -8
  87. data/lib/review/sec_counter.rb +14 -0
  88. data/lib/review/template.rb +11 -1
  89. data/lib/review/textmaker.rb +27 -32
  90. data/lib/review/textutils.rb +3 -12
  91. data/lib/review/tocprinter.rb +242 -97
  92. data/lib/review/topbuilder.rb +98 -31
  93. data/lib/review/update.rb +12 -13
  94. data/lib/review/version.rb +1 -1
  95. data/lib/review/volumeprinter.rb +97 -0
  96. data/lib/review/webmaker.rb +40 -47
  97. data/lib/review/webtocprinter.rb +39 -35
  98. data/lib/review/yamlloader.rb +2 -1
  99. data/review.gemspec +5 -3
  100. data/samples/sample-book/src/config-epub2.yml +1 -1
  101. data/samples/sample-book/src/config.yml +3 -3
  102. data/samples/sample-book/src/lib/tasks/review.rake +19 -1
  103. data/samples/sample-book/src/lib/tasks/z01_copy_sty.rake +2 -1
  104. data/samples/syntax-book/Gemfile +1 -1
  105. data/samples/syntax-book/ch01.re +1 -1
  106. data/samples/syntax-book/ch02.re +21 -6
  107. data/samples/syntax-book/ch03.re +1 -1
  108. data/samples/syntax-book/config.yml +1 -1
  109. data/samples/syntax-book/images/img3-2.png +0 -0
  110. data/samples/syntax-book/lib/tasks/z01_copy_sty.rake +2 -1
  111. data/templates/html/_colophon.html.erb +23 -0
  112. data/templates/html/_colophon_history.html.erb +9 -0
  113. data/templates/html/_cover.html.erb +10 -0
  114. data/templates/html/_part_body.html.erb +6 -0
  115. data/templates/html/_titlepage.html.erb +20 -0
  116. data/templates/html/layout-html5.html.erb +6 -0
  117. data/templates/html/layout-xhtml1.html.erb +6 -0
  118. data/templates/latex/config.erb +35 -23
  119. data/templates/latex/review-jlreq/README.md +3 -1
  120. data/templates/latex/review-jlreq/review-base.sty +36 -23
  121. data/templates/latex/review-jlreq/review-jlreq.cls +18 -25
  122. data/templates/latex/review-jlreq/review-style.sty +6 -1
  123. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  124. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  125. data/templates/latex/review-jsbook/README.md +7 -5
  126. data/templates/latex/review-jsbook/review-base.sty +40 -24
  127. data/templates/latex/review-jsbook/review-jsbook.cls +13 -3
  128. data/templates/latex/review-jsbook/review-style.sty +6 -1
  129. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  130. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  131. data/templates/opf/epubv2.opf.erb +7 -7
  132. data/templates/opf/epubv3.opf.erb +7 -7
  133. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  134. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  135. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  136. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  137. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  138. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  139. data/templates/web/html/layout-html5.html.erb +9 -8
  140. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  141. data/test/assets/header_listener.html +35 -0
  142. data/test/assets/img_math/img1.png +0 -0
  143. data/test/assets/img_math/img2.png +0 -0
  144. data/test/assets/img_math/img3.png +0 -0
  145. data/test/assets/syntax_book_index_detail.txt +58 -0
  146. data/test/assets/test_template.tex +6 -3
  147. data/test/assets/test_template_backmatter.tex +6 -3
  148. data/test/book_test_helper.rb +11 -5
  149. data/test/run_test.rb +1 -1
  150. data/test/test_book.rb +54 -63
  151. data/test/test_book_chapter.rb +95 -54
  152. data/test/test_book_part.rb +3 -3
  153. data/test/test_builder.rb +29 -20
  154. data/test/test_catalog_converter_cmd.rb +1 -1
  155. data/test/test_converter.rb +1 -0
  156. data/test/test_epub3maker.rb +170 -126
  157. data/test/test_epubmaker.rb +254 -129
  158. data/test/test_epubmaker_cmd.rb +15 -4
  159. data/test/test_helper.rb +12 -5
  160. data/test/test_htmlbuilder.rb +926 -76
  161. data/test/test_htmlutils.rb +0 -12
  162. data/test/test_i18n.rb +33 -33
  163. data/test/test_idgxmlbuilder.rb +531 -20
  164. data/test/test_idgxmlmaker_cmd.rb +7 -3
  165. data/test/test_img_math.rb +111 -0
  166. data/test/test_index.rb +62 -52
  167. data/test/test_indexbuilder.rb +52 -0
  168. data/test/test_latexbuilder.rb +891 -20
  169. data/test/test_latexbuilder_v2.rb +56 -10
  170. data/test/test_lineinput.rb +20 -93
  171. data/test/test_logger.rb +7 -7
  172. data/test/test_makerhelper.rb +0 -12
  173. data/test/test_markdownbuilder.rb +32 -0
  174. data/test/test_pdfmaker.rb +100 -11
  175. data/test/test_pdfmaker_cmd.rb +3 -3
  176. data/test/test_plaintextbuilder.rb +546 -32
  177. data/test/test_preprocessor.rb +188 -1
  178. data/test/test_review_ext.rb +2 -1
  179. data/test/test_reviewheaderlistener.rb +49 -0
  180. data/test/test_rstbuilder.rb +25 -1
  181. data/test/test_sec_counter.rb +156 -0
  182. data/test/test_template.rb +12 -2
  183. data/test/test_textmaker_cmd.rb +5 -1
  184. data/test/test_tocprinter.rb +46 -0
  185. data/test/test_topbuilder.rb +324 -20
  186. data/test/test_update.rb +44 -44
  187. data/test/test_webtocprinter.rb +75 -43
  188. data/test/test_zip_exporter.rb +5 -6
  189. data/vendor/gentombow/LICENSE +1 -1
  190. data/vendor/gentombow/Makefile +0 -1
  191. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  192. data/vendor/gentombow/bounddvi-en.tex +1 -0
  193. data/vendor/gentombow/bounddvi.pdf +0 -0
  194. data/vendor/gentombow/bounddvi.sty +30 -7
  195. data/vendor/gentombow/bounddvi.tex +1 -0
  196. data/vendor/gentombow/create_archive.sh +1 -0
  197. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  198. data/vendor/gentombow/gentombow-ja.tex +9 -0
  199. data/vendor/gentombow/gentombow.pdf +0 -0
  200. data/vendor/gentombow/gentombow.sty +32 -10
  201. data/vendor/gentombow/gentombow.tex +8 -0
  202. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  203. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  204. data/vendor/jsclasses/Makefile +3 -2
  205. data/vendor/jsclasses/create_archive.sh +5 -5
  206. data/vendor/jsclasses/jis/Makefile +3 -2
  207. data/vendor/jsclasses/jis/jsarticle.cls +22 -18
  208. data/vendor/jsclasses/jis/jsbook.cls +22 -18
  209. data/vendor/jsclasses/jis/jsclasses.dtx +94 -13
  210. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  211. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  212. data/vendor/jsclasses/jis/jslogo.sty +1 -13
  213. data/vendor/jsclasses/jis/jspf.cls +22 -18
  214. data/vendor/jsclasses/jis/jsreport.cls +22 -18
  215. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  216. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  217. data/vendor/jsclasses/jis/kiyou.cls +22 -18
  218. data/vendor/jsclasses/jis/minijs.sty +65 -22
  219. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  220. data/vendor/jsclasses/jis/okumacro.sty +1 -13
  221. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  222. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  223. data/vendor/jsclasses/jis/winjis.sty +23 -19
  224. data/vendor/jsclasses/jsarticle.cls +22 -18
  225. data/vendor/jsclasses/jsbook.cls +22 -18
  226. data/vendor/jsclasses/jsclasses.dtx +94 -13
  227. data/vendor/jsclasses/jsclasses.ins +15 -5
  228. data/vendor/jsclasses/jsclasses.pdf +0 -0
  229. data/vendor/jsclasses/jslogo.ins +9 -0
  230. data/vendor/jsclasses/jslogo.pdf +0 -0
  231. data/vendor/jsclasses/jslogo.sty +1 -13
  232. data/vendor/jsclasses/jspf.cls +22 -18
  233. data/vendor/jsclasses/jsreport.cls +22 -18
  234. data/vendor/jsclasses/jsverb.ins +9 -0
  235. data/vendor/jsclasses/jsverb.pdf +0 -0
  236. data/vendor/jsclasses/jsverb.sty +1 -13
  237. data/vendor/jsclasses/kiyou.cls +22 -18
  238. data/vendor/jsclasses/minijs.sty +68 -22
  239. data/vendor/jsclasses/okumacro.ins +9 -0
  240. data/vendor/jsclasses/okumacro.pdf +0 -0
  241. data/vendor/jsclasses/okumacro.sty +1 -13
  242. data/vendor/jsclasses/okuverb.ins +9 -0
  243. data/vendor/jsclasses/okuverb.pdf +0 -0
  244. data/vendor/jsclasses/okuverb.sty +1 -13
  245. data/vendor/jsclasses/tests/relfont.tex +10 -0
  246. data/vendor/jsclasses/winjis.sty +23 -19
  247. metadata +106 -22
  248. data/.rubocop_todo.yml +0 -7
  249. data/lib/epubmaker.rb +0 -23
  250. data/lib/epubmaker/content.rb +0 -110
  251. data/lib/epubmaker/epubcommon.rb +0 -441
  252. data/lib/epubmaker/epubv2.rb +0 -143
  253. data/lib/epubmaker/epubv3.rb +0 -233
  254. data/lib/epubmaker/producer.rb +0 -375
  255. data/lib/epubmaker/zip_exporter.rb +0 -81
  256. data/lib/lineinput.rb +0 -155
  257. data/lib/review/book/compilable.rb +0 -178
  258. data/lib/review/tocparser.rb +0 -275
  259. data/test/test_tocparser.rb +0 -25
@@ -7,6 +7,15 @@
7
7
  #
8
8
  module ReVIEW
9
9
  class EPUBMaker
10
+ # Listener class to scan HTML and get heading information
11
+ #
12
+ # The heading information this listener will retrieve is as follows:
13
+ #
14
+ # * level: Heading level (1..6)
15
+ # * id: HTMl ID attribute. Basically the `id` attribute of the h(1-6) element, but if there is an `a` element within the h(1-6) element, it will be its `id` attribute.
16
+ # * title: The title string of the headline. Usually, it is the text within the h(1-6) element, but if there is an `img` element, it will be the text with its `alt` attribute.
17
+ # * notoc: The `notoc` attribute of the headline element.
18
+ #
10
19
  class ReVIEWHeaderListener
11
20
  include REXML::StreamListener
12
21
  def initialize(headlines)
@@ -18,10 +27,11 @@ module ReVIEW
18
27
  def tag_start(name, attrs)
19
28
  if name =~ /\Ah(\d+)/
20
29
  raise "#{name}, #{attrs}" if @level.present?
30
+
21
31
  @level = $1.to_i
22
32
  @id = attrs['id'] if attrs['id'].present?
23
33
  @notoc = attrs['notoc'] if attrs['notoc'].present?
24
- elsif !@level.nil?
34
+ elsif @level.present? # if in <hN> tag
25
35
  if name == 'img' && attrs['alt'].present?
26
36
  @content << attrs['alt']
27
37
  elsif name == 'a' && attrs['id'].present?
@@ -49,7 +59,7 @@ module ReVIEW
49
59
 
50
60
  def text(text)
51
61
  if @level.present?
52
- @content << text.gsub("\t", ' ')
62
+ @content << text.tr("\t", ' ')
53
63
  end
54
64
  end
55
65
  end
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2010-2017 Kenshi Muto and Masayoshi Takahashi
2
+ #
3
+ # This program is free software.
4
+ # You can distribute or modify this program under the terms of
5
+ # the GNU LGPL, Lesser General Public License version 2.1.
6
+ # For details of the GNU LGPL, see the file "COPYING".
7
+ #
8
+
9
+ require 'pathname'
10
+ begin
11
+ require 'zip'
12
+ rescue LoadError
13
+ ## I cannot find rubyzip library, so I use external zip command.
14
+ warn 'rubyzip not found, so use external zip command'
15
+ end
16
+
17
+ module ReVIEW
18
+ class EPUBMaker
19
+ ##
20
+ # Export into zip file for EPUB producer.
21
+ #
22
+ class ZipExporter
23
+ attr_reader :tmpdir
24
+
25
+ def initialize(tmpdir, config)
26
+ @tmpdir = tmpdir
27
+ @config = config
28
+ end
29
+
30
+ def export_zip(epubfile)
31
+ if defined?(Zip)
32
+ export_zip_rubyzip(epubfile)
33
+ else
34
+ export_zip_extcmd(epubfile)
35
+ end
36
+ end
37
+
38
+ def export_zip_extcmd(epubfile)
39
+ stage1 = @config['epubmaker']['zip_stage1'].to_s.split
40
+ path1 = stage1[0] || 'zip'
41
+ opt1 = stage1[1] || '-0Xq'
42
+ stage2 = @config['epubmaker']['zip_stage2'].to_s.split
43
+ path2 = stage2[0] || 'zip'
44
+ opt2 = stage2[1] || '-Xr9Dq'
45
+
46
+ Dir.chdir(tmpdir) do
47
+ system(path1, opt1, epubfile, 'mimetype')
48
+ addpath = @config['epubmaker']['zip_addpath']
49
+ if addpath
50
+ system(path2, opt2, epubfile, 'META-INF', 'OEBPS', addpath)
51
+ else
52
+ system(path2, opt2, epubfile, 'META-INF', 'OEBPS')
53
+ end
54
+ end
55
+ end
56
+
57
+ def export_zip_rubyzip(epubfile)
58
+ Dir.chdir(tmpdir) do
59
+ Zip::OutputStream.open(epubfile) do |epub|
60
+ root_pathname = Pathname.new(tmpdir)
61
+ epub.put_next_entry('mimetype', nil, nil, Zip::Entry::STORED)
62
+ epub << 'application/epub+zip'
63
+
64
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, 'META-INF'), root_pathname)
65
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, 'OEBPS'), root_pathname)
66
+ if @config['zip_addpath'].present?
67
+ export_zip_rubyzip_addpath(epub, File.join(tmpdir, @config['zip_addpath']), root_pathname)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def export_zip_rubyzip_addpath(epub, dirname, rootdir)
74
+ Dir[File.join(dirname, '**', '**')].each do |path|
75
+ next if File.directory?(path)
76
+
77
+ relpath = Pathname.new(path).relative_path_from(rootdir)
78
+ epub.put_next_entry(relpath)
79
+ epub << File.binread(path)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -10,10 +10,23 @@
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
25
+
26
+ class BuildError < ApplicationError
27
+ def initialize(msg, location: nil)
28
+ @location = location
29
+ super(msg)
30
+ end
31
+ end
19
32
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2008-2019 Minero Aoki, Kenshi Muto, Masayoshi Takahashi,
1
+ # Copyright (c) 2008-2021 Minero Aoki, Kenshi Muto, Masayoshi Takahashi,
2
2
  # KADO Masanori
3
3
  # 2002-2007 Minero Aoki
4
4
  #
@@ -41,22 +41,21 @@ module ReVIEW
41
41
  ".#{@book.config['htmlext']}"
42
42
  end
43
43
 
44
- def builder_init
45
- end
46
- private :builder_init
47
-
48
44
  def builder_init_file
45
+ super
49
46
  @noindent = nil
50
47
  @ol_num = nil
51
- @warns = []
52
- @errors = []
53
48
  @chapter.book.image_types = %w[.png .jpg .jpeg .gif .svg]
54
49
  @column = 0
55
- @sec_counter = SecCounter.new(5, @chapter)
56
50
  @nonum_counter = 0
57
51
  @first_line_num = nil
58
52
  @body_ext = nil
59
53
  @toc = nil
54
+ @javascripts = []
55
+ @section_stack = []
56
+
57
+ maker = @book.config.maker || 'epubmaker' # for review-compile
58
+ @use_section = @book.config[maker] && @book.config[maker]['use_section']
60
59
  end
61
60
  private :builder_init_file
62
61
 
@@ -78,9 +77,10 @@ module ReVIEW
78
77
  if !File.exist?(layout_file) && File.exist?(File.join(@book.basedir, 'layouts', 'layout.erb'))
79
78
  raise ReVIEW::ConfigError, 'layout.erb is obsoleted. Please use layout.html.erb.'
80
79
  end
80
+
81
81
  if File.exist?(layout_file)
82
82
  if ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
83
- warn %Q(user's layout is prohibited in safe mode. ignored.)
83
+ warn %Q(user's layout is prohibited in safe mode. ignored.), location: location
84
84
  layout_file = File.expand_path(htmlfilename, ReVIEW::Template::TEMPLATE_DIR)
85
85
  end
86
86
  else
@@ -89,10 +89,36 @@ module ReVIEW
89
89
  layout_file
90
90
  end
91
91
 
92
+ def use_section?
93
+ @use_section
94
+ end
95
+
96
+ def open_section(level)
97
+ result = []
98
+
99
+ while @section_stack.size > 0 && level <= @section_stack[-1]
100
+ result << '</section>'
101
+ @section_stack.pop
102
+ end
103
+ @section_stack.push(level)
104
+ result << %Q(<section class="level#{level}">)
105
+
106
+ return result.join("\n")
107
+ end
108
+
109
+ def close_sections
110
+ "</section>\n" * @section_stack.size
111
+ end
112
+
92
113
  def result
114
+ # flush all `</section>`
115
+ if use_section?
116
+ print close_sections
117
+ end
118
+
93
119
  # default XHTML header/footer
94
120
  @title = strip_html(compile_inline(@chapter.title))
95
- @body = @output.string
121
+ @body = solve_nest(@output.string)
96
122
  @language = @book.config['language']
97
123
  @stylesheets = @book.config['stylesheet']
98
124
  @next = @chapter.next_chapter
@@ -104,9 +130,28 @@ module ReVIEW
104
130
  @toc = ReVIEW::WEBTOCPrinter.book_to_string(@book)
105
131
  end
106
132
 
133
+ if @book.config['math_format'] == 'mathjax'
134
+ @javascripts.push(%Q(<script>MathJax = { tex: { inlineMath: [['\\\\(', '\\\\)']] }, svg: { fontCache: 'global' } };</script>))
135
+ @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>))
136
+ end
137
+
107
138
  ReVIEW::Template.load(layoutfile).result(binding)
108
139
  end
109
140
 
141
+ def solve_nest(s)
142
+ check_nest
143
+ s.gsub("</dd>\n</dl>\n\x01→dl←\x01", '').
144
+ gsub("\x01→/dl←\x01", "</dd>\n</dl>←END\x01").
145
+ gsub("</li>\n</ul>\n\x01→ul←\x01", '').
146
+ gsub("\x01→/ul←\x01", "</li>\n</ul>←END\x01").
147
+ gsub("</li>\n</ol>\n\x01→ol←\x01", '').
148
+ gsub("\x01→/ol←\x01", "</li>\n</ol>←END\x01").
149
+ gsub("</dl>←END\x01\n<dl>", '').
150
+ gsub("</ul>←END\x01\n<ul>", '').
151
+ gsub("</ol>←END\x01\n<ol>", '').
152
+ gsub("←END\x01", '')
153
+ end
154
+
110
155
  def xmlns_ops_prefix
111
156
  if @book.config['epubversion'].to_i == 3
112
157
  'epub'
@@ -116,6 +161,9 @@ module ReVIEW
116
161
  end
117
162
 
118
163
  def headline(level, label, caption)
164
+ if use_section?
165
+ print open_section(level)
166
+ end
119
167
  prefix, anchor = headline_prefix(level)
120
168
  if prefix
121
169
  prefix = %Q(<span class="secno">#{prefix}</span>)
@@ -139,6 +187,7 @@ module ReVIEW
139
187
  @nonum_counter += 1
140
188
  puts if level > 1
141
189
  return unless caption.present?
190
+
142
191
  if label
143
192
  puts %Q(<h#{level} id="#{normalize_id(label)}">#{compile_inline(caption)}</h#{level}>)
144
193
  else
@@ -154,6 +203,7 @@ module ReVIEW
154
203
  @nonum_counter += 1
155
204
  puts if level > 1
156
205
  return unless caption.present?
206
+
157
207
  if label
158
208
  puts %Q(<h#{level} id="#{normalize_id(label)}" notoc="true">#{compile_inline(caption)}</h#{level}>)
159
209
  else
@@ -169,6 +219,7 @@ module ReVIEW
169
219
  @nonum_counter += 1
170
220
  puts '' if level > 1
171
221
  return unless caption.present?
222
+
172
223
  if label
173
224
  puts %Q(<a id="#{normalize_id(label)}" /><h#{level} id="#{normalize_id(label)}" hidden="true">#{compile_inline(caption)}</h#{level}>)
174
225
  else
@@ -228,6 +279,7 @@ module ReVIEW
228
279
  end
229
280
 
230
281
  def captionblock(type, lines, caption)
282
+ check_nested_minicolumn
231
283
  puts %Q(<div class="#{type}">)
232
284
  if caption.present?
233
285
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
@@ -286,15 +338,25 @@ module ReVIEW
286
338
  end
287
339
 
288
340
  def box(lines, caption = nil)
289
- puts %Q(<div class="syntax">)
341
+ captionstr = nil
290
342
  if caption.present?
291
- puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
343
+ captionstr = %Q(<p class="caption">#{compile_inline(caption)}</p>)
292
344
  end
345
+ puts %Q(<div class="syntax">)
346
+
347
+ if caption_top?('list') && caption.present?
348
+ puts captionstr
349
+ end
350
+
293
351
  print %Q(<pre class="syntax">)
294
352
  lines.each do |line|
295
353
  puts detab(line)
296
354
  end
297
355
  puts '</pre>'
356
+
357
+ if !caption_top?('list') && caption.present?
358
+ puts captionstr
359
+ end
298
360
  puts '</div>'
299
361
  end
300
362
 
@@ -302,6 +364,24 @@ module ReVIEW
302
364
  captionblock('note', lines, caption)
303
365
  end
304
366
 
367
+ CAPTION_TITLES.each do |name|
368
+ class_eval %Q(
369
+ def #{name}_begin(caption = nil)
370
+ check_nested_minicolumn
371
+ @doc_status[:minicolumn] = '#{name}'
372
+ puts %Q(<div class="#{name}">)
373
+ if caption.present?
374
+ puts %Q(<p class="caption">\#{compile_inline(caption)}</p>)
375
+ end
376
+ end
377
+
378
+ def #{name}_end
379
+ puts '</div>'
380
+ @doc_status[:minicolumn] = nil
381
+ end
382
+ ), __FILE__, __LINE__ - 14
383
+ end
384
+
305
385
  def ul_begin
306
386
  puts '<ul>'
307
387
  end
@@ -444,7 +524,7 @@ module ReVIEW
444
524
 
445
525
  def emlist(lines, caption = nil, lang = nil)
446
526
  puts %Q(<div class="emlist-code">)
447
- if caption.present?
527
+ if caption_top?('list') && caption.present?
448
528
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
449
529
  end
450
530
  class_names = ['emlist']
@@ -455,12 +535,15 @@ module ReVIEW
455
535
  lexer = lang
456
536
  puts highlight(body: body, lexer: lexer, format: 'html')
457
537
  puts '</pre>'
538
+ if !caption_top?('list') && caption.present?
539
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
540
+ end
458
541
  puts '</div>'
459
542
  end
460
543
 
461
544
  def emlistnum(lines, caption = nil, lang = nil)
462
545
  puts %Q(<div class="emlistnum-code">)
463
- if caption.present?
546
+ if caption_top?('list') && caption.present?
464
547
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
465
548
  end
466
549
 
@@ -482,19 +565,29 @@ module ReVIEW
482
565
  puts '</pre>'
483
566
  end
484
567
 
568
+ if !caption_top?('list') && caption.present?
569
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
570
+ end
571
+
485
572
  puts '</div>'
486
573
  end
487
574
 
488
575
  def cmd(lines, caption = nil)
489
576
  puts %Q(<div class="cmd-code">)
490
- if caption.present?
577
+ if caption_top?('list') && caption.present?
491
578
  puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
492
579
  end
580
+
493
581
  print %Q(<pre class="cmd">)
494
582
  body = lines.inject('') { |i, j| i + detab(j) + "\n" }
495
583
  lexer = 'shell-session'
496
584
  puts highlight(body: body, lexer: lexer, format: 'html')
497
585
  puts '</pre>'
586
+
587
+ if !caption_top?('list') && caption.present?
588
+ puts %Q(<p class="caption">#{compile_inline(caption)}</p>)
589
+ end
590
+
498
591
  puts '</div>'
499
592
  end
500
593
 
@@ -530,12 +623,13 @@ module ReVIEW
530
623
  def texequation(lines, id = nil, caption = '')
531
624
  if id
532
625
  puts %Q(<div id="#{normalize_id(id)}" class="caption-equation">)
533
- texequation_header(id, caption)
626
+ texequation_header(id, caption) if caption_top?('equation')
534
627
  end
535
628
 
536
629
  texequation_body(lines)
537
630
 
538
631
  if id
632
+ texequation_header(id, caption) unless caption_top?('equation')
539
633
  puts '</div>'
540
634
  end
541
635
  end
@@ -550,24 +644,27 @@ module ReVIEW
550
644
 
551
645
  def texequation_body(lines)
552
646
  puts %Q(<div class="equation">)
553
- if @book.config['mathml']
554
- require 'math_ml'
555
- require 'math_ml/symbol/character_reference'
647
+ if @book.config['math_format'] == 'mathml'
648
+ begin
649
+ require 'math_ml'
650
+ require 'math_ml/symbol/character_reference'
651
+ rescue LoadError
652
+ app_error 'not found math_ml'
653
+ end
556
654
  p = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
557
655
  print p.parse(lines.join("\n") + "\n", true)
558
- elsif @book.config['imgmath']
656
+ elsif @book.config['math_format'] == 'mathjax'
657
+ puts "$$#{lines.join("\n")}$$"
658
+ elsif @book.config['math_format'] == 'imgmath'
559
659
  fontsize = @book.config['imgmath_options']['fontsize'].to_f
560
660
  lineheight = @book.config['imgmath_options']['lineheight'].to_f
561
661
  math_str = "\\begin{equation*}\n\\fontsize{#{fontsize}}{#{lineheight}}\\selectfont\n#{lines.join("\n")}\n\\end{equation*}\n"
562
662
  key = Digest::SHA256.hexdigest(math_str)
563
- math_dir = File.join(@book.config['imagedir'], '_review_math')
564
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
565
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
566
663
  if @book.config.check_version('2', exception: false)
567
- make_math_image(math_str, img_path)
664
+ img_path = @img_math.make_math_image(math_str, key)
568
665
  puts %Q(<img src="#{img_path}" />)
569
666
  else
570
- defer_math_image(math_str, img_path, key)
667
+ img_path = @img_math.defer_math_image(math_str, key)
571
668
  puts %Q(<img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(lines.join(' '))}" />)
572
669
  end
573
670
  else
@@ -603,20 +700,22 @@ module ReVIEW
603
700
  def image_image(id, caption, metric)
604
701
  metrics = parse_metric('html', metric)
605
702
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
703
+ image_header(id, caption) if caption_top?('image')
606
704
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
607
- image_header(id, caption)
705
+ image_header(id, caption) unless caption_top?('image')
608
706
  puts '</div>'
609
707
  end
610
708
 
611
709
  def image_dummy(id, caption, lines)
612
- warn "image not bound: #{id}"
710
+ warn "image not bound: #{id}", location: location
613
711
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
712
+ image_header(id, caption) if caption_top?('image')
614
713
  puts %Q(<pre class="dummyimage">)
615
714
  lines.each do |line|
616
715
  puts detab(line)
617
716
  end
618
717
  puts '</pre>'
619
- image_header(id, caption)
718
+ image_header(id, caption) unless caption_top?('image')
620
719
  puts '</div>'
621
720
  end
622
721
 
@@ -672,22 +771,26 @@ module ReVIEW
672
771
 
673
772
  def imgtable(lines, id, caption = nil, metric = nil)
674
773
  unless @chapter.image_bound?(id)
675
- warn "image not bound: #{id}"
774
+ warn "image not bound: #{id}", location: location
676
775
  image_dummy(id, caption, lines)
677
776
  return
678
777
  end
679
778
 
680
779
  puts %Q(<div id="#{normalize_id(id)}" class="imgtable image">)
681
780
  begin
682
- if caption.present?
781
+ if caption_top?('table') && caption.present?
782
+ table_header(id, caption)
783
+ end
784
+
785
+ imgtable_image(id, caption, metric)
786
+
787
+ if !caption_top?('table') && caption.present?
683
788
  table_header(id, caption)
684
789
  end
685
790
  rescue KeyError
686
- error "no such table: #{id}"
791
+ app_error "no such table: #{id}"
687
792
  end
688
793
 
689
- imgtable_image(id, caption, metric)
690
-
691
794
  puts '</div>'
692
795
  end
693
796
 
@@ -702,6 +805,7 @@ module ReVIEW
702
805
 
703
806
  def comment(lines, comment = nil)
704
807
  return unless @book.config['draft']
808
+
705
809
  lines ||= []
706
810
  lines.unshift(escape(comment)) unless comment.blank?
707
811
  str = lines.join('<br />')
@@ -724,11 +828,23 @@ module ReVIEW
724
828
  def indepimage(lines, id, caption = '', metric = nil)
725
829
  metrics = parse_metric('html', metric)
726
830
  caption = '' unless caption.present?
831
+ caption_str = nil
832
+ if caption.present?
833
+ caption_str = <<-EOS
834
+ <p class="caption">
835
+ #{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)}
836
+ </p>
837
+ EOS
838
+ end
839
+
727
840
  puts %Q(<div id="#{normalize_id(id)}" class="image">)
841
+ if caption_top?('image') && caption.present?
842
+ puts caption_str
843
+ end
728
844
  begin
729
845
  puts %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="#{escape(compile_inline(caption))}"#{metrics} />)
730
846
  rescue
731
- warn "image not bound: #{id}"
847
+ warn "image not bound: #{id}", location: location
732
848
  if lines
733
849
  puts %Q(<pre class="dummyimage">)
734
850
  lines.each do |line|
@@ -738,10 +854,8 @@ module ReVIEW
738
854
  end
739
855
  end
740
856
 
741
- if caption.present?
742
- puts %Q(<p class="caption">)
743
- puts %Q(#{I18n.t('numberless_image')}#{I18n.t('caption_prefix')}#{compile_inline(caption)})
744
- puts '</p>'
857
+ if !caption_top?('image') && caption.present?
858
+ puts caption_str
745
859
  end
746
860
  puts '</div>'
747
861
  end
@@ -783,7 +897,7 @@ module ReVIEW
783
897
  alias_method :inline_ref, :inline_labelref
784
898
 
785
899
  def inline_pageref(id)
786
- error "pageref op is unsupported on this builder: #{id}"
900
+ app_error "pageref op is unsupported on this builder: #{id}"
787
901
  end
788
902
 
789
903
  def inline_chapref(id)
@@ -794,7 +908,7 @@ module ReVIEW
794
908
  title
795
909
  end
796
910
  rescue KeyError
797
- error "unknown chapter: #{id}"
911
+ app_error "unknown chapter: #{id}"
798
912
  end
799
913
 
800
914
  def inline_chap(id)
@@ -804,7 +918,7 @@ module ReVIEW
804
918
  @book.chapter_index.number(id)
805
919
  end
806
920
  rescue KeyError
807
- error "unknown chapter: #{id}"
921
+ app_error "unknown chapter: #{id}"
808
922
  end
809
923
 
810
924
  def inline_title(id)
@@ -815,7 +929,7 @@ module ReVIEW
815
929
  title
816
930
  end
817
931
  rescue KeyError
818
- error "unknown chapter: #{id}"
932
+ app_error "unknown chapter: #{id}"
819
933
  end
820
934
 
821
935
  def inline_fn(id)
@@ -825,7 +939,7 @@ module ReVIEW
825
939
  %Q(<a id="fnb-#{normalize_id(id)}" href="#fn-#{normalize_id(id)}" class="noteref">*#{@chapter.footnote(id).number}</a>)
826
940
  end
827
941
  rescue KeyError
828
- error "unknown footnote: #{id}"
942
+ app_error "unknown footnote: #{id}"
829
943
  end
830
944
 
831
945
  def compile_ruby(base, ruby)
@@ -902,22 +1016,25 @@ module ReVIEW
902
1016
  end
903
1017
 
904
1018
  def inline_m(str)
905
- if @book.config['mathml']
906
- require 'math_ml'
907
- require 'math_ml/symbol/character_reference'
1019
+ if @book.config['math_format'] == 'mathml'
1020
+ begin
1021
+ require 'math_ml'
1022
+ require 'math_ml/symbol/character_reference'
1023
+ rescue LoadError
1024
+ app_error 'not found math_ml'
1025
+ end
908
1026
  parser = MathML::LaTeX::Parser.new(symbol: MathML::Symbol::CharacterReference)
909
1027
  %Q(<span class="equation">#{parser.parse(str, nil)}</span>)
910
- elsif @book.config['imgmath']
1028
+ elsif @book.config['math_format'] == 'mathjax'
1029
+ %Q(<span class="equation">\\( #{str} \\)</span>)
1030
+ elsif @book.config['math_format'] == 'imgmath'
911
1031
  math_str = '$' + str + '$'
912
1032
  key = Digest::SHA256.hexdigest(str)
913
- math_dir = File.join(@book.config['imagedir'], '_review_math')
914
- Dir.mkdir(math_dir) unless Dir.exist?(math_dir)
915
- img_path = File.join(math_dir, "_gen_#{key}.#{@book.config['imgmath_options']['format']}")
916
1033
  if @book.config.check_version('2', exception: false)
917
- make_math_image(math_str, img_path)
1034
+ img_path = @img_math.make_math_image(math_str, key)
918
1035
  %Q(<span class="equation"><img src="#{img_path}" /></span>)
919
1036
  else
920
- defer_math_image(math_str, img_path, key)
1037
+ img_path = @img_math.defer_math_image(math_str, key)
921
1038
  %Q(<span class="equation"><img src="#{img_path}" class="math_gen_#{key}" alt="#{escape(str)}" /></span>)
922
1039
  end
923
1040
  else
@@ -950,7 +1067,7 @@ module ReVIEW
950
1067
  def inline_bib(id)
951
1068
  %Q(<a href="#{@book.bib_file.gsub(/\.re\Z/, ".#{@book.config['htmlext']}")}#bib-#{normalize_id(id)}">[#{@chapter.bibpaper(id).number}]</a>)
952
1069
  rescue KeyError
953
- error "unknown bib: #{id}"
1070
+ app_error "unknown bib: #{id}"
954
1071
  end
955
1072
 
956
1073
  def inline_hd_chap(chap, id)
@@ -961,13 +1078,13 @@ module ReVIEW
961
1078
  str = I18n.t('hd_quote_without_number', compile_inline(chap.headline(id).caption))
962
1079
  end
963
1080
  if @book.config['chapterlink']
964
- anchor = 'h' + n.gsub('.', '-')
1081
+ anchor = 'h' + n.tr('.', '-')
965
1082
  %Q(<a href="#{chap.id}#{extname}##{anchor}">#{str}</a>)
966
1083
  else
967
1084
  str
968
1085
  end
969
1086
  rescue KeyError
970
- error "unknown headline: #{id}"
1087
+ app_error "unknown headline: #{id}"
971
1088
  end
972
1089
 
973
1090
  def column_label(id, chapter = @chapter)
@@ -978,12 +1095,12 @@ module ReVIEW
978
1095
 
979
1096
  def inline_column_chap(chapter, id)
980
1097
  if @book.config['chapterlink']
981
- %Q(<a href="\##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
1098
+ %Q(<a href="#{chapter.id}#{extname}##{column_label(id, chapter)}" class="columnref">#{I18n.t('column', compile_inline(chapter.column(id).caption))}</a>)
982
1099
  else
983
1100
  I18n.t('column', compile_inline(chapter.column(id).caption))
984
1101
  end
985
1102
  rescue KeyError
986
- error "unknown column: #{id}"
1103
+ app_error "unknown column: #{id}"
987
1104
  end
988
1105
 
989
1106
  def inline_list(id)
@@ -1110,7 +1227,7 @@ module ReVIEW
1110
1227
  begin
1111
1228
  %Q(<img src="#{@chapter.image(id).path.sub(%r{\A\./}, '')}" alt="[#{id}]" />)
1112
1229
  rescue
1113
- warn "image not bound: #{id}"
1230
+ warn "image not bound: #{id}", location: location
1114
1231
  %Q(<pre>missing image: #{id}</pre>)
1115
1232
  end
1116
1233
  end
@@ -1140,7 +1257,7 @@ module ReVIEW
1140
1257
  %Q(<span class="balloon">#{escape_html(str)}</span>)
1141
1258
  end
1142
1259
 
1143
- def inline_raw(str)
1260
+ def inline_raw(str) # rubocop:disable Lint/UselessMethodDefinition
1144
1261
  super(str)
1145
1262
  end
1146
1263
 
@@ -1171,35 +1288,5 @@ module ReVIEW
1171
1288
  def olnum(num)
1172
1289
  @ol_num = num.to_i
1173
1290
  end
1174
-
1175
- def make_math_image(str, path, fontsize = 12)
1176
- # Re:VIEW 2 compatibility
1177
- fontsize2 = (fontsize * 1.2).round.to_i
1178
- texsrc = <<-EOB
1179
- \\documentclass[12pt]{article}
1180
- \\usepackage[utf8]{inputenc}
1181
- \\usepackage{amsmath}
1182
- \\usepackage{amsthm}
1183
- \\usepackage{amssymb}
1184
- \\usepackage{amsfonts}
1185
- \\usepackage{anyfontsize}
1186
- \\usepackage{bm}
1187
- \\pagestyle{empty}
1188
-
1189
- \\begin{document}
1190
- \\fontsize{#{fontsize}}{#{fontsize2}}\\selectfont #{str}
1191
- \\end{document}
1192
- EOB
1193
- Dir.mktmpdir do |tmpdir|
1194
- tex_path = File.join(tmpdir, 'tmpmath.tex')
1195
- dvi_path = File.join(tmpdir, 'tmpmath.dvi')
1196
- File.write(tex_path, texsrc)
1197
- cmd = "latex --interaction=nonstopmode --output-directory=#{tmpdir} #{tex_path} && dvipng -T tight -z9 -o #{path} #{dvi_path}"
1198
- out, status = Open3.capture2e(cmd)
1199
- unless status.success?
1200
- error "latex compile error\n\nError log:\n" + out
1201
- end
1202
- end
1203
- end
1204
1291
  end
1205
1292
  end # module ReVIEW