asciidoctor 2.0.15 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +38 -2
- data/LICENSE +1 -1
- data/README-de.adoc +3 -3
- data/README-fr.adoc +3 -3
- data/README-jp.adoc +3 -3
- data/README-zh_CN.adoc +3 -3
- data/README.adoc +2 -2
- data/asciidoctor.gemspec +1 -8
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/stylesheets/asciidoctor-default.css +50 -48
- data/lib/asciidoctor.rb +7 -7
- data/lib/asciidoctor/abstract_block.rb +4 -4
- data/lib/asciidoctor/abstract_node.rb +9 -8
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +0 -1
- data/lib/asciidoctor/cli/options.rb +22 -22
- data/lib/asciidoctor/convert.rb +1 -0
- data/lib/asciidoctor/converter.rb +5 -3
- data/lib/asciidoctor/converter/docbook5.rb +20 -22
- data/lib/asciidoctor/converter/html5.rb +70 -60
- data/lib/asciidoctor/converter/manpage.rb +61 -52
- data/lib/asciidoctor/converter/template.rb +11 -12
- data/lib/asciidoctor/document.rb +22 -37
- data/lib/asciidoctor/extensions.rb +10 -10
- data/lib/asciidoctor/list.rb +2 -6
- data/lib/asciidoctor/load.rb +10 -9
- data/lib/asciidoctor/logging.rb +10 -8
- data/lib/asciidoctor/parser.rb +122 -141
- data/lib/asciidoctor/path_resolver.rb +3 -3
- data/lib/asciidoctor/reader.rb +67 -68
- data/lib/asciidoctor/rx.rb +2 -1
- data/lib/asciidoctor/substitutors.rb +97 -99
- data/lib/asciidoctor/syntax_highlighter.rb +8 -11
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +2 -1
- data/lib/asciidoctor/table.rb +17 -19
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +8 -9
- data/man/asciidoctor.adoc +7 -6
- metadata +7 -61
@@ -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
|
data/lib/asciidoctor/reader.rb
CHANGED
@@ -59,8 +59,7 @@ class Reader
|
|
59
59
|
end
|
60
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
|
@@ -576,8 +576,7 @@ class Reader
|
|
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
578
|
if (normalize = opts[:normalize])
|
579
|
-
|
580
|
-
::Array === data ? (Helpers.prepare_source_array data, trim_end) : (Helpers.prepare_source_string data, trim_end)
|
579
|
+
::Array === data ? (Helpers.prepare_source_array data, normalize != :chomp) : (Helpers.prepare_source_string data, normalize != :chomp)
|
581
580
|
elsif ::Array === data
|
582
581
|
data.drop 0
|
583
582
|
elsif data
|
@@ -725,16 +724,11 @@ class PreprocessorReader < Reader
|
|
725
724
|
else
|
726
725
|
# FIXME we eventually want to handle leveloffset without affecting the lines
|
727
726
|
if attributes.key? 'leveloffset'
|
728
|
-
@lines.
|
729
|
-
|
730
|
-
@lines << ''
|
731
|
-
if (old_leveloffset = @document.attr 'leveloffset')
|
732
|
-
@lines << %(:leveloffset: #{old_leveloffset})
|
733
|
-
else
|
734
|
-
@lines << ':leveloffset!:'
|
735
|
-
end
|
736
|
-
# 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
|
737
729
|
@lineno -= 2
|
730
|
+
else
|
731
|
+
@lines.reverse!
|
738
732
|
end
|
739
733
|
|
740
734
|
# FIXME kind of a hack
|
@@ -804,10 +798,8 @@ class PreprocessorReader < Reader
|
|
804
798
|
result = super
|
805
799
|
|
806
800
|
# QUESTION should this work for AsciiDoc table cell content? Currently it does not.
|
807
|
-
if @document && @document.attributes['skip-front-matter']
|
808
|
-
|
809
|
-
@document.attributes['front-matter'] = front_matter.join LF
|
810
|
-
end
|
801
|
+
if @document && @document.attributes['skip-front-matter'] && (front_matter = skip_front_matter! result)
|
802
|
+
@document.attributes['front-matter'] = front_matter.join LF
|
811
803
|
end
|
812
804
|
|
813
805
|
if opts.fetch :condense, true
|
@@ -957,11 +949,12 @@ class PreprocessorReader < Reader
|
|
957
949
|
if no_target
|
958
950
|
# the text in brackets must match a conditional expression
|
959
951
|
if text && EvalExpressionRx =~ text.strip
|
952
|
+
# NOTE assignments must happen before call to resolve_expr_val for compatiblity with Opal
|
960
953
|
lhs = $1
|
954
|
+
# regex enforces a restricted set of math-related operations (==, !=, <=, >=, <, >)
|
961
955
|
op = $2
|
962
956
|
rhs = $3
|
963
|
-
|
964
|
-
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
|
965
958
|
else
|
966
959
|
logger.error message_with_context %(malformed preprocessor directive - #{text ? 'invalid expression' : 'missing expression'}: ifeval::[#{text}]), source_location: cursor
|
967
960
|
return true
|
@@ -1051,10 +1044,11 @@ class PreprocessorReader < Reader
|
|
1051
1044
|
|
1052
1045
|
parsed_attrs = doc.parse_attributes attrlist, [], sub_input: true
|
1053
1046
|
inc_path, target_type, relpath = resolve_include_path expanded_target, attrlist, parsed_attrs
|
1054
|
-
|
1047
|
+
case target_type
|
1048
|
+
when :file
|
1055
1049
|
reader = ::File.method :open
|
1056
1050
|
read_mode = FILE_READ_MODE
|
1057
|
-
|
1051
|
+
when :uri
|
1058
1052
|
reader = ::OpenURI.method :open_uri
|
1059
1053
|
read_mode = URI_READ_MODE
|
1060
1054
|
else
|
@@ -1075,7 +1069,7 @@ class PreprocessorReader < Reader
|
|
1075
1069
|
(split_delimited_value parsed_attrs['lines']).each do |linedef|
|
1076
1070
|
if linedef.include? '..'
|
1077
1071
|
from, _, to = linedef.partition '..'
|
1078
|
-
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
|
1079
1073
|
else
|
1080
1074
|
inc_linenos << linedef.to_i
|
1081
1075
|
end
|
@@ -1133,16 +1127,21 @@ class PreprocessorReader < Reader
|
|
1133
1127
|
elsif inc_tags
|
1134
1128
|
inc_lines, inc_offset, inc_lineno, tag_stack, tags_used, active_tag = [], nil, 0, [], ::Set.new, nil
|
1135
1129
|
if inc_tags.key? '**'
|
1130
|
+
select = base_select = inc_tags.delete '**'
|
1136
1131
|
if inc_tags.key? '*'
|
1137
|
-
select = base_select = inc_tags.delete '**'
|
1138
1132
|
wildcard = inc_tags.delete '*'
|
1139
|
-
|
1140
|
-
|
1133
|
+
elsif !select && inc_tags.values.first == false
|
1134
|
+
wildcard = true
|
1141
1135
|
end
|
1142
1136
|
elsif inc_tags.key? '*'
|
1143
|
-
|
1137
|
+
if inc_tags.keys.first == '*'
|
1138
|
+
select = base_select = !(wildcard = inc_tags.delete '*')
|
1139
|
+
else
|
1140
|
+
select = base_select = false
|
1141
|
+
wildcard = inc_tags.delete '*'
|
1142
|
+
end
|
1144
1143
|
else
|
1145
|
-
select = base_select =
|
1144
|
+
select = base_select = !(inc_tags.value? true)
|
1146
1145
|
end
|
1147
1146
|
begin
|
1148
1147
|
reader.call inc_path, read_mode do |f|
|
@@ -1193,7 +1192,7 @@ class PreprocessorReader < Reader
|
|
1193
1192
|
end
|
1194
1193
|
shift
|
1195
1194
|
if inc_offset
|
1196
|
-
parsed_attrs['partial-option'] = '' unless base_select && wildcard && inc_tags.empty?
|
1195
|
+
parsed_attrs['partial-option'] = '' unless base_select && wildcard != false && inc_tags.empty?
|
1197
1196
|
# FIXME not accounting for skipped lines in reader line numbering
|
1198
1197
|
push_include inc_lines, inc_path, relpath, inc_offset, parsed_attrs
|
1199
1198
|
end
|
@@ -1264,7 +1263,7 @@ class PreprocessorReader < Reader
|
|
1264
1263
|
end
|
1265
1264
|
|
1266
1265
|
def pop_include
|
1267
|
-
|
1266
|
+
unless @include_stack.empty?
|
1268
1267
|
@lines, @file, @dir, @path, @lineno, @maxdepth, @process_lines = @include_stack.pop
|
1269
1268
|
# FIXME kind of a hack
|
1270
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).
|
@@ -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
|
#
|
@@ -330,13 +330,13 @@ module Substitutors
|
|
330
330
|
# NOTE for convenience, map content (unparsed attrlist) to target when format is short
|
331
331
|
target ||= ext_config[:format] == :short ? content : target
|
332
332
|
end
|
333
|
-
if
|
333
|
+
if Inline === (replacement = extension.process_method[self, target, attributes])
|
334
334
|
if (inline_subs = replacement.attributes.delete 'subs') && (inline_subs = expand_subs inline_subs, 'custom inline macro')
|
335
335
|
replacement.text = apply_subs replacement.text, inline_subs
|
336
336
|
end
|
337
337
|
replacement.convert
|
338
338
|
elsif replacement
|
339
|
-
logger.info %(expected substitution value for custom inline macro to be of type Inline; got #{replacement.class}: #{match})
|
339
|
+
logger.info { %(expected substitution value for custom inline macro to be of type Inline; got #{replacement.class}: #{match}) }
|
340
340
|
replacement
|
341
341
|
else
|
342
342
|
''
|
@@ -445,23 +445,16 @@ module Substitutors
|
|
445
445
|
# indexterm:[Tigers,Big cats]
|
446
446
|
if (attrlist = normalize_text $2, true, true).include? '='
|
447
447
|
if (primary = (attrs = (AttributeList.new attrlist, self).parse)[1])
|
448
|
-
attrs['terms'] =
|
449
|
-
if (secondary = attrs[2])
|
450
|
-
terms << secondary
|
451
|
-
if (tertiary = attrs[3])
|
452
|
-
terms << tertiary
|
453
|
-
end
|
454
|
-
end
|
448
|
+
attrs['terms'] = [primary]
|
455
449
|
if (see_also = attrs['see-also'])
|
456
450
|
attrs['see-also'] = (see_also.include? ',') ? (see_also.split ',').map {|it| it.lstrip } : [see_also]
|
457
451
|
end
|
458
452
|
else
|
459
|
-
attrs = { 'terms' =>
|
453
|
+
attrs = { 'terms' => attrlist }
|
460
454
|
end
|
461
455
|
else
|
462
|
-
attrs = { 'terms' => (
|
456
|
+
attrs = { 'terms' => (split_simple_csv attrlist) }
|
463
457
|
end
|
464
|
-
#doc.register :indexterms, terms
|
465
458
|
(Inline.new self, :indexterm, nil, attributes: attrs).convert
|
466
459
|
when 'indexterm2'
|
467
460
|
# honor the escape
|
@@ -474,34 +467,33 @@ module Substitutors
|
|
474
467
|
attrs['see-also'] = (see_also.include? ',') ? (see_also.split ',').map {|it| it.lstrip } : [see_also]
|
475
468
|
end
|
476
469
|
end
|
477
|
-
#doc.register :indexterms, [term]
|
478
470
|
(Inline.new self, :indexterm, term, attributes: attrs, type: :visible).convert
|
479
471
|
else
|
480
|
-
|
472
|
+
encl_text = $3
|
481
473
|
# honor the escape
|
482
474
|
if $&.start_with? RS
|
483
475
|
# escape concealed index term, but process nested flow index term
|
484
|
-
if (
|
485
|
-
|
476
|
+
if (encl_text.start_with? '(') && (encl_text.end_with? ')')
|
477
|
+
encl_text = encl_text.slice 1, encl_text.length - 2
|
486
478
|
visible, before, after = true, '(', ')'
|
487
479
|
else
|
488
480
|
next $&.slice 1, $&.length
|
489
481
|
end
|
490
482
|
else
|
491
483
|
visible = true
|
492
|
-
if
|
493
|
-
if
|
494
|
-
|
484
|
+
if encl_text.start_with? '('
|
485
|
+
if encl_text.end_with? ')'
|
486
|
+
encl_text, visible = (encl_text.slice 1, encl_text.length - 2), false
|
495
487
|
else
|
496
|
-
|
488
|
+
encl_text, before, after = (encl_text.slice 1, encl_text.length), '(', ''
|
497
489
|
end
|
498
|
-
elsif
|
499
|
-
|
490
|
+
elsif encl_text.end_with? ')'
|
491
|
+
encl_text, before, after = encl_text.chop, '', ')'
|
500
492
|
end
|
501
493
|
end
|
502
494
|
if visible
|
503
495
|
# ((Tigers))
|
504
|
-
if (term = normalize_text
|
496
|
+
if (term = normalize_text encl_text, true).include? ';&'
|
505
497
|
if term.include? ' >> '
|
506
498
|
term, _, see = term.partition ' >> '
|
507
499
|
attrs = { 'see' => see }
|
@@ -510,12 +502,11 @@ module Substitutors
|
|
510
502
|
attrs = { 'see-also' => see_also }
|
511
503
|
end
|
512
504
|
end
|
513
|
-
#doc.register :indexterms, [term]
|
514
505
|
subbed_term = (Inline.new self, :indexterm, term, attributes: attrs, type: :visible).convert
|
515
506
|
else
|
516
507
|
# (((Tigers,Big cats)))
|
517
508
|
attrs = {}
|
518
|
-
if (terms = normalize_text
|
509
|
+
if (terms = normalize_text encl_text, true).include? ';&'
|
519
510
|
if terms.include? ' >> '
|
520
511
|
terms, _, see = terms.partition ' >> '
|
521
512
|
attrs['see'] = see
|
@@ -524,8 +515,7 @@ module Substitutors
|
|
524
515
|
attrs['see-also'] = see_also
|
525
516
|
end
|
526
517
|
end
|
527
|
-
attrs['terms'] =
|
528
|
-
#doc.register :indexterms, terms
|
518
|
+
attrs['terms'] = split_simple_csv terms
|
529
519
|
subbed_term = (Inline.new self, :indexterm, nil, attributes: attrs).convert
|
530
520
|
end
|
531
521
|
before ? %(#{before}#{subbed_term}#{after}) : subbed_term
|
@@ -545,7 +535,7 @@ module Substitutors
|
|
545
535
|
# NOTE if $4 is set, we're looking at a formal macro (e.g., https://example.org[])
|
546
536
|
if $4
|
547
537
|
prefix = '' if prefix == 'link:'
|
548
|
-
|
538
|
+
link_text = nil if (link_text = $4).empty?
|
549
539
|
else
|
550
540
|
# invalid macro syntax (link: prefix w/o trailing square brackets or enclosed in double quotes)
|
551
541
|
# FIXME we probably shouldn't even get here when the link: prefix is present; the regex is doing too much
|
@@ -553,7 +543,6 @@ module Substitutors
|
|
553
543
|
when 'link:', ?", ?'
|
554
544
|
next $&
|
555
545
|
end
|
556
|
-
text = ''
|
557
546
|
case $3
|
558
547
|
when ')', '?', '!'
|
559
548
|
target = target.chop
|
@@ -593,27 +582,37 @@ module Substitutors
|
|
593
582
|
end
|
594
583
|
|
595
584
|
attrs, link_opts = nil, { type: :link }
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
585
|
+
|
586
|
+
if link_text
|
587
|
+
new_link_text = link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
|
588
|
+
if !doc.compat_mode && (link_text.include? '=')
|
589
|
+
# NOTE if an equals sign (=) is present, extract attributes from link text
|
590
|
+
link_text, attrs = extract_attributes_from_text link_text, ''
|
591
|
+
new_link_text = link_text
|
601
592
|
link_opts[:id] = attrs['id']
|
602
593
|
end
|
603
594
|
|
604
|
-
if
|
605
|
-
|
595
|
+
if link_text.end_with? '^'
|
596
|
+
new_link_text = link_text = link_text.chop
|
606
597
|
if attrs
|
607
598
|
attrs['window'] ||= '_blank'
|
608
599
|
else
|
609
600
|
attrs = { 'window' => '_blank' }
|
610
601
|
end
|
611
602
|
end
|
612
|
-
end
|
613
603
|
|
614
|
-
|
604
|
+
if new_link_text && new_link_text.empty?
|
605
|
+
# NOTE it's not possible for the URI scheme to be bare in this case
|
606
|
+
link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
|
607
|
+
bare = true
|
608
|
+
end
|
609
|
+
else
|
615
610
|
# NOTE it's not possible for the URI scheme to be bare in this case
|
616
|
-
|
611
|
+
link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
|
612
|
+
bare = true
|
613
|
+
end
|
614
|
+
|
615
|
+
if bare
|
617
616
|
if attrs
|
618
617
|
attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
|
619
618
|
else
|
@@ -623,7 +622,7 @@ module Substitutors
|
|
623
622
|
|
624
623
|
doc.register :links, (link_opts[:target] = target)
|
625
624
|
link_opts[:attributes] = attrs if attrs
|
626
|
-
%(#{prefix}#{(Inline.new self, :anchor,
|
625
|
+
%(#{prefix}#{(Inline.new self, :anchor, link_text, link_opts).convert}#{suffix})
|
627
626
|
end
|
628
627
|
end
|
629
628
|
|
@@ -639,12 +638,12 @@ module Substitutors
|
|
639
638
|
target = $2
|
640
639
|
end
|
641
640
|
attrs, link_opts = nil, { type: :link }
|
642
|
-
unless (
|
643
|
-
|
641
|
+
unless (link_text = $3).empty?
|
642
|
+
link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
|
644
643
|
if mailto
|
645
|
-
if !doc.compat_mode && (
|
646
|
-
# NOTE if a comma (,) is present, extract attributes from text
|
647
|
-
|
644
|
+
if !doc.compat_mode && (link_text.include? ',')
|
645
|
+
# NOTE if a comma (,) is present, extract attributes from link text
|
646
|
+
link_text, attrs = extract_attributes_from_text link_text, ''
|
648
647
|
link_opts[:id] = attrs['id']
|
649
648
|
if attrs.key? 2
|
650
649
|
if attrs.key? 3
|
@@ -654,14 +653,14 @@ module Substitutors
|
|
654
653
|
end
|
655
654
|
end
|
656
655
|
end
|
657
|
-
elsif !doc.compat_mode && (
|
658
|
-
# NOTE if an equals sign (=) is present, extract attributes from text
|
659
|
-
|
656
|
+
elsif !doc.compat_mode && (link_text.include? '=')
|
657
|
+
# NOTE if an equals sign (=) is present, extract attributes from link text
|
658
|
+
link_text, attrs = extract_attributes_from_text link_text, ''
|
660
659
|
link_opts[:id] = attrs['id']
|
661
660
|
end
|
662
661
|
|
663
|
-
if
|
664
|
-
|
662
|
+
if link_text.end_with? '^'
|
663
|
+
link_text = link_text.chop
|
665
664
|
if attrs
|
666
665
|
attrs['window'] ||= '_blank'
|
667
666
|
else
|
@@ -670,17 +669,17 @@ module Substitutors
|
|
670
669
|
end
|
671
670
|
end
|
672
671
|
|
673
|
-
if
|
672
|
+
if link_text.empty?
|
674
673
|
# mailto is a special case, already processed
|
675
674
|
if mailto
|
676
|
-
|
675
|
+
link_text = mailto_text
|
677
676
|
else
|
678
677
|
if doc_attrs.key? 'hide-uri-scheme'
|
679
|
-
if (
|
680
|
-
|
678
|
+
if (link_text = target.sub UriSniffRx, '').empty?
|
679
|
+
link_text = target
|
681
680
|
end
|
682
681
|
else
|
683
|
-
|
682
|
+
link_text = target
|
684
683
|
end
|
685
684
|
if attrs
|
686
685
|
attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
|
@@ -693,7 +692,7 @@ module Substitutors
|
|
693
692
|
# QUESTION should a mailto be registered as an e-mail address?
|
694
693
|
doc.register :links, (link_opts[:target] = target)
|
695
694
|
link_opts[:attributes] = attrs if attrs
|
696
|
-
Inline.new(self, :anchor,
|
695
|
+
Inline.new(self, :anchor, link_text, link_opts).convert
|
697
696
|
end
|
698
697
|
end
|
699
698
|
|
@@ -740,15 +739,17 @@ module Substitutors
|
|
740
739
|
|
741
740
|
attrs = {}
|
742
741
|
if (refid = $1)
|
743
|
-
|
744
|
-
|
742
|
+
if refid.include? ','
|
743
|
+
refid, _, link_text = refid.partition ','
|
744
|
+
link_text = nil if (link_text = link_text.lstrip).empty?
|
745
|
+
end
|
745
746
|
else
|
746
747
|
macro = true
|
747
748
|
refid = $2
|
748
|
-
if (
|
749
|
-
|
750
|
-
# NOTE if an equals sign (=) is present, extract attributes from text
|
751
|
-
|
749
|
+
if (link_text = $3)
|
750
|
+
link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
|
751
|
+
# NOTE if an equals sign (=) is present, extract attributes from link text
|
752
|
+
link_text, attrs = extract_attributes_from_text link_text if !doc.compat_mode && (link_text.include? '=')
|
752
753
|
end
|
753
754
|
end
|
754
755
|
|
@@ -827,7 +828,7 @@ module Substitutors
|
|
827
828
|
attrs['path'] = path
|
828
829
|
attrs['fragment'] = fragment
|
829
830
|
attrs['refid'] = refid
|
830
|
-
Inline.new(self, :anchor,
|
831
|
+
Inline.new(self, :anchor, link_text, type: :xref, target: target, attributes: attrs).convert
|
831
832
|
end
|
832
833
|
end
|
833
834
|
|
@@ -839,7 +840,7 @@ module Substitutors
|
|
839
840
|
# footnoteref
|
840
841
|
if $1
|
841
842
|
if $3
|
842
|
-
id,
|
843
|
+
id, content = $3.split ',', 2
|
843
844
|
logger.warn %(found deprecated footnoteref macro: #{$&}; use footnote macro with target instead) unless doc.compat_mode
|
844
845
|
else
|
845
846
|
next $&
|
@@ -847,31 +848,31 @@ module Substitutors
|
|
847
848
|
# footnote
|
848
849
|
else
|
849
850
|
id = $2
|
850
|
-
|
851
|
+
content = $3
|
851
852
|
end
|
852
853
|
|
853
854
|
if id
|
854
855
|
if (footnote = doc.footnotes.find {|candidate| candidate.id == id })
|
855
|
-
index,
|
856
|
+
index, content = footnote.index, footnote.text
|
856
857
|
type, target, id = :xref, id, nil
|
857
|
-
elsif
|
858
|
-
|
858
|
+
elsif content
|
859
|
+
content = restore_passthroughs(normalize_text content, true, true)
|
859
860
|
index = doc.counter('footnote-number')
|
860
|
-
doc.register(:footnotes, Document::Footnote.new(index, id,
|
861
|
+
doc.register(:footnotes, Document::Footnote.new(index, id, content))
|
861
862
|
type, target = :ref, nil
|
862
863
|
else
|
863
864
|
logger.warn %(invalid footnote reference: #{id})
|
864
|
-
type, target,
|
865
|
+
type, target, content, id = :xref, id, id, nil
|
865
866
|
end
|
866
|
-
elsif
|
867
|
-
|
867
|
+
elsif content
|
868
|
+
content = restore_passthroughs(normalize_text content, true, true)
|
868
869
|
index = doc.counter('footnote-number')
|
869
|
-
doc.register(:footnotes, Document::Footnote.new(index, id,
|
870
|
+
doc.register(:footnotes, Document::Footnote.new(index, id, content))
|
870
871
|
type = target = nil
|
871
872
|
else
|
872
873
|
next $&
|
873
874
|
end
|
874
|
-
Inline.new(self, :footnote,
|
875
|
+
Inline.new(self, :footnote, content, attributes: { 'index' => index }, id: id, target: target, type: type).convert
|
875
876
|
end
|
876
877
|
end
|
877
878
|
|
@@ -948,8 +949,9 @@ module Substitutors
|
|
948
949
|
|
949
950
|
doc_attrs = @document.attributes
|
950
951
|
syntax_hl_name = syntax_hl.name
|
951
|
-
if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil)
|
952
|
-
|
952
|
+
if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil) &&
|
953
|
+
(start_line_number = (attr 'start', 1).to_i) < 1
|
954
|
+
start_line_number = 1
|
953
955
|
end
|
954
956
|
highlight_lines = resolve_lines_to_highlight source, (attr 'highlight'), start_line_number if attr? 'highlight'
|
955
957
|
|
@@ -986,7 +988,7 @@ module Substitutors
|
|
986
988
|
negate = true
|
987
989
|
end
|
988
990
|
if (delim = (entry.include? '..') ? '..' : ((entry.include? '-') ? '-' : nil))
|
989
|
-
from,
|
991
|
+
from, _, to = entry.partition delim
|
990
992
|
to = (source.count LF) + 1 if to.empty? || (to = to.to_i) < 0
|
991
993
|
if negate
|
992
994
|
lines -= (from.to_i..to).to_a
|
@@ -1241,9 +1243,10 @@ module Substitutors
|
|
1241
1243
|
#
|
1242
1244
|
# Returns a Symbol Array of substitutions to pass to apply_subs or nil if no substitutions were resolved.
|
1243
1245
|
def expand_subs subs, subject = nil
|
1244
|
-
|
1246
|
+
case subs
|
1247
|
+
when ::Symbol
|
1245
1248
|
subs == :none ? nil : SUB_GROUPS[subs] || [subs]
|
1246
|
-
|
1249
|
+
when ::Array
|
1247
1250
|
expanded_subs = []
|
1248
1251
|
subs.each do |key|
|
1249
1252
|
unless key == :none
|
@@ -1481,26 +1484,21 @@ module Substitutors
|
|
1481
1484
|
if (str = str.strip).empty?
|
1482
1485
|
{}
|
1483
1486
|
elsif (str.start_with? '.', '#') && Compliance.shorthand_property_syntax
|
1484
|
-
|
1485
|
-
|
1486
|
-
if
|
1487
|
-
|
1487
|
+
before, _, after = str.partition '#'
|
1488
|
+
attrs = {}
|
1489
|
+
if after.empty?
|
1490
|
+
attrs['role'] = (before.tr '.', ' ').lstrip if before.length > 1
|
1488
1491
|
else
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1498
|
-
roles.concat more_roles
|
1492
|
+
id, _, roles = after.partition '.'
|
1493
|
+
attrs['id'] = id unless id.empty?
|
1494
|
+
if roles.empty?
|
1495
|
+
attrs['role'] = (before.tr '.', ' ').lstrip if before.length > 1
|
1496
|
+
elsif before.length > 1
|
1497
|
+
attrs['role'] = ((before + '.' + roles).tr '.', ' ').lstrip
|
1498
|
+
else
|
1499
|
+
attrs['role'] = roles.tr '.', ' '
|
1500
|
+
end
|
1499
1501
|
end
|
1500
|
-
|
1501
|
-
attrs = {}
|
1502
|
-
attrs['id'] = id if id
|
1503
|
-
attrs['role'] = roles.join ' ' unless roles.empty?
|
1504
1502
|
attrs
|
1505
1503
|
else
|
1506
1504
|
{ 'role' => str }
|
@@ -1534,7 +1532,7 @@ module Substitutors
|
|
1534
1532
|
case c
|
1535
1533
|
when ','
|
1536
1534
|
if quote_open
|
1537
|
-
accum
|
1535
|
+
accum += c
|
1538
1536
|
else
|
1539
1537
|
values << accum.strip
|
1540
1538
|
accum = ''
|
@@ -1542,7 +1540,7 @@ module Substitutors
|
|
1542
1540
|
when '"'
|
1543
1541
|
quote_open = !quote_open
|
1544
1542
|
else
|
1545
|
-
accum
|
1543
|
+
accum += c
|
1546
1544
|
end
|
1547
1545
|
end
|
1548
1546
|
values << accum.strip
|