asciidoctor 1.5.5 → 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +216 -1
- data/CONTRIBUTING.adoc +2 -2
- data/Gemfile +20 -1
- data/LICENSE.adoc +1 -1
- data/README-fr.adoc +4 -3
- data/README-jp.adoc +11 -10
- data/README-zh_CN.adoc +4 -3
- data/README.adoc +17 -202
- data/Rakefile +41 -25
- data/asciidoctor.gemspec +9 -10
- data/data/locale/attributes.adoc +216 -34
- data/data/stylesheets/asciidoctor-default.css +23 -16
- data/features/step_definitions.rb +15 -19
- data/features/xref.feature +584 -20
- data/lib/asciidoctor.rb +292 -278
- data/lib/asciidoctor/abstract_block.rb +155 -94
- data/lib/asciidoctor/abstract_node.rb +108 -94
- data/lib/asciidoctor/attribute_list.rb +30 -22
- data/lib/asciidoctor/block.rb +7 -7
- data/lib/asciidoctor/cli/invoker.rb +47 -34
- data/lib/asciidoctor/cli/options.rb +22 -11
- data/lib/asciidoctor/converter.rb +3 -3
- data/lib/asciidoctor/converter/base.rb +2 -2
- data/lib/asciidoctor/converter/composite.rb +1 -1
- data/lib/asciidoctor/converter/docbook45.rb +2 -2
- data/lib/asciidoctor/converter/docbook5.rb +132 -87
- data/lib/asciidoctor/converter/factory.rb +0 -1
- data/lib/asciidoctor/converter/html5.rb +116 -98
- data/lib/asciidoctor/converter/manpage.rb +51 -52
- data/lib/asciidoctor/converter/template.rb +47 -36
- data/lib/asciidoctor/core_ext.rb +8 -2
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +4 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +5 -0
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +1 -1
- data/lib/asciidoctor/core_ext/1.8.7/string/{limit.rb → limit_bytesize.rb} +7 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +6 -0
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +1 -1
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +5 -5
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +3 -0
- data/lib/asciidoctor/core_ext/string/{limit.rb → limit_bytesize.rb} +2 -2
- data/lib/asciidoctor/document.rb +216 -213
- data/lib/asciidoctor/extensions.rb +318 -185
- data/lib/asciidoctor/helpers.rb +35 -35
- data/lib/asciidoctor/inline.rb +32 -1
- data/lib/asciidoctor/list.rb +22 -6
- data/lib/asciidoctor/parser.rb +1008 -1038
- data/lib/asciidoctor/path_resolver.rb +46 -50
- data/lib/asciidoctor/reader.rb +275 -251
- data/lib/asciidoctor/section.rb +86 -58
- data/lib/asciidoctor/stylesheets.rb +6 -6
- data/lib/asciidoctor/substitutors.rb +567 -649
- data/lib/asciidoctor/table.rb +163 -108
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +18 -16
- data/man/asciidoctor.adoc +15 -13
- data/test/attributes_test.rb +138 -22
- data/test/blocks_test.rb +377 -97
- data/test/converter_test.rb +13 -0
- data/test/document_test.rb +244 -34
- data/test/extensions_test.rb +409 -42
- data/test/fixtures/asciidoc_index.txt +521 -0
- data/test/fixtures/basic-docinfo-footer.html +6 -0
- data/test/fixtures/basic-docinfo-footer.xml +8 -0
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +5 -0
- data/test/fixtures/chapter-a.adoc +3 -0
- data/test/fixtures/child-include.adoc +5 -0
- data/test/fixtures/circle.svg +9 -0
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +6 -0
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +6 -0
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +1 -0
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +3 -0
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +5 -0
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +6 -0
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +3 -0
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +5 -0
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +1 -0
- data/test/fixtures/custom-docinfodir/docinfo.html +1 -0
- data/test/fixtures/docinfo-footer.html +1 -0
- data/test/fixtures/docinfo-footer.xml +9 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +3 -0
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +13 -0
- data/test/fixtures/grandchild-include.adoc +3 -0
- data/test/fixtures/hello-asciidoctor.pdf +69 -0
- data/test/fixtures/include-file.asciidoc +24 -0
- data/test/fixtures/include-file.ml +3 -0
- data/test/fixtures/include-file.xml +5 -0
- data/test/fixtures/master.adoc +5 -0
- data/test/fixtures/mismatched-end-tag.adoc +7 -0
- data/test/fixtures/parent-include-restricted.adoc +5 -0
- data/test/fixtures/parent-include.adoc +5 -0
- data/test/fixtures/sample.asciidoc +26 -0
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/fixtures/tagged-class-enclosed.rb +26 -0
- data/test/fixtures/tagged-class.rb +23 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/invoker_test.rb +82 -4
- data/test/links_test.rb +312 -37
- data/test/lists_test.rb +204 -25
- data/test/manpage_test.rb +191 -4
- data/test/options_test.rb +18 -1
- data/test/paragraphs_test.rb +32 -7
- data/test/parser_test.rb +150 -30
- data/test/paths_test.rb +47 -13
- data/test/preamble_test.rb +1 -1
- data/test/reader_test.rb +366 -126
- data/test/sections_test.rb +203 -56
- data/test/substitutions_test.rb +339 -131
- data/test/tables_test.rb +315 -15
- data/test/test_helper.rb +400 -0
- data/test/text_test.rb +5 -5
- metadata +110 -22
@@ -128,28 +128,27 @@ class PathResolver
|
|
128
128
|
else
|
129
129
|
@working_dir = ::File.expand_path ::Dir.pwd
|
130
130
|
end
|
131
|
-
@_partition_path_sys = {}
|
132
|
-
@_partition_path_web = {}
|
131
|
+
@_partition_path_sys, @_partition_path_web = {}, {}
|
133
132
|
end
|
134
133
|
|
135
|
-
# Public: Check if the specified path is an absolute root path
|
136
|
-
# This operation
|
134
|
+
# Public: Check if the specified path is an absolute root path.
|
135
|
+
# This operation considers posix paths, windows paths, and file URLs.
|
136
|
+
#
|
137
|
+
# Unix absolute paths and UNC paths start with slash. Windows roots can start
|
138
|
+
# with a drive letter. Absolute paths in the browser start with file://.
|
137
139
|
#
|
138
140
|
# path - the String path to check
|
139
141
|
#
|
140
142
|
# returns a Boolean indicating whether the path is an absolute root path
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
true
|
151
|
-
else
|
152
|
-
false
|
143
|
+
if RUBY_ENGINE == 'opal'
|
144
|
+
def is_root? path
|
145
|
+
(path.start_with? SLASH) ||
|
146
|
+
(::JAVASCRIPT_IO_MODULE == 'xmlhttprequest' && (path.start_with? 'file://')) ||
|
147
|
+
(@file_separator == BACKSLASH && (WindowsRootRx.match? path))
|
148
|
+
end
|
149
|
+
else
|
150
|
+
def is_root? path
|
151
|
+
(path.start_with? SLASH) || (@file_separator == BACKSLASH && (WindowsRootRx.match? path))
|
153
152
|
end
|
154
153
|
end
|
155
154
|
|
@@ -176,7 +175,7 @@ class PathResolver
|
|
176
175
|
# path - the String path to normalize
|
177
176
|
#
|
178
177
|
# returns a String path with any backslashes replaced with forward slashes
|
179
|
-
def
|
178
|
+
def posixify path
|
180
179
|
if path.nil_or_empty?
|
181
180
|
''
|
182
181
|
elsif path.include? BACKSLASH
|
@@ -185,6 +184,7 @@ class PathResolver
|
|
185
184
|
path
|
186
185
|
end
|
187
186
|
end
|
187
|
+
alias posixfy posixify
|
188
188
|
|
189
189
|
# Public: Expand the path by resolving any parent references (..)
|
190
190
|
# and cleaning self references (.).
|
@@ -206,23 +206,23 @@ class PathResolver
|
|
206
206
|
# or segments that are self references (.). The path is converted to a posix
|
207
207
|
# path before being partitioned.
|
208
208
|
#
|
209
|
-
# path
|
210
|
-
#
|
211
|
-
#
|
209
|
+
# path - the String path to partition
|
210
|
+
# web - a Boolean indicating whether the path should be handled
|
211
|
+
# as a web path (optional, default: false)
|
212
212
|
#
|
213
213
|
# Returns a 3-item Array containing the Array of String path segments, the
|
214
214
|
# path root (e.g., '/', './', 'c:/') if the path is absolute and the posix
|
215
215
|
# version of the path.
|
216
216
|
#--
|
217
217
|
# QUESTION is it worth it to normalize slashes? it doubles the time elapsed
|
218
|
-
def partition_path path,
|
219
|
-
if (result =
|
218
|
+
def partition_path path, web = nil
|
219
|
+
if (result = (cache = web ? @_partition_path_web : @_partition_path_sys)[path])
|
220
220
|
return result
|
221
221
|
end
|
222
222
|
|
223
|
-
posix_path =
|
223
|
+
posix_path = posixify path
|
224
224
|
|
225
|
-
root = if
|
225
|
+
root = if web
|
226
226
|
# ex. /sample/path
|
227
227
|
if is_web_root? posix_path
|
228
228
|
SLASH
|
@@ -241,9 +241,9 @@ class PathResolver
|
|
241
241
|
# ex. /sample/path
|
242
242
|
elsif posix_path.start_with? SLASH
|
243
243
|
SLASH
|
244
|
-
# ex.
|
244
|
+
# ex. C:/sample/path (or file:///sample/path in browser environment)
|
245
245
|
else
|
246
|
-
posix_path
|
246
|
+
posix_path.slice 0, (posix_path.index SLASH) + 1
|
247
247
|
end
|
248
248
|
# ex. ./sample/path
|
249
249
|
elsif posix_path.start_with? DOT_SLASH
|
@@ -260,7 +260,7 @@ class PathResolver
|
|
260
260
|
path_segments = path_segments[2..-1]
|
261
261
|
# shift twice for a file:/// path and adjust root
|
262
262
|
# NOTE technically file:/// paths work without this adjustment
|
263
|
-
#elsif ::RUBY_ENGINE_OPAL && ::
|
263
|
+
#elsif ::RUBY_ENGINE_OPAL && ::JAVASCRIPT_IO_MODULE == 'xmlhttprequest' && root == 'file:/'
|
264
264
|
# root = 'file://'
|
265
265
|
# path_segments = path_segments[2..-1]
|
266
266
|
# shift once for any other root
|
@@ -269,9 +269,9 @@ class PathResolver
|
|
269
269
|
end
|
270
270
|
# strip out all dot entries
|
271
271
|
path_segments.delete DOT
|
272
|
-
# QUESTION should we
|
273
|
-
#posix_path = posix_path.
|
274
|
-
|
272
|
+
# QUESTION should we chop trailing /? (we pay a small fraction)
|
273
|
+
#posix_path = posix_path.chop if posix_path.end_with? SLASH
|
274
|
+
cache[path] = [path_segments, root, posix_path]
|
275
275
|
end
|
276
276
|
|
277
277
|
# Public: Join the segments using the posix file separator (since Ruby knows
|
@@ -285,11 +285,7 @@ class PathResolver
|
|
285
285
|
# returns a String path formed by joining the segments using the posix file
|
286
286
|
# separator and prepending the root, if specified
|
287
287
|
def join_path segments, root = nil
|
288
|
-
|
289
|
-
%(#{root}#{segments * SLASH})
|
290
|
-
else
|
291
|
-
segments * SLASH
|
292
|
-
end
|
288
|
+
root ? %(#{root}#{segments * SLASH}) : segments * SLASH
|
293
289
|
end
|
294
290
|
|
295
291
|
# Public: Resolve a system path from the target and start paths. If a jail
|
@@ -300,8 +296,8 @@ class PathResolver
|
|
300
296
|
# specified in the constructor.
|
301
297
|
#
|
302
298
|
# target - the String target path
|
303
|
-
# start - the String start (i.e., parent) path
|
304
|
-
# jail - the String jail path to confine the resolved path
|
299
|
+
# start - the String start (i.e., parent) path (default: nil)
|
300
|
+
# jail - the String jail path to confine the resolved path (default: nil)
|
305
301
|
# opts - an optional Hash of options to control processing (default: {}):
|
306
302
|
# * :recover is used to control whether the processor should auto-recover
|
307
303
|
# when an illegal path is encountered
|
@@ -310,12 +306,12 @@ class PathResolver
|
|
310
306
|
# returns a String path that joins the target path with the start path with
|
311
307
|
# any parent references resolved and self references removed and enforces
|
312
308
|
# that the resolved path be contained within the jail, if provided
|
313
|
-
def system_path target, start, jail = nil, opts = {}
|
309
|
+
def system_path target, start = nil, jail = nil, opts = {}
|
314
310
|
if jail
|
315
311
|
unless is_root? jail
|
316
312
|
raise ::SecurityError, %(Jail is not an absolute path: #{jail})
|
317
313
|
end
|
318
|
-
jail =
|
314
|
+
jail = posixify jail
|
319
315
|
end
|
320
316
|
|
321
317
|
if target.nil_or_empty?
|
@@ -348,7 +344,7 @@ class PathResolver
|
|
348
344
|
if start.nil_or_empty?
|
349
345
|
start = jail ? jail : @working_dir
|
350
346
|
elsif is_root? start
|
351
|
-
start =
|
347
|
+
start = posixify start
|
352
348
|
else
|
353
349
|
start = system_path start, jail, jail, opts
|
354
350
|
end
|
@@ -379,7 +375,7 @@ class PathResolver
|
|
379
375
|
target_segments.each do |segment|
|
380
376
|
if segment == DOT_DOT
|
381
377
|
if jail
|
382
|
-
if resolved_segments.
|
378
|
+
if resolved_segments.size > jail_segments.size
|
383
379
|
resolved_segments.pop
|
384
380
|
elsif !(recover ||= (opts.fetch :recover, true))
|
385
381
|
raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} refers to location outside jail: #{jail} (disallowed in safe mode))
|
@@ -391,7 +387,7 @@ class PathResolver
|
|
391
387
|
resolved_segments.pop
|
392
388
|
end
|
393
389
|
else
|
394
|
-
resolved_segments
|
390
|
+
resolved_segments << segment
|
395
391
|
end
|
396
392
|
end
|
397
393
|
|
@@ -412,12 +408,12 @@ class PathResolver
|
|
412
408
|
# start path with any parent references resolved and self
|
413
409
|
# references removed
|
414
410
|
def web_path target, start = nil
|
415
|
-
target =
|
416
|
-
start =
|
411
|
+
target = posixify target
|
412
|
+
start = posixify start
|
417
413
|
uri_prefix = nil
|
418
414
|
|
419
415
|
unless start.nil_or_empty? || (is_web_root? target)
|
420
|
-
target = %(#{start
|
416
|
+
target = (start.end_with? SLASH) ? %(#{start}#{target}) : %(#{start}#{SLASH}#{target})
|
421
417
|
if (uri_prefix = Helpers.uri_prefix target)
|
422
418
|
target = target[uri_prefix.length..-1]
|
423
419
|
end
|
@@ -453,11 +449,11 @@ class PathResolver
|
|
453
449
|
end
|
454
450
|
end
|
455
451
|
|
456
|
-
if
|
457
|
-
|
458
|
-
else
|
459
|
-
join_path resolved_segments, target_root
|
452
|
+
if (resolved_path = join_path resolved_segments, target_root).include? ' '
|
453
|
+
resolved_path = resolved_path.gsub ' ', '%20'
|
460
454
|
end
|
455
|
+
|
456
|
+
uri_prefix ? %(#{uri_prefix}#{resolved_path}) : resolved_path
|
461
457
|
end
|
462
458
|
|
463
459
|
# Public: Calculate the relative path to this absolute filename from the specified base directory
|
@@ -470,7 +466,7 @@ class PathResolver
|
|
470
466
|
# Return the relative path String of the filename calculated from the base directory
|
471
467
|
def relative_path filename, base_directory
|
472
468
|
if (is_root? filename) && (is_root? base_directory)
|
473
|
-
offset = base_directory.
|
469
|
+
offset = (base_directory.end_with? @file_separator) ? base_directory.length : base_directory.length + 1
|
474
470
|
filename[offset..-1]
|
475
471
|
else
|
476
472
|
filename
|
data/lib/asciidoctor/reader.rb
CHANGED
@@ -19,7 +19,7 @@ class Reader
|
|
19
19
|
%(#{path}: line #{lineno})
|
20
20
|
end
|
21
21
|
|
22
|
-
alias
|
22
|
+
alias to_s line_info
|
23
23
|
end
|
24
24
|
|
25
25
|
attr_reader :file
|
@@ -36,7 +36,7 @@ class Reader
|
|
36
36
|
attr_accessor :process_lines
|
37
37
|
|
38
38
|
# Public: Initialize the Reader object
|
39
|
-
def initialize data = nil, cursor = nil, opts = {
|
39
|
+
def initialize data = nil, cursor = nil, opts = {}
|
40
40
|
if !cursor
|
41
41
|
@file = @dir = nil
|
42
42
|
@path = '<stdin>'
|
@@ -88,7 +88,7 @@ class Reader
|
|
88
88
|
if opts[:normalize]
|
89
89
|
Helpers.normalize_lines_from_string data
|
90
90
|
else
|
91
|
-
data.split
|
91
|
+
data.split LF, -1
|
92
92
|
end
|
93
93
|
else
|
94
94
|
if opts[:normalize]
|
@@ -133,16 +133,19 @@ class Reader
|
|
133
133
|
peek_line.nil_or_empty?
|
134
134
|
end
|
135
135
|
|
136
|
-
# Public: Peek at the next line of source data. Processes the line
|
136
|
+
# Public: Peek at the next line of source data. Processes the line if not
|
137
137
|
# already marked as processed, but does not consume it.
|
138
138
|
#
|
139
139
|
# This method will probe the reader for more lines. If there is a next line
|
140
140
|
# that has not previously been visited, the line is passed to the
|
141
141
|
# Reader#process_line method to be initialized. This call gives
|
142
|
-
# sub-
|
142
|
+
# sub-classes the opportunity to do preprocessing. If the return value of
|
143
143
|
# the Reader#process_line is nil, the data is assumed to be changed and
|
144
144
|
# Reader#peek_line is invoked again to perform further processing.
|
145
145
|
#
|
146
|
+
# If has_more_lines? is called immediately before peek_line, the direct flag
|
147
|
+
# is implicitly true (since the line is flagged as visited).
|
148
|
+
#
|
146
149
|
# direct - A Boolean flag to bypasses the check for more lines and immediately
|
147
150
|
# returns the first element of the internal @lines Array. (default: false)
|
148
151
|
#
|
@@ -167,7 +170,7 @@ class Reader
|
|
167
170
|
end
|
168
171
|
end
|
169
172
|
|
170
|
-
# Public: Peek at the next multiple lines of source data. Processes the lines
|
173
|
+
# Public: Peek at the next multiple lines of source data. Processes the lines if not
|
171
174
|
# already marked as processed, but does not consume them.
|
172
175
|
#
|
173
176
|
# This method delegates to Reader#read_line to process and collect the line, then
|
@@ -175,7 +178,7 @@ class Reader
|
|
175
178
|
# be processed and marked as such so that subsequent reads will not need to process
|
176
179
|
# the lines again.
|
177
180
|
#
|
178
|
-
# num - The Integer number of lines to peek.
|
181
|
+
# num - The positive Integer number of lines to peek (must be greater than 0).
|
179
182
|
# direct - A Boolean indicating whether processing should be disabled when reading lines
|
180
183
|
#
|
181
184
|
# Returns A String Array of the next multiple lines of source data, or an empty Array
|
@@ -187,12 +190,13 @@ class Reader
|
|
187
190
|
if (line = read_line direct)
|
188
191
|
result << line
|
189
192
|
else
|
193
|
+
@lineno -= 1 if direct
|
190
194
|
break
|
191
195
|
end
|
192
196
|
end
|
193
197
|
|
194
198
|
unless result.empty?
|
195
|
-
result
|
199
|
+
unshift_all result
|
196
200
|
@look_ahead = old_look_ahead if direct
|
197
201
|
end
|
198
202
|
|
@@ -229,7 +233,7 @@ class Reader
|
|
229
233
|
end
|
230
234
|
lines
|
231
235
|
end
|
232
|
-
alias
|
236
|
+
alias readlines read_lines
|
233
237
|
|
234
238
|
# Public: Get the remaining lines of source data joined as a String.
|
235
239
|
#
|
@@ -237,7 +241,7 @@ class Reader
|
|
237
241
|
#
|
238
242
|
# Returns the lines read joined as a String
|
239
243
|
def read
|
240
|
-
read_lines *
|
244
|
+
read_lines * LF
|
241
245
|
end
|
242
246
|
|
243
247
|
# Public: Advance to the next line by discarding the line at the front of the stack
|
@@ -252,8 +256,10 @@ class Reader
|
|
252
256
|
|
253
257
|
# Public: Push the String line onto the beginning of the Array of source data.
|
254
258
|
#
|
255
|
-
#
|
256
|
-
#
|
259
|
+
# A line pushed on the reader using this method is not processed again. The
|
260
|
+
# method assumes the line was previously retrieved from the reader or does
|
261
|
+
# not otherwise contain preprocessor directives. Therefore, it is marked as
|
262
|
+
# processed immediately.
|
257
263
|
#
|
258
264
|
# line_to_restore - the line to restore onto the stack
|
259
265
|
#
|
@@ -262,20 +268,21 @@ class Reader
|
|
262
268
|
unshift line_to_restore
|
263
269
|
nil
|
264
270
|
end
|
265
|
-
alias
|
271
|
+
alias restore_line unshift_line
|
266
272
|
|
267
273
|
# Public: Push an Array of lines onto the front of the Array of source data.
|
268
274
|
#
|
269
|
-
#
|
270
|
-
#
|
275
|
+
# Lines pushed on the reader using this method are not processed again. The
|
276
|
+
# method assumes the lines were previously retrieved from the reader or do
|
277
|
+
# not otherwise contain preprocessor directives. Therefore, they are marked
|
278
|
+
# as processed immediately.
|
271
279
|
#
|
272
280
|
# Returns nothing.
|
273
281
|
def unshift_lines lines_to_restore
|
274
|
-
|
275
|
-
lines_to_restore.reverse_each {|line| unshift line }
|
282
|
+
unshift_all lines_to_restore
|
276
283
|
nil
|
277
284
|
end
|
278
|
-
alias
|
285
|
+
alias restore_lines unshift_lines
|
279
286
|
|
280
287
|
# Public: Replace the next line with the specified line.
|
281
288
|
#
|
@@ -292,7 +299,7 @@ class Reader
|
|
292
299
|
nil
|
293
300
|
end
|
294
301
|
# deprecated
|
295
|
-
alias
|
302
|
+
alias replace_line replace_next_line
|
296
303
|
|
297
304
|
# Public: Strip off leading blank lines in the Array of lines.
|
298
305
|
#
|
@@ -346,10 +353,10 @@ class Reader
|
|
346
353
|
while (next_line = peek_line)
|
347
354
|
if include_blank_lines && next_line.empty?
|
348
355
|
comment_lines << shift
|
349
|
-
elsif (commentish = next_line.start_with?('//')) && (
|
356
|
+
elsif (commentish = next_line.start_with?('//')) && (CommentBlockRx.match? next_line)
|
350
357
|
comment_lines << shift
|
351
|
-
comment_lines.push(*(read_lines_until(:terminator =>
|
352
|
-
elsif commentish && CommentLineRx
|
358
|
+
comment_lines.push(*(read_lines_until(:terminator => next_line, :read_last_line => true, :skip_processing => true)))
|
359
|
+
elsif commentish && (CommentLineRx.match? next_line)
|
353
360
|
comment_lines << shift
|
354
361
|
else
|
355
362
|
break
|
@@ -366,7 +373,7 @@ class Reader
|
|
366
373
|
comment_lines = []
|
367
374
|
# optimized code for shortest execution path
|
368
375
|
while (next_line = peek_line)
|
369
|
-
if CommentLineRx
|
376
|
+
if CommentLineRx.match? next_line
|
370
377
|
comment_lines << shift
|
371
378
|
else
|
372
379
|
break
|
@@ -393,7 +400,7 @@ class Reader
|
|
393
400
|
def eof?
|
394
401
|
!has_more_lines?
|
395
402
|
end
|
396
|
-
alias
|
403
|
+
alias empty? eof?
|
397
404
|
|
398
405
|
# Public: Return all the lines from `@lines` until we (1) run out them,
|
399
406
|
# (2) find a blank line with :break_on_blank_lines => true, or (3) find
|
@@ -470,7 +477,7 @@ class Reader
|
|
470
477
|
line_restored = true
|
471
478
|
end
|
472
479
|
else
|
473
|
-
unless skip_comments && line.start_with?
|
480
|
+
unless skip_comments && (line.start_with? '//') && (CommentLineRx.match? line)
|
474
481
|
result << line
|
475
482
|
line_read = true
|
476
483
|
end
|
@@ -504,6 +511,14 @@ class Reader
|
|
504
511
|
@lines.unshift line
|
505
512
|
end
|
506
513
|
|
514
|
+
# Internal: Restore the lines to the stack and decrement the lineno
|
515
|
+
def unshift_all lines
|
516
|
+
@lineno -= lines.size
|
517
|
+
@look_ahead += lines.size
|
518
|
+
@eof = false
|
519
|
+
@lines.unshift(*lines)
|
520
|
+
end
|
521
|
+
|
507
522
|
def cursor
|
508
523
|
Cursor.new @file, @dir, @path, @lineno
|
509
524
|
end
|
@@ -514,7 +529,7 @@ class Reader
|
|
514
529
|
def line_info
|
515
530
|
%(#{@path}: line #{@lineno})
|
516
531
|
end
|
517
|
-
alias
|
532
|
+
alias next_line_info line_info
|
518
533
|
|
519
534
|
def prev_line_info
|
520
535
|
%(#{@path}: line #{@lineno - 1})
|
@@ -529,12 +544,12 @@ class Reader
|
|
529
544
|
|
530
545
|
# Public: Get a copy of the remaining lines managed by this Reader joined as a String
|
531
546
|
def string
|
532
|
-
@lines *
|
547
|
+
@lines * LF
|
533
548
|
end
|
534
549
|
|
535
550
|
# Public: Get the source lines for this Reader joined as a String
|
536
551
|
def source
|
537
|
-
@source_lines *
|
552
|
+
@source_lines * LF
|
538
553
|
end
|
539
554
|
|
540
555
|
# Public: Get a summary of this Reader.
|
@@ -553,15 +568,15 @@ class PreprocessorReader < Reader
|
|
553
568
|
attr_reader :includes
|
554
569
|
|
555
570
|
# Public: Initialize the PreprocessorReader object
|
556
|
-
def initialize document, data = nil, cursor = nil
|
571
|
+
def initialize document, data = nil, cursor = nil, opts = {}
|
557
572
|
@document = document
|
558
|
-
super data, cursor,
|
573
|
+
super data, cursor, opts
|
559
574
|
include_depth_default = document.attributes.fetch('max-include-depth', 64).to_i
|
560
575
|
include_depth_default = 0 if include_depth_default < 0
|
561
576
|
# track both absolute depth for comparing to size of include stack and relative depth for reporting
|
562
577
|
@maxdepth = {:abs => include_depth_default, :rel => include_depth_default}
|
563
578
|
@include_stack = []
|
564
|
-
@includes =
|
579
|
+
@includes = document.catalog[:includes]
|
565
580
|
@skipping = false
|
566
581
|
@conditional_stack = []
|
567
582
|
@include_processor_extensions = nil
|
@@ -571,9 +586,9 @@ class PreprocessorReader < Reader
|
|
571
586
|
result = super
|
572
587
|
|
573
588
|
# QUESTION should this work for AsciiDoc table cell content? Currently it does not.
|
574
|
-
if @document && (@document.attributes.
|
589
|
+
if @document && (@document.attributes.key? 'skip-front-matter')
|
575
590
|
if (front_matter = skip_front_matter! result)
|
576
|
-
@document.attributes['front-matter'] = front_matter *
|
591
|
+
@document.attributes['front-matter'] = front_matter * LF
|
577
592
|
end
|
578
593
|
end
|
579
594
|
|
@@ -599,45 +614,41 @@ class PreprocessorReader < Reader
|
|
599
614
|
|
600
615
|
# NOTE highly optimized
|
601
616
|
if line.end_with?(']') && !line.start_with?('[') && line.include?('::')
|
602
|
-
if line.include?
|
617
|
+
if (line.include? 'if') && ConditionalDirectiveRx =~ line
|
603
618
|
# if escaped, mark as processed and return line unescaped
|
604
|
-
if
|
619
|
+
if $1 == '\\'
|
605
620
|
@unescape_next_line = true
|
606
621
|
@look_ahead += 1
|
607
622
|
line[1..-1]
|
623
|
+
elsif preprocess_conditional_directive $2, $3, $4, $5
|
624
|
+
# move the pointer past the conditional line
|
625
|
+
advance
|
626
|
+
# treat next line as uncharted territory
|
627
|
+
nil
|
608
628
|
else
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
nil
|
614
|
-
else
|
615
|
-
# the line was not a valid conditional line
|
616
|
-
# mark it as visited and return it
|
617
|
-
@look_ahead += 1
|
618
|
-
line
|
619
|
-
end
|
629
|
+
# the line was not a valid conditional line
|
630
|
+
# mark it as visited and return it
|
631
|
+
@look_ahead += 1
|
632
|
+
line
|
620
633
|
end
|
621
634
|
elsif @skipping
|
622
635
|
advance
|
623
636
|
nil
|
624
|
-
elsif (
|
637
|
+
elsif (line.start_with? 'inc', '\\inc') && IncludeDirectiveRx =~ line
|
625
638
|
# if escaped, mark as processed and return line unescaped
|
626
|
-
if
|
639
|
+
if $1 == '\\'
|
627
640
|
@unescape_next_line = true
|
628
641
|
@look_ahead += 1
|
629
642
|
line[1..-1]
|
643
|
+
# QUESTION should we strip whitespace from raw attributes in Substitutors#parse_attributes? (check perf)
|
644
|
+
elsif preprocess_include_directive $2, $3.strip
|
645
|
+
# peek again since the content has changed
|
646
|
+
nil
|
630
647
|
else
|
631
|
-
#
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
else
|
636
|
-
# the line was not a valid include line and is unchanged
|
637
|
-
# mark it as visited and return it
|
638
|
-
@look_ahead += 1
|
639
|
-
line
|
640
|
-
end
|
648
|
+
# the line was not a valid include line and is unchanged
|
649
|
+
# mark it as visited and return it
|
650
|
+
@look_ahead += 1
|
651
|
+
line
|
641
652
|
end
|
642
653
|
else
|
643
654
|
# NOTE optimization to inline super
|
@@ -672,95 +683,89 @@ class PreprocessorReader < Reader
|
|
672
683
|
end
|
673
684
|
end
|
674
685
|
|
675
|
-
# Internal: Preprocess the directive
|
676
|
-
#
|
677
|
-
# Preprocess the conditional
|
678
|
-
#
|
679
|
-
#
|
680
|
-
#
|
681
|
-
#
|
682
|
-
#
|
683
|
-
#
|
684
|
-
#
|
685
|
-
# target
|
686
|
-
#
|
687
|
-
# delimiter
|
688
|
-
#
|
689
|
-
#
|
690
|
-
# text
|
691
|
-
#
|
692
|
-
#
|
686
|
+
# Internal: Preprocess the directive to conditionally include or exclude content.
|
687
|
+
#
|
688
|
+
# Preprocess the conditional directive (ifdef, ifndef, ifeval, endif) under
|
689
|
+
# the cursor. If Reader is currently skipping content, then simply track the
|
690
|
+
# open and close delimiters of any nested conditional blocks. If Reader is
|
691
|
+
# not skipping, mark whether the condition is satisfied and continue
|
692
|
+
# preprocessing recursively until the next line of available content is
|
693
|
+
# found.
|
694
|
+
#
|
695
|
+
# keyword - The conditional inclusion directive (ifdef, ifndef, ifeval, endif)
|
696
|
+
# target - The target, which is the name of one or more attributes that are
|
697
|
+
# used in the condition (blank in the case of the ifeval directive)
|
698
|
+
# delimiter - The conditional delimiter for multiple attributes ('+' means all
|
699
|
+
# attributes must be defined or undefined, ',' means any of the attributes
|
700
|
+
# can be defined or undefined.
|
701
|
+
# text - The text associated with this directive (occurring between the square brackets)
|
702
|
+
# Used for a single-line conditional block in the case of the ifdef or
|
703
|
+
# ifndef directives, and for the conditional expression for the ifeval directive.
|
693
704
|
#
|
694
705
|
# Returns a Boolean indicating whether the cursor should be advanced
|
695
|
-
def
|
706
|
+
def preprocess_conditional_directive keyword, target, delimiter, text
|
707
|
+
# attributes are case insensitive
|
708
|
+
target = target.downcase unless (no_target = target.empty?)
|
709
|
+
|
696
710
|
# must have a target before brackets if ifdef or ifndef
|
697
711
|
# must not have text between brackets if endif
|
698
|
-
#
|
712
|
+
# skip line if it doesn't meet this criteria
|
699
713
|
# QUESTION should we warn for these bogus declarations?
|
700
|
-
if ((
|
701
|
-
(directive == 'endif' && text)
|
702
|
-
return false
|
703
|
-
end
|
714
|
+
return false if (no_target && (keyword == 'ifdef' || keyword == 'ifndef')) || (text && keyword == 'endif')
|
704
715
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
if directive == 'endif'
|
709
|
-
stack_size = @conditional_stack.size
|
710
|
-
if stack_size > 0
|
711
|
-
pair = @conditional_stack[-1]
|
712
|
-
if target.empty? || target == pair[:target]
|
713
|
-
@conditional_stack.pop
|
714
|
-
@skipping = @conditional_stack.empty? ? false : @conditional_stack[-1][:skipping]
|
715
|
-
else
|
716
|
-
warn %(asciidoctor: ERROR: #{line_info}: mismatched macro: endif::#{target}[], expected endif::#{pair[:target]}[])
|
717
|
-
end
|
718
|
-
else
|
716
|
+
if keyword == 'endif'
|
717
|
+
if @conditional_stack.empty?
|
719
718
|
warn %(asciidoctor: ERROR: #{line_info}: unmatched macro: endif::#{target}[])
|
719
|
+
elsif no_target || target == (pair = @conditional_stack[-1])[:target]
|
720
|
+
@conditional_stack.pop
|
721
|
+
@skipping = @conditional_stack.empty? ? false : @conditional_stack[-1][:skipping]
|
722
|
+
else
|
723
|
+
warn %(asciidoctor: ERROR: #{line_info}: mismatched macro: endif::#{target}[], expected endif::#{pair[:target]}[])
|
720
724
|
end
|
721
725
|
return true
|
722
726
|
end
|
723
727
|
|
724
|
-
|
725
|
-
|
728
|
+
if @skipping
|
729
|
+
skip = false
|
730
|
+
else
|
726
731
|
# QUESTION any way to wrap ifdef & ifndef logic up together?
|
727
|
-
case
|
732
|
+
case keyword
|
728
733
|
when 'ifdef'
|
729
734
|
case delimiter
|
730
|
-
when nil
|
731
|
-
# if the attribute is undefined, then skip
|
732
|
-
skip = !@document.attributes.has_key?(target)
|
733
735
|
when ','
|
734
|
-
# if
|
735
|
-
skip = target.split(',').none? {|name| @document.attributes.
|
736
|
+
# skip if no attribute is defined
|
737
|
+
skip = target.split(',', -1).none? {|name| @document.attributes.key? name }
|
736
738
|
when '+'
|
737
|
-
# if any attribute is undefined
|
738
|
-
skip = target.split('+').any? {|name| !@document.attributes.
|
739
|
+
# skip if any attribute is undefined
|
740
|
+
skip = target.split('+', -1).any? {|name| !@document.attributes.key? name }
|
741
|
+
else
|
742
|
+
# if the attribute is undefined, then skip
|
743
|
+
skip = !@document.attributes.key?(target)
|
739
744
|
end
|
740
745
|
when 'ifndef'
|
741
746
|
case delimiter
|
742
|
-
when nil
|
743
|
-
# if the attribute is defined, then skip
|
744
|
-
skip = @document.attributes.has_key?(target)
|
745
747
|
when ','
|
746
|
-
# if any attribute is
|
747
|
-
skip = target.split(',').
|
748
|
+
# skip if any attribute is defined
|
749
|
+
skip = target.split(',', -1).any? {|name| @document.attributes.key? name }
|
748
750
|
when '+'
|
749
|
-
# if
|
750
|
-
skip = target.split('+').
|
751
|
+
# skip if all attributes are defined
|
752
|
+
skip = target.split('+', -1).all? {|name| @document.attributes.key? name }
|
753
|
+
else
|
754
|
+
# if the attribute is defined, then skip
|
755
|
+
skip = @document.attributes.key?(target)
|
751
756
|
end
|
752
757
|
when 'ifeval'
|
753
758
|
# the text in brackets must match an expression
|
754
759
|
# don't honor match if it doesn't meet this criteria
|
755
|
-
|
756
|
-
return false
|
757
|
-
end
|
760
|
+
return false unless no_target && EvalExpressionRx =~ text.strip
|
758
761
|
|
759
|
-
|
760
|
-
rhs =
|
762
|
+
# NOTE save values eagerly for Ruby 1.8.7 compat
|
763
|
+
lhs, op, rhs = $1, $2, $3
|
764
|
+
lhs = resolve_expr_val lhs
|
765
|
+
rhs = resolve_expr_val rhs
|
761
766
|
|
762
767
|
# regex enforces a restricted set of math-related operations
|
763
|
-
if
|
768
|
+
if op == '!='
|
764
769
|
skip = lhs.send :==, rhs
|
765
770
|
else
|
766
771
|
skip = !(lhs.send op.to_sym, rhs)
|
@@ -769,26 +774,25 @@ class PreprocessorReader < Reader
|
|
769
774
|
end
|
770
775
|
|
771
776
|
# conditional inclusion block
|
772
|
-
if
|
777
|
+
if keyword == 'ifeval' || !text
|
773
778
|
@skipping = true if skip
|
774
779
|
@conditional_stack << {:target => target, :skip => skip, :skipping => @skipping}
|
775
780
|
# single line conditional inclusion
|
776
781
|
else
|
777
782
|
unless @skipping || skip
|
778
|
-
# FIXME slight hack to skip past conditional line
|
779
|
-
# but keep our synthetic line marked as processed
|
780
|
-
# QUESTION can we use read_line true and unshift twice instead?
|
781
|
-
conditional_line = peek_line true
|
782
783
|
replace_next_line text.rstrip
|
783
|
-
|
784
|
-
|
784
|
+
# HACK push dummy line to stand in for the opening conditional directive that's subsequently dropped
|
785
|
+
unshift ''
|
786
|
+
# NOTE force line to be processed again if it looks like an include directive
|
787
|
+
# QUESTION should we just call preprocess_include_directive here?
|
788
|
+
@look_ahead -= 1 if text.start_with? 'include::'
|
785
789
|
end
|
786
790
|
end
|
787
791
|
|
788
792
|
true
|
789
793
|
end
|
790
794
|
|
791
|
-
# Internal: Preprocess the directive
|
795
|
+
# Internal: Preprocess the directive to include lines from another document.
|
792
796
|
#
|
793
797
|
# Preprocess the directive to include the target document. The scenarios
|
794
798
|
# are as follows:
|
@@ -806,23 +810,21 @@ class PreprocessorReader < Reader
|
|
806
810
|
# If none of the above apply, emit the include directive line verbatim.
|
807
811
|
#
|
808
812
|
# target - The name of the source document to include as specified in the
|
809
|
-
# target slot of the include::[]
|
813
|
+
# target slot of the include::[] directive
|
810
814
|
#
|
811
815
|
# Returns a Boolean indicating whether the line under the cursor has changed.
|
812
|
-
def
|
813
|
-
if (target =
|
816
|
+
def preprocess_include_directive raw_target, raw_attributes
|
817
|
+
if ((target = raw_target).include? '{') &&
|
818
|
+
(target = @document.sub_attributes raw_target, :attribute_missing => 'drop-line').empty?
|
814
819
|
advance
|
815
820
|
if @document.attributes.fetch('attribute-missing', Compliance.attribute_missing) == 'skip'
|
816
821
|
unshift %(Unresolved directive in #{@path} - include::#{raw_target}[#{raw_attributes}])
|
817
822
|
end
|
818
823
|
true
|
819
|
-
|
820
|
-
# to handle when and how to process the include
|
821
|
-
elsif include_processors? &&
|
822
|
-
(extension = @include_processor_extensions.find {|candidate| candidate.instance.handles? target })
|
824
|
+
elsif include_processors? && (ext = @include_processor_extensions.find {|candidate| candidate.instance.handles? target })
|
823
825
|
advance
|
824
|
-
# FIXME parse attributes if requested by extension
|
825
|
-
|
826
|
+
# FIXME parse attributes only if requested by extension
|
827
|
+
ext.process_method[@document, self, target, AttributeList.new(raw_attributes).parse]
|
826
828
|
true
|
827
829
|
# if running in SafeMode::SECURE or greater, don't process this directive
|
828
830
|
# however, be friendly and at least make it a link to the source document
|
@@ -835,25 +837,20 @@ class PreprocessorReader < Reader
|
|
835
837
|
warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
|
836
838
|
return false
|
837
839
|
end
|
838
|
-
if ::RUBY_ENGINE_OPAL
|
840
|
+
if ::RUBY_ENGINE_OPAL && ::JAVASCRIPT_IO_MODULE == 'xmlhttprequest'
|
839
841
|
# NOTE resolves uri relative to currently loaded document
|
840
842
|
# NOTE we defer checking if file exists and catch the 404 error if it does not
|
841
|
-
# TODO only use this logic if env-browser is set
|
842
843
|
target_type = :file
|
843
|
-
|
844
|
-
::Dir.pwd == @document.base_dir ? target : (::File.join @dir, target)
|
845
|
-
else
|
846
|
-
::File.join @dir, target
|
847
|
-
end
|
844
|
+
inc_path = relpath = @include_stack.empty? && ::Dir.pwd == @document.base_dir ? target : (::File.join @dir, target)
|
848
845
|
elsif Helpers.uriish? target
|
849
|
-
unless @document.attributes.
|
846
|
+
unless @document.attributes.key? 'allow-uri-read'
|
850
847
|
replace_next_line %(link:#{target}[])
|
851
848
|
return true
|
852
849
|
end
|
853
850
|
|
854
851
|
target_type = :uri
|
855
|
-
|
856
|
-
if @document.attributes.
|
852
|
+
inc_path = relpath = target
|
853
|
+
if @document.attributes.key? 'cache-uri'
|
857
854
|
# caching requires the open-uri-cached gem to be installed
|
858
855
|
# processing will be automatically aborted if these libraries can't be opened
|
859
856
|
Helpers.require_library 'open-uri/cached', 'open-uri-cached' unless defined? ::OpenURI::Cache
|
@@ -864,130 +861,159 @@ class PreprocessorReader < Reader
|
|
864
861
|
else
|
865
862
|
target_type = :file
|
866
863
|
# include file is resolved relative to dir of current include, or base_dir if within original docfile
|
867
|
-
|
868
|
-
unless ::File.file?
|
869
|
-
warn %(asciidoctor: WARNING: #{line_info}: include file not found: #{
|
864
|
+
inc_path = @document.normalize_system_path target, @dir, nil, :target_name => 'include file'
|
865
|
+
unless ::File.file? inc_path
|
866
|
+
warn %(asciidoctor: WARNING: #{line_info}: include file not found: #{inc_path})
|
870
867
|
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
871
868
|
return true
|
872
869
|
end
|
873
|
-
#path
|
874
|
-
|
870
|
+
# NOTE relpath is the path relative to the outermost document (or base_dir, if set)
|
871
|
+
#relpath = @document.relative_path inc_path
|
872
|
+
relpath = PathResolver.new.relative_path inc_path, @document.base_dir
|
875
873
|
end
|
876
874
|
|
877
|
-
|
878
|
-
|
879
|
-
attributes = {}
|
880
|
-
if !raw_attributes.empty?
|
875
|
+
inc_linenos, inc_tags, attributes = nil, nil, {}
|
876
|
+
unless raw_attributes.empty?
|
881
877
|
# QUESTION should we use @document.parse_attribues?
|
882
878
|
attributes = AttributeList.new(raw_attributes).parse
|
883
|
-
if attributes.
|
884
|
-
|
879
|
+
if attributes.key? 'lines'
|
880
|
+
inc_linenos = []
|
885
881
|
attributes['lines'].split(DataDelimiterRx).each do |linedef|
|
886
882
|
if linedef.include?('..')
|
887
|
-
from, to = linedef.split('..', 2).map
|
883
|
+
from, to = linedef.split('..', 2).map {|it| it.to_i }
|
888
884
|
if to == -1
|
889
|
-
|
890
|
-
|
885
|
+
inc_linenos << from
|
886
|
+
inc_linenos << 1.0/0.0
|
891
887
|
else
|
892
|
-
|
888
|
+
inc_linenos.concat ::Range.new(from, to).to_a
|
893
889
|
end
|
894
890
|
else
|
895
|
-
|
891
|
+
inc_linenos << linedef.to_i
|
896
892
|
end
|
897
893
|
end
|
898
|
-
|
899
|
-
elsif attributes.
|
900
|
-
|
901
|
-
|
902
|
-
|
894
|
+
inc_linenos = inc_linenos.empty? ? nil : inc_linenos.sort.uniq
|
895
|
+
elsif attributes.key? 'tag'
|
896
|
+
unless (tag = attributes['tag']).empty?
|
897
|
+
if tag.start_with? '!'
|
898
|
+
inc_tags = { (tag.slice 1, tag.length) => false } unless tag == '!'
|
899
|
+
else
|
900
|
+
inc_tags = { tag => true }
|
901
|
+
end
|
902
|
+
end
|
903
|
+
elsif attributes.key? 'tags'
|
904
|
+
inc_tags = {}
|
905
|
+
attributes['tags'].split(DataDelimiterRx).each do |tagdef|
|
906
|
+
if tagdef.start_with? '!'
|
907
|
+
inc_tags[tagdef.slice 1, tagdef.length] = false unless tagdef == '!'
|
908
|
+
else
|
909
|
+
inc_tags[tagdef] = true
|
910
|
+
end unless tagdef.empty?
|
911
|
+
end
|
912
|
+
inc_tags = nil if inc_tags.empty?
|
903
913
|
end
|
904
914
|
end
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
end
|
924
|
-
break if inc_lines.empty?
|
915
|
+
|
916
|
+
if inc_linenos
|
917
|
+
inc_lines, inc_offset, inc_lineno = [], nil, 0
|
918
|
+
begin
|
919
|
+
open(inc_path, 'r') do |f|
|
920
|
+
f.each_line do |l|
|
921
|
+
inc_lineno += 1
|
922
|
+
select = inc_linenos[0]
|
923
|
+
if ::Float === select && select.infinite?
|
924
|
+
# NOTE record line where we started selecting
|
925
|
+
inc_offset ||= inc_lineno
|
926
|
+
inc_lines << l
|
927
|
+
else
|
928
|
+
if inc_lineno == select
|
929
|
+
# NOTE record line where we started selecting
|
930
|
+
inc_offset ||= inc_lineno
|
931
|
+
inc_lines << l
|
932
|
+
inc_linenos.shift
|
925
933
|
end
|
934
|
+
break if inc_linenos.empty?
|
926
935
|
end
|
927
936
|
end
|
928
|
-
rescue
|
929
|
-
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
|
930
|
-
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
931
|
-
return true
|
932
937
|
end
|
933
|
-
|
934
|
-
|
935
|
-
|
938
|
+
rescue
|
939
|
+
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{inc_path})
|
940
|
+
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
941
|
+
return true
|
936
942
|
end
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
|
943
|
+
advance
|
944
|
+
# FIXME not accounting for skipped lines in reader line numbering
|
945
|
+
push_include inc_lines, inc_path, relpath, inc_offset, attributes if inc_offset
|
946
|
+
elsif inc_tags
|
947
|
+
inc_lines, inc_offset, inc_lineno, tag_stack, tags_used, active_tag = [], nil, 0, [], ::Set.new, nil
|
948
|
+
if inc_tags.key? '**'
|
949
|
+
if inc_tags.key? '*'
|
950
|
+
select = base_select = (inc_tags.delete '**')
|
951
|
+
wildcard = inc_tags.delete '*'
|
952
|
+
else
|
953
|
+
select = base_select = wildcard = (inc_tags.delete '**')
|
954
|
+
end
|
955
|
+
else
|
956
|
+
select = base_select = !(inc_tags.value? true)
|
957
|
+
wildcard = inc_tags.delete '*'
|
958
|
+
end
|
959
|
+
if (ext_idx = inc_path.rindex '.') && (circ_cmt = CIRCUMFIX_COMMENTS[inc_path.slice ext_idx, inc_path.length])
|
960
|
+
cmt_suffix_len = (tag_suffix = %([] #{circ_cmt[:suffix]})).length - 2
|
961
|
+
end
|
962
|
+
begin
|
963
|
+
open(inc_path, 'r') do |f|
|
964
|
+
f.each_line do |l|
|
965
|
+
inc_lineno += 1
|
966
|
+
# must force encoding since we're performing String operations on line
|
967
|
+
l.force_encoding ::Encoding::UTF_8 if FORCE_ENCODING
|
968
|
+
if (((tl = l.chomp).end_with? '[]') ||
|
969
|
+
(tag_suffix && (tl.end_with? tag_suffix) && (tl = tl.slice 0, tl.length - cmt_suffix_len))) &&
|
970
|
+
TagDirectiveRx =~ tl
|
971
|
+
if $1 # end tag
|
972
|
+
if (this_tag = $2) == active_tag
|
973
|
+
tag_stack.pop
|
974
|
+
active_tag, select = tag_stack.empty? ? [nil, base_select] : tag_stack[-1]
|
975
|
+
elsif inc_tags.key? this_tag
|
976
|
+
if (idx = tag_stack.rindex {|key, _| key == this_tag })
|
977
|
+
idx == 0 ? tag_stack.shift : (tag_stack.delete_at idx)
|
978
|
+
warn %(asciidoctor: WARNING: #{target}: line #{inc_lineno}: mismatched end tag in include: expected #{active_tag}, found #{this_tag})
|
979
|
+
else
|
980
|
+
warn %(asciidoctor: WARNING: #{target}: line #{inc_lineno}: unexpected end tag in include: #{this_tag})
|
966
981
|
end
|
967
|
-
end
|
982
|
+
end
|
983
|
+
elsif inc_tags.key?(this_tag = $2)
|
984
|
+
tags_used << this_tag
|
985
|
+
# QUESTION should we prevent tag from being selected when enclosing tag is excluded?
|
986
|
+
tag_stack << [(active_tag = this_tag), (select = inc_tags[this_tag])]
|
987
|
+
elsif !wildcard.nil?
|
988
|
+
select = active_tag && !select ? false : wildcard
|
989
|
+
tag_stack << [(active_tag = this_tag), select]
|
968
990
|
end
|
991
|
+
elsif select
|
992
|
+
# NOTE record the line where we started selecting
|
993
|
+
inc_offset ||= inc_lineno
|
994
|
+
inc_lines << l
|
969
995
|
end
|
970
996
|
end
|
971
|
-
rescue
|
972
|
-
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{include_file})
|
973
|
-
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
974
|
-
return true
|
975
|
-
end
|
976
|
-
unless (missing_tags = tags.to_a - tags_found.to_a).empty?
|
977
|
-
warn %(asciidoctor: WARNING: #{line_info}: tag#{missing_tags.size > 1 ? 's' : nil} '#{missing_tags * ','}' not found in include #{target_type}: #{include_file})
|
978
997
|
end
|
979
|
-
|
980
|
-
|
981
|
-
|
998
|
+
rescue
|
999
|
+
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{inc_path})
|
1000
|
+
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
1001
|
+
return true
|
982
1002
|
end
|
1003
|
+
unless (missing_tags = inc_tags.keys.to_a - tags_used.to_a).empty?
|
1004
|
+
warn %(asciidoctor: WARNING: #{line_info}: tag#{missing_tags.size > 1 ? 's' : nil} '#{missing_tags * ','}' not found in include #{target_type}: #{inc_path})
|
1005
|
+
end
|
1006
|
+
advance
|
1007
|
+
# FIXME not accounting for skipped lines in reader line numbering
|
1008
|
+
push_include inc_lines, inc_path, relpath, inc_offset, attributes if inc_offset
|
983
1009
|
else
|
984
1010
|
begin
|
985
1011
|
# NOTE read content first so that we only advance cursor if IO operation succeeds
|
986
|
-
|
1012
|
+
inc_content = target_type == :file ? (::IO.read inc_path) : open(inc_path, 'r') {|f| f.read }
|
987
1013
|
advance
|
988
|
-
push_include
|
1014
|
+
push_include inc_content, inc_path, relpath, 1, attributes
|
989
1015
|
rescue
|
990
|
-
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{
|
1016
|
+
warn %(asciidoctor: WARNING: #{line_info}: include #{target_type} not readable: #{inc_path})
|
991
1017
|
replace_next_line %(Unresolved directive in #{@path} - include::#{target}[#{raw_attributes}])
|
992
1018
|
return true
|
993
1019
|
end
|
@@ -1018,7 +1044,7 @@ class PreprocessorReader < Reader
|
|
1018
1044
|
@file = file
|
1019
1045
|
@dir = File.dirname file
|
1020
1046
|
# only process lines in AsciiDoc files
|
1021
|
-
@process_lines = ASCIIDOC_EXTENSIONS[::File.extname
|
1047
|
+
@process_lines = ASCIIDOC_EXTENSIONS[::File.extname file]
|
1022
1048
|
else
|
1023
1049
|
@file = nil
|
1024
1050
|
@dir = '.' # right?
|
@@ -1026,16 +1052,16 @@ class PreprocessorReader < Reader
|
|
1026
1052
|
@process_lines = true
|
1027
1053
|
end
|
1028
1054
|
|
1029
|
-
|
1055
|
+
if path
|
1030
1056
|
@includes << Helpers.rootname(path)
|
1031
|
-
path
|
1057
|
+
@path = path
|
1032
1058
|
else
|
1033
|
-
'<stdin>'
|
1059
|
+
@path = '<stdin>'
|
1034
1060
|
end
|
1035
1061
|
|
1036
1062
|
@lineno = lineno
|
1037
1063
|
|
1038
|
-
if attributes.
|
1064
|
+
if attributes.key? 'depth'
|
1039
1065
|
depth = attributes['depth'].to_i
|
1040
1066
|
depth = 1 if depth <= 0
|
1041
1067
|
@maxdepth = {:abs => (@include_stack.size - 1) + depth, :rel => depth}
|
@@ -1046,14 +1072,14 @@ class PreprocessorReader < Reader
|
|
1046
1072
|
pop_include
|
1047
1073
|
else
|
1048
1074
|
# FIXME we eventually want to handle leveloffset without affecting the lines
|
1049
|
-
if attributes.
|
1075
|
+
if attributes.key? 'leveloffset'
|
1050
1076
|
@lines.unshift ''
|
1051
1077
|
@lines.unshift %(:leveloffset: #{attributes['leveloffset']})
|
1052
|
-
@lines
|
1078
|
+
@lines << ''
|
1053
1079
|
if (old_leveloffset = @document.attr 'leveloffset')
|
1054
|
-
@lines
|
1080
|
+
@lines << %(:leveloffset: #{old_leveloffset})
|
1055
1081
|
else
|
1056
|
-
@lines
|
1082
|
+
@lines << ':leveloffset!:'
|
1057
1083
|
end
|
1058
1084
|
# compensate for these extra lines
|
1059
1085
|
@lineno -= 2
|
@@ -1113,7 +1139,7 @@ class PreprocessorReader < Reader
|
|
1113
1139
|
data.shift
|
1114
1140
|
@lineno += 1 if increment_linenos
|
1115
1141
|
while !data.empty? && data[0] != '---'
|
1116
|
-
front_matter
|
1142
|
+
front_matter << data.shift
|
1117
1143
|
@lineno += 1 if increment_linenos
|
1118
1144
|
end
|
1119
1145
|
|
@@ -1171,9 +1197,7 @@ class PreprocessorReader < Reader
|
|
1171
1197
|
|
1172
1198
|
# QUESTION should we substitute first?
|
1173
1199
|
# QUESTION should we also require string to be single quoted (like block attribute values?)
|
1174
|
-
if val.include? '{'
|
1175
|
-
val = @document.sub_attributes val, :attribute_missing => 'drop'
|
1176
|
-
end
|
1200
|
+
val = @document.sub_attributes val, :attribute_missing => 'drop' if val.include? '{'
|
1177
1201
|
|
1178
1202
|
if quoted
|
1179
1203
|
val
|
@@ -1209,7 +1233,7 @@ class PreprocessorReader < Reader
|
|
1209
1233
|
end
|
1210
1234
|
|
1211
1235
|
def to_s
|
1212
|
-
%(#<#{self.class}@#{object_id} {path: #{@path.inspect}, line #: #{@lineno}, include depth: #{@include_stack.size}, include stack: [#{@include_stack.map {|inc| inc.to_s}
|
1236
|
+
%(#<#{self.class}@#{object_id} {path: #{@path.inspect}, line #: #{@lineno}, include depth: #{@include_stack.size}, include stack: [#{@include_stack.map {|inc| inc.to_s } * ', '}]}>)
|
1213
1237
|
end
|
1214
1238
|
end
|
1215
1239
|
end
|