asciidoctor 2.0.7 → 2.0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +169 -7
- data/LICENSE +2 -1
- data/README-de.adoc +5 -15
- data/README-fr.adoc +4 -14
- data/README-jp.adoc +234 -186
- data/README-zh_CN.adoc +7 -17
- data/README.adoc +18 -18
- data/asciidoctor.gemspec +4 -4
- data/data/locale/attributes-ar.adoc +4 -3
- 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 +6 -5
- data/data/locale/attributes-hu.adoc +4 -3
- data/data/locale/attributes-id.adoc +4 -3
- data/data/locale/attributes-it.adoc +4 -3
- 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 +4 -3
- 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-tr.adoc +4 -3
- data/data/locale/attributes-uk.adoc +6 -5
- data/data/locale/attributes-zh_CN.adoc +4 -3
- data/data/locale/attributes-zh_TW.adoc +4 -3
- data/data/stylesheets/asciidoctor-default.css +33 -30
- data/lib/asciidoctor.rb +89 -791
- data/lib/asciidoctor/abstract_block.rb +19 -11
- data/lib/asciidoctor/abstract_node.rb +21 -15
- data/lib/asciidoctor/attribute_list.rb +59 -67
- data/lib/asciidoctor/cli/invoker.rb +2 -0
- data/lib/asciidoctor/cli/options.rb +3 -3
- data/lib/asciidoctor/convert.rb +167 -162
- data/lib/asciidoctor/converter.rb +14 -13
- data/lib/asciidoctor/converter/docbook5.rb +10 -26
- data/lib/asciidoctor/converter/html5.rb +62 -43
- data/lib/asciidoctor/converter/manpage.rb +13 -12
- data/lib/asciidoctor/converter/template.rb +6 -3
- data/lib/asciidoctor/document.rb +25 -41
- data/lib/asciidoctor/extensions.rb +3 -3
- data/lib/asciidoctor/helpers.rb +38 -39
- data/lib/asciidoctor/inline.rb +1 -1
- data/lib/asciidoctor/load.rb +101 -101
- data/lib/asciidoctor/parser.rb +30 -25
- data/lib/asciidoctor/path_resolver.rb +35 -25
- data/lib/asciidoctor/reader.rb +14 -7
- data/lib/asciidoctor/rx.rb +722 -0
- data/lib/asciidoctor/substitutors.rb +61 -39
- data/lib/asciidoctor/syntax_highlighter.rb +22 -8
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +1 -1
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +12 -4
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -3
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +15 -7
- data/lib/asciidoctor/table.rb +52 -23
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +6 -6
- data/man/asciidoctor.adoc +4 -3
- metadata +10 -9
data/lib/asciidoctor/parser.rb
CHANGED
@@ -433,8 +433,10 @@ class Parser
|
|
433
433
|
# is treated like an untitled section
|
434
434
|
elsif preamble # implies parent == document
|
435
435
|
if preamble.blocks?
|
436
|
+
if book || document.blocks[1] || !Compliance.unwrap_standalone_preamble
|
437
|
+
preamble.source_location = preamble.blocks[0].source_location if document.sourcemap
|
436
438
|
# unwrap standalone preamble (i.e., document has no sections) except for books, if permissible
|
437
|
-
|
439
|
+
else
|
438
440
|
document.blocks.shift
|
439
441
|
while (child_block = preamble.blocks.shift)
|
440
442
|
document << child_block
|
@@ -596,7 +598,8 @@ class Parser
|
|
596
598
|
end
|
597
599
|
end
|
598
600
|
if blk_ctx == :image
|
599
|
-
document.register :images,
|
601
|
+
document.register :images, target
|
602
|
+
attributes['imagesdir'] = doc_attrs['imagesdir']
|
600
603
|
# NOTE style is the value of the first positional attribute in the block attribute line
|
601
604
|
attributes['alt'] ||= style || (attributes['default-alt'] = Helpers.basename(target, true).tr('_-', ' '))
|
602
605
|
unless (scaledwidth = attributes.delete 'scaledwidth').nil_or_empty?
|
@@ -857,6 +860,7 @@ class Parser
|
|
857
860
|
when :literal
|
858
861
|
block = build_block(block_context, :verbatim, terminator, parent, reader, attributes)
|
859
862
|
when :example
|
863
|
+
attributes['caption'] = '' if attributes['collapsible-option']
|
860
864
|
block = build_block(block_context, :compound, terminator, parent, reader, attributes)
|
861
865
|
when :quote, :verse
|
862
866
|
AttributeList.rekey(attributes, [nil, 'attribution', 'citetitle'])
|
@@ -898,7 +902,7 @@ class Parser
|
|
898
902
|
# FIXME title and caption should be assigned when block is constructed (though we need to handle all cases)
|
899
903
|
if attributes['title']
|
900
904
|
block.title = block_title = attributes.delete 'title'
|
901
|
-
if (caption_attr_name =
|
905
|
+
if (caption_attr_name = CAPTION_ATTRIBUTE_NAMES[block.context]) && document.attributes[caption_attr_name]
|
902
906
|
block.assign_caption (attributes.delete 'caption')
|
903
907
|
end
|
904
908
|
end
|
@@ -1147,14 +1151,16 @@ class Parser
|
|
1147
1151
|
def self.catalog_inline_anchors text, block, document, reader
|
1148
1152
|
text.scan InlineAnchorScanRx do
|
1149
1153
|
if (id = $1)
|
1150
|
-
if (reftext = $2)
|
1151
|
-
next if (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
|
1152
|
-
end
|
1154
|
+
next if (reftext = $2) && (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
|
1153
1155
|
else
|
1154
1156
|
id = $3
|
1155
1157
|
if (reftext = $4)
|
1156
|
-
|
1157
|
-
|
1158
|
+
if reftext.include? ']'
|
1159
|
+
reftext = reftext.gsub '\]', ']'
|
1160
|
+
reftext = document.sub_attributes reftext if reftext.include? ATTR_REF_HEAD
|
1161
|
+
elsif (reftext.include? ATTR_REF_HEAD) && (reftext = document.sub_attributes reftext).empty?
|
1162
|
+
next
|
1163
|
+
end
|
1158
1164
|
end
|
1159
1165
|
end
|
1160
1166
|
unless document.register :refs, [id, (Inline.new block, :anchor, reftext, type: :ref, id: id)]
|
@@ -1532,7 +1538,7 @@ class Parser
|
|
1532
1538
|
|
1533
1539
|
reader.unshift_line this_line if this_line
|
1534
1540
|
|
1535
|
-
buffer
|
1541
|
+
buffer[detached_continuation] = '' if detached_continuation
|
1536
1542
|
|
1537
1543
|
until buffer.empty?
|
1538
1544
|
# strip trailing blank lines to prevent empty blocks
|
@@ -2118,6 +2124,8 @@ class Parser
|
|
2118
2124
|
name = 'sectnums'
|
2119
2125
|
elsif name == 'hardbreaks'
|
2120
2126
|
name = 'hardbreaks-option'
|
2127
|
+
elsif name == 'showtitle'
|
2128
|
+
store_attribute 'notitle', (value ? nil : ''), doc, attrs
|
2121
2129
|
end
|
2122
2130
|
|
2123
2131
|
if doc
|
@@ -2272,9 +2280,15 @@ class Parser
|
|
2272
2280
|
end
|
2273
2281
|
|
2274
2282
|
skipped = table_reader.skip_blank_lines || 0
|
2283
|
+
if attributes['header-option']
|
2284
|
+
table.has_header_option = true
|
2285
|
+
elsif skipped == 0 && !attributes['noheader-option']
|
2286
|
+
# NOTE: assume table has header until we know otherwise; if it doesn't (nil), cells in first row get reprocessed
|
2287
|
+
table.has_header_option = :implicit
|
2288
|
+
implicit_header = true
|
2289
|
+
end
|
2275
2290
|
parser_ctx = Table::ParserContext.new table_reader, table, attributes
|
2276
2291
|
format, loop_idx, implicit_header_boundary = parser_ctx.format, -1, nil
|
2277
|
-
implicit_header = true unless skipped > 0 || attributes['header-option'] || attributes['noheader-option']
|
2278
2292
|
|
2279
2293
|
while (line = table_reader.read_line)
|
2280
2294
|
if (beyond_first = (loop_idx += 1) > 0) && line.empty?
|
@@ -2294,7 +2308,7 @@ class Parser
|
|
2294
2308
|
implicit_header_boundary = nil if implicit_header_boundary
|
2295
2309
|
# otherwise, the cell continues from previous line
|
2296
2310
|
elsif implicit_header_boundary && implicit_header_boundary == loop_idx
|
2297
|
-
implicit_header
|
2311
|
+
table.has_header_option = implicit_header = implicit_header_boundary = nil
|
2298
2312
|
end
|
2299
2313
|
end
|
2300
2314
|
end
|
@@ -2306,7 +2320,7 @@ class Parser
|
|
2306
2320
|
if table_reader.has_more_lines? && table_reader.peek_line.empty?
|
2307
2321
|
implicit_header_boundary = 1
|
2308
2322
|
else
|
2309
|
-
implicit_header =
|
2323
|
+
table.has_header_option = implicit_header = nil
|
2310
2324
|
end
|
2311
2325
|
end
|
2312
2326
|
end
|
@@ -2357,7 +2371,7 @@ class Parser
|
|
2357
2371
|
case format
|
2358
2372
|
when 'csv'
|
2359
2373
|
if parser_ctx.buffer_has_unclosed_quotes?
|
2360
|
-
implicit_header
|
2374
|
+
table.has_header_option = implicit_header = implicit_header_boundary = nil if implicit_header_boundary && loop_idx == 0
|
2361
2375
|
parser_ctx.keep_cell_open
|
2362
2376
|
else
|
2363
2377
|
parser_ctx.close_cell true
|
@@ -2379,15 +2393,8 @@ class Parser
|
|
2379
2393
|
end
|
2380
2394
|
end
|
2381
2395
|
|
2382
|
-
unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_colspecs
|
2383
|
-
|
2384
|
-
end
|
2385
|
-
|
2386
|
-
if implicit_header
|
2387
|
-
table.has_header_option = true
|
2388
|
-
attributes['header-option'] = ''
|
2389
|
-
end
|
2390
|
-
|
2396
|
+
table.assign_column_widths unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_colspecs
|
2397
|
+
table.has_header_option = true if implicit_header
|
2391
2398
|
table.partition_header_footer attributes
|
2392
2399
|
|
2393
2400
|
table
|
@@ -2578,9 +2585,7 @@ class Parser
|
|
2578
2585
|
attributes['role'] = (existing_role = attributes['role']).nil_or_empty? ? (parsed_attrs[:role].join ' ') : %(#{existing_role} #{parsed_attrs[:role].join ' '})
|
2579
2586
|
end
|
2580
2587
|
|
2581
|
-
if parsed_attrs.key? :option
|
2582
|
-
(opts = parsed_attrs[:option]).each {|opt| attributes[%(#{opt}-option)] = '' }
|
2583
|
-
end
|
2588
|
+
parsed_attrs[:option].each {|opt| attributes[%(#{opt}-option)] = '' } if parsed_attrs.key? :option
|
2584
2589
|
|
2585
2590
|
parsed_style
|
2586
2591
|
else
|
@@ -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))
|
@@ -476,25 +478,15 @@ class PathResolver
|
|
476
478
|
def web_path target, start = nil
|
477
479
|
target = posixify target
|
478
480
|
start = posixify start
|
479
|
-
uri_prefix = nil
|
480
481
|
|
481
482
|
unless start.nil_or_empty? || (web_root? target)
|
482
|
-
target = (start.end_with? SLASH) ?
|
483
|
-
if (uri_prefix = Helpers.uri_prefix target)
|
484
|
-
target = target[uri_prefix.length..-1]
|
485
|
-
end
|
483
|
+
target, uri_prefix = extract_uri_prefix %(#{start}#{(start.end_with? SLASH) ? '' : SLASH}#{target})
|
486
484
|
end
|
487
485
|
|
488
486
|
# use this logic instead if we want to normalize target if it contains a URI
|
489
487
|
#unless web_root? target
|
490
|
-
#
|
491
|
-
#
|
492
|
-
# elsif !start.nil_or_empty?
|
493
|
-
# target = %(#{start}#{SLASH}#{target})
|
494
|
-
# if (uri_prefix = Helpers.uri_prefix target)
|
495
|
-
# target = target[uri_prefix.length..-1]
|
496
|
-
# end
|
497
|
-
# end
|
488
|
+
# target, uri_prefix = extract_uri_prefix target if preserve_uri_target
|
489
|
+
# target, uri_prefix = extract_uri_prefix %(#{start}#{SLASH}#{target}) unless uri_prefix || start.nil_or_empty?
|
498
490
|
#end
|
499
491
|
|
500
492
|
target_segments, target_root = partition_path target, true
|
@@ -521,5 +513,23 @@ class PathResolver
|
|
521
513
|
|
522
514
|
uri_prefix ? %(#{uri_prefix}#{resolved_path}) : resolved_path
|
523
515
|
end
|
516
|
+
|
517
|
+
private
|
518
|
+
|
519
|
+
# Internal: Efficiently extracts the URI prefix from the specified String if the String is a URI
|
520
|
+
#
|
521
|
+
# Uses the Asciidoctor::UriSniffRx regex to match the URI prefix in the specified String (e.g., http://). If present,
|
522
|
+
# the prefix is removed.
|
523
|
+
#
|
524
|
+
# str - the String to check
|
525
|
+
#
|
526
|
+
# returns a tuple containing the specified string without the URI prefix, if present, and the extracted URI prefix.
|
527
|
+
def extract_uri_prefix str
|
528
|
+
if (str.include? ':') && UriSniffRx =~ str
|
529
|
+
[(str.slice $&.length, str.length), $&]
|
530
|
+
else
|
531
|
+
str
|
532
|
+
end
|
533
|
+
end
|
524
534
|
end
|
525
535
|
end
|
data/lib/asciidoctor/reader.rb
CHANGED
@@ -570,17 +570,18 @@ 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
|
-
|
578
|
+
if (normalize = opts[:normalize])
|
579
|
+
trim_end = normalize == :chomp ? false : true
|
580
|
+
::Array === data ? (Helpers.prepare_source_array data, trim_end) : (Helpers.prepare_source_string data, trim_end)
|
580
581
|
elsif ::Array === data
|
581
582
|
data.drop 0
|
582
583
|
elsif data
|
583
|
-
data.split LF, -1
|
584
|
+
data.chomp.split LF, -1
|
584
585
|
else
|
585
586
|
[]
|
586
587
|
end
|
@@ -717,7 +718,7 @@ class PreprocessorReader < Reader
|
|
717
718
|
end
|
718
719
|
|
719
720
|
# effectively fill the buffer
|
720
|
-
if (@lines = prepare_lines data, normalize:
|
721
|
+
if (@lines = prepare_lines data, normalize: @process_lines || :chomp, condense: @process_lines, indent: attributes['indent']).empty?
|
721
722
|
pop_include
|
722
723
|
else
|
723
724
|
# FIXME we eventually want to handle leveloffset without affecting the lines
|
@@ -1060,7 +1061,13 @@ class PreprocessorReader < Reader
|
|
1060
1061
|
return inc_path
|
1061
1062
|
end
|
1062
1063
|
|
1064
|
+
if (enc = parsed_attrs['encoding']) && (::Encoding.find enc rescue nil)
|
1065
|
+
(read_mode_params = read_mode.split ':')[1] = enc
|
1066
|
+
read_mode = read_mode_params.join ':'
|
1067
|
+
end unless RUBY_ENGINE_OPAL
|
1068
|
+
|
1063
1069
|
inc_linenos = inc_tags = nil
|
1070
|
+
# NOTE attrlist is nil if missing from include directive
|
1064
1071
|
if attrlist
|
1065
1072
|
if parsed_attrs.key? 'lines'
|
1066
1073
|
inc_linenos = []
|
@@ -1148,7 +1155,7 @@ class PreprocessorReader < Reader
|
|
1148
1155
|
active_tag, select = tag_stack.empty? ? [nil, base_select] : tag_stack[-1]
|
1149
1156
|
elsif inc_tags.key? this_tag
|
1150
1157
|
include_cursor = create_include_cursor inc_path, expanded_target, inc_lineno
|
1151
|
-
if (idx = tag_stack.rindex {|key
|
1158
|
+
if (idx = tag_stack.rindex {|key,| key == this_tag })
|
1152
1159
|
idx == 0 ? tag_stack.shift : (tag_stack.delete_at idx)
|
1153
1160
|
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
1161
|
else
|
@@ -0,0 +1,722 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
# A collection of regular expression constants used by the parser. (For speed, these are not defined in the Rx module,
|
3
|
+
# but rather directly in the Asciidoctor module).
|
4
|
+
#
|
5
|
+
# NOTE The following pattern, which appears frequently, captures the contents between square brackets, ignoring
|
6
|
+
# escaped closing brackets (closing brackets prefixed with a backslash '\' character)
|
7
|
+
#
|
8
|
+
# Pattern: \[(|#{CC_ALL}*?[^\\])\]
|
9
|
+
# Matches: [enclosed text] and [enclosed [text\]], not [enclosed text \\] or [\\] (as these require a trailing space)
|
10
|
+
module Rx; end
|
11
|
+
|
12
|
+
## Document header
|
13
|
+
|
14
|
+
# Matches the author info line immediately following the document title.
|
15
|
+
#
|
16
|
+
# Examples
|
17
|
+
#
|
18
|
+
# Doc Writer <doc@example.com>
|
19
|
+
# Mary_Sue Brontë
|
20
|
+
#
|
21
|
+
AuthorInfoLineRx = /^(#{CG_WORD}[#{CC_WORD}\-'.]*)(?: +(#{CG_WORD}[#{CC_WORD}\-'.]*))?(?: +(#{CG_WORD}[#{CC_WORD}\-'.]*))?(?: +<([^>]+)>)?$/
|
22
|
+
|
23
|
+
# Matches the delimiter that separates multiple authors.
|
24
|
+
#
|
25
|
+
# Examples
|
26
|
+
#
|
27
|
+
# Doc Writer; Junior Writer
|
28
|
+
#
|
29
|
+
AuthorDelimiterRx = /;(?: |$)/
|
30
|
+
|
31
|
+
# Matches the revision info line, which appears immediately following
|
32
|
+
# the author info line beneath the document title.
|
33
|
+
#
|
34
|
+
# Examples
|
35
|
+
#
|
36
|
+
# v1.0
|
37
|
+
# 2013-01-01
|
38
|
+
# v1.0, 2013-01-01: Ring in the new year release
|
39
|
+
# 1.0, Jan 01, 2013
|
40
|
+
#
|
41
|
+
RevisionInfoLineRx = /^(?:[^\d{]*(#{CC_ANY}*?),)? *(?!:)(#{CC_ANY}*?)(?: *(?!^),?: *(#{CC_ANY}*))?$/
|
42
|
+
|
43
|
+
# Matches the title and volnum in the manpage doctype.
|
44
|
+
#
|
45
|
+
# Examples
|
46
|
+
#
|
47
|
+
# = asciidoctor(1)
|
48
|
+
# = asciidoctor ( 1 )
|
49
|
+
#
|
50
|
+
ManpageTitleVolnumRx = /^(#{CC_ANY}+?) *\( *(#{CC_ANY}+?) *\)$/
|
51
|
+
|
52
|
+
# Matches the name and purpose in the manpage doctype.
|
53
|
+
#
|
54
|
+
# Examples
|
55
|
+
#
|
56
|
+
# asciidoctor - converts AsciiDoc source files to HTML, DocBook and other formats
|
57
|
+
#
|
58
|
+
ManpageNamePurposeRx = /^(#{CC_ANY}+?) +- +(#{CC_ANY}+)$/
|
59
|
+
|
60
|
+
## Preprocessor directives
|
61
|
+
|
62
|
+
# Matches a conditional preprocessor directive (e.g., ifdef, ifndef, ifeval and endif).
|
63
|
+
#
|
64
|
+
# Examples
|
65
|
+
#
|
66
|
+
# ifdef::basebackend-html[]
|
67
|
+
# ifndef::theme[]
|
68
|
+
# ifeval::["{asciidoctor-version}" >= "0.1.0"]
|
69
|
+
# ifdef::asciidoctor[Asciidoctor!]
|
70
|
+
# endif::theme[]
|
71
|
+
# endif::basebackend-html[]
|
72
|
+
# endif::[]
|
73
|
+
#
|
74
|
+
ConditionalDirectiveRx = /^(\\)?(ifdef|ifndef|ifeval|endif)::(\S*?(?:([,+])\S*?)?)\[(#{CC_ANY}+)?\]$/
|
75
|
+
|
76
|
+
# Matches a restricted (read as safe) eval expression.
|
77
|
+
#
|
78
|
+
# Examples
|
79
|
+
#
|
80
|
+
# "{asciidoctor-version}" >= "0.1.0"
|
81
|
+
#
|
82
|
+
EvalExpressionRx = /^(#{CC_ANY}+?) *([=!><]=|[><]) *(#{CC_ANY}+)$/
|
83
|
+
|
84
|
+
# Matches an include preprocessor directive.
|
85
|
+
#
|
86
|
+
# Examples
|
87
|
+
#
|
88
|
+
# include::chapter1.ad[]
|
89
|
+
# include::example.txt[lines=1;2;5..10]
|
90
|
+
#
|
91
|
+
IncludeDirectiveRx = /^(\\)?include::([^\[][^\[]*)\[(#{CC_ANY}+)?\]$/
|
92
|
+
|
93
|
+
# Matches a trailing tag directive in an include file.
|
94
|
+
#
|
95
|
+
# Examples
|
96
|
+
#
|
97
|
+
# // tag::try-catch[]
|
98
|
+
# try {
|
99
|
+
# someMethod();
|
100
|
+
# catch (Exception e) {
|
101
|
+
# log(e);
|
102
|
+
# }
|
103
|
+
# // end::try-catch[]
|
104
|
+
# NOTE m flag is required for Asciidoctor.js
|
105
|
+
TagDirectiveRx = /\b(?:tag|(e)nd)::(\S+?)\[\](?=$|[ \r])/m
|
106
|
+
|
107
|
+
## Attribute entries and references
|
108
|
+
|
109
|
+
# Matches a document attribute entry.
|
110
|
+
#
|
111
|
+
# Examples
|
112
|
+
#
|
113
|
+
# :foo: bar
|
114
|
+
# :First Name: Dan
|
115
|
+
# :sectnums!:
|
116
|
+
# :!toc:
|
117
|
+
# :long-entry: Attribute value lines ending in ' \' \
|
118
|
+
# are joined together as a single value, \
|
119
|
+
# collapsing the line breaks and indentation to \
|
120
|
+
# a single space.
|
121
|
+
#
|
122
|
+
AttributeEntryRx = /^:(!?#{CG_WORD}[^:]*):(?:[ \t]+(#{CC_ANY}*))?$/
|
123
|
+
|
124
|
+
# Matches invalid characters in an attribute name.
|
125
|
+
InvalidAttributeNameCharsRx = /[^#{CC_WORD}-]/
|
126
|
+
|
127
|
+
# Matches a pass inline macro that surrounds the value of an attribute
|
128
|
+
# entry once it has been parsed.
|
129
|
+
#
|
130
|
+
# Examples
|
131
|
+
#
|
132
|
+
# pass:[text]
|
133
|
+
# pass:a[{a} {b} {c}]
|
134
|
+
#
|
135
|
+
if RUBY_ENGINE == 'opal'
|
136
|
+
# NOTE In JavaScript, ^ and $ match the boundaries of the string when the m flag is not set
|
137
|
+
AttributeEntryPassMacroRx = /^pass:([a-z]+(?:,[a-z-]+)*)?\[(#{CC_ALL}*)\]$/
|
138
|
+
else
|
139
|
+
AttributeEntryPassMacroRx = /\Apass:([a-z]+(?:,[a-z-]+)*)?\[(.*)\]\Z/m
|
140
|
+
end
|
141
|
+
|
142
|
+
# Matches an inline attribute reference.
|
143
|
+
#
|
144
|
+
# Examples
|
145
|
+
#
|
146
|
+
# {foobar} or {app_name} or {product-version}
|
147
|
+
# {counter:sequence-name:1}
|
148
|
+
# {set:foo:bar}
|
149
|
+
# {set:name!}
|
150
|
+
#
|
151
|
+
AttributeReferenceRx = /(\\)?\{(#{CG_WORD}[#{CC_WORD}-]*|(set|counter2?):#{CC_ANY}+?)(\\)?\}/
|
152
|
+
|
153
|
+
## Paragraphs and delimited blocks
|
154
|
+
|
155
|
+
# Matches an anchor (i.e., id + optional reference text) on a line above a block.
|
156
|
+
#
|
157
|
+
# Examples
|
158
|
+
#
|
159
|
+
# [[idname]]
|
160
|
+
# [[idname,Reference Text]]
|
161
|
+
#
|
162
|
+
BlockAnchorRx = /^\[\[(?:|([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+))?)\]\]$/
|
163
|
+
|
164
|
+
# Matches an attribute list above a block element.
|
165
|
+
#
|
166
|
+
# Examples
|
167
|
+
#
|
168
|
+
# # strictly positional
|
169
|
+
# [quote, Adam Smith, Wealth of Nations]
|
170
|
+
#
|
171
|
+
# # name/value pairs
|
172
|
+
# [NOTE, caption="Good to know"]
|
173
|
+
#
|
174
|
+
# # as attribute reference
|
175
|
+
# [{lead}]
|
176
|
+
#
|
177
|
+
BlockAttributeListRx = /^\[(|[#{CC_WORD}.#%{,"']#{CC_ANY}*)\]$/
|
178
|
+
|
179
|
+
# A combined pattern that matches either a block anchor or a block attribute list.
|
180
|
+
#
|
181
|
+
# TODO this one gets hit a lot, should be optimized as much as possible
|
182
|
+
BlockAttributeLineRx = /^\[(?:|[#{CC_WORD}.#%{,"']#{CC_ANY}*|\[(?:|[#{CC_ALPHA}_:][#{CC_WORD}\-:.]*(?:, *#{CC_ANY}+)?)\])\]$/
|
183
|
+
|
184
|
+
# Matches a title above a block.
|
185
|
+
#
|
186
|
+
# Examples
|
187
|
+
#
|
188
|
+
# .Title goes here
|
189
|
+
#
|
190
|
+
BlockTitleRx = /^\.(\.?[^ \t.]#{CC_ANY}*)$/
|
191
|
+
|
192
|
+
# Matches an admonition label at the start of a paragraph.
|
193
|
+
#
|
194
|
+
# Examples
|
195
|
+
#
|
196
|
+
# NOTE: Just a little note.
|
197
|
+
# TIP: Don't forget!
|
198
|
+
#
|
199
|
+
AdmonitionParagraphRx = /^(#{ADMONITION_STYLES.to_a.join '|'}):[ \t]+/
|
200
|
+
|
201
|
+
# Matches a literal paragraph, which is a line of text preceded by at least one space.
|
202
|
+
#
|
203
|
+
# Examples
|
204
|
+
#
|
205
|
+
# <SPACE>Foo
|
206
|
+
# <TAB>Foo
|
207
|
+
LiteralParagraphRx = /^([ \t]+#{CC_ANY}*)$/
|
208
|
+
|
209
|
+
# Matches a comment block.
|
210
|
+
#
|
211
|
+
# Examples
|
212
|
+
#
|
213
|
+
# ////
|
214
|
+
# This is a block comment.
|
215
|
+
# It can span one or more lines.
|
216
|
+
# ////
|
217
|
+
#CommentBlockRx = %r(^/{4,}$)
|
218
|
+
|
219
|
+
# Matches a comment line.
|
220
|
+
#
|
221
|
+
# Examples
|
222
|
+
#
|
223
|
+
# // note to author
|
224
|
+
#
|
225
|
+
#CommentLineRx = %r(^//(?=[^/]|$))
|
226
|
+
|
227
|
+
## Section titles
|
228
|
+
|
229
|
+
# Matches an Atx (single-line) section title.
|
230
|
+
#
|
231
|
+
# Examples
|
232
|
+
#
|
233
|
+
# == Foo
|
234
|
+
# // ^ a level 1 (h2) section title
|
235
|
+
#
|
236
|
+
# == Foo ==
|
237
|
+
# // ^ also a level 1 (h2) section title
|
238
|
+
#
|
239
|
+
AtxSectionTitleRx = /^(=={0,5})[ \t]+(#{CC_ANY}+?)(?:[ \t]+\1)?$/
|
240
|
+
|
241
|
+
# Matches an extended Atx section title that includes support for the Markdown variant.
|
242
|
+
ExtAtxSectionTitleRx = /^(=={0,5}|#\#{0,5})[ \t]+(#{CC_ANY}+?)(?:[ \t]+\1)?$/
|
243
|
+
|
244
|
+
# Matches the title only (first line) of an Setext (two-line) section title.
|
245
|
+
# The title cannot begin with a dot and must have at least one alphanumeric character.
|
246
|
+
SetextSectionTitleRx = /^((?!\.)#{CC_ANY}*?#{CG_ALNUM}#{CC_ANY}*)$/
|
247
|
+
|
248
|
+
# Matches an anchor (i.e., id + optional reference text) inside a section title.
|
249
|
+
#
|
250
|
+
# Examples
|
251
|
+
#
|
252
|
+
# Section Title [[idname]]
|
253
|
+
# Section Title [[idname,Reference Text]]
|
254
|
+
#
|
255
|
+
InlineSectionAnchorRx = / (\\)?\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+))?\]\]$/
|
256
|
+
|
257
|
+
# Matches invalid ID characters in a section title.
|
258
|
+
#
|
259
|
+
# NOTE uppercase chars not included since expression is only run on a lowercase string
|
260
|
+
InvalidSectionIdCharsRx = /<[^>]+>|&(?:[a-z][a-z]+\d{0,2}|#\d\d\d{0,4}|#x[\da-f][\da-f][\da-f]{0,3});|[^ #{CC_WORD}\-.]+?/
|
261
|
+
|
262
|
+
# Matches an explicit section level style like sect1
|
263
|
+
#
|
264
|
+
SectionLevelStyleRx = /^sect\d$/
|
265
|
+
|
266
|
+
## Lists
|
267
|
+
|
268
|
+
# Detects the start of any list item.
|
269
|
+
#
|
270
|
+
# NOTE we only have to check as far as the blank character because we know it means non-whitespace follows.
|
271
|
+
# 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])|<(?:\d+|\.)>[ \t]))
|
273
|
+
|
274
|
+
# Matches an unordered list item (one level for hyphens, up to 5 levels for asterisks).
|
275
|
+
#
|
276
|
+
# Examples
|
277
|
+
#
|
278
|
+
# * Foo
|
279
|
+
# - Foo
|
280
|
+
#
|
281
|
+
# NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
|
282
|
+
UnorderedListRx = /^[ \t]*(-|\*\**|\u2022)[ \t]+(#{CC_ANY}*)$/
|
283
|
+
|
284
|
+
# Matches an ordered list item (explicit numbering or up to 5 consecutive dots).
|
285
|
+
#
|
286
|
+
# Examples
|
287
|
+
#
|
288
|
+
# . Foo
|
289
|
+
# .. Foo
|
290
|
+
# 1. Foo (arabic, default)
|
291
|
+
# a. Foo (loweralpha)
|
292
|
+
# A. Foo (upperalpha)
|
293
|
+
# i. Foo (lowerroman)
|
294
|
+
# I. Foo (upperroman)
|
295
|
+
#
|
296
|
+
# NOTE leading space match is not always necessary, but is used for list reader
|
297
|
+
# NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
|
298
|
+
OrderedListRx = /^[ \t]*(\.\.*|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]+(#{CC_ANY}*)$/
|
299
|
+
|
300
|
+
# Matches the ordinals for each type of ordered list.
|
301
|
+
OrderedListMarkerRxMap = {
|
302
|
+
arabic: /\d+\./,
|
303
|
+
loweralpha: /[a-z]\./,
|
304
|
+
lowerroman: /[ivx]+\)/,
|
305
|
+
upperalpha: /[A-Z]\./,
|
306
|
+
upperroman: /[IVX]+\)/,
|
307
|
+
#lowergreek: /[a-z]\]/,
|
308
|
+
}
|
309
|
+
|
310
|
+
# Matches a description list entry.
|
311
|
+
#
|
312
|
+
# Examples
|
313
|
+
#
|
314
|
+
# foo::
|
315
|
+
# bar:::
|
316
|
+
# baz::::
|
317
|
+
# blah;;
|
318
|
+
#
|
319
|
+
# # the term may be followed by a description on the same line...
|
320
|
+
#
|
321
|
+
# foo:: The metasyntactic variable that commonly accompanies 'bar' (see also, <<bar>>).
|
322
|
+
#
|
323
|
+
# # ...or on a separate line, which may optionally be indented
|
324
|
+
#
|
325
|
+
# foo::
|
326
|
+
# The metasyntactic variable that commonly accompanies 'bar' (see also, <<bar>>).
|
327
|
+
#
|
328
|
+
# # attribute references may be used in both the term and the description
|
329
|
+
#
|
330
|
+
# {foo-term}:: {foo-desc}
|
331
|
+
#
|
332
|
+
# NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
|
333
|
+
# NOTE must skip line comment when looking for next list item inside list
|
334
|
+
DescriptionListRx = %r(^(?!//[^/])[ \t]*([^ \t]#{CC_ANY}*?)(:::{0,2}|;;)(?:$|[ \t]+(#{CC_ANY}*)$))
|
335
|
+
|
336
|
+
# Matches a sibling description list item (excluding the delimiter specified by the key).
|
337
|
+
# NOTE must skip line comment when looking for sibling list item
|
338
|
+
DescriptionListSiblingRx = {
|
339
|
+
'::' => %r(^(?!//[^/])[ \t]*([^ \t]#{CC_ANY}*?[^:]|[^ \t:])(::)(?:$|[ \t]+(#{CC_ANY}*)$)),
|
340
|
+
':::' => %r(^(?!//[^/])[ \t]*([^ \t]#{CC_ANY}*?[^:]|[^ \t:])(:::)(?:$|[ \t]+(#{CC_ANY}*)$)),
|
341
|
+
'::::' => %r(^(?!//[^/])[ \t]*([^ \t]#{CC_ANY}*?[^:]|[^ \t:])(::::)(?:$|[ \t]+(#{CC_ANY}*)$)),
|
342
|
+
';;' => %r(^(?!//[^/])[ \t]*([^ \t]#{CC_ANY}*?)(;;)(?:$|[ \t]+(#{CC_ANY}*)$))
|
343
|
+
}
|
344
|
+
|
345
|
+
# Matches a callout list item.
|
346
|
+
#
|
347
|
+
# Examples
|
348
|
+
#
|
349
|
+
# <1> Explanation
|
350
|
+
#
|
351
|
+
# or
|
352
|
+
#
|
353
|
+
# <.> Explanation with automatic number
|
354
|
+
#
|
355
|
+
# NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
|
356
|
+
CalloutListRx = /^<(\d+|\.)>[ \t]+(#{CC_ANY}*)$/
|
357
|
+
|
358
|
+
# Matches a callout reference inside literal text.
|
359
|
+
#
|
360
|
+
# Examples
|
361
|
+
# <1> (optionally prefixed by //, #, -- or ;; line comment chars)
|
362
|
+
# <1> <2> (multiple callouts on one line)
|
363
|
+
# <!--1--> (for XML-based languages)
|
364
|
+
# <.> (auto-numbered)
|
365
|
+
#
|
366
|
+
# NOTE extract regexps are applied line-by-line, so we can use $ as end-of-line char
|
367
|
+
CalloutExtractRx = %r(((?://|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\3>(?=(?: ?\\?<!?\3(?:\d+|\.)\3>)*$))
|
368
|
+
CalloutExtractRxt = '(\\\\)?<()(\\d+|\\.)>(?=(?: ?\\\\?<(?:\\d+|\\.)>)*$)'
|
369
|
+
CalloutExtractRxMap = ::Hash.new {|h, k| h[k] = /(#{k.empty? ? '' : "#{::Regexp.escape k} ?"})?#{CalloutExtractRxt}/ }
|
370
|
+
# NOTE special characters have not been replaced when scanning
|
371
|
+
CalloutScanRx = /\\?<!?(|--)(\d+|\.)\1>(?=(?: ?\\?<!?\1(?:\d+|\.)\1>)*#{CC_EOL})/
|
372
|
+
# NOTE special characters have already been replaced when converting to an SGML format
|
373
|
+
CalloutSourceRx = %r(((?://|#|--|;;) ?)?(\\)?<!?(|--)(\d+|\.)\3>(?=(?: ?\\?<!?\3(?:\d+|\.)\3>)*#{CC_EOL}))
|
374
|
+
CalloutSourceRxt = "(\\\\)?<()(\\d+|\\.)>(?=(?: ?\\\\?<(?:\\d+|\\.)>)*#{CC_EOL})"
|
375
|
+
CalloutSourceRxMap = ::Hash.new {|h, k| h[k] = /(#{k.empty? ? '' : "#{::Regexp.escape k} ?"})?#{CalloutSourceRxt}/ }
|
376
|
+
|
377
|
+
# A Hash of regexps for lists used for dynamic access.
|
378
|
+
ListRxMap = { ulist: UnorderedListRx, olist: OrderedListRx, dlist: DescriptionListRx, colist: CalloutListRx }
|
379
|
+
|
380
|
+
## Tables
|
381
|
+
|
382
|
+
# Parses the column spec (i.e., colspec) for a table.
|
383
|
+
#
|
384
|
+
# Examples
|
385
|
+
#
|
386
|
+
# 1*h,2*,^3e
|
387
|
+
#
|
388
|
+
ColumnSpecRx = /^(?:(\d+)\*)?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?(\d+%?|~)?([a-z])?$/
|
389
|
+
|
390
|
+
# Parses the start and end of a cell spec (i.e., cellspec) for a table.
|
391
|
+
#
|
392
|
+
# Examples
|
393
|
+
#
|
394
|
+
# 2.3+<.>m
|
395
|
+
#
|
396
|
+
# FIXME use step-wise scan (or treetop) rather than this mega-regexp
|
397
|
+
CellSpecStartRx = /^[ \t]*(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/
|
398
|
+
CellSpecEndRx = /[ \t]+(?:(\d+(?:\.\d*)?|(?:\d*\.)?\d+)([*+]))?([<^>](?:\.[<^>]?)?|(?:[<^>]?\.)?[<^>])?([a-z])?$/
|
399
|
+
|
400
|
+
# Block macros
|
401
|
+
|
402
|
+
# Matches the custom block macro pattern.
|
403
|
+
#
|
404
|
+
# Examples
|
405
|
+
#
|
406
|
+
# gist::123456[]
|
407
|
+
#
|
408
|
+
#--
|
409
|
+
# NOTE we've relaxed the match for target to accomodate the short format (e.g., name::[attrlist])
|
410
|
+
CustomBlockMacroRx = /^(#{CG_WORD}[#{CC_WORD}-]*)::(|\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
|
411
|
+
|
412
|
+
# Matches an image, video or audio block macro.
|
413
|
+
#
|
414
|
+
# Examples
|
415
|
+
#
|
416
|
+
# image::filename.png[Caption]
|
417
|
+
# video::http://youtube.com/12345[Cats vs Dogs]
|
418
|
+
#
|
419
|
+
BlockMediaMacroRx = /^(image|video|audio)::(\S|\S#{CC_ANY}*?\S)\[(#{CC_ANY}+)?\]$/
|
420
|
+
|
421
|
+
# Matches the TOC block macro.
|
422
|
+
#
|
423
|
+
# Examples
|
424
|
+
#
|
425
|
+
# toc::[]
|
426
|
+
# toc::[levels=2]
|
427
|
+
#
|
428
|
+
BlockTocMacroRx = /^toc::\[(#{CC_ANY}+)?\]$/
|
429
|
+
|
430
|
+
## Inline macros
|
431
|
+
|
432
|
+
# Matches an anchor (i.e., id + optional reference text) in the flow of text.
|
433
|
+
#
|
434
|
+
# Examples
|
435
|
+
#
|
436
|
+
# [[idname]]
|
437
|
+
# [[idname,Reference Text]]
|
438
|
+
# anchor:idname[]
|
439
|
+
# anchor:idname[Reference Text]
|
440
|
+
#
|
441
|
+
InlineAnchorRx = /(\\)?(?:\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]|anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\]))/
|
442
|
+
|
443
|
+
# Scans for a non-escaped anchor (i.e., id + optional reference text) in the flow of text.
|
444
|
+
InlineAnchorScanRx = /(?:^|[^\\\[])\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]|(?:^|[^\\])anchor:([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)\[(?:\]|(#{CC_ANY}*?[^\\])\])/
|
445
|
+
|
446
|
+
# Scans for a leading, non-escaped anchor (i.e., id + optional reference text).
|
447
|
+
LeadingInlineAnchorRx = /^\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]/
|
448
|
+
|
449
|
+
# Matches a bibliography anchor at the start of the list item text (in a bibliography list).
|
450
|
+
#
|
451
|
+
# Examples
|
452
|
+
#
|
453
|
+
# [[[Fowler_1997]]] Fowler M. ...
|
454
|
+
#
|
455
|
+
InlineBiblioAnchorRx = /^\[\[\[([#{CC_ALPHA}_:][#{CC_WORD}\-:.]*)(?:, *(#{CC_ANY}+?))?\]\]\]/
|
456
|
+
|
457
|
+
# Matches an inline e-mail address.
|
458
|
+
#
|
459
|
+
# doc.writer@example.com
|
460
|
+
#
|
461
|
+
InlineEmailRx = %r(([\\>:/])?#{CG_WORD}(?:&|[#{CC_WORD}\-.%+])*@#{CG_ALNUM}[#{CC_ALNUM}_\-.]*\.[a-zA-Z]{2,5}\b)
|
462
|
+
|
463
|
+
# Matches an inline footnote macro, which is allowed to span multiple lines.
|
464
|
+
#
|
465
|
+
# Examples
|
466
|
+
# footnote:[text] (not referenceable)
|
467
|
+
# footnote:id[text] (referenceable)
|
468
|
+
# footnote:id[] (reference)
|
469
|
+
# footnoteref:[id,text] (legacy)
|
470
|
+
# footnoteref:[id] (legacy)
|
471
|
+
#
|
472
|
+
InlineFootnoteMacroRx = /\\?footnote(?:(ref):|:([#{CC_WORD}-]+)?)\[(?:|(#{CC_ALL}*?[^\\]))\](?!<\/a>)/m
|
473
|
+
|
474
|
+
# Matches an image or icon inline macro.
|
475
|
+
#
|
476
|
+
# Examples
|
477
|
+
#
|
478
|
+
# image:filename.png[Alt Text]
|
479
|
+
# image:http://example.com/images/filename.png[Alt Text]
|
480
|
+
# image:filename.png[More [Alt\] Text] (alt text becomes "More [Alt] Text")
|
481
|
+
# icon:github[large]
|
482
|
+
#
|
483
|
+
# NOTE be as non-greedy as possible by not allowing newline or left square bracket in target
|
484
|
+
InlineImageMacroRx = /\\?i(?:mage|con):([^:\s\[](?:[^\n\[]*[^\s\[])?)\[(|#{CC_ALL}*?[^\\])\]/m
|
485
|
+
|
486
|
+
# Matches an indexterm inline macro, which may span multiple lines.
|
487
|
+
#
|
488
|
+
# Examples
|
489
|
+
#
|
490
|
+
# indexterm:[Tigers,Big cats]
|
491
|
+
# (((Tigers,Big cats)))
|
492
|
+
# indexterm2:[Tigers]
|
493
|
+
# ((Tigers))
|
494
|
+
#
|
495
|
+
InlineIndextermMacroRx = /\\?(?:(indexterm2?):\[(#{CC_ALL}*?[^\\])\]|\(\((#{CC_ALL}+?)\)\)(?!\)))/m
|
496
|
+
|
497
|
+
# Matches either the kbd or btn inline macro.
|
498
|
+
#
|
499
|
+
# Examples
|
500
|
+
#
|
501
|
+
# kbd:[F3]
|
502
|
+
# kbd:[Ctrl+Shift+T]
|
503
|
+
# kbd:[Ctrl+\]]
|
504
|
+
# kbd:[Ctrl,T]
|
505
|
+
# btn:[Save]
|
506
|
+
#
|
507
|
+
InlineKbdBtnMacroRx = /(\\)?(kbd|btn):\[(#{CC_ALL}*?[^\\])\]/m
|
508
|
+
|
509
|
+
# Matches an implicit link and some of the link inline macro.
|
510
|
+
#
|
511
|
+
# Examples
|
512
|
+
#
|
513
|
+
# https://github.com
|
514
|
+
# https://github.com[GitHub]
|
515
|
+
# <https://github.com>
|
516
|
+
# link:https://github.com[]
|
517
|
+
# "https://github.com[]"
|
518
|
+
#
|
519
|
+
# FIXME revisit! the main issue is we need different rules for implicit vs explicit
|
520
|
+
InlineLinkRx = %r((^|link:|#{CG_BLANK}|<|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*([^\s.,\[\]<]))(?:\[(|#{CC_ALL}*?[^\\])\])?)m
|
521
|
+
|
522
|
+
# Match a link or e-mail inline macro.
|
523
|
+
#
|
524
|
+
# Examples
|
525
|
+
#
|
526
|
+
# link:path[label]
|
527
|
+
# mailto:doc.writer@example.com[]
|
528
|
+
#
|
529
|
+
# NOTE be as non-greedy as possible by not allowing space or left square bracket in target
|
530
|
+
InlineLinkMacroRx = /\\?(?:link|(mailto)):(|[^:\s\[][^\s\[]*)\[(|#{CC_ALL}*?[^\\])\]/m
|
531
|
+
|
532
|
+
# Matches the name of a macro.
|
533
|
+
#
|
534
|
+
MacroNameRx = /^#{CG_WORD}[#{CC_WORD}-]*$/
|
535
|
+
|
536
|
+
# Matches a stem (and alternatives, asciimath and latexmath) inline macro, which may span multiple lines.
|
537
|
+
#
|
538
|
+
# Examples
|
539
|
+
#
|
540
|
+
# stem:[x != 0]
|
541
|
+
# asciimath:[x != 0]
|
542
|
+
# latexmath:[\sqrt{4} = 2]
|
543
|
+
#
|
544
|
+
InlineStemMacroRx = /\\?(stem|(?:latex|ascii)math):([a-z]+(?:,[a-z-]+)*)?\[(#{CC_ALL}*?[^\\])\]/m
|
545
|
+
|
546
|
+
# Matches a menu inline macro.
|
547
|
+
#
|
548
|
+
# Examples
|
549
|
+
#
|
550
|
+
# menu:File[Save As...]
|
551
|
+
# menu:Edit[]
|
552
|
+
# menu:View[Page Style > No Style]
|
553
|
+
# menu:View[Page Style, No Style]
|
554
|
+
#
|
555
|
+
InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))\]/m
|
556
|
+
|
557
|
+
# Matches an implicit menu inline macro.
|
558
|
+
#
|
559
|
+
# Examples
|
560
|
+
#
|
561
|
+
# "File > New..."
|
562
|
+
#
|
563
|
+
InlineMenuRx = /\\?"([#{CC_WORD}&][^"]*?[ \n]+>[ \n]+[^"]*)"/
|
564
|
+
|
565
|
+
# Matches an inline passthrough, which may span multiple lines.
|
566
|
+
#
|
567
|
+
# Examples
|
568
|
+
#
|
569
|
+
# +text+
|
570
|
+
# `text` (compat)
|
571
|
+
#
|
572
|
+
# NOTE we always capture the attributes so we know when to use compatible (i.e., legacy) behavior
|
573
|
+
InlinePassRx = {
|
574
|
+
false => ['+', '`', /(^|[^#{CC_WORD};:])(?:\[([^\]]+)\])?(\\?(\+|`)(\S|\S#{CC_ALL}*?\S)\4)(?!#{CG_WORD})/m],
|
575
|
+
true => ['`', nil, /(^|[^`#{CC_WORD}])(?:\[([^\]]+)\])?(\\?(`)([^`\s]|[^`\s]#{CC_ALL}*?\S)\4)(?![`#{CC_WORD}])/m]
|
576
|
+
}
|
577
|
+
|
578
|
+
# Matches an inline plus passthrough spanning multiple lines, but only when it occurs directly
|
579
|
+
# inside constrained monospaced formatting in non-compat mode.
|
580
|
+
#
|
581
|
+
# Examples
|
582
|
+
#
|
583
|
+
# +text+
|
584
|
+
#
|
585
|
+
SinglePlusInlinePassRx = /^(\\)?\+(\S|\S#{CC_ALL}*?\S)\+$/m
|
586
|
+
|
587
|
+
# Matches several variants of the passthrough inline macro, which may span multiple lines.
|
588
|
+
#
|
589
|
+
# Examples
|
590
|
+
#
|
591
|
+
# +++text+++
|
592
|
+
# $$text$$
|
593
|
+
# pass:quotes[text]
|
594
|
+
#
|
595
|
+
# NOTE we have to support an empty pass:[] for compatibility with AsciiDoc Python
|
596
|
+
InlinePassMacroRx = /(?:(?:(\\?)\[([^\]]+)\])?(\\{0,2})(\+\+\+?|\$\$)(#{CC_ALL}*?)\4|(\\?)pass:([a-z]+(?:,[a-z-]+)*)?\[(|#{CC_ALL}*?[^\\])\])/m
|
597
|
+
|
598
|
+
# Matches an xref (i.e., cross-reference) inline macro, which may span multiple lines.
|
599
|
+
#
|
600
|
+
# Examples
|
601
|
+
#
|
602
|
+
# <<id,reftext>>
|
603
|
+
# xref:id[reftext]
|
604
|
+
#
|
605
|
+
# NOTE special characters have already been escaped, hence the entity references
|
606
|
+
# NOTE { is included in start characters to support target that begins with attribute reference in title content
|
607
|
+
InlineXrefMacroRx = %r(\\?(?:<<([#{CC_WORD}#/.:{]#{CC_ALL}*?)>>|xref:([#{CC_WORD}#/.:{]#{CC_ALL}*?)\[(?:\]|(#{CC_ALL}*?[^\\])\])))m
|
608
|
+
|
609
|
+
## Layout
|
610
|
+
|
611
|
+
# Matches a trailing + preceded by at least one space character,
|
612
|
+
# which forces a hard line break (<br> tag in HTML output).
|
613
|
+
#
|
614
|
+
# NOTE AsciiDoc Python allows + to be preceded by TAB; Asciidoctor does not
|
615
|
+
#
|
616
|
+
# Examples
|
617
|
+
#
|
618
|
+
# Humpty Dumpty sat on a wall, +
|
619
|
+
# Humpty Dumpty had a great fall.
|
620
|
+
#
|
621
|
+
if RUBY_ENGINE == 'opal'
|
622
|
+
# NOTE In JavaScript, ^ and $ only match the start and end of line if the multiline flag is present
|
623
|
+
HardLineBreakRx = /^(#{CC_ANY}*) \+$/m
|
624
|
+
else
|
625
|
+
# NOTE In Ruby, ^ and $ always match start and end of line
|
626
|
+
HardLineBreakRx = /^(.*) \+$/
|
627
|
+
end
|
628
|
+
|
629
|
+
# Matches a Markdown horizontal rule.
|
630
|
+
#
|
631
|
+
# Examples
|
632
|
+
#
|
633
|
+
# --- or - - -
|
634
|
+
# *** or * * *
|
635
|
+
# ___ or _ _ _
|
636
|
+
#
|
637
|
+
MarkdownThematicBreakRx = /^ {0,3}([-*_])( *)\1\2\1$/
|
638
|
+
|
639
|
+
# Matches an AsciiDoc or Markdown horizontal rule or AsciiDoc page break.
|
640
|
+
#
|
641
|
+
# Examples
|
642
|
+
#
|
643
|
+
# ''' (horizontal rule)
|
644
|
+
# <<< (page break)
|
645
|
+
# --- or - - - (horizontal rule, Markdown)
|
646
|
+
# *** or * * * (horizontal rule, Markdown)
|
647
|
+
# ___ or _ _ _ (horizontal rule, Markdown)
|
648
|
+
#
|
649
|
+
ExtLayoutBreakRx = /^(?:'{3,}|<{3,}|([-*_])( *)\1\2\1)$/
|
650
|
+
|
651
|
+
## General
|
652
|
+
|
653
|
+
# Matches consecutive blank lines.
|
654
|
+
#
|
655
|
+
# Examples
|
656
|
+
#
|
657
|
+
# one
|
658
|
+
#
|
659
|
+
# two
|
660
|
+
#
|
661
|
+
BlankLineRx = /\n{2,}/
|
662
|
+
|
663
|
+
# Matches a comma or semi-colon delimiter.
|
664
|
+
#
|
665
|
+
# Examples
|
666
|
+
#
|
667
|
+
# one,two
|
668
|
+
# three;four
|
669
|
+
#
|
670
|
+
#DataDelimiterRx = /[,;]/
|
671
|
+
|
672
|
+
# Matches whitespace (space, tab, newline) escaped by a backslash.
|
673
|
+
#
|
674
|
+
# Examples
|
675
|
+
#
|
676
|
+
# three\ blind\ mice
|
677
|
+
#
|
678
|
+
EscapedSpaceRx = /\\([ \t\n])/
|
679
|
+
|
680
|
+
# Detects if text is a possible candidate for the replacements substitution.
|
681
|
+
#
|
682
|
+
ReplaceableTextRx = /[&']|--|\.\.\.|\([CRT]M?\)/
|
683
|
+
|
684
|
+
# Matches a whitespace delimiter, a sequence of spaces, tabs, and/or newlines.
|
685
|
+
# Matches the parsing rules of %w strings in Ruby.
|
686
|
+
#
|
687
|
+
# Examples
|
688
|
+
#
|
689
|
+
# one two three four
|
690
|
+
# five six
|
691
|
+
#
|
692
|
+
# TODO change to /(?<!\\)[ \t\n]+/ once lookbehind assertions are implemented in all modern browsers
|
693
|
+
SpaceDelimiterRx = /([^\\])[ \t\n]+/
|
694
|
+
|
695
|
+
# Matches a + or - modifier in a subs list
|
696
|
+
#
|
697
|
+
SubModifierSniffRx = /[+-]/
|
698
|
+
|
699
|
+
# Matches one or more consecutive digits at the end of a line.
|
700
|
+
#
|
701
|
+
# Examples
|
702
|
+
#
|
703
|
+
# docbook5
|
704
|
+
# html5
|
705
|
+
#
|
706
|
+
TrailingDigitsRx = /\d+$/
|
707
|
+
|
708
|
+
# Detects strings that resemble URIs.
|
709
|
+
#
|
710
|
+
# Examples
|
711
|
+
# http://domain
|
712
|
+
# https://domain
|
713
|
+
# file:///path
|
714
|
+
# data:info
|
715
|
+
#
|
716
|
+
# not c:/sample.adoc or c:\sample.adoc
|
717
|
+
#
|
718
|
+
UriSniffRx = %r(^#{CG_ALPHA}[#{CC_ALNUM}.+-]+:/{0,2})
|
719
|
+
|
720
|
+
# Detects XML tags
|
721
|
+
XmlSanitizeRx = /<[^>]+>/
|
722
|
+
end
|