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