review 4.0.0 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (268) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-tex.yml +31 -0
  3. data/.github/workflows/ruby-win.yml +45 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.rubocop.yml +141 -38
  6. data/Dockerfile +21 -5
  7. data/NEWS.ja.md +338 -1
  8. data/NEWS.md +339 -2
  9. data/README.md +11 -7
  10. data/Rakefile +7 -2
  11. data/appveyor.yml +0 -20
  12. data/bin/review +2 -4
  13. data/bin/review-catalog-converter +4 -4
  14. data/bin/review-check +8 -12
  15. data/bin/review-checkdep +2 -5
  16. data/bin/review-compile +11 -20
  17. data/bin/review-epub2html +1 -4
  18. data/bin/review-epubmaker +3 -4
  19. data/bin/review-idgxmlmaker +1 -3
  20. data/bin/review-index +5 -86
  21. data/bin/review-init +1 -4
  22. data/bin/review-pdfmaker +1 -3
  23. data/bin/review-preproc +3 -5
  24. data/bin/review-textmaker +1 -3
  25. data/bin/review-update +1 -4
  26. data/bin/review-validate +5 -5
  27. data/bin/review-vol +5 -82
  28. data/bin/review-webmaker +1 -3
  29. data/doc/config.yml.sample +55 -12
  30. data/doc/config.yml.sample-simple +4 -3
  31. data/doc/format.ja.md +119 -17
  32. data/doc/format.md +106 -17
  33. data/doc/makeindex.ja.md +2 -2
  34. data/doc/pdfmaker.ja.md +42 -0
  35. data/doc/pdfmaker.md +41 -0
  36. data/doc/quickstart.ja.md +55 -25
  37. data/doc/quickstart.md +47 -17
  38. data/lib/review.rb +1 -1
  39. data/lib/review/book.rb +2 -2
  40. data/lib/review/book/base.rb +69 -30
  41. data/lib/review/book/bib.rb +21 -0
  42. data/lib/review/book/book_unit.rb +158 -0
  43. data/lib/review/book/chapter.rb +33 -26
  44. data/lib/review/book/index.rb +39 -206
  45. data/lib/review/book/index/item.rb +8 -2
  46. data/lib/review/book/page_metric.rb +7 -7
  47. data/lib/review/book/part.rb +26 -11
  48. data/lib/review/book/volume.rb +5 -5
  49. data/lib/review/builder.rb +124 -27
  50. data/lib/review/call_hook.rb +20 -0
  51. data/lib/review/catalog.rb +3 -2
  52. data/lib/review/compiler.rb +197 -91
  53. data/lib/review/configure.rb +95 -9
  54. data/lib/review/converter.rb +1 -1
  55. data/lib/review/epub2html.rb +6 -1
  56. data/lib/review/epubmaker.rb +116 -117
  57. data/lib/review/epubmaker/content.rb +113 -0
  58. data/lib/review/epubmaker/epubcommon.rb +372 -0
  59. data/lib/review/epubmaker/epubv2.rb +178 -0
  60. data/lib/review/epubmaker/epubv3.rb +231 -0
  61. data/lib/review/epubmaker/producer.rb +168 -0
  62. data/lib/review/epubmaker/reviewheaderlistener.rb +12 -2
  63. data/lib/review/epubmaker/zip_exporter.rb +84 -0
  64. data/lib/review/exception.rb +6 -0
  65. data/lib/review/extentions/string.rb +0 -4
  66. data/lib/review/htmlbuilder.rb +132 -87
  67. data/lib/review/htmlutils.rb +8 -11
  68. data/lib/review/i18n.rb +2 -1
  69. data/lib/review/idgxmlbuilder.rb +156 -76
  70. data/lib/review/idgxmlmaker.rb +22 -18
  71. data/lib/review/img_math.rb +245 -0
  72. data/lib/review/index_builder.rb +654 -0
  73. data/lib/review/init.rb +17 -18
  74. data/lib/review/latexbox.rb +58 -0
  75. data/lib/review/latexbuilder.rb +173 -43
  76. data/lib/review/latexutils.rb +9 -1
  77. data/lib/review/lineinput.rb +112 -2
  78. data/lib/review/logger.rb +42 -3
  79. data/lib/review/makerhelper.rb +12 -187
  80. data/lib/review/markdownbuilder.rb +51 -2
  81. data/lib/review/pdfmaker.rb +78 -73
  82. data/lib/review/plaintextbuilder.rb +98 -14
  83. data/lib/review/preprocessor.rb +18 -12
  84. data/lib/review/rstbuilder.rb +28 -9
  85. data/lib/review/sec_counter.rb +14 -0
  86. data/lib/review/template.rb +6 -0
  87. data/lib/review/textmaker.rb +21 -19
  88. data/lib/review/textutils.rb +3 -12
  89. data/lib/review/tocprinter.rb +242 -97
  90. data/lib/review/topbuilder.rb +91 -24
  91. data/lib/review/update.rb +12 -13
  92. data/lib/review/version.rb +1 -1
  93. data/lib/review/volumeprinter.rb +97 -0
  94. data/lib/review/webmaker.rb +34 -33
  95. data/lib/review/webtocprinter.rb +39 -35
  96. data/lib/review/yamlloader.rb +2 -1
  97. data/review.gemspec +5 -3
  98. data/samples/sample-book/src/.gitignore +1 -0
  99. data/samples/sample-book/src/config-ebook.yml +4 -0
  100. data/samples/sample-book/src/config-epub2.yml +1 -1
  101. data/samples/sample-book/src/config-jlreq-ebook.yml +4 -0
  102. data/samples/sample-book/src/config.yml +3 -3
  103. data/samples/sample-book/src/lib/tasks/review.rake +26 -6
  104. data/samples/syntax-book/Gemfile +1 -1
  105. data/samples/syntax-book/ch01.re +3 -1
  106. data/samples/syntax-book/ch02.re +28 -21
  107. data/samples/syntax-book/ch03.re +1 -1
  108. data/samples/syntax-book/config-jlreq-lualatex.yml +4 -0
  109. data/samples/syntax-book/config-print.yml +3 -0
  110. data/samples/syntax-book/config.yml +1 -1
  111. data/samples/syntax-book/images/img3-2.png +0 -0
  112. data/samples/syntax-book/lib/tasks/review.rake +23 -8
  113. data/templates/html/_colophon.html.erb +23 -0
  114. data/templates/html/_colophon_history.html.erb +9 -0
  115. data/templates/html/_cover.html.erb +10 -0
  116. data/templates/html/_part_body.html.erb +6 -0
  117. data/templates/html/_titlepage.html.erb +20 -0
  118. data/templates/html/layout-html5.html.erb +6 -0
  119. data/templates/html/layout-xhtml1.html.erb +6 -0
  120. data/templates/latex/config.erb +41 -29
  121. data/templates/latex/review-jlreq/README.md +3 -1
  122. data/templates/latex/review-jlreq/review-base.sty +47 -22
  123. data/templates/latex/review-jlreq/review-jlreq.cls +25 -24
  124. data/templates/latex/review-jlreq/review-style.sty +6 -1
  125. data/templates/latex/review-jlreq/review-tcbox.sty +348 -0
  126. data/templates/latex/review-jlreq/reviewmacro.sty +5 -0
  127. data/templates/latex/review-jsbook/README.md +7 -5
  128. data/templates/latex/review-jsbook/review-base.sty +47 -21
  129. data/templates/latex/review-jsbook/review-jsbook.cls +12 -2
  130. data/templates/latex/review-jsbook/review-style.sty +6 -1
  131. data/templates/latex/review-jsbook/review-tcbox.sty +348 -0
  132. data/templates/latex/review-jsbook/reviewmacro.sty +5 -0
  133. data/templates/opf/epubv2.opf.erb +7 -7
  134. data/templates/opf/epubv3.opf.erb +7 -7
  135. data/templates/opf/opf_manifest_epubv2.opf.erb +10 -0
  136. data/templates/opf/opf_manifest_epubv3.opf.erb +10 -0
  137. data/templates/opf/opf_metainfo_epubv2.opf.erb +17 -0
  138. data/templates/opf/opf_metainfo_epubv3.opf.erb +49 -0
  139. data/templates/opf/opf_tocx_epubv2.opf.erb +9 -0
  140. data/templates/opf/opf_tocx_epubv3.opf.erb +17 -0
  141. data/templates/web/html/layout-html5.html.erb +9 -8
  142. data/templates/web/html/layout-xhtml1.html.erb +6 -0
  143. data/test/assets/header_listener.html +35 -0
  144. data/test/assets/img_math/img1.png +0 -0
  145. data/test/assets/img_math/img2.png +0 -0
  146. data/test/assets/img_math/img3.png +0 -0
  147. data/test/assets/syntax_book_index_detail.txt +58 -0
  148. data/test/assets/test_template.tex +12 -9
  149. data/test/assets/test_template_backmatter.tex +12 -9
  150. data/test/book_test_helper.rb +11 -5
  151. data/test/run_test.rb +1 -1
  152. data/test/test_book.rb +62 -63
  153. data/test/test_book_chapter.rb +99 -56
  154. data/test/test_book_part.rb +3 -3
  155. data/test/test_builder.rb +24 -15
  156. data/test/test_catalog.rb +1 -0
  157. data/test/test_catalog_converter_cmd.rb +1 -1
  158. data/test/test_converter.rb +1 -0
  159. data/test/test_epub3maker.rb +170 -126
  160. data/test/test_epubmaker.rb +249 -129
  161. data/test/test_epubmaker_cmd.rb +14 -7
  162. data/test/test_helper.rb +23 -11
  163. data/test/test_htmlbuilder.rb +956 -76
  164. data/test/test_htmlutils.rb +0 -12
  165. data/test/test_i18n.rb +33 -33
  166. data/test/test_idgxmlbuilder.rb +568 -10
  167. data/test/test_idgxmlmaker_cmd.rb +50 -0
  168. data/test/test_image_finder.rb +52 -70
  169. data/test/test_img_math.rb +111 -0
  170. data/test/test_index.rb +62 -52
  171. data/test/test_indexbuilder.rb +52 -0
  172. data/test/test_latexbuilder.rb +1056 -30
  173. data/test/test_latexbuilder_v2.rb +52 -12
  174. data/test/test_lineinput.rb +20 -93
  175. data/test/test_logger.rb +7 -7
  176. data/test/test_makerhelper.rb +0 -12
  177. data/test/test_markdownbuilder.rb +32 -0
  178. data/test/test_pdfmaker.rb +100 -11
  179. data/test/test_pdfmaker_cmd.rb +101 -7
  180. data/test/test_plaintextbuilder.rb +531 -25
  181. data/test/test_review_ext.rb +2 -1
  182. data/test/test_reviewheaderlistener.rb +49 -0
  183. data/test/test_rstbuilder.rb +25 -1
  184. data/test/test_sec_counter.rb +156 -0
  185. data/test/test_template.rb +12 -2
  186. data/test/test_textmaker_cmd.rb +58 -0
  187. data/test/test_tocprinter.rb +46 -0
  188. data/test/test_topbuilder.rb +365 -10
  189. data/test/test_update.rb +44 -44
  190. data/test/test_webtocprinter.rb +75 -43
  191. data/test/test_zip_exporter.rb +5 -6
  192. data/vendor/gentombow/LICENSE +1 -1
  193. data/vendor/gentombow/Makefile +0 -1
  194. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  195. data/vendor/gentombow/bounddvi-en.tex +1 -0
  196. data/vendor/gentombow/bounddvi.pdf +0 -0
  197. data/vendor/gentombow/bounddvi.sty +30 -7
  198. data/vendor/gentombow/bounddvi.tex +1 -0
  199. data/vendor/gentombow/create_archive.sh +1 -0
  200. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  201. data/vendor/gentombow/gentombow-ja.tex +9 -0
  202. data/vendor/gentombow/gentombow.pdf +0 -0
  203. data/vendor/gentombow/gentombow.sty +32 -10
  204. data/vendor/gentombow/gentombow.tex +8 -0
  205. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  206. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  207. data/vendor/jsclasses/LICENSE +1 -1
  208. data/vendor/jsclasses/Makefile +3 -2
  209. data/vendor/jsclasses/create_archive.sh +5 -5
  210. data/vendor/jsclasses/jis/Makefile +3 -2
  211. data/vendor/jsclasses/jis/jsarticle.cls +74 -31
  212. data/vendor/jsclasses/jis/jsbook.cls +74 -31
  213. data/vendor/jsclasses/jis/jsclasses.dtx +176 -36
  214. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  215. data/vendor/jsclasses/jis/jslogo.dtx +4 -4
  216. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  217. data/vendor/jsclasses/jis/jslogo.sty +4 -16
  218. data/vendor/jsclasses/jis/jspf.cls +73 -30
  219. data/vendor/jsclasses/jis/jsreport.cls +74 -31
  220. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  221. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  222. data/vendor/jsclasses/jis/kiyou.cls +74 -31
  223. data/vendor/jsclasses/jis/minijs.sty +65 -22
  224. data/vendor/jsclasses/jis/okumacro.dtx +4 -5
  225. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  226. data/vendor/jsclasses/jis/okumacro.sty +4 -17
  227. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  228. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  229. data/vendor/jsclasses/jis/winjis.sty +23 -19
  230. data/vendor/jsclasses/jsarticle.cls +74 -31
  231. data/vendor/jsclasses/jsbook.cls +74 -31
  232. data/vendor/jsclasses/jsclasses.dtx +176 -36
  233. data/vendor/jsclasses/jsclasses.ins +15 -5
  234. data/vendor/jsclasses/jsclasses.pdf +0 -0
  235. data/vendor/jsclasses/jslogo.dtx +4 -4
  236. data/vendor/jsclasses/jslogo.ins +9 -0
  237. data/vendor/jsclasses/jslogo.pdf +0 -0
  238. data/vendor/jsclasses/jslogo.sty +4 -16
  239. data/vendor/jsclasses/jspf.cls +73 -30
  240. data/vendor/jsclasses/jsreport.cls +74 -31
  241. data/vendor/jsclasses/jsverb.ins +9 -0
  242. data/vendor/jsclasses/jsverb.pdf +0 -0
  243. data/vendor/jsclasses/jsverb.sty +1 -13
  244. data/vendor/jsclasses/kiyou.cls +74 -31
  245. data/vendor/jsclasses/minijs.sty +68 -22
  246. data/vendor/jsclasses/okumacro.dtx +4 -5
  247. data/vendor/jsclasses/okumacro.ins +9 -0
  248. data/vendor/jsclasses/okumacro.pdf +0 -0
  249. data/vendor/jsclasses/okumacro.sty +4 -17
  250. data/vendor/jsclasses/okuverb.ins +9 -0
  251. data/vendor/jsclasses/okuverb.pdf +0 -0
  252. data/vendor/jsclasses/okuverb.sty +1 -13
  253. data/vendor/jsclasses/tests/relfont.tex +10 -0
  254. data/vendor/jsclasses/winjis.sty +23 -19
  255. metadata +109 -20
  256. data/.rubocop_todo.yml +0 -7
  257. data/lib/epubmaker.rb +0 -23
  258. data/lib/epubmaker/content.rb +0 -110
  259. data/lib/epubmaker/epubcommon.rb +0 -441
  260. data/lib/epubmaker/epubv2.rb +0 -143
  261. data/lib/epubmaker/epubv3.rb +0 -233
  262. data/lib/epubmaker/producer.rb +0 -375
  263. data/lib/epubmaker/zip_exporter.rb +0 -81
  264. data/lib/lineinput.rb +0 -155
  265. data/lib/review/book/compilable.rb +0 -178
  266. data/lib/review/tocparser.rb +0 -271
  267. data/samples/syntax-book/review-ext.rb +0 -14
  268. data/test/test_tocparser.rb +0 -25
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2009-2020 Minero Aoki, Kenshi Muto
2
2
  # Copyright (c) 2002-2007 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -14,8 +14,10 @@ require 'strscan'
14
14
 
15
15
  module ReVIEW
16
16
  class Compiler
17
- def initialize(strategy)
18
- @strategy = strategy
17
+ MAX_HEADLINE_LEVEL = 6
18
+
19
+ def initialize(builder)
20
+ @builder = builder
19
21
 
20
22
  ## commands which do not parse block lines in compiler
21
23
  @non_parsed_commands = %i[embed texequation graph]
@@ -24,12 +26,25 @@ module ReVIEW
24
26
  @command_name_stack = []
25
27
  end
26
28
 
27
- attr_reader :strategy
29
+ attr_reader :builder, :previous_list_type
30
+
31
+ def strategy
32
+ error 'Compiler#strategy is obsoleted. Use Compiler#builder.'
33
+ @builder
34
+ end
35
+
36
+ def non_escaped_commands
37
+ if @builder.highlight?
38
+ %i[list emlist listnum emlistnum cmd]
39
+ else
40
+ []
41
+ end
42
+ end
28
43
 
29
44
  def compile(chap)
30
45
  @chapter = chap
31
46
  do_compile
32
- @strategy.result
47
+ @builder.result
33
48
  end
34
49
 
35
50
  class SyntaxElement
@@ -46,6 +61,7 @@ module ReVIEW
46
61
  unless @argc_spec === args.size
47
62
  raise CompileError, "wrong # of parameters (block command //#{@name}, expect #{@argc_spec} but #{args.size})"
48
63
  end
64
+
49
65
  if @checker
50
66
  @checker.call(*args)
51
67
  end
@@ -60,12 +76,16 @@ module ReVIEW
60
76
  end
61
77
  end
62
78
 
79
+ def minicolumn?
80
+ @type == :minicolumn
81
+ end
82
+
63
83
  def block_required?
64
- @type == :block
84
+ @type == :block or @type == :minicolumn
65
85
  end
66
86
 
67
87
  def block_allowed?
68
- @type == :block or @type == :optional
88
+ @type == :block or @type == :optional or @type == :minicolumn
69
89
  end
70
90
  end
71
91
 
@@ -75,6 +95,10 @@ module ReVIEW
75
95
  defsyntax(name, (optional ? :optional : :block), argc, &block)
76
96
  end
77
97
 
98
+ def self.defminicolumn(name, argc, _optional = false, &block)
99
+ defsyntax(name, :minicolumn, argc, &block)
100
+ end
101
+
78
102
  def self.defsingle(name, argc, &block)
79
103
  defsyntax(name, :line, argc, &block)
80
104
  end
@@ -87,6 +111,16 @@ module ReVIEW
87
111
  INLINE[name] = InlineSyntaxElement.new(name)
88
112
  end
89
113
 
114
+ def self.minicolumn_names
115
+ buf = []
116
+ SYNTAX.each do |name, syntax|
117
+ if syntax.minicolumn?
118
+ buf << name.to_s
119
+ end
120
+ end
121
+ buf
122
+ end
123
+
90
124
  def syntax_defined?(name)
91
125
  SYNTAX.key?(name.to_sym)
92
126
  end
@@ -115,7 +149,7 @@ module ReVIEW
115
149
  defblock :emlist, 0..2
116
150
  defblock :cmd, 0..1
117
151
  defblock :table, 0..2
118
- defblock :imgtable, 0..2
152
+ defblock :imgtable, 0..3
119
153
  defblock :emtable, 0..1
120
154
  defblock :quote, 0
121
155
  defblock :image, 2..3, true
@@ -135,18 +169,19 @@ module ReVIEW
135
169
  defblock :bpo, 0
136
170
  defblock :flushright, 0
137
171
  defblock :centering, 0
138
- defblock :note, 0..1
139
- defblock :memo, 0..1
140
- defblock :info, 0..1
141
- defblock :important, 0..1
142
- defblock :caution, 0..1
143
- defblock :notice, 0..1
144
- defblock :warning, 0..1
145
- defblock :tip, 0..1
146
172
  defblock :box, 0..1
147
173
  defblock :comment, 0..1, true
148
174
  defblock :embed, 0..1
149
175
 
176
+ defminicolumn :note, 0..1
177
+ defminicolumn :memo, 0..1
178
+ defminicolumn :tip, 0..1
179
+ defminicolumn :info, 0..1
180
+ defminicolumn :warning, 0..1
181
+ defminicolumn :important, 0..1
182
+ defminicolumn :caution, 0..1
183
+ defminicolumn :notice, 0..1
184
+
150
185
  defsingle :footnote, 2
151
186
  defsingle :noindent, 0
152
187
  defsingle :blankline, 0
@@ -159,6 +194,8 @@ module ReVIEW
159
194
  defsingle :include, 1
160
195
  defsingle :olnum, 1
161
196
  defsingle :firstlinenum, 1
197
+ defsingle :beginchild, 0
198
+ defsingle :endchild, 0
162
199
 
163
200
  definline :chapref
164
201
  definline :chap
@@ -223,47 +260,62 @@ module ReVIEW
223
260
 
224
261
  def do_compile
225
262
  f = LineInput.new(StringIO.new(@chapter.content))
226
- @strategy.bind(self, @chapter, Location.new(@chapter.basename, f))
263
+ @builder.bind(self, @chapter, Location.new(@chapter.basename, f))
227
264
 
228
- @non_parsed_commands = %i[embed texequation graph]
229
- if @strategy.highlight?
230
- @non_escaped_commands = %i[list emlist listnum emlistnum cmd]
231
- else
232
- @non_escaped_commands = []
233
- end
234
- @command_name_stack = []
265
+ ## in minicolumn, such as note/info/alert...
266
+ @minicolumn_name = nil
235
267
 
236
268
  tagged_section_init
237
269
  while f.next?
238
270
  case f.peek
239
271
  when /\A\#@/
240
272
  f.gets # Nothing to do
241
- when /\A=+[\[\s\{]/
273
+ when /\A=+[\[\s{]/
242
274
  compile_headline(f.gets)
275
+ @builder.previous_list_type = nil
243
276
  when /\A\s+\*/
244
277
  compile_ulist(f)
278
+ @builder.previous_list_type = 'ul'
245
279
  when /\A\s+\d+\./
246
280
  compile_olist(f)
281
+ @builder.previous_list_type = 'ol'
247
282
  when /\A\s+:\s/
248
283
  compile_dlist(f)
284
+ @builder.previous_list_type = 'dl'
249
285
  when /\A\s*:\s/
250
286
  warn 'Definition list starting with `:` is deprecated. It should start with ` : `.'
251
287
  compile_dlist(f)
288
+ @builder.previous_list_type = 'dl'
252
289
  when %r{\A//\}}
253
- f.gets
254
- error 'block end seen but not opened'
290
+ if in_minicolumn?
291
+ _line = f.gets
292
+ compile_minicolumn_end
293
+ else
294
+ f.gets
295
+ error 'block end seen but not opened'
296
+ end
255
297
  when %r{\A//[a-z]+}
256
- # @command_name_stack.push(name) ## <- move into read_command() to use name
257
- name, args, lines = read_command(f)
258
- syntax = syntax_descriptor(name)
259
- unless syntax
260
- error "unknown command: //#{name}"
261
- compile_unknown_command(args, lines)
298
+ line = f.peek
299
+ matched = line =~ %r|\A//([a-z]+)(:?\[.*\])?{\s*$|
300
+ if matched && minicolumn_block_name?($1)
301
+ line = f.gets
302
+ name = $1
303
+ args = parse_args(line.sub(%r{\A//[a-z]+}, '').rstrip.chomp('{'), name)
304
+ compile_minicolumn_begin(name, *args)
305
+ else
306
+ # @command_name_stack.push(name) ## <- move into read_command() to use name
307
+ name, args, lines = read_command(f)
308
+ syntax = syntax_descriptor(name)
309
+ unless syntax
310
+ error "unknown command: //#{name}"
311
+ compile_unknown_command(args, lines)
312
+ @command_name_stack.pop
313
+ next
314
+ end
315
+ compile_command(syntax, args, lines)
262
316
  @command_name_stack.pop
263
- next
264
317
  end
265
- compile_command(syntax, args, lines)
266
- @command_name_stack.pop
318
+ @builder.previous_list_type = nil
267
319
  when %r{\A//}
268
320
  line = f.gets
269
321
  warn "`//' seen but is not valid command: #{line.strip.inspect}"
@@ -271,39 +323,74 @@ module ReVIEW
271
323
  warn 'skipping block...'
272
324
  read_block(f, false)
273
325
  end
326
+ @builder.previous_list_type = nil
274
327
  else
275
328
  if f.peek.strip.empty?
276
329
  f.gets
277
330
  next
278
331
  end
279
332
  compile_paragraph(f)
333
+ @builder.previous_list_type = nil
280
334
  end
281
335
  end
282
336
  close_all_tagged_section
337
+ rescue SyntaxError => e
338
+ error e
339
+ end
340
+
341
+ def compile_minicolumn_begin(name, caption = nil)
342
+ mid = "#{name}_begin"
343
+ unless @builder.respond_to?(mid)
344
+ error "strategy does not support minicolumn: #{name}"
345
+ end
346
+
347
+ if @minicolumn_name
348
+ error "minicolumn cannot be nested: #{name}"
349
+ return
350
+ end
351
+ @minicolumn_name = name
352
+
353
+ @builder.__send__(mid, caption)
354
+ end
355
+
356
+ def compile_minicolumn_end
357
+ unless @minicolumn_name
358
+ error "minicolumn is not used: #{name}"
359
+ return
360
+ end
361
+ name = @minicolumn_name
362
+
363
+ mid = "#{name}_end"
364
+ @builder.__send__(mid)
365
+ @minicolumn_name = nil
283
366
  end
284
367
 
285
368
  def compile_headline(line)
286
369
  @headline_indexs ||= [@chapter.number.to_i - 1]
287
370
  m = /\A(=+)(?:\[(.+?)\])?(?:\{(.+?)\})?(.*)/.match(line)
288
371
  level = m[1].size
372
+ if level > MAX_HEADLINE_LEVEL
373
+ raise CompileError, "Invalid header: max headline level is #{MAX_HEADLINE_LEVEL}"
374
+ end
375
+
289
376
  tag = m[2]
290
377
  label = m[3]
291
378
  caption = m[4].strip
292
379
  index = level - 1
293
380
  if tag
294
- if tag !~ %r{\A/}
295
- if caption.empty?
296
- warn 'headline is empty.'
297
- end
298
- close_current_tagged_section(level)
299
- open_tagged_section(tag, level, label, caption)
300
- else
381
+ if tag.start_with?('/')
301
382
  open_tag = tag[1..-1]
302
383
  prev_tag_info = @tagged_section.pop
303
384
  if prev_tag_info.nil? || prev_tag_info.first != open_tag
304
385
  error "#{open_tag} is not opened."
305
386
  end
306
387
  close_tagged_section(*prev_tag_info)
388
+ else
389
+ if caption.empty?
390
+ warn 'headline is empty.'
391
+ end
392
+ close_current_tagged_section(level)
393
+ open_tagged_section(tag, level, label, caption)
307
394
  end
308
395
  else
309
396
  if caption.empty?
@@ -317,18 +404,18 @@ module ReVIEW
317
404
  end
318
405
  @headline_indexs[index] += 1
319
406
  close_current_tagged_section(level)
320
- @strategy.headline(level, label, caption)
407
+ @builder.headline(level, label, caption)
321
408
  end
322
409
  end
323
410
 
324
411
  def close_current_tagged_section(level)
325
- while @tagged_section.last and @tagged_section.last[1] >= level
412
+ while @tagged_section.last && (@tagged_section.last[1] >= level)
326
413
  close_tagged_section(* @tagged_section.pop)
327
414
  end
328
415
  end
329
416
 
330
417
  def headline(level, label, caption)
331
- @strategy.headline(level, label, caption)
418
+ @builder.headline(level, label, caption)
332
419
  end
333
420
 
334
421
  def tagged_section_init
@@ -337,21 +424,21 @@ module ReVIEW
337
424
 
338
425
  def open_tagged_section(tag, level, label, caption)
339
426
  mid = "#{tag}_begin"
340
- unless @strategy.respond_to?(mid)
341
- error "strategy does not support tagged section: #{tag}"
427
+ unless @builder.respond_to?(mid)
428
+ error "builder does not support tagged section: #{tag}"
342
429
  headline(level, label, caption)
343
430
  return
344
431
  end
345
432
  @tagged_section.push([tag, level])
346
- @strategy.__send__(mid, level, label, caption)
433
+ @builder.__send__(mid, level, label, caption)
347
434
  end
348
435
 
349
436
  def close_tagged_section(tag, level)
350
437
  mid = "#{tag}_end"
351
- if @strategy.respond_to?(mid)
352
- @strategy.__send__(mid, level)
438
+ if @builder.respond_to?(mid)
439
+ @builder.__send__(mid, level)
353
440
  else
354
- error "strategy does not support block op: #{mid}"
441
+ error "builder does not support block op: #{mid}"
355
442
  end
356
443
  end
357
444
 
@@ -374,38 +461,38 @@ module ReVIEW
374
461
  line =~ /\A\s+(\*+)/
375
462
  current_level = $1.size
376
463
  if level == current_level
377
- @strategy.ul_item_end
464
+ @builder.ul_item_end
378
465
  # body
379
- @strategy.ul_item_begin(buf)
466
+ @builder.ul_item_begin(buf)
380
467
  elsif level < current_level # down
381
468
  level_diff = current_level - level
382
469
  if level_diff != 1
383
470
  error 'too many *.'
384
471
  end
385
472
  level = current_level
386
- @strategy.ul_begin { level }
387
- @strategy.ul_item_begin(buf)
473
+ @builder.ul_begin { level }
474
+ @builder.ul_item_begin(buf)
388
475
  elsif level > current_level # up
389
476
  level_diff = level - current_level
390
477
  level = current_level
391
478
  (1..level_diff).to_a.reverse_each do |i|
392
- @strategy.ul_item_end
393
- @strategy.ul_end { level + i }
479
+ @builder.ul_item_end
480
+ @builder.ul_end { level + i }
394
481
  end
395
- @strategy.ul_item_end
482
+ @builder.ul_item_end
396
483
  # body
397
- @strategy.ul_item_begin(buf)
484
+ @builder.ul_item_begin(buf)
398
485
  end
399
486
  end
400
487
 
401
488
  (1..level).to_a.reverse_each do |i|
402
- @strategy.ul_item_end
403
- @strategy.ul_end { i }
489
+ @builder.ul_item_end
490
+ @builder.ul_end { i }
404
491
  end
405
492
  end
406
493
 
407
494
  def compile_olist(f)
408
- @strategy.ol_begin
495
+ @builder.ol_begin
409
496
  f.while_match(/\A\s+\d+\.|\A\#@/) do |line|
410
497
  next if line =~ /\A\#@/
411
498
 
@@ -414,30 +501,37 @@ module ReVIEW
414
501
  f.while_match(/\A\s+(?!\d+\.)\S/) do |cont|
415
502
  buf.push(text(cont.strip))
416
503
  end
417
- @strategy.ol_item(buf, num)
504
+ @builder.ol_item(buf, num)
418
505
  end
419
- @strategy.ol_end
506
+ @builder.ol_end
420
507
  end
421
508
 
422
509
  def compile_dlist(f)
423
- @strategy.dl_begin
510
+ @builder.dl_begin
424
511
  while /\A\s*:/ =~ f.peek
425
- @strategy.dt(text(f.gets.sub(/\A\s*:/, '').strip))
426
- desc = f.break(/\A(\S|\s*:|\s+\d+\.\s|\s+\*\s)/).map { |line| text(line.strip) }
427
- @strategy.dd(desc)
512
+ # defer compile_inline to handle footnotes
513
+ @builder.doc_status[:dt] = true
514
+ @builder.dt(text(f.gets.sub(/\A\s*:/, '').strip))
515
+ @builder.doc_status[:dt] = nil
516
+ desc = []
517
+ f.until_match(/\A(\S|\s*:|\s+\d+\.\s|\s+\*\s)/) do |line|
518
+ desc << text(line.strip)
519
+ end
520
+ @builder.dd(desc)
428
521
  f.skip_blank_lines
429
522
  f.skip_comment_lines
430
523
  end
431
- @strategy.dl_end
524
+ @builder.dl_end
432
525
  end
433
526
 
434
527
  def compile_paragraph(f)
435
528
  buf = []
436
529
  f.until_match(%r{\A//|\A\#@}) do |line|
437
530
  break if line.strip.empty?
531
+
438
532
  buf.push(text(line.sub(/^(\t+)\s*/) { |m| '<!ESCAPETAB!>' * m.size }.strip.gsub('<!ESCAPETAB!>', "\t")))
439
533
  end
440
- @strategy.paragraph(buf)
534
+ @builder.paragraph(buf)
441
535
  end
442
536
 
443
537
  def read_command(f)
@@ -446,9 +540,9 @@ module ReVIEW
446
540
  ignore_inline = @non_parsed_commands.include?(name)
447
541
  @command_name_stack.push(name)
448
542
  args = parse_args(line.sub(%r{\A//[a-z]+}, '').rstrip.chomp('{'), name)
449
- @strategy.doc_status[name] = true
543
+ @builder.doc_status[name] = true
450
544
  lines = block_open?(line) ? read_block(f, ignore_inline) : nil
451
- @strategy.doc_status[name] = nil
545
+ @builder.doc_status[name] = nil
452
546
  [name, args, lines]
453
547
  end
454
548
 
@@ -466,7 +560,7 @@ module ReVIEW
466
560
  buf.push(text(line.rstrip, true))
467
561
  end
468
562
  end
469
- unless %r{\A//\}} =~ f.peek
563
+ unless f.peek.to_s.start_with?('//}')
470
564
  error "unexpected EOF (block begins at: #{head})"
471
565
  return buf
472
566
  end
@@ -476,6 +570,7 @@ module ReVIEW
476
570
 
477
571
  def parse_args(str, _name = nil)
478
572
  return [] if str.empty?
573
+
479
574
  scanner = StringScanner.new(str)
480
575
  words = []
481
576
  while word = scanner.scan(/(\[\]|\[.*?[^\\]\])/)
@@ -493,8 +588,8 @@ module ReVIEW
493
588
  end
494
589
 
495
590
  def compile_command(syntax, args, lines)
496
- unless @strategy.respond_to?(syntax.name)
497
- error "strategy does not support command: //#{syntax.name}"
591
+ unless @builder.respond_to?(syntax.name)
592
+ error "builder does not support command: //#{syntax.name}"
498
593
  compile_unknown_command(args, lines)
499
594
  return
500
595
  end
@@ -515,11 +610,11 @@ module ReVIEW
515
610
  end
516
611
 
517
612
  def compile_unknown_command(args, lines)
518
- @strategy.unknown_command(args, lines)
613
+ @builder.unknown_command(args, lines)
519
614
  end
520
615
 
521
616
  def compile_block(syntax, args, lines)
522
- @strategy.__send__(syntax.name, (lines || default_block(syntax)), *args)
617
+ @builder.__send__(syntax.name, (lines || default_block(syntax)), *args)
523
618
  end
524
619
 
525
620
  def default_block(syntax)
@@ -530,7 +625,7 @@ module ReVIEW
530
625
  end
531
626
 
532
627
  def compile_single(syntax, args)
533
- @strategy.__send__(syntax.name, *args)
628
+ @builder.__send__(syntax.name, *args)
534
629
  end
535
630
 
536
631
  def replace_fence(str)
@@ -540,23 +635,24 @@ module ReVIEW
540
635
  if arg =~ /[\x01\x02\x03\x04]/
541
636
  error "invalid character in '#{str}'"
542
637
  end
543
- replaced = arg.gsub('@', "\x01").gsub('\\', "\x02").gsub('{', "\x03").gsub('}', "\x04")
638
+ replaced = arg.tr('@', "\x01").tr('\\', "\x02").tr('{', "\x03").tr('}', "\x04")
544
639
  "@<#{op}>{#{replaced}}"
545
640
  end
546
641
  end
547
642
 
548
643
  def revert_replace_fence(str)
549
- str.gsub("\x01", '@').gsub("\x02", '\\').gsub("\x03", '{').gsub("\x04", '}')
644
+ str.tr("\x01", '@').tr("\x02", '\\').tr("\x03", '{').tr("\x04", '}')
550
645
  end
551
646
 
552
647
  def in_non_escaped_command?
553
648
  current_command = @command_name_stack.last
554
- current_command && @non_escaped_commands.include?(current_command)
649
+ current_command && non_escaped_commands.include?(current_command)
555
650
  end
556
651
 
557
652
  def text(str, block_mode = false)
558
653
  return '' if str.empty?
559
- words = replace_fence(str).split(/(@<\w+>\{(?:[^\}\\]|\\.)*?\})/, -1)
654
+
655
+ words = replace_fence(str).split(/(@<\w+>\{(?:[^}\\]|\\.)*?\})/, -1)
560
656
  words.each do |w|
561
657
  if w.scan(/@<\w+>/).size > 1 && !/\A@<raw>/.match(w)
562
658
  error "`@<xxx>' seen but is not valid inline op: #{w}"
@@ -567,37 +663,47 @@ module ReVIEW
567
663
  if in_non_escaped_command? && block_mode
568
664
  result << revert_replace_fence(words.shift)
569
665
  else
570
- result << @strategy.nofunc_text(revert_replace_fence(words.shift))
666
+ result << @builder.nofunc_text(revert_replace_fence(words.shift))
571
667
  end
572
668
  break if words.empty?
669
+
573
670
  result << compile_inline(revert_replace_fence(words.shift.gsub(/\\\}/, '}').gsub(/\\\\/, '\\')))
574
671
  end
575
672
  result
576
673
  rescue => e
577
674
  error e.message
578
675
  end
579
- public :text # called from strategy
676
+ public :text # called from builder
580
677
 
581
678
  def compile_inline(str)
582
679
  op, arg = /\A@<(\w+)>\{(.*?)\}\z/.match(str).captures
583
680
  unless inline_defined?(op)
584
681
  raise CompileError, "no such inline op: #{op}"
585
682
  end
586
- unless @strategy.respond_to?("inline_#{op}")
587
- raise "strategy does not support inline op: @<#{op}>"
683
+ unless @builder.respond_to?("inline_#{op}")
684
+ raise "builder does not support inline op: @<#{op}>"
588
685
  end
589
- @strategy.__send__("inline_#{op}", arg)
686
+
687
+ @builder.__send__("inline_#{op}", arg)
590
688
  rescue => e
591
689
  error e.message
592
- @strategy.nofunc_text(str)
690
+ @builder.nofunc_text(str)
691
+ end
692
+
693
+ def in_minicolumn?
694
+ @builder.in_minicolumn?
695
+ end
696
+
697
+ def minicolumn_block_name?(name)
698
+ @builder.minicolumn_block_name?(name)
593
699
  end
594
700
 
595
701
  def warn(msg)
596
- @strategy.warn msg
702
+ @builder.warn msg
597
703
  end
598
704
 
599
705
  def error(msg)
600
- @strategy.error msg
706
+ @builder.error msg
601
707
  end
602
708
  end
603
709
  end # module ReVIEW