review 4.2.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby-win.yml +11 -5
  3. data/.rubocop.yml +113 -24
  4. data/NEWS.ja.md +94 -0
  5. data/NEWS.md +94 -0
  6. data/bin/review-catalog-converter +1 -1
  7. data/bin/review-check +2 -4
  8. data/bin/review-checkdep +1 -1
  9. data/bin/review-compile +8 -14
  10. data/bin/review-validate +1 -1
  11. data/doc/config.yml.sample +4 -1
  12. data/doc/config.yml.sample-simple +1 -1
  13. data/doc/format.ja.md +83 -4
  14. data/doc/format.md +84 -7
  15. data/doc/makeindex.ja.md +2 -2
  16. data/doc/quickstart.ja.md +3 -3
  17. data/doc/quickstart.md +2 -2
  18. data/lib/epubmaker/content.rb +3 -2
  19. data/lib/epubmaker/epubcommon.rb +33 -25
  20. data/lib/epubmaker/epubv2.rb +5 -6
  21. data/lib/epubmaker/epubv3.rb +20 -18
  22. data/lib/review/book.rb +2 -2
  23. data/lib/review/book/base.rb +61 -25
  24. data/lib/review/book/bib.rb +21 -0
  25. data/lib/review/book/book_unit.rb +155 -0
  26. data/lib/review/book/chapter.rb +30 -26
  27. data/lib/review/book/index.rb +23 -185
  28. data/lib/review/book/index/item.rb +7 -1
  29. data/lib/review/book/part.rb +21 -9
  30. data/lib/review/book/volume.rb +1 -1
  31. data/lib/review/builder.rb +68 -13
  32. data/lib/review/catalog.rb +2 -2
  33. data/lib/review/compiler.rb +159 -73
  34. data/lib/review/configure.rb +22 -1
  35. data/lib/review/converter.rb +1 -1
  36. data/lib/review/epub2html.rb +6 -1
  37. data/lib/review/epubmaker.rb +12 -23
  38. data/lib/review/htmlbuilder.rb +36 -7
  39. data/lib/review/htmlutils.rb +7 -10
  40. data/lib/review/i18n.rb +1 -1
  41. data/lib/review/idgxmlbuilder.rb +51 -6
  42. data/lib/review/idgxmlmaker.rb +9 -14
  43. data/lib/review/index_builder.rb +653 -0
  44. data/lib/review/init.rb +5 -13
  45. data/lib/review/latexbuilder.rb +65 -4
  46. data/lib/review/logger.rb +2 -2
  47. data/lib/review/makerhelper.rb +11 -0
  48. data/lib/review/markdownbuilder.rb +19 -1
  49. data/lib/review/pdfmaker.rb +17 -36
  50. data/lib/review/plaintextbuilder.rb +48 -2
  51. data/lib/review/preprocessor.rb +5 -5
  52. data/lib/review/rstbuilder.rb +25 -6
  53. data/lib/review/sec_counter.rb +13 -0
  54. data/lib/review/textmaker.rb +4 -12
  55. data/lib/review/tocprinter.rb +2 -3
  56. data/lib/review/topbuilder.rb +26 -0
  57. data/lib/review/update.rb +7 -7
  58. data/lib/review/version.rb +1 -1
  59. data/lib/review/volumeprinter.rb +2 -3
  60. data/lib/review/webmaker.rb +9 -20
  61. data/review.gemspec +2 -2
  62. data/samples/sample-book/src/config.yml +1 -1
  63. data/samples/syntax-book/Gemfile +1 -1
  64. data/samples/syntax-book/config.yml +1 -1
  65. data/templates/latex/config.erb +27 -23
  66. data/templates/latex/review-jlreq/README.md +3 -1
  67. data/templates/latex/review-jlreq/review-base.sty +31 -15
  68. data/templates/latex/review-jlreq/review-jlreq.cls +8 -24
  69. data/templates/latex/review-jsbook/README.md +7 -5
  70. data/templates/latex/review-jsbook/review-base.sty +34 -16
  71. data/templates/latex/review-jsbook/review-jsbook.cls +4 -2
  72. data/templates/web/html/layout-html5.html.erb +1 -1
  73. data/test/assets/test_template.tex +3 -3
  74. data/test/assets/test_template_backmatter.tex +3 -3
  75. data/test/book_test_helper.rb +11 -5
  76. data/test/test_book.rb +54 -63
  77. data/test/test_book_chapter.rb +93 -52
  78. data/test/test_builder.rb +24 -15
  79. data/test/test_converter.rb +1 -0
  80. data/test/test_epub3maker.rb +2 -2
  81. data/test/test_epubmaker.rb +8 -0
  82. data/test/test_helper.rb +4 -1
  83. data/test/test_htmlbuilder.rb +627 -56
  84. data/test/test_htmlutils.rb +0 -12
  85. data/test/test_i18n.rb +33 -33
  86. data/test/test_idgxmlbuilder.rb +358 -11
  87. data/test/test_idgxmlmaker_cmd.rb +1 -1
  88. data/test/test_index.rb +62 -52
  89. data/test/test_indexbuilder.rb +52 -0
  90. data/test/test_latexbuilder.rb +547 -10
  91. data/test/test_latexbuilder_v2.rb +43 -5
  92. data/test/test_logger.rb +7 -7
  93. data/test/test_makerhelper.rb +0 -12
  94. data/test/test_markdownbuilder.rb +3 -0
  95. data/test/test_pdfmaker.rb +13 -12
  96. data/test/test_pdfmaker_cmd.rb +1 -1
  97. data/test/test_plaintextbuilder.rb +422 -7
  98. data/test/test_review_ext.rb +2 -1
  99. data/test/test_rstbuilder.rb +25 -1
  100. data/test/test_sec_counter.rb +156 -0
  101. data/test/test_textmaker_cmd.rb +1 -1
  102. data/test/test_topbuilder.rb +187 -10
  103. data/test/test_update.rb +10 -10
  104. data/test/test_webtocprinter.rb +12 -12
  105. data/vendor/gentombow/LICENSE +1 -1
  106. data/vendor/gentombow/Makefile +0 -1
  107. data/vendor/gentombow/bounddvi-en.pdf +0 -0
  108. data/vendor/gentombow/bounddvi-en.tex +1 -0
  109. data/vendor/gentombow/bounddvi.pdf +0 -0
  110. data/vendor/gentombow/bounddvi.sty +30 -7
  111. data/vendor/gentombow/bounddvi.tex +1 -0
  112. data/vendor/gentombow/create_archive.sh +1 -0
  113. data/vendor/gentombow/gentombow-ja.pdf +0 -0
  114. data/vendor/gentombow/gentombow-ja.tex +9 -0
  115. data/vendor/gentombow/gentombow.pdf +0 -0
  116. data/vendor/gentombow/gentombow.sty +32 -10
  117. data/vendor/gentombow/gentombow.tex +8 -0
  118. data/vendor/gentombow/tests/gentombow-01-pdfx.tex +8 -0
  119. data/vendor/gentombow/tests/gentombow-02-pdfx.tex +8 -0
  120. data/vendor/jsclasses/Makefile +3 -2
  121. data/vendor/jsclasses/create_archive.sh +5 -5
  122. data/vendor/jsclasses/jis/Makefile +3 -2
  123. data/vendor/jsclasses/jis/jsarticle.cls +22 -18
  124. data/vendor/jsclasses/jis/jsbook.cls +22 -18
  125. data/vendor/jsclasses/jis/jsclasses.dtx +94 -13
  126. data/vendor/jsclasses/jis/jsclasses.ins +15 -5
  127. data/vendor/jsclasses/jis/jslogo.ins +9 -0
  128. data/vendor/jsclasses/jis/jslogo.sty +1 -13
  129. data/vendor/jsclasses/jis/jspf.cls +22 -18
  130. data/vendor/jsclasses/jis/jsreport.cls +22 -18
  131. data/vendor/jsclasses/jis/jsverb.ins +9 -0
  132. data/vendor/jsclasses/jis/jsverb.sty +1 -13
  133. data/vendor/jsclasses/jis/kiyou.cls +22 -18
  134. data/vendor/jsclasses/jis/minijs.sty +65 -22
  135. data/vendor/jsclasses/jis/okumacro.ins +9 -0
  136. data/vendor/jsclasses/jis/okumacro.sty +1 -13
  137. data/vendor/jsclasses/jis/okuverb.ins +9 -0
  138. data/vendor/jsclasses/jis/okuverb.sty +1 -13
  139. data/vendor/jsclasses/jis/winjis.sty +23 -19
  140. data/vendor/jsclasses/jsarticle.cls +22 -18
  141. data/vendor/jsclasses/jsbook.cls +22 -18
  142. data/vendor/jsclasses/jsclasses.dtx +94 -13
  143. data/vendor/jsclasses/jsclasses.ins +15 -5
  144. data/vendor/jsclasses/jsclasses.pdf +0 -0
  145. data/vendor/jsclasses/jslogo.ins +9 -0
  146. data/vendor/jsclasses/jslogo.pdf +0 -0
  147. data/vendor/jsclasses/jslogo.sty +1 -13
  148. data/vendor/jsclasses/jspf.cls +22 -18
  149. data/vendor/jsclasses/jsreport.cls +22 -18
  150. data/vendor/jsclasses/jsverb.ins +9 -0
  151. data/vendor/jsclasses/jsverb.pdf +0 -0
  152. data/vendor/jsclasses/jsverb.sty +1 -13
  153. data/vendor/jsclasses/kiyou.cls +22 -18
  154. data/vendor/jsclasses/minijs.sty +68 -22
  155. data/vendor/jsclasses/okumacro.ins +9 -0
  156. data/vendor/jsclasses/okumacro.pdf +0 -0
  157. data/vendor/jsclasses/okumacro.sty +1 -13
  158. data/vendor/jsclasses/okuverb.ins +9 -0
  159. data/vendor/jsclasses/okuverb.pdf +0 -0
  160. data/vendor/jsclasses/okuverb.sty +1 -13
  161. data/vendor/jsclasses/tests/relfont.tex +10 -0
  162. data/vendor/jsclasses/winjis.sty +23 -19
  163. metadata +14 -6
  164. data/.rubocop_todo.yml +0 -7
  165. data/lib/review/book/compilable.rb +0 -174
@@ -32,7 +32,13 @@ module ReVIEW
32
32
  alias_method :content, :caption
33
33
 
34
34
  def path
35
- @path ||= @index.find_path(id)
35
+ if @path
36
+ return @path
37
+ end
38
+
39
+ @path = @index.find_path(@id)
40
+
41
+ @path
36
42
  end
37
43
  end
38
44
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2009-2019 Minero Aoki, Kenshi Muto
1
+ # Copyright (c) 2009-2020 Minero Aoki, Kenshi Muto, Masayoshi Takahashi
2
2
  # 2002-2008 Minero Aoki
3
3
  #
4
4
  # This program is free software.
@@ -6,13 +6,11 @@
6
6
  # the GNU LGPL, Lesser General Public License version 2.1.
7
7
  # For details of the GNU LGPL, see the file "COPYING".
8
8
  #
9
- require 'review/book/compilable'
9
+ require 'review/book/book_unit'
10
10
 
11
11
  module ReVIEW
12
12
  module Book
13
- class Part
14
- include Compilable
15
-
13
+ class Part < BookUnit
16
14
  def self.mkpart_from_namelistfile(book, path)
17
15
  chaps = []
18
16
  File.read(path, mode: 'rt:BOM|utf-8').split.each_with_index do |name, number|
@@ -30,7 +28,7 @@ module ReVIEW
30
28
  end
31
29
 
32
30
  def self.mkpart(chaps)
33
- chaps.empty? ? nil : Part.new(self, nil, chaps)
31
+ chaps.empty? ? nil : Part.new(chaps[0].book, nil, chaps)
34
32
  end
35
33
 
36
34
  # if Part is dummy, `number` is nil.
@@ -38,15 +36,16 @@ module ReVIEW
38
36
  def initialize(book, number, chapters, name = '', io = nil)
39
37
  @book = book
40
38
  @number = number
41
- @chapters = chapters
42
39
  @name = name
40
+ @chapters = chapters
43
41
  @path = name
44
- @content = ''
45
42
  if io
46
43
  @content = io.read
47
44
  elsif @path.present? && File.exist?(File.join(@book.config['contentdir'], @path))
48
45
  @content = File.read(File.join(@book.config['contentdir'], @path), mode: 'rt:BOM|utf-8')
49
- @name = File.basename(@name, '.re')
46
+ @name = File.basename(name, '.re')
47
+ else
48
+ @content = ''
50
49
  end
51
50
  if file?
52
51
  @title = nil
@@ -54,6 +53,19 @@ module ReVIEW
54
53
  @title = name
55
54
  end
56
55
  @volume = nil
56
+
57
+ super()
58
+ end
59
+
60
+ def generate_indexes
61
+ super
62
+
63
+ return unless content
64
+
65
+ @numberless_image_index = @indexes.numberless_image_index
66
+ @image_index = @indexes.image_index
67
+ @icon_index = @indexes.icon_index
68
+ @indepimage_index = @indexes.indepimage_index
57
69
  end
58
70
 
59
71
  attr_reader :number
@@ -22,7 +22,7 @@ module ReVIEW
22
22
  end
23
23
 
24
24
  def self.sum(vols)
25
- vols.inject(new) { |sum, i| sum + i }
25
+ vols.inject(new) { |sum, i| sum + i } # rubocop:disable Performance/Sum
26
26
  end
27
27
 
28
28
  def self.dummy
@@ -11,7 +11,6 @@ require 'review/textutils'
11
11
  require 'review/compiler'
12
12
  require 'review/sec_counter'
13
13
  require 'stringio'
14
- require 'cgi'
15
14
  require 'fileutils'
16
15
  require 'tempfile'
17
16
  require 'csv'
@@ -20,7 +19,7 @@ module ReVIEW
20
19
  class Builder
21
20
  include TextUtils
22
21
 
23
- CAPTION_TITLES = %w[note memo tip info warning important caution notice].freeze
22
+ CAPTION_TITLES = Compiler.minicolumn_names
24
23
 
25
24
  def pre_paragraph
26
25
  nil
@@ -30,21 +29,17 @@ module ReVIEW
30
29
  nil
31
30
  end
32
31
 
33
- attr_accessor :doc_status
32
+ attr_accessor :doc_status, :previous_list_type
34
33
 
35
- def initialize(strict = false, *args)
34
+ def initialize(strict = false, *_args)
36
35
  @strict = strict
37
36
  @output = nil
38
37
  @logger = ReVIEW.logger
39
38
  @doc_status = {}
40
39
  @dictionary = {}
41
- builder_init(*args)
40
+ @previous_list_type = nil
42
41
  end
43
42
 
44
- def builder_init(*args)
45
- end
46
- private :builder_init
47
-
48
43
  def bind(compiler, chapter, location)
49
44
  @compiler = compiler
50
45
  @chapter = chapter
@@ -53,6 +48,10 @@ module ReVIEW
53
48
  if @chapter.present?
54
49
  @book = @chapter.book
55
50
  end
51
+ @chapter.generate_indexes
52
+ if @book
53
+ @book.generate_indexes
54
+ end
56
55
  @tabwidth = nil
57
56
  @tsize = nil
58
57
  if @book && @book.config
@@ -84,6 +83,7 @@ module ReVIEW
84
83
 
85
84
  def builder_init_file
86
85
  @sec_counter = SecCounter.new(5, @chapter)
86
+ @doc_status = {}
87
87
  end
88
88
  private :builder_init_file
89
89
 
@@ -91,8 +91,19 @@ module ReVIEW
91
91
  false
92
92
  end
93
93
 
94
+ def solve_nest(s)
95
+ check_nest
96
+ s.gsub(/\x01→.+?←\x01/, '')
97
+ end
98
+
99
+ def check_nest
100
+ if @children && !@children.empty?
101
+ error "//beginchild of #{@children.reverse.join(',')} misses //endchild"
102
+ end
103
+ end
104
+
94
105
  def result
95
- @output.string
106
+ solve_nest(@output.string)
96
107
  end
97
108
 
98
109
  alias_method :raw_result, :result
@@ -211,7 +222,7 @@ module ReVIEW
211
222
  sepidx = nil
212
223
  rows = []
213
224
  lines.each_with_index do |line, idx|
214
- if /\A[\=\-]{12}/ =~ line || /\A[\=\{\-\}]{12}/ =~ line
225
+ if /\A[=\-]{12}/ =~ line || /\A[={\-}]{12}/ =~ line
215
226
  sepidx ||= idx
216
227
  next
217
228
  end
@@ -240,7 +251,7 @@ module ReVIEW
240
251
 
241
252
  def adjust_n_cols(rows)
242
253
  rows.each do |cols|
243
- while cols.last and cols.last.strip.empty?
254
+ while cols.last && cols.last.strip.empty?
244
255
  cols.pop
245
256
  end
246
257
  end
@@ -544,9 +555,36 @@ module ReVIEW
544
555
  CAPTION_TITLES.each do |name|
545
556
  class_eval %Q(
546
557
  def #{name}(lines, caption = nil)
558
+ check_nested_minicolumn
547
559
  captionblock("#{name}", lines, caption)
548
560
  end
549
- )
561
+
562
+ def #{name}_begin(caption = nil)
563
+ check_nested_minicolumn
564
+ @doc_status[:minicolumn] = '#{name}'
565
+ if caption
566
+ puts compile_inline(caption)
567
+ end
568
+ end
569
+
570
+ def #{name}_end
571
+ @doc_status[:minicolumn] = nil
572
+ end
573
+ ), __FILE__, __LINE__ - 17
574
+ end
575
+
576
+ def check_nested_minicolumn
577
+ if @doc_status[:minicolumn]
578
+ error "#{@location}: nested mini-column is not allowed"
579
+ end
580
+ end
581
+
582
+ def in_minicolumn?
583
+ @doc_status[:minicolumn]
584
+ end
585
+
586
+ def minicolumn_block_name?(name)
587
+ CAPTION_TITLES.include?(name)
550
588
  end
551
589
 
552
590
  def graph(lines, id, command, caption = '')
@@ -687,6 +725,23 @@ EOTGNUPLOT
687
725
  str
688
726
  end
689
727
 
728
+ def beginchild
729
+ @children ||= []
730
+ unless @previous_list_type
731
+ error "//beginchild is shown, but previous element isn't ul, ol, or dl"
732
+ end
733
+ puts "\x01→#{@previous_list_type}←\x01"
734
+ @children.push(@previous_list_type)
735
+ end
736
+
737
+ def endchild
738
+ if @children.nil? || @children.empty?
739
+ error "//endchild is shown, but any opened //beginchild doesn't exist"
740
+ else
741
+ puts "\x01→/#{@children.pop}←\x01"
742
+ end
743
+ end
744
+
690
745
  def caption_top?(type)
691
746
  unless %w[top bottom].include?(@book.config['caption_position'][type])
692
747
  warn("invalid caption_position/#{type} parameter. 'top' is assumed")
@@ -41,7 +41,7 @@ module ReVIEW
41
41
 
42
42
  def replace_part(old_name, new_name)
43
43
  @yaml['CHAPS'].map! do |e|
44
- if e.is_a?(Hash) and (e.keys.first == old_name)
44
+ if e.is_a?(Hash) && (e.keys.first == old_name)
45
45
  e = { new_name => e.values.first }
46
46
  end
47
47
  e
@@ -89,7 +89,7 @@ module ReVIEW
89
89
  filenames.concat(postdef)
90
90
  end
91
91
  filenames.each do |filename|
92
- refile = File.join(basedir, config['contentdir'], filename)
92
+ refile = File.expand_path(File.join(config['contentdir'], filename), basedir)
93
93
  unless File.exist?(refile)
94
94
  raise FileNotFound, "file not found in catalog.yml: #{refile}"
95
95
  end
@@ -14,8 +14,8 @@ require 'strscan'
14
14
 
15
15
  module ReVIEW
16
16
  class Compiler
17
- def initialize(strategy)
18
- @strategy = strategy
17
+ def initialize(builder)
18
+ @builder = builder
19
19
 
20
20
  ## commands which do not parse block lines in compiler
21
21
  @non_parsed_commands = %i[embed texequation graph]
@@ -24,10 +24,15 @@ module ReVIEW
24
24
  @command_name_stack = []
25
25
  end
26
26
 
27
- attr_reader :strategy
27
+ attr_reader :builder, :previous_list_type
28
+
29
+ def strategy
30
+ error 'Compiler#strategy is obsoleted. Use Compiler#builder.'
31
+ @builder
32
+ end
28
33
 
29
34
  def non_escaped_commands
30
- if @strategy.highlight?
35
+ if @builder.highlight?
31
36
  %i[list emlist listnum emlistnum cmd]
32
37
  else
33
38
  []
@@ -37,7 +42,7 @@ module ReVIEW
37
42
  def compile(chap)
38
43
  @chapter = chap
39
44
  do_compile
40
- @strategy.result
45
+ @builder.result
41
46
  end
42
47
 
43
48
  class SyntaxElement
@@ -68,12 +73,16 @@ module ReVIEW
68
73
  end
69
74
  end
70
75
 
76
+ def minicolumn?
77
+ @type == :minicolumn
78
+ end
79
+
71
80
  def block_required?
72
- @type == :block
81
+ @type == :block or @type == :minicolumn
73
82
  end
74
83
 
75
84
  def block_allowed?
76
- @type == :block or @type == :optional
85
+ @type == :block or @type == :optional or @type == :minicolumn
77
86
  end
78
87
  end
79
88
 
@@ -83,6 +92,10 @@ module ReVIEW
83
92
  defsyntax(name, (optional ? :optional : :block), argc, &block)
84
93
  end
85
94
 
95
+ def self.defminicolumn(name, argc, _optional = false, &block)
96
+ defsyntax(name, :minicolumn, argc, &block)
97
+ end
98
+
86
99
  def self.defsingle(name, argc, &block)
87
100
  defsyntax(name, :line, argc, &block)
88
101
  end
@@ -95,6 +108,16 @@ module ReVIEW
95
108
  INLINE[name] = InlineSyntaxElement.new(name)
96
109
  end
97
110
 
111
+ def self.minicolumn_names
112
+ buf = []
113
+ SYNTAX.each do |name, syntax|
114
+ if syntax.minicolumn?
115
+ buf << name.to_s
116
+ end
117
+ end
118
+ buf
119
+ end
120
+
98
121
  def syntax_defined?(name)
99
122
  SYNTAX.key?(name.to_sym)
100
123
  end
@@ -143,18 +166,19 @@ module ReVIEW
143
166
  defblock :bpo, 0
144
167
  defblock :flushright, 0
145
168
  defblock :centering, 0
146
- defblock :note, 0..1
147
- defblock :memo, 0..1
148
- defblock :info, 0..1
149
- defblock :important, 0..1
150
- defblock :caution, 0..1
151
- defblock :notice, 0..1
152
- defblock :warning, 0..1
153
- defblock :tip, 0..1
154
169
  defblock :box, 0..1
155
170
  defblock :comment, 0..1, true
156
171
  defblock :embed, 0..1
157
172
 
173
+ defminicolumn :note, 0..1
174
+ defminicolumn :memo, 0..1
175
+ defminicolumn :tip, 0..1
176
+ defminicolumn :info, 0..1
177
+ defminicolumn :warning, 0..1
178
+ defminicolumn :important, 0..1
179
+ defminicolumn :caution, 0..1
180
+ defminicolumn :notice, 0..1
181
+
158
182
  defsingle :footnote, 2
159
183
  defsingle :noindent, 0
160
184
  defsingle :blankline, 0
@@ -167,6 +191,8 @@ module ReVIEW
167
191
  defsingle :include, 1
168
192
  defsingle :olnum, 1
169
193
  defsingle :firstlinenum, 1
194
+ defsingle :beginchild, 0
195
+ defsingle :endchild, 0
170
196
 
171
197
  definline :chapref
172
198
  definline :chap
@@ -231,39 +257,62 @@ module ReVIEW
231
257
 
232
258
  def do_compile
233
259
  f = LineInput.new(StringIO.new(@chapter.content))
234
- @strategy.bind(self, @chapter, Location.new(@chapter.basename, f))
260
+ @builder.bind(self, @chapter, Location.new(@chapter.basename, f))
261
+
262
+ ## in minicolumn, such as note/info/alert...
263
+ @minicolumn_name = nil
235
264
 
236
265
  tagged_section_init
237
266
  while f.next?
238
267
  case f.peek
239
268
  when /\A\#@/
240
269
  f.gets # Nothing to do
241
- when /\A=+[\[\s\{]/
270
+ when /\A=+[\[\s{]/
242
271
  compile_headline(f.gets)
272
+ @builder.previous_list_type = nil
243
273
  when /\A\s+\*/
244
274
  compile_ulist(f)
275
+ @builder.previous_list_type = 'ul'
245
276
  when /\A\s+\d+\./
246
277
  compile_olist(f)
278
+ @builder.previous_list_type = 'ol'
247
279
  when /\A\s+:\s/
248
280
  compile_dlist(f)
281
+ @builder.previous_list_type = 'dl'
249
282
  when /\A\s*:\s/
250
283
  warn 'Definition list starting with `:` is deprecated. It should start with ` : `.'
251
284
  compile_dlist(f)
285
+ @builder.previous_list_type = 'dl'
252
286
  when %r{\A//\}}
253
- f.gets
254
- error 'block end seen but not opened'
287
+ if in_minicolumn?
288
+ _line = f.gets
289
+ compile_minicolumn_end
290
+ else
291
+ f.gets
292
+ error 'block end seen but not opened'
293
+ end
255
294
  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)
295
+ line = f.peek
296
+ matched = line =~ %r|\A//([a-z]+)(:?\[.*\])?{\s*$|
297
+ if matched && minicolumn_block_name?($1)
298
+ line = f.gets
299
+ name = $1
300
+ args = parse_args(line.sub(%r{\A//[a-z]+}, '').rstrip.chomp('{'), name)
301
+ compile_minicolumn_begin(name, *args)
302
+ else
303
+ # @command_name_stack.push(name) ## <- move into read_command() to use name
304
+ name, args, lines = read_command(f)
305
+ syntax = syntax_descriptor(name)
306
+ unless syntax
307
+ error "unknown command: //#{name}"
308
+ compile_unknown_command(args, lines)
309
+ @command_name_stack.pop
310
+ next
311
+ end
312
+ compile_command(syntax, args, lines)
262
313
  @command_name_stack.pop
263
- next
264
314
  end
265
- compile_command(syntax, args, lines)
266
- @command_name_stack.pop
315
+ @builder.previous_list_type = nil
267
316
  when %r{\A//}
268
317
  line = f.gets
269
318
  warn "`//' seen but is not valid command: #{line.strip.inspect}"
@@ -271,17 +320,46 @@ module ReVIEW
271
320
  warn 'skipping block...'
272
321
  read_block(f, false)
273
322
  end
323
+ @builder.previous_list_type = nil
274
324
  else
275
325
  if f.peek.strip.empty?
276
326
  f.gets
277
327
  next
278
328
  end
279
329
  compile_paragraph(f)
330
+ @builder.previous_list_type = nil
280
331
  end
281
332
  end
282
333
  close_all_tagged_section
283
334
  end
284
335
 
336
+ def compile_minicolumn_begin(name, caption = nil)
337
+ mid = "#{name}_begin"
338
+ unless @builder.respond_to?(mid)
339
+ error "strategy does not support minicolumn: #{name}"
340
+ end
341
+
342
+ if @minicolumn_name
343
+ error "minicolumn cannot be nested: #{name}"
344
+ return
345
+ end
346
+ @minicolumn_name = name
347
+
348
+ @builder.__send__(mid, caption)
349
+ end
350
+
351
+ def compile_minicolumn_end
352
+ unless @minicolumn_name
353
+ error "minicolumn is not used: #{name}"
354
+ return
355
+ end
356
+ name = @minicolumn_name
357
+
358
+ mid = "#{name}_end"
359
+ @builder.__send__(mid)
360
+ @minicolumn_name = nil
361
+ end
362
+
285
363
  def compile_headline(line)
286
364
  @headline_indexs ||= [@chapter.number.to_i - 1]
287
365
  m = /\A(=+)(?:\[(.+?)\])?(?:\{(.+?)\})?(.*)/.match(line)
@@ -317,18 +395,18 @@ module ReVIEW
317
395
  end
318
396
  @headline_indexs[index] += 1
319
397
  close_current_tagged_section(level)
320
- @strategy.headline(level, label, caption)
398
+ @builder.headline(level, label, caption)
321
399
  end
322
400
  end
323
401
 
324
402
  def close_current_tagged_section(level)
325
- while @tagged_section.last and @tagged_section.last[1] >= level
403
+ while @tagged_section.last && (@tagged_section.last[1] >= level)
326
404
  close_tagged_section(* @tagged_section.pop)
327
405
  end
328
406
  end
329
407
 
330
408
  def headline(level, label, caption)
331
- @strategy.headline(level, label, caption)
409
+ @builder.headline(level, label, caption)
332
410
  end
333
411
 
334
412
  def tagged_section_init
@@ -337,21 +415,21 @@ module ReVIEW
337
415
 
338
416
  def open_tagged_section(tag, level, label, caption)
339
417
  mid = "#{tag}_begin"
340
- unless @strategy.respond_to?(mid)
341
- error "strategy does not support tagged section: #{tag}"
418
+ unless @builder.respond_to?(mid)
419
+ error "builder does not support tagged section: #{tag}"
342
420
  headline(level, label, caption)
343
421
  return
344
422
  end
345
423
  @tagged_section.push([tag, level])
346
- @strategy.__send__(mid, level, label, caption)
424
+ @builder.__send__(mid, level, label, caption)
347
425
  end
348
426
 
349
427
  def close_tagged_section(tag, level)
350
428
  mid = "#{tag}_end"
351
- if @strategy.respond_to?(mid)
352
- @strategy.__send__(mid, level)
429
+ if @builder.respond_to?(mid)
430
+ @builder.__send__(mid, level)
353
431
  else
354
- error "strategy does not support block op: #{mid}"
432
+ error "builder does not support block op: #{mid}"
355
433
  end
356
434
  end
357
435
 
@@ -374,38 +452,38 @@ module ReVIEW
374
452
  line =~ /\A\s+(\*+)/
375
453
  current_level = $1.size
376
454
  if level == current_level
377
- @strategy.ul_item_end
455
+ @builder.ul_item_end
378
456
  # body
379
- @strategy.ul_item_begin(buf)
457
+ @builder.ul_item_begin(buf)
380
458
  elsif level < current_level # down
381
459
  level_diff = current_level - level
382
460
  if level_diff != 1
383
461
  error 'too many *.'
384
462
  end
385
463
  level = current_level
386
- @strategy.ul_begin { level }
387
- @strategy.ul_item_begin(buf)
464
+ @builder.ul_begin { level }
465
+ @builder.ul_item_begin(buf)
388
466
  elsif level > current_level # up
389
467
  level_diff = level - current_level
390
468
  level = current_level
391
469
  (1..level_diff).to_a.reverse_each do |i|
392
- @strategy.ul_item_end
393
- @strategy.ul_end { level + i }
470
+ @builder.ul_item_end
471
+ @builder.ul_end { level + i }
394
472
  end
395
- @strategy.ul_item_end
473
+ @builder.ul_item_end
396
474
  # body
397
- @strategy.ul_item_begin(buf)
475
+ @builder.ul_item_begin(buf)
398
476
  end
399
477
  end
400
478
 
401
479
  (1..level).to_a.reverse_each do |i|
402
- @strategy.ul_item_end
403
- @strategy.ul_end { i }
480
+ @builder.ul_item_end
481
+ @builder.ul_end { i }
404
482
  end
405
483
  end
406
484
 
407
485
  def compile_olist(f)
408
- @strategy.ol_begin
486
+ @builder.ol_begin
409
487
  f.while_match(/\A\s+\d+\.|\A\#@/) do |line|
410
488
  next if line =~ /\A\#@/
411
489
 
@@ -414,24 +492,24 @@ module ReVIEW
414
492
  f.while_match(/\A\s+(?!\d+\.)\S/) do |cont|
415
493
  buf.push(text(cont.strip))
416
494
  end
417
- @strategy.ol_item(buf, num)
495
+ @builder.ol_item(buf, num)
418
496
  end
419
- @strategy.ol_end
497
+ @builder.ol_end
420
498
  end
421
499
 
422
500
  def compile_dlist(f)
423
- @strategy.dl_begin
501
+ @builder.dl_begin
424
502
  while /\A\s*:/ =~ f.peek
425
503
  # defer compile_inline to handle footnotes
426
- @strategy.doc_status[:dt] = true
427
- @strategy.dt(text(f.gets.sub(/\A\s*:/, '').strip))
428
- @strategy.doc_status[:dt] = nil
504
+ @builder.doc_status[:dt] = true
505
+ @builder.dt(text(f.gets.sub(/\A\s*:/, '').strip))
506
+ @builder.doc_status[:dt] = nil
429
507
  desc = f.break(/\A(\S|\s*:|\s+\d+\.\s|\s+\*\s)/).map { |line| text(line.strip) }
430
- @strategy.dd(desc)
508
+ @builder.dd(desc)
431
509
  f.skip_blank_lines
432
510
  f.skip_comment_lines
433
511
  end
434
- @strategy.dl_end
512
+ @builder.dl_end
435
513
  end
436
514
 
437
515
  def compile_paragraph(f)
@@ -440,7 +518,7 @@ module ReVIEW
440
518
  break if line.strip.empty?
441
519
  buf.push(text(line.sub(/^(\t+)\s*/) { |m| '<!ESCAPETAB!>' * m.size }.strip.gsub('<!ESCAPETAB!>', "\t")))
442
520
  end
443
- @strategy.paragraph(buf)
521
+ @builder.paragraph(buf)
444
522
  end
445
523
 
446
524
  def read_command(f)
@@ -449,9 +527,9 @@ module ReVIEW
449
527
  ignore_inline = @non_parsed_commands.include?(name)
450
528
  @command_name_stack.push(name)
451
529
  args = parse_args(line.sub(%r{\A//[a-z]+}, '').rstrip.chomp('{'), name)
452
- @strategy.doc_status[name] = true
530
+ @builder.doc_status[name] = true
453
531
  lines = block_open?(line) ? read_block(f, ignore_inline) : nil
454
- @strategy.doc_status[name] = nil
532
+ @builder.doc_status[name] = nil
455
533
  [name, args, lines]
456
534
  end
457
535
 
@@ -496,8 +574,8 @@ module ReVIEW
496
574
  end
497
575
 
498
576
  def compile_command(syntax, args, lines)
499
- unless @strategy.respond_to?(syntax.name)
500
- error "strategy does not support command: //#{syntax.name}"
577
+ unless @builder.respond_to?(syntax.name)
578
+ error "builder does not support command: //#{syntax.name}"
501
579
  compile_unknown_command(args, lines)
502
580
  return
503
581
  end
@@ -518,11 +596,11 @@ module ReVIEW
518
596
  end
519
597
 
520
598
  def compile_unknown_command(args, lines)
521
- @strategy.unknown_command(args, lines)
599
+ @builder.unknown_command(args, lines)
522
600
  end
523
601
 
524
602
  def compile_block(syntax, args, lines)
525
- @strategy.__send__(syntax.name, (lines || default_block(syntax)), *args)
603
+ @builder.__send__(syntax.name, (lines || default_block(syntax)), *args)
526
604
  end
527
605
 
528
606
  def default_block(syntax)
@@ -533,7 +611,7 @@ module ReVIEW
533
611
  end
534
612
 
535
613
  def compile_single(syntax, args)
536
- @strategy.__send__(syntax.name, *args)
614
+ @builder.__send__(syntax.name, *args)
537
615
  end
538
616
 
539
617
  def replace_fence(str)
@@ -559,7 +637,7 @@ module ReVIEW
559
637
 
560
638
  def text(str, block_mode = false)
561
639
  return '' if str.empty?
562
- words = replace_fence(str).split(/(@<\w+>\{(?:[^\}\\]|\\.)*?\})/, -1)
640
+ words = replace_fence(str).split(/(@<\w+>\{(?:[^}\\]|\\.)*?\})/, -1)
563
641
  words.each do |w|
564
642
  if w.scan(/@<\w+>/).size > 1 && !/\A@<raw>/.match(w)
565
643
  error "`@<xxx>' seen but is not valid inline op: #{w}"
@@ -570,7 +648,7 @@ module ReVIEW
570
648
  if in_non_escaped_command? && block_mode
571
649
  result << revert_replace_fence(words.shift)
572
650
  else
573
- result << @strategy.nofunc_text(revert_replace_fence(words.shift))
651
+ result << @builder.nofunc_text(revert_replace_fence(words.shift))
574
652
  end
575
653
  break if words.empty?
576
654
  result << compile_inline(revert_replace_fence(words.shift.gsub(/\\\}/, '}').gsub(/\\\\/, '\\')))
@@ -579,28 +657,36 @@ module ReVIEW
579
657
  rescue => e
580
658
  error e.message
581
659
  end
582
- public :text # called from strategy
660
+ public :text # called from builder
583
661
 
584
662
  def compile_inline(str)
585
663
  op, arg = /\A@<(\w+)>\{(.*?)\}\z/.match(str).captures
586
664
  unless inline_defined?(op)
587
665
  raise CompileError, "no such inline op: #{op}"
588
666
  end
589
- unless @strategy.respond_to?("inline_#{op}")
590
- raise "strategy does not support inline op: @<#{op}>"
667
+ unless @builder.respond_to?("inline_#{op}")
668
+ raise "builder does not support inline op: @<#{op}>"
591
669
  end
592
- @strategy.__send__("inline_#{op}", arg)
670
+ @builder.__send__("inline_#{op}", arg)
593
671
  rescue => e
594
672
  error e.message
595
- @strategy.nofunc_text(str)
673
+ @builder.nofunc_text(str)
674
+ end
675
+
676
+ def in_minicolumn?
677
+ @builder.in_minicolumn?
678
+ end
679
+
680
+ def minicolumn_block_name?(name)
681
+ @builder.minicolumn_block_name?(name)
596
682
  end
597
683
 
598
684
  def warn(msg)
599
- @strategy.warn msg
685
+ @builder.warn msg
600
686
  end
601
687
 
602
688
  def error(msg)
603
- @strategy.error msg
689
+ @builder.error msg
604
690
  end
605
691
  end
606
692
  end # module ReVIEW