asciidoctor 2.0.10 → 2.0.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +294 -30
- data/LICENSE +1 -1
- data/README-de.adoc +16 -20
- data/README-fr.adoc +15 -22
- data/README-jp.adoc +15 -26
- data/README-zh_CN.adoc +21 -25
- data/README.adoc +161 -138
- data/asciidoctor.gemspec +6 -13
- data/data/locale/attributes-ar.adoc +4 -3
- data/data/locale/attributes-be.adoc +23 -0
- data/data/locale/attributes-bg.adoc +4 -3
- data/data/locale/attributes-ca.adoc +6 -5
- data/data/locale/attributes-cs.adoc +4 -3
- data/data/locale/attributes-da.adoc +6 -5
- data/data/locale/attributes-de.adoc +4 -4
- data/data/locale/attributes-en.adoc +4 -4
- data/data/locale/attributes-es.adoc +6 -5
- data/data/locale/attributes-fa.adoc +4 -3
- data/data/locale/attributes-fi.adoc +4 -3
- data/data/locale/attributes-fr.adoc +8 -7
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +6 -5
- data/data/locale/attributes-ja.adoc +4 -3
- data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
- data/data/locale/attributes-nb.adoc +4 -3
- data/data/locale/attributes-nl.adoc +6 -5
- data/data/locale/attributes-nn.adoc +4 -3
- data/data/locale/attributes-pl.adoc +8 -7
- data/data/locale/attributes-pt.adoc +6 -5
- data/data/locale/attributes-pt_BR.adoc +6 -5
- data/data/locale/attributes-ro.adoc +4 -3
- data/data/locale/attributes-ru.adoc +6 -5
- data/data/locale/attributes-sr.adoc +4 -4
- data/data/locale/attributes-sr_Latn.adoc +4 -4
- data/data/locale/attributes-sv.adoc +4 -4
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/reference/syntax.adoc +14 -7
- data/data/stylesheets/asciidoctor-default.css +76 -76
- data/data/stylesheets/coderay-asciidoctor.css +9 -9
- data/lib/asciidoctor/abstract_block.rb +20 -13
- data/lib/asciidoctor/abstract_node.rb +23 -12
- data/lib/asciidoctor/attribute_list.rb +64 -72
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +3 -2
- data/lib/asciidoctor/cli/options.rb +32 -31
- data/lib/asciidoctor/convert.rb +168 -162
- data/lib/asciidoctor/converter/docbook5.rb +49 -34
- data/lib/asciidoctor/converter/html5.rb +180 -139
- data/lib/asciidoctor/converter/manpage.rb +118 -90
- data/lib/asciidoctor/converter/template.rb +15 -13
- data/lib/asciidoctor/converter.rb +19 -16
- data/lib/asciidoctor/core_ext/hash/merge.rb +1 -1
- data/lib/asciidoctor/document.rb +77 -86
- data/lib/asciidoctor/extensions.rb +22 -16
- data/lib/asciidoctor/helpers.rb +20 -15
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +103 -101
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +211 -220
- data/lib/asciidoctor/path_resolver.rb +17 -15
- data/lib/asciidoctor/reader.rb +87 -79
- data/lib/asciidoctor/rx.rb +9 -7
- data/lib/asciidoctor/section.rb +7 -0
- data/lib/asciidoctor/substitutors.rb +167 -148
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +3 -2
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +13 -5
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +19 -11
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +35 -20
- data/lib/asciidoctor/syntax_highlighter.rb +16 -16
- data/lib/asciidoctor/table.rb +70 -43
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/lib/asciidoctor.rb +45 -19
- data/man/asciidoctor.1 +29 -31
- data/man/asciidoctor.adoc +35 -29
- metadata +17 -70
@@ -109,7 +109,7 @@ class PathResolver
|
|
109
109
|
SLASH = '/'
|
110
110
|
BACKSLASH = '\\'
|
111
111
|
DOUBLE_SLASH = '//'
|
112
|
-
WindowsRootRx =
|
112
|
+
WindowsRootRx = %r(^(?:[a-zA-Z]:)?[\\/])
|
113
113
|
|
114
114
|
attr_accessor :file_separator
|
115
115
|
attr_accessor :working_dir
|
@@ -290,8 +290,8 @@ class PathResolver
|
|
290
290
|
# ex. ./sample/path
|
291
291
|
elsif posix_path.start_with? DOT_SLASH
|
292
292
|
root = DOT_SLASH
|
293
|
-
# else ex. sample/path
|
294
293
|
end
|
294
|
+
# otherwise ex. sample/path
|
295
295
|
elsif root? posix_path
|
296
296
|
# ex. //sample/path
|
297
297
|
if unc? posix_path
|
@@ -306,8 +306,8 @@ class PathResolver
|
|
306
306
|
# ex. ./sample/path
|
307
307
|
elsif posix_path.start_with? DOT_SLASH
|
308
308
|
root = DOT_SLASH
|
309
|
-
# else ex. sample/path
|
310
309
|
end
|
310
|
+
# otherwise ex. sample/path
|
311
311
|
|
312
312
|
path_segments = (root ? (posix_path.slice root.length, posix_path.length) : posix_path).split SLASH
|
313
313
|
# strip out all dot entries
|
@@ -331,11 +331,12 @@ class PathResolver
|
|
331
331
|
|
332
332
|
# Public: Securely resolve a system path
|
333
333
|
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
# that
|
337
|
-
# path
|
338
|
-
#
|
334
|
+
# Resolves the target to an absolute path on the current filesystem. The target is assumed to be
|
335
|
+
# relative to the start path, jail path, or working directory (specified in the constructor), in
|
336
|
+
# that order. If a jail path is specified, the resolved path is forced to descend from the jail
|
337
|
+
# path. If a jail path is not provided, the resolved path may be any location on the system. If
|
338
|
+
# the target is an absolute path, use it as is (unless it breaches the jail path). Expands all
|
339
|
+
# parent and self references in the resolved path.
|
339
340
|
#
|
340
341
|
# target - the String target path
|
341
342
|
# start - the String start path from which to resolve a relative target; falls back to jail, if
|
@@ -347,8 +348,9 @@ class PathResolver
|
|
347
348
|
# automatically recover when an illegal path is encountered
|
348
349
|
# * :target_name is used in messages to refer to the path being resolved
|
349
350
|
#
|
350
|
-
#
|
351
|
-
# if specified. The path is posixified and all parent and self references in the path
|
351
|
+
# Returns an absolute String path relative to the start path, if specified, and confined to the
|
352
|
+
# jail path, if specified. The path is posixified and all parent and self references in the path
|
353
|
+
# are expanded.
|
352
354
|
def system_path target, start = nil, jail = nil, opts = {}
|
353
355
|
if jail
|
354
356
|
raise ::SecurityError, %(Jail is not an absolute path: #{jail}) unless root? jail
|
@@ -362,7 +364,7 @@ class PathResolver
|
|
362
364
|
if jail && !(descends_from? target_path, jail)
|
363
365
|
if opts.fetch :recover, true
|
364
366
|
logger.warn %(#{opts[:target_name] || 'path'} is outside of jail; recovering automatically)
|
365
|
-
target_segments,
|
367
|
+
target_segments, = partition_path target_path
|
366
368
|
jail_segments, jail_root = partition_path jail
|
367
369
|
return join_path jail_segments + target_segments, jail_root
|
368
370
|
else
|
@@ -371,7 +373,7 @@ class PathResolver
|
|
371
373
|
end
|
372
374
|
return target_path
|
373
375
|
else
|
374
|
-
target_segments,
|
376
|
+
target_segments, = partition_path target
|
375
377
|
end
|
376
378
|
else
|
377
379
|
target_segments = []
|
@@ -387,7 +389,7 @@ class PathResolver
|
|
387
389
|
return expand_path start
|
388
390
|
end
|
389
391
|
else
|
390
|
-
target_segments,
|
392
|
+
target_segments, = partition_path start
|
391
393
|
start = jail || @working_dir
|
392
394
|
end
|
393
395
|
elsif start.nil_or_empty?
|
@@ -419,7 +421,7 @@ class PathResolver
|
|
419
421
|
if (resolved_segments = start_segments + target_segments).include? DOT_DOT
|
420
422
|
unresolved_segments, resolved_segments = resolved_segments, []
|
421
423
|
if jail
|
422
|
-
jail_segments,
|
424
|
+
jail_segments, = partition_path jail unless jail_segments
|
423
425
|
warned = false
|
424
426
|
unresolved_segments.each do |segment|
|
425
427
|
if segment == DOT_DOT
|
@@ -450,7 +452,7 @@ class PathResolver
|
|
450
452
|
target_path
|
451
453
|
elsif opts.fetch :recover, true
|
452
454
|
logger.warn %(#{opts[:target_name] || 'path'} is outside of jail; recovering automatically)
|
453
|
-
jail_segments,
|
455
|
+
jail_segments, = partition_path jail unless jail_segments
|
454
456
|
join_path jail_segments + target_segments, jail_root
|
455
457
|
else
|
456
458
|
raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} is outside of jail: #{jail} (disallowed in safe mode))
|
data/lib/asciidoctor/reader.rb
CHANGED
@@ -44,11 +44,11 @@ class Reader
|
|
44
44
|
@file = nil
|
45
45
|
@dir = '.'
|
46
46
|
@path = '<stdin>'
|
47
|
-
@lineno = 1
|
47
|
+
@lineno = 1
|
48
48
|
elsif ::String === cursor
|
49
49
|
@file = cursor
|
50
50
|
@dir, @path = ::File.split @file
|
51
|
-
@lineno = 1
|
51
|
+
@lineno = 1
|
52
52
|
else
|
53
53
|
if (@file = cursor.file)
|
54
54
|
@dir = cursor.dir || (::File.dirname @file)
|
@@ -57,10 +57,9 @@ class Reader
|
|
57
57
|
@dir = cursor.dir || '.'
|
58
58
|
@path = cursor.path || '<stdin>'
|
59
59
|
end
|
60
|
-
@lineno = cursor.lineno || 1
|
60
|
+
@lineno = cursor.lineno || 1
|
61
61
|
end
|
62
|
-
@lines = prepare_lines data, opts
|
63
|
-
@source_lines = @lines.drop 0
|
62
|
+
@lines = (@source_lines = prepare_lines data, opts).reverse
|
64
63
|
@mark = nil
|
65
64
|
@look_ahead = 0
|
66
65
|
@process_lines = true
|
@@ -127,7 +126,7 @@ class Reader
|
|
127
126
|
# Returns nothing if there is no more data.
|
128
127
|
def peek_line direct = false
|
129
128
|
if direct || @look_ahead > 0
|
130
|
-
@unescape_next_line ? ((line = @lines[
|
129
|
+
@unescape_next_line ? ((line = @lines[-1]).slice 1, line.length) : @lines[-1]
|
131
130
|
elsif @lines.empty?
|
132
131
|
@look_ahead = 0
|
133
132
|
nil
|
@@ -135,7 +134,7 @@ class Reader
|
|
135
134
|
# FIXME the problem with this approach is that we aren't
|
136
135
|
# retaining the modified line (hence the @unescape_next_line tweak)
|
137
136
|
# perhaps we need a stack of proxied lines
|
138
|
-
(
|
137
|
+
(process_line @lines[-1]) || peek_line
|
139
138
|
end
|
140
139
|
end
|
141
140
|
|
@@ -192,9 +191,7 @@ class Reader
|
|
192
191
|
def read_lines
|
193
192
|
lines = []
|
194
193
|
# has_more_lines? triggers preprocessor
|
195
|
-
while has_more_lines?
|
196
|
-
lines << shift
|
197
|
-
end
|
194
|
+
lines << shift while has_more_lines?
|
198
195
|
lines
|
199
196
|
end
|
200
197
|
alias readlines read_lines
|
@@ -241,7 +238,6 @@ class Reader
|
|
241
238
|
# Returns nothing.
|
242
239
|
def unshift_lines lines_to_restore
|
243
240
|
unshift_all lines_to_restore
|
244
|
-
nil
|
245
241
|
end
|
246
242
|
alias restore_lines unshift_lines
|
247
243
|
|
@@ -334,7 +330,7 @@ class Reader
|
|
334
330
|
comment_lines = []
|
335
331
|
# optimized code for shortest execution path
|
336
332
|
while (next_line = peek_line) && !next_line.empty?
|
337
|
-
if
|
333
|
+
if next_line.start_with? '//'
|
338
334
|
comment_lines << shift
|
339
335
|
else
|
340
336
|
break
|
@@ -407,34 +403,22 @@ class Reader
|
|
407
403
|
break_on_list_continuation = options[:break_on_list_continuation]
|
408
404
|
end
|
409
405
|
skip_comments = options[:skip_line_comments]
|
410
|
-
|
406
|
+
line_read = line_restored = nil
|
411
407
|
shift if options[:skip_first_line]
|
412
|
-
while
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
if break_on_list_continuation && line_read && line == LIST_CONTINUATION
|
418
|
-
options[:preserve_last_line] = true
|
419
|
-
break true
|
420
|
-
end
|
421
|
-
break true if block_given? && (yield line)
|
422
|
-
break false
|
423
|
-
end
|
424
|
-
if complete
|
425
|
-
if options[:read_last_line]
|
426
|
-
result << line
|
427
|
-
line_read = true
|
428
|
-
end
|
408
|
+
while (line = read_line)
|
409
|
+
if terminator ? line == terminator : ((break_on_blank_lines && line.empty?) ||
|
410
|
+
(break_on_list_continuation && line_read && line == LIST_CONTINUATION && (options[:preserve_last_line] = true)) ||
|
411
|
+
(block_given? && (yield line)))
|
412
|
+
result << line if options[:read_last_line]
|
429
413
|
if options[:preserve_last_line]
|
430
414
|
unshift line
|
431
415
|
line_restored = true
|
432
416
|
end
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
417
|
+
break
|
418
|
+
end
|
419
|
+
unless skip_comments && (line.start_with? '//') && !(line.start_with? '///')
|
420
|
+
result << line
|
421
|
+
line_read = true
|
438
422
|
end
|
439
423
|
end
|
440
424
|
if restore_process_lines
|
@@ -459,21 +443,37 @@ class Reader
|
|
459
443
|
def shift
|
460
444
|
@lineno += 1
|
461
445
|
@look_ahead -= 1 unless @look_ahead == 0
|
462
|
-
@lines.
|
446
|
+
@lines.pop
|
463
447
|
end
|
464
448
|
|
465
449
|
# Internal: Restore the line to the stack and decrement the lineno
|
466
450
|
def unshift line
|
467
451
|
@lineno -= 1
|
468
452
|
@look_ahead += 1
|
469
|
-
@lines.
|
453
|
+
@lines.push line
|
454
|
+
nil
|
470
455
|
end
|
471
456
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
457
|
+
if ::RUBY_ENGINE == 'jruby'
|
458
|
+
# Internal: Restore the lines to the stack and decrement the lineno
|
459
|
+
def unshift_all lines_to_restore
|
460
|
+
@lineno -= lines_to_restore.size
|
461
|
+
@look_ahead += lines_to_restore.size
|
462
|
+
if lines_to_restore.respond_to? :reverse
|
463
|
+
@lines.push(*lines_to_restore.reverse)
|
464
|
+
else
|
465
|
+
lines_to_restore.reverse_each {|it| @lines.push it }
|
466
|
+
end
|
467
|
+
nil
|
468
|
+
end
|
469
|
+
else
|
470
|
+
# Internal: Restore the lines to the stack and decrement the lineno
|
471
|
+
def unshift_all lines_to_restore
|
472
|
+
@lineno -= lines_to_restore.size
|
473
|
+
@look_ahead += lines_to_restore.size
|
474
|
+
@lines.push(*lines_to_restore.reverse)
|
475
|
+
nil
|
476
|
+
end
|
477
477
|
end
|
478
478
|
|
479
479
|
def cursor
|
@@ -516,12 +516,12 @@ class Reader
|
|
516
516
|
#
|
517
517
|
# Returns A copy of the String Array of lines remaining in this Reader
|
518
518
|
def lines
|
519
|
-
@lines.
|
519
|
+
@lines.reverse
|
520
520
|
end
|
521
521
|
|
522
522
|
# Public: Get a copy of the remaining lines managed by this Reader joined as a String
|
523
523
|
def string
|
524
|
-
@lines.join LF
|
524
|
+
@lines.reverse.join LF
|
525
525
|
end
|
526
526
|
|
527
527
|
# Public: Get the source lines for this Reader joined as a String
|
@@ -570,17 +570,17 @@ class Reader
|
|
570
570
|
#
|
571
571
|
# data - A String Array or String of source data to be normalized.
|
572
572
|
# opts - A Hash of options to control how lines are prepared.
|
573
|
-
# :normalize - Enables line normalization, which coerces the encoding to UTF-8 and removes trailing whitespace
|
574
|
-
# (optional,
|
573
|
+
# :normalize - Enables line normalization, which coerces the encoding to UTF-8 and removes trailing whitespace;
|
574
|
+
# :rstrip removes all trailing whitespace; :chomp removes trailing newline only (optional, not set).
|
575
575
|
#
|
576
576
|
# Returns A String Array of source lines. If the source data is an Array, this method returns a copy.
|
577
577
|
def prepare_lines data, opts = {}
|
578
|
-
if opts[:normalize]
|
579
|
-
::Array === data ? (Helpers.prepare_source_array data) : (Helpers.prepare_source_string data)
|
578
|
+
if (normalize = opts[:normalize])
|
579
|
+
::Array === data ? (Helpers.prepare_source_array data, normalize != :chomp) : (Helpers.prepare_source_string data, normalize != :chomp)
|
580
580
|
elsif ::Array === data
|
581
581
|
data.drop 0
|
582
582
|
elsif data
|
583
|
-
data.split LF, -1
|
583
|
+
data.chomp.split LF, -1
|
584
584
|
else
|
585
585
|
[]
|
586
586
|
end
|
@@ -689,6 +689,7 @@ class PreprocessorReader < Reader
|
|
689
689
|
@path = (path ||= ::File.basename file)
|
690
690
|
# only process lines in AsciiDoc files
|
691
691
|
if (@process_lines = file.end_with?(*ASCIIDOC_EXTENSIONS.keys))
|
692
|
+
# NOTE registering the include with a nil value tracks it while not making it visible to interdocument xrefs
|
692
693
|
@includes[path.slice 0, (path.rindex '.')] = attributes['partial-option'] ? nil : true
|
693
694
|
end
|
694
695
|
else
|
@@ -696,6 +697,7 @@ class PreprocessorReader < Reader
|
|
696
697
|
# we don't know what file type we have, so assume AsciiDoc
|
697
698
|
@process_lines = true
|
698
699
|
if (@path = path)
|
700
|
+
# NOTE registering the include with a nil value tracks it while not making it visible to interdocument xrefs
|
699
701
|
@includes[Helpers.rootname path] = attributes['partial-option'] ? nil : true
|
700
702
|
else
|
701
703
|
@path = '<stdin>'
|
@@ -717,21 +719,16 @@ class PreprocessorReader < Reader
|
|
717
719
|
end
|
718
720
|
|
719
721
|
# effectively fill the buffer
|
720
|
-
if (@lines = prepare_lines data, normalize:
|
722
|
+
if (@lines = prepare_lines data, normalize: @process_lines || :chomp, condense: false, indent: attributes['indent']).empty?
|
721
723
|
pop_include
|
722
724
|
else
|
723
725
|
# FIXME we eventually want to handle leveloffset without affecting the lines
|
724
726
|
if attributes.key? 'leveloffset'
|
725
|
-
@lines.
|
726
|
-
|
727
|
-
@lines << ''
|
728
|
-
if (old_leveloffset = @document.attr 'leveloffset')
|
729
|
-
@lines << %(:leveloffset: #{old_leveloffset})
|
730
|
-
else
|
731
|
-
@lines << ':leveloffset!:'
|
732
|
-
end
|
733
|
-
# compensate for these extra lines
|
727
|
+
@lines = [((leveloffset = @document.attr 'leveloffset') ? %(:leveloffset: #{leveloffset}) : ':leveloffset!:'), ''] + @lines.reverse + ['', %(:leveloffset: #{attributes['leveloffset']})]
|
728
|
+
# compensate for these extra lines at the top
|
734
729
|
@lineno -= 2
|
730
|
+
else
|
731
|
+
@lines.reverse!
|
735
732
|
end
|
736
733
|
|
737
734
|
# FIXME kind of a hack
|
@@ -801,14 +798,11 @@ class PreprocessorReader < Reader
|
|
801
798
|
result = super
|
802
799
|
|
803
800
|
# QUESTION should this work for AsciiDoc table cell content? Currently it does not.
|
804
|
-
if @document && @document.attributes['skip-front-matter']
|
805
|
-
|
806
|
-
@document.attributes['front-matter'] = front_matter.join LF
|
807
|
-
end
|
801
|
+
if @document && @document.attributes['skip-front-matter'] && (front_matter = skip_front_matter! result)
|
802
|
+
@document.attributes['front-matter'] = front_matter.join LF
|
808
803
|
end
|
809
804
|
|
810
805
|
if opts.fetch :condense, true
|
811
|
-
result.shift && @lineno += 1 while (first = result[0]) && first.empty?
|
812
806
|
result.pop while (last = result[-1]) && last.empty?
|
813
807
|
end
|
814
808
|
|
@@ -955,11 +949,12 @@ class PreprocessorReader < Reader
|
|
955
949
|
if no_target
|
956
950
|
# the text in brackets must match a conditional expression
|
957
951
|
if text && EvalExpressionRx =~ text.strip
|
952
|
+
# NOTE assignments must happen before call to resolve_expr_val for compatibility with Opal
|
958
953
|
lhs = $1
|
954
|
+
# regex enforces a restricted set of math-related operations (==, !=, <=, >=, <, >)
|
959
955
|
op = $2
|
960
956
|
rhs = $3
|
961
|
-
|
962
|
-
skip = ((resolve_expr_val lhs).send op, (resolve_expr_val rhs)) ? false : true
|
957
|
+
skip = ((resolve_expr_val lhs).send op, (resolve_expr_val rhs)) ? false : true rescue true
|
963
958
|
else
|
964
959
|
logger.error message_with_context %(malformed preprocessor directive - #{text ? 'invalid expression' : 'missing expression'}: ifeval::[#{text}]), source_location: cursor
|
965
960
|
return true
|
@@ -1049,10 +1044,11 @@ class PreprocessorReader < Reader
|
|
1049
1044
|
|
1050
1045
|
parsed_attrs = doc.parse_attributes attrlist, [], sub_input: true
|
1051
1046
|
inc_path, target_type, relpath = resolve_include_path expanded_target, attrlist, parsed_attrs
|
1052
|
-
|
1047
|
+
case target_type
|
1048
|
+
when :file
|
1053
1049
|
reader = ::File.method :open
|
1054
1050
|
read_mode = FILE_READ_MODE
|
1055
|
-
|
1051
|
+
when :uri
|
1056
1052
|
reader = ::OpenURI.method :open_uri
|
1057
1053
|
read_mode = URI_READ_MODE
|
1058
1054
|
else
|
@@ -1060,14 +1056,20 @@ class PreprocessorReader < Reader
|
|
1060
1056
|
return inc_path
|
1061
1057
|
end
|
1062
1058
|
|
1059
|
+
if (enc = parsed_attrs['encoding']) && (::Encoding.find enc rescue nil)
|
1060
|
+
(read_mode_params = read_mode.split ':')[1] = enc
|
1061
|
+
read_mode = read_mode_params.join ':'
|
1062
|
+
end unless RUBY_ENGINE_OPAL
|
1063
|
+
|
1063
1064
|
inc_linenos = inc_tags = nil
|
1065
|
+
# NOTE attrlist is nil if missing from include directive
|
1064
1066
|
if attrlist
|
1065
1067
|
if parsed_attrs.key? 'lines'
|
1066
1068
|
inc_linenos = []
|
1067
1069
|
(split_delimited_value parsed_attrs['lines']).each do |linedef|
|
1068
1070
|
if linedef.include? '..'
|
1069
1071
|
from, _, to = linedef.partition '..'
|
1070
|
-
inc_linenos += (to.empty? || (to = to.to_i) < 0) ? [from.to_i,
|
1072
|
+
inc_linenos += (to.empty? || (to = to.to_i) < 0) ? [from.to_i, ::Float::INFINITY] : (from.to_i..to).to_a
|
1071
1073
|
else
|
1072
1074
|
inc_linenos << linedef.to_i
|
1073
1075
|
end
|
@@ -1123,17 +1125,23 @@ class PreprocessorReader < Reader
|
|
1123
1125
|
push_include inc_lines, inc_path, relpath, inc_offset, parsed_attrs
|
1124
1126
|
end
|
1125
1127
|
elsif inc_tags
|
1126
|
-
inc_lines, inc_offset, inc_lineno, tag_stack,
|
1128
|
+
inc_lines, inc_offset, inc_lineno, tag_stack, tags_selected, active_tag = [], nil, 0, [], ::Set.new, nil
|
1127
1129
|
if inc_tags.key? '**'
|
1130
|
+
select = base_select = inc_tags.delete '**'
|
1128
1131
|
if inc_tags.key? '*'
|
1129
|
-
select = base_select = inc_tags.delete '**'
|
1130
1132
|
wildcard = inc_tags.delete '*'
|
1133
|
+
elsif !select && inc_tags.values.first == false
|
1134
|
+
wildcard = true
|
1135
|
+
end
|
1136
|
+
elsif inc_tags.key? '*'
|
1137
|
+
if inc_tags.keys.first == '*'
|
1138
|
+
select = base_select = !(wildcard = inc_tags.delete '*')
|
1131
1139
|
else
|
1132
|
-
select = base_select =
|
1140
|
+
select = base_select = false
|
1141
|
+
wildcard = inc_tags.delete '*'
|
1133
1142
|
end
|
1134
1143
|
else
|
1135
1144
|
select = base_select = !(inc_tags.value? true)
|
1136
|
-
wildcard = inc_tags.delete '*'
|
1137
1145
|
end
|
1138
1146
|
begin
|
1139
1147
|
reader.call inc_path, read_mode do |f|
|
@@ -1148,7 +1156,7 @@ class PreprocessorReader < Reader
|
|
1148
1156
|
active_tag, select = tag_stack.empty? ? [nil, base_select] : tag_stack[-1]
|
1149
1157
|
elsif inc_tags.key? this_tag
|
1150
1158
|
include_cursor = create_include_cursor inc_path, expanded_target, inc_lineno
|
1151
|
-
if (idx = tag_stack.rindex {|key
|
1159
|
+
if (idx = tag_stack.rindex {|key,| key == this_tag })
|
1152
1160
|
idx == 0 ? tag_stack.shift : (tag_stack.delete_at idx)
|
1153
1161
|
logger.warn message_with_context %(mismatched end tag (expected '#{active_tag}' but found '#{this_tag}') at line #{inc_lineno} of include #{target_type}: #{inc_path}), source_location: cursor, include_location: include_cursor
|
1154
1162
|
else
|
@@ -1156,9 +1164,9 @@ class PreprocessorReader < Reader
|
|
1156
1164
|
end
|
1157
1165
|
end
|
1158
1166
|
elsif inc_tags.key? this_tag
|
1159
|
-
|
1167
|
+
tags_selected << this_tag if (select = inc_tags[this_tag])
|
1160
1168
|
# QUESTION should we prevent tag from being selected when enclosing tag is excluded?
|
1161
|
-
tag_stack << [(active_tag = this_tag),
|
1169
|
+
tag_stack << [(active_tag = this_tag), select, inc_lineno]
|
1162
1170
|
elsif !wildcard.nil?
|
1163
1171
|
select = active_tag && !select ? false : wildcard
|
1164
1172
|
tag_stack << [(active_tag = this_tag), select, inc_lineno]
|
@@ -1179,12 +1187,12 @@ class PreprocessorReader < Reader
|
|
1179
1187
|
logger.warn message_with_context %(detected unclosed tag '#{tag_name}' starting at line #{tag_lineno} of include #{target_type}: #{inc_path}), source_location: cursor, include_location: (create_include_cursor inc_path, expanded_target, tag_lineno)
|
1180
1188
|
end
|
1181
1189
|
end
|
1182
|
-
unless (missing_tags = inc_tags.keys -
|
1190
|
+
unless (missing_tags = inc_tags.keep_if {|_, v| v }.keys - tags_selected.to_a).empty?
|
1183
1191
|
logger.warn message_with_context %(tag#{missing_tags.size > 1 ? 's' : ''} '#{missing_tags.join ', '}' not found in include #{target_type}: #{inc_path}), source_location: cursor
|
1184
1192
|
end
|
1185
1193
|
shift
|
1186
1194
|
if inc_offset
|
1187
|
-
parsed_attrs['partial-option'] = '' unless base_select && wildcard && inc_tags.empty?
|
1195
|
+
parsed_attrs['partial-option'] = '' unless base_select && wildcard != false && inc_tags.empty?
|
1188
1196
|
# FIXME not accounting for skipped lines in reader line numbering
|
1189
1197
|
push_include inc_lines, inc_path, relpath, inc_offset, parsed_attrs
|
1190
1198
|
end
|
@@ -1255,7 +1263,7 @@ class PreprocessorReader < Reader
|
|
1255
1263
|
end
|
1256
1264
|
|
1257
1265
|
def pop_include
|
1258
|
-
|
1266
|
+
unless @include_stack.empty?
|
1259
1267
|
@lines, @file, @dir, @path, @lineno, @maxdepth, @process_lines = @include_stack.pop
|
1260
1268
|
# FIXME kind of a hack
|
1261
1269
|
#Document::AttributeEntry.new('infile', @file).save_to_next_block @document
|
data/lib/asciidoctor/rx.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Asciidoctor
|
2
3
|
# A collection of regular expression constants used by the parser. (For speed, these are not defined in the Rx module,
|
3
4
|
# but rather directly in the Asciidoctor module).
|
@@ -269,7 +270,7 @@ module Asciidoctor
|
|
269
270
|
#
|
270
271
|
# NOTE we only have to check as far as the blank character because we know it means non-whitespace follows.
|
271
272
|
# IMPORTANT if this regexp does not agree with the regexp for each list type, the parser will hang.
|
272
|
-
AnyListRx = %r(^(?:[ \t]*(?:-|\*\**|\.\.*|\u2022|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!//[^/])[ \t]*[^ \t]#{CC_ANY}*?(?::::{0,2}|;;)(?:$|[ \t])
|
273
|
+
AnyListRx = %r(^(?:[ \t]*(?:-|\*\**|\.\.*|\u2022|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!//[^/])[ \t]*[^ \t]#{CC_ANY}*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t]))
|
273
274
|
|
274
275
|
# Matches an unordered list item (one level for hyphens, up to 5 levels for asterisks).
|
275
276
|
#
|
@@ -406,7 +407,7 @@ module Asciidoctor
|
|
406
407
|
# gist::123456[]
|
407
408
|
#
|
408
409
|
#--
|
409
|
-
# NOTE we've relaxed the match for target to
|
410
|
+
# NOTE we've relaxed the match for target to accommodate the short format (e.g., name::[attrlist])
|
410
411
|
CustomBlockMacroRx = /^(#{CG_WORD}[#{CC_WORD}-]*)::(|\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
|
411
412
|
|
412
413
|
# Matches an image, video or audio block macro.
|
@@ -469,7 +470,7 @@ module Asciidoctor
|
|
469
470
|
# footnoteref:[id,text] (legacy)
|
470
471
|
# footnoteref:[id] (legacy)
|
471
472
|
#
|
472
|
-
InlineFootnoteMacroRx =
|
473
|
+
InlineFootnoteMacroRx = %r(\\?footnote(?:(ref):|:([#{CC_WORD}-]+)?)\[(?:|(#{CC_ALL}*?[^\\]))\](?!</a>))m
|
473
474
|
|
474
475
|
# Matches an image or icon inline macro.
|
475
476
|
#
|
@@ -514,9 +515,10 @@ module Asciidoctor
|
|
514
515
|
# https://github.com[GitHub]
|
515
516
|
# <https://github.com>
|
516
517
|
# link:https://github.com[]
|
518
|
+
# "https://github.com[]"
|
517
519
|
#
|
518
520
|
# FIXME revisit! the main issue is we need different rules for implicit vs explicit
|
519
|
-
InlineLinkRx = %r((^|link:|#{CG_BLANK}|<|[>\(\)\[\];])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*([^\s.,\[\]<]))(?:\[(|#{CC_ALL}*?[^\\])\])?)m
|
521
|
+
InlineLinkRx = %r((^|link:|#{CG_BLANK}|<|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*([^\s.,\[\]<]))(?:\[(|#{CC_ALL}*?[^\\])\])?)m
|
520
522
|
|
521
523
|
# Match a link or e-mail inline macro.
|
522
524
|
#
|
@@ -551,7 +553,7 @@ module Asciidoctor
|
|
551
553
|
# menu:View[Page Style > No Style]
|
552
554
|
# menu:View[Page Style, No Style]
|
553
555
|
#
|
554
|
-
InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))
|
556
|
+
InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))\]/m
|
555
557
|
|
556
558
|
# Matches an implicit menu inline macro.
|
557
559
|
#
|
@@ -591,7 +593,7 @@ module Asciidoctor
|
|
591
593
|
# $$text$$
|
592
594
|
# pass:quotes[text]
|
593
595
|
#
|
594
|
-
# NOTE we have to support an empty pass:[] for compatibility with AsciiDoc
|
596
|
+
# NOTE we have to support an empty pass:[] for compatibility with AsciiDoc.py
|
595
597
|
InlinePassMacroRx = /(?:(?:(\\?)\[([^\]]+)\])?(\\{0,2})(\+\+\+?|\$\$)(#{CC_ALL}*?)\4|(\\?)pass:([a-z]+(?:,[a-z-]+)*)?\[(|#{CC_ALL}*?[^\\])\])/m
|
596
598
|
|
597
599
|
# Matches an xref (i.e., cross-reference) inline macro, which may span multiple lines.
|
@@ -610,7 +612,7 @@ module Asciidoctor
|
|
610
612
|
# Matches a trailing + preceded by at least one space character,
|
611
613
|
# which forces a hard line break (<br> tag in HTML output).
|
612
614
|
#
|
613
|
-
# NOTE AsciiDoc
|
615
|
+
# NOTE AsciiDoc.py allows + to be preceded by TAB; Asciidoctor does not
|
614
616
|
#
|
615
617
|
# Examples
|
616
618
|
#
|
data/lib/asciidoctor/section.rb
CHANGED
@@ -64,6 +64,13 @@ class Section < AbstractBlock
|
|
64
64
|
Section.generate_id title, @document
|
65
65
|
end
|
66
66
|
|
67
|
+
# Public: Check whether this Section has any child Section objects.
|
68
|
+
#
|
69
|
+
# Returns A [Boolean] to indicate whether this Section has child Section objects
|
70
|
+
def sections?
|
71
|
+
@next_section_index > 0
|
72
|
+
end
|
73
|
+
|
67
74
|
# Public: Get the section number for the current Section
|
68
75
|
#
|
69
76
|
# The section number is a dot-separated String that uniquely describes the position of this
|