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
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Asciidoctor
|
3
3
|
# Public: Methods to perform substitutions on lines of AsciiDoc text. This module
|
4
|
-
# is
|
4
|
+
# is intended to be mixed-in to Section and Block to provide operations for performing
|
5
5
|
# the necessary substitutions.
|
6
6
|
module Substitutors
|
7
7
|
SpecialCharsRx = /[<&>]/
|
@@ -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
|
334
|
-
if (inline_subs = replacement.attributes.delete 'subs')
|
335
|
-
replacement.text = apply_subs replacement.text,
|
333
|
+
if Inline === (replacement = extension.process_method[self, target, attributes])
|
334
|
+
if (inline_subs = replacement.attributes.delete 'subs') && (inline_subs = expand_subs inline_subs, 'custom inline macro')
|
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
|
@@ -542,20 +532,24 @@ module Substitutors
|
|
542
532
|
end
|
543
533
|
|
544
534
|
prefix, suffix = $1, ''
|
545
|
-
# NOTE if $4 is set,
|
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
|
-
# invalid macro syntax (link: prefix w/o trailing square brackets)
|
551
|
-
# FIXME we probably shouldn't even get here
|
552
|
-
|
553
|
-
|
540
|
+
# invalid macro syntax (link: prefix w/o trailing square brackets or enclosed in double quotes)
|
541
|
+
# FIXME we probably shouldn't even get here when the link: prefix is present; the regex is doing too much
|
542
|
+
case prefix
|
543
|
+
when 'link:', ?", ?'
|
544
|
+
next $&
|
545
|
+
end
|
554
546
|
case $3
|
555
|
-
when ')'
|
556
|
-
# move trailing ) out of URL
|
547
|
+
when ')', '?', '!'
|
557
548
|
target = target.chop
|
558
|
-
suffix = ')'
|
549
|
+
if (suffix = $3) == ')' && (target.end_with? '.', '?', '!')
|
550
|
+
suffix = target[-1] + suffix
|
551
|
+
target = target.chop
|
552
|
+
end
|
559
553
|
# NOTE handle case when modified target is a URI scheme (e.g., http://)
|
560
554
|
next $& if target.end_with? '://'
|
561
555
|
when ';'
|
@@ -588,26 +582,37 @@ module Substitutors
|
|
588
582
|
end
|
589
583
|
|
590
584
|
attrs, link_opts = nil, { type: :link }
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
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
|
595
592
|
link_opts[:id] = attrs['id']
|
596
593
|
end
|
597
594
|
|
598
|
-
if
|
599
|
-
|
595
|
+
if link_text.end_with? '^'
|
596
|
+
new_link_text = link_text = link_text.chop
|
600
597
|
if attrs
|
601
598
|
attrs['window'] ||= '_blank'
|
602
599
|
else
|
603
600
|
attrs = { 'window' => '_blank' }
|
604
601
|
end
|
605
602
|
end
|
606
|
-
end
|
607
603
|
|
608
|
-
|
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
|
609
610
|
# NOTE it's not possible for the URI scheme to be bare in this case
|
610
|
-
|
611
|
+
link_text = (doc_attrs.key? 'hide-uri-scheme') ? (target.sub UriSniffRx, '') : target
|
612
|
+
bare = true
|
613
|
+
end
|
614
|
+
|
615
|
+
if bare
|
611
616
|
if attrs
|
612
617
|
attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
|
613
618
|
else
|
@@ -617,7 +622,7 @@ module Substitutors
|
|
617
622
|
|
618
623
|
doc.register :links, (link_opts[:target] = target)
|
619
624
|
link_opts[:attributes] = attrs if attrs
|
620
|
-
%(#{prefix}#{(Inline.new self, :anchor,
|
625
|
+
%(#{prefix}#{(Inline.new self, :anchor, link_text, link_opts).convert}#{suffix})
|
621
626
|
end
|
622
627
|
end
|
623
628
|
|
@@ -633,11 +638,12 @@ module Substitutors
|
|
633
638
|
target = $2
|
634
639
|
end
|
635
640
|
attrs, link_opts = nil, { type: :link }
|
636
|
-
unless (
|
637
|
-
|
641
|
+
unless (link_text = $3).empty?
|
642
|
+
link_text = link_text.gsub ESC_R_SB, R_SB if link_text.include? R_SB
|
638
643
|
if mailto
|
639
|
-
if !doc.compat_mode && (
|
640
|
-
|
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, ''
|
641
647
|
link_opts[:id] = attrs['id']
|
642
648
|
if attrs.key? 2
|
643
649
|
if attrs.key? 3
|
@@ -647,13 +653,14 @@ module Substitutors
|
|
647
653
|
end
|
648
654
|
end
|
649
655
|
end
|
650
|
-
elsif !doc.compat_mode && (
|
651
|
-
|
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, ''
|
652
659
|
link_opts[:id] = attrs['id']
|
653
660
|
end
|
654
661
|
|
655
|
-
if
|
656
|
-
|
662
|
+
if link_text.end_with? '^'
|
663
|
+
link_text = link_text.chop
|
657
664
|
if attrs
|
658
665
|
attrs['window'] ||= '_blank'
|
659
666
|
else
|
@@ -662,17 +669,17 @@ module Substitutors
|
|
662
669
|
end
|
663
670
|
end
|
664
671
|
|
665
|
-
if
|
672
|
+
if link_text.empty?
|
666
673
|
# mailto is a special case, already processed
|
667
674
|
if mailto
|
668
|
-
|
675
|
+
link_text = mailto_text
|
669
676
|
else
|
670
677
|
if doc_attrs.key? 'hide-uri-scheme'
|
671
|
-
if (
|
672
|
-
|
678
|
+
if (link_text = target.sub UriSniffRx, '').empty?
|
679
|
+
link_text = target
|
673
680
|
end
|
674
681
|
else
|
675
|
-
|
682
|
+
link_text = target
|
676
683
|
end
|
677
684
|
if attrs
|
678
685
|
attrs['role'] = (attrs.key? 'role') ? %(bare #{attrs['role']}) : 'bare'
|
@@ -685,7 +692,7 @@ module Substitutors
|
|
685
692
|
# QUESTION should a mailto be registered as an e-mail address?
|
686
693
|
doc.register :links, (link_opts[:target] = target)
|
687
694
|
link_opts[:attributes] = attrs if attrs
|
688
|
-
Inline.new(self, :anchor,
|
695
|
+
Inline.new(self, :anchor, link_text, link_opts).convert
|
689
696
|
end
|
690
697
|
end
|
691
698
|
|
@@ -732,15 +739,17 @@ module Substitutors
|
|
732
739
|
|
733
740
|
attrs = {}
|
734
741
|
if (refid = $1)
|
735
|
-
|
736
|
-
|
742
|
+
if refid.include? ','
|
743
|
+
refid, _, link_text = refid.partition ','
|
744
|
+
link_text = nil if (link_text = link_text.lstrip).empty?
|
745
|
+
end
|
737
746
|
else
|
738
747
|
macro = true
|
739
748
|
refid = $2
|
740
|
-
if (
|
741
|
-
|
742
|
-
# NOTE if an
|
743
|
-
|
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? '=')
|
744
753
|
end
|
745
754
|
end
|
746
755
|
|
@@ -794,7 +803,7 @@ module Substitutors
|
|
794
803
|
refid, path, target = nil, nil, '#'
|
795
804
|
end
|
796
805
|
else
|
797
|
-
refid, path = path, %(#{doc.attributes['relfileprefix']}#{path}#{src2src ? (doc.attributes.fetch 'relfilesuffix', doc.outfilesuffix) : ''})
|
806
|
+
refid, path = path, %(#{doc.attributes['relfileprefix'] || ''}#{path}#{src2src ? (doc.attributes.fetch 'relfilesuffix', doc.outfilesuffix) : ''})
|
798
807
|
if fragment
|
799
808
|
refid, target = %(#{refid}##{fragment}), %(#{path}##{fragment})
|
800
809
|
else
|
@@ -804,7 +813,7 @@ module Substitutors
|
|
804
813
|
# handles: id (in compat mode or when natural xrefs are disabled)
|
805
814
|
elsif doc.compat_mode || !Compliance.natural_xrefs
|
806
815
|
refid, target = fragment, %(##{fragment})
|
807
|
-
logger.info %(possible invalid reference: #{refid}) if logger.info? && doc.catalog[:refs][refid]
|
816
|
+
logger.info %(possible invalid reference: #{refid}) if logger.info? && !doc.catalog[:refs][refid]
|
808
817
|
# handles: id
|
809
818
|
elsif doc.catalog[:refs][fragment]
|
810
819
|
refid, target = fragment, %(##{fragment})
|
@@ -819,7 +828,7 @@ module Substitutors
|
|
819
828
|
attrs['path'] = path
|
820
829
|
attrs['fragment'] = fragment
|
821
830
|
attrs['refid'] = refid
|
822
|
-
Inline.new(self, :anchor,
|
831
|
+
Inline.new(self, :anchor, link_text, type: :xref, target: target, attributes: attrs).convert
|
823
832
|
end
|
824
833
|
end
|
825
834
|
|
@@ -831,7 +840,7 @@ module Substitutors
|
|
831
840
|
# footnoteref
|
832
841
|
if $1
|
833
842
|
if $3
|
834
|
-
id,
|
843
|
+
id, content = $3.split ',', 2
|
835
844
|
logger.warn %(found deprecated footnoteref macro: #{$&}; use footnote macro with target instead) unless doc.compat_mode
|
836
845
|
else
|
837
846
|
next $&
|
@@ -839,33 +848,31 @@ module Substitutors
|
|
839
848
|
# footnote
|
840
849
|
else
|
841
850
|
id = $2
|
842
|
-
|
851
|
+
content = $3
|
843
852
|
end
|
844
853
|
|
845
854
|
if id
|
846
|
-
if
|
847
|
-
|
855
|
+
if (footnote = doc.footnotes.find {|candidate| candidate.id == id })
|
856
|
+
index, content = footnote.index, footnote.text
|
857
|
+
type, target, id = :xref, id, nil
|
858
|
+
elsif content
|
859
|
+
content = restore_passthroughs(normalize_text content, true, true)
|
848
860
|
index = doc.counter('footnote-number')
|
849
|
-
doc.register(:footnotes, Document::Footnote.new(index, id,
|
861
|
+
doc.register(:footnotes, Document::Footnote.new(index, id, content))
|
850
862
|
type, target = :ref, nil
|
851
863
|
else
|
852
|
-
|
853
|
-
|
854
|
-
else
|
855
|
-
logger.warn %(invalid footnote reference: #{id})
|
856
|
-
index, text = nil, id
|
857
|
-
end
|
858
|
-
type, target, id = :xref, id, nil
|
864
|
+
logger.warn %(invalid footnote reference: #{id})
|
865
|
+
type, target, content, id = :xref, id, id, nil
|
859
866
|
end
|
860
|
-
elsif
|
861
|
-
|
867
|
+
elsif content
|
868
|
+
content = restore_passthroughs(normalize_text content, true, true)
|
862
869
|
index = doc.counter('footnote-number')
|
863
|
-
doc.register(:footnotes, Document::Footnote.new(index, id,
|
870
|
+
doc.register(:footnotes, Document::Footnote.new(index, id, content))
|
864
871
|
type = target = nil
|
865
872
|
else
|
866
873
|
next $&
|
867
874
|
end
|
868
|
-
Inline.new(self, :footnote,
|
875
|
+
Inline.new(self, :footnote, content, attributes: { 'index' => index }, id: id, target: target, type: type).convert
|
869
876
|
end
|
870
877
|
end
|
871
878
|
|
@@ -917,7 +924,7 @@ module Substitutors
|
|
917
924
|
# use sub since it might be behind a line comment
|
918
925
|
$&.sub RS, ''
|
919
926
|
else
|
920
|
-
Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, id: @document.callouts.read_next_id, attributes: { 'guard' => $1 }).convert
|
927
|
+
Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, id: @document.callouts.read_next_id, attributes: { 'guard' => $1 || ($3 == '--' ? ['<!--', '-->'] : nil) }).convert
|
921
928
|
end
|
922
929
|
end
|
923
930
|
end
|
@@ -933,7 +940,7 @@ module Substitutors
|
|
933
940
|
# process_callouts - a Boolean flag indicating whether callout marks should be located and substituted
|
934
941
|
#
|
935
942
|
# Returns the highlighted source code, if a syntax highlighter is defined on the document, otherwise the source with
|
936
|
-
# verbatim
|
943
|
+
# verbatim substitutions applied
|
937
944
|
def highlight_source source, process_callouts
|
938
945
|
# NOTE the call to highlight? is a defensive check since, normally, we wouldn't arrive here unless it returns true
|
939
946
|
return sub_source source, process_callouts unless (syntax_hl = @document.syntax_highlighter) && syntax_hl.highlight?
|
@@ -942,10 +949,11 @@ module Substitutors
|
|
942
949
|
|
943
950
|
doc_attrs = @document.attributes
|
944
951
|
syntax_hl_name = syntax_hl.name
|
945
|
-
if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil)
|
946
|
-
|
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
|
947
955
|
end
|
948
|
-
highlight_lines = resolve_lines_to_highlight source, (attr 'highlight') if attr? 'highlight'
|
956
|
+
highlight_lines = resolve_lines_to_highlight source, (attr 'highlight'), start_line_number if attr? 'highlight'
|
949
957
|
|
950
958
|
highlighted, source_offset = syntax_hl.highlight self, source, (attr 'language'),
|
951
959
|
callouts: callout_marks,
|
@@ -968,9 +976,10 @@ module Substitutors
|
|
968
976
|
#
|
969
977
|
# source - The String source.
|
970
978
|
# spec - The lines specifier (e.g., "1-5, !2, 10" or "1..5;!2;10")
|
979
|
+
# start - The line number of the first line (optional, default: false)
|
971
980
|
#
|
972
981
|
# Returns an [Array] of unique, sorted line numbers.
|
973
|
-
def resolve_lines_to_highlight source, spec
|
982
|
+
def resolve_lines_to_highlight source, spec, start = nil
|
974
983
|
lines = []
|
975
984
|
spec = spec.delete ' ' if spec.include? ' '
|
976
985
|
((spec.include? ',') ? (spec.split ',') : (spec.split ';')).map do |entry|
|
@@ -979,28 +988,29 @@ module Substitutors
|
|
979
988
|
negate = true
|
980
989
|
end
|
981
990
|
if (delim = (entry.include? '..') ? '..' : ((entry.include? '-') ? '-' : nil))
|
982
|
-
from,
|
991
|
+
from, _, to = entry.partition delim
|
983
992
|
to = (source.count LF) + 1 if to.empty? || (to = to.to_i) < 0
|
984
|
-
line_nums = (from.to_i..to).to_a
|
985
993
|
if negate
|
986
|
-
lines -=
|
994
|
+
lines -= (from.to_i..to).to_a
|
987
995
|
else
|
988
|
-
lines.
|
989
|
-
end
|
990
|
-
else
|
991
|
-
if negate
|
992
|
-
lines.delete entry.to_i
|
993
|
-
else
|
994
|
-
lines << entry.to_i
|
996
|
+
lines |= (from.to_i..to).to_a
|
995
997
|
end
|
998
|
+
elsif negate
|
999
|
+
lines.delete entry.to_i
|
1000
|
+
elsif !lines.include?(line = entry.to_i)
|
1001
|
+
lines << line
|
996
1002
|
end
|
997
1003
|
end
|
998
|
-
lines.
|
1004
|
+
# If the start attribute is defined, then the lines to highlight specified by the provided spec should be relative to the start value.
|
1005
|
+
unless (shift = start ? start - 1 : 0) == 0
|
1006
|
+
lines = lines.map {|it| it - shift }
|
1007
|
+
end
|
1008
|
+
lines.sort
|
999
1009
|
end
|
1000
1010
|
|
1001
1011
|
# Public: Extract the passthrough text from the document for reinsertion after processing.
|
1002
1012
|
#
|
1003
|
-
# text - The String from which to extract passthrough
|
1013
|
+
# text - The String from which to extract passthrough fragments
|
1004
1014
|
#
|
1005
1015
|
# Returns the String text with passthrough regions substituted with placeholders
|
1006
1016
|
def extract_passthroughs text
|
@@ -1112,7 +1122,7 @@ module Substitutors
|
|
1112
1122
|
end
|
1113
1123
|
subs = $2
|
1114
1124
|
content = normalize_text $3, nil, true
|
1115
|
-
# NOTE drop enclosing $ signs around latexmath for backwards compatibility with AsciiDoc
|
1125
|
+
# NOTE drop enclosing $ signs around latexmath for backwards compatibility with AsciiDoc.py
|
1116
1126
|
content = content.slice 1, content.length - 2 if type == :latexmath && (content.start_with? '$') && (content.end_with? '$')
|
1117
1127
|
subs = subs ? (resolve_pass_subs subs) : ((@document.basebackend? 'html') ? BASIC_SUBS : nil)
|
1118
1128
|
passthrus[passthru_key = passthrus.size] = { text: content, subs: subs, type: type }
|
@@ -1207,7 +1217,7 @@ module Substitutors
|
|
1207
1217
|
end
|
1208
1218
|
end
|
1209
1219
|
return unless candidates
|
1210
|
-
# weed out invalid options and remove duplicates (order is preserved; first
|
1220
|
+
# weed out invalid options and remove duplicates (order is preserved; first occurrence wins)
|
1211
1221
|
resolved = candidates & SUB_OPTIONS[type]
|
1212
1222
|
unless (candidates - resolved).empty?
|
1213
1223
|
invalid = candidates - resolved
|
@@ -1226,17 +1236,17 @@ module Substitutors
|
|
1226
1236
|
resolve_subs subs, :inline, nil, 'passthrough macro'
|
1227
1237
|
end
|
1228
1238
|
|
1229
|
-
# Public: Expand all groups in the subs list and return. If no subs are
|
1239
|
+
# Public: Expand all groups in the subs list and return. If no subs are resolved, return nil.
|
1230
1240
|
#
|
1231
|
-
# subs - The substitutions to expand; can be a Symbol, Symbol Array or
|
1241
|
+
# subs - The substitutions to expand; can be a Symbol, Symbol Array, or String
|
1242
|
+
# subject - The String to use in log messages to communicate the subject for which subs are being resolved (default: nil)
|
1232
1243
|
#
|
1233
1244
|
# Returns a Symbol Array of substitutions to pass to apply_subs or nil if no substitutions were resolved.
|
1234
|
-
def expand_subs subs
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
else
|
1245
|
+
def expand_subs subs, subject = nil
|
1246
|
+
case subs
|
1247
|
+
when ::Symbol
|
1248
|
+
subs == :none ? nil : SUB_GROUPS[subs] || [subs]
|
1249
|
+
when ::Array
|
1240
1250
|
expanded_subs = []
|
1241
1251
|
subs.each do |key|
|
1242
1252
|
unless key == :none
|
@@ -1247,8 +1257,9 @@ module Substitutors
|
|
1247
1257
|
end
|
1248
1258
|
end
|
1249
1259
|
end
|
1250
|
-
|
1251
1260
|
expanded_subs.empty? ? nil : expanded_subs
|
1261
|
+
else
|
1262
|
+
resolve_subs subs, :inline, nil, subject
|
1252
1263
|
end
|
1253
1264
|
end
|
1254
1265
|
|
@@ -1270,7 +1281,7 @@ module Substitutors
|
|
1270
1281
|
# NOTE :literal with listparagraph-option gets folded into text of list item later
|
1271
1282
|
default_subs = @context == :verse ? NORMAL_SUBS : VERBATIM_SUBS
|
1272
1283
|
when :raw
|
1273
|
-
# TODO make pass subs a compliance setting; AsciiDoc
|
1284
|
+
# TODO make pass subs a compliance setting; AsciiDoc.py performs :attributes and :macros on a pass block
|
1274
1285
|
default_subs = @context == :stem ? BASIC_SUBS : NO_SUBS
|
1275
1286
|
else
|
1276
1287
|
return @subs
|
@@ -1321,10 +1332,23 @@ module Substitutors
|
|
1321
1332
|
|
1322
1333
|
private
|
1323
1334
|
|
1335
|
+
# This method is used in cases when the attrlist can be mixed with the text of a macro.
|
1336
|
+
# If no attributes are detected aside from the first positional attribute, and the first positional
|
1337
|
+
# attribute matches the attrlist, then the original text is returned.
|
1338
|
+
def extract_attributes_from_text text, default_text = nil
|
1339
|
+
attrlist = (text.include? LF) ? (text.tr LF, ' ') : text
|
1340
|
+
if (resolved_text = (attrs = (AttributeList.new attrlist, self).parse)[1])
|
1341
|
+
# NOTE if resolved text remains unchanged, clear attributes and return unparsed text
|
1342
|
+
resolved_text == attrlist ? [text, attrs.clear] : [resolved_text, attrs]
|
1343
|
+
else
|
1344
|
+
[default_text, attrs]
|
1345
|
+
end
|
1346
|
+
end
|
1347
|
+
|
1324
1348
|
# Internal: Extract the callout numbers from the source to prepare it for syntax highlighting.
|
1325
1349
|
def extract_callouts source
|
1326
1350
|
callout_marks = {}
|
1327
|
-
lineno = 0
|
1351
|
+
autonum = lineno = 0
|
1328
1352
|
last_lineno = nil
|
1329
1353
|
callout_rx = (attr? 'line-comment') ? CalloutExtractRxMap[attr 'line-comment'] : CalloutExtractRx
|
1330
1354
|
# extract callout marks, indexed by line number
|
@@ -1336,7 +1360,7 @@ module Substitutors
|
|
1336
1360
|
# use sub since it might be behind a line comment
|
1337
1361
|
$&.sub RS, ''
|
1338
1362
|
else
|
1339
|
-
(callout_marks[lineno] ||= []) << [$1, $4]
|
1363
|
+
(callout_marks[lineno] ||= []) << [$1 || ($3 == '--' ? ['<!--', '-->'] : nil), $4 == '.' ? (autonum += 1).to_s : $4]
|
1340
1364
|
last_lineno = lineno
|
1341
1365
|
''
|
1342
1366
|
end
|
@@ -1358,15 +1382,15 @@ module Substitutors
|
|
1358
1382
|
else
|
1359
1383
|
preamble = ''
|
1360
1384
|
end
|
1361
|
-
|
1385
|
+
lineno = 0
|
1362
1386
|
preamble + ((source.split LF, -1).map do |line|
|
1363
1387
|
if (conums = callout_marks.delete lineno += 1)
|
1364
1388
|
if conums.size == 1
|
1365
|
-
guard,
|
1366
|
-
%(#{line}#{Inline.new(self, :callout,
|
1389
|
+
guard, numeral = conums[0]
|
1390
|
+
%(#{line}#{Inline.new(self, :callout, numeral, id: @document.callouts.read_next_id, attributes: { 'guard' => guard }).convert})
|
1367
1391
|
else
|
1368
|
-
%(#{line}#{conums.map do |guard_it,
|
1369
|
-
Inline.new(self, :callout,
|
1392
|
+
%(#{line}#{conums.map do |guard_it, numeral_it|
|
1393
|
+
Inline.new(self, :callout, numeral_it, id: @document.callouts.read_next_id, attributes: { 'guard' => guard_it }).convert
|
1370
1394
|
end.join ' '})
|
1371
1395
|
end
|
1372
1396
|
else
|
@@ -1453,33 +1477,28 @@ module Substitutors
|
|
1453
1477
|
#
|
1454
1478
|
# Returns a Hash of attributes (role and id only)
|
1455
1479
|
def parse_quoted_text_attributes str
|
1456
|
-
return {} if (str = str.rstrip).empty?
|
1457
1480
|
# NOTE attributes are typically resolved after quoted text, so substitute eagerly
|
1458
1481
|
str = sub_attributes str if str.include? ATTR_REF_HEAD
|
1459
1482
|
# for compliance, only consider first positional attribute (very unlikely)
|
1460
1483
|
str = str.slice 0, (str.index ',') if str.include? ','
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1484
|
+
if (str = str.strip).empty?
|
1485
|
+
{}
|
1486
|
+
elsif (str.start_with? '.', '#') && Compliance.shorthand_property_syntax
|
1487
|
+
before, _, after = str.partition '#'
|
1488
|
+
attrs = {}
|
1489
|
+
if after.empty?
|
1490
|
+
attrs['role'] = (before.tr '.', ' ').lstrip if before.length > 1
|
1467
1491
|
else
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
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
|
1478
1501
|
end
|
1479
|
-
|
1480
|
-
attrs = {}
|
1481
|
-
attrs['id'] = id if id
|
1482
|
-
attrs['role'] = roles.join ' ' unless roles.empty?
|
1483
1502
|
attrs
|
1484
1503
|
else
|
1485
1504
|
{ 'role' => str }
|
@@ -1513,7 +1532,7 @@ module Substitutors
|
|
1513
1532
|
case c
|
1514
1533
|
when ','
|
1515
1534
|
if quote_open
|
1516
|
-
accum
|
1535
|
+
accum += c
|
1517
1536
|
else
|
1518
1537
|
values << accum.strip
|
1519
1538
|
accum = ''
|
@@ -1521,7 +1540,7 @@ module Substitutors
|
|
1521
1540
|
when '"'
|
1522
1541
|
quote_open = !quote_open
|
1523
1542
|
else
|
1524
|
-
accum
|
1543
|
+
accum += c
|
1525
1544
|
end
|
1526
1545
|
end
|
1527
1546
|
values << accum.strip
|