asciidoctor 2.0.15 → 2.0.17
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 +86 -11
- data/LICENSE +1 -1
- data/README-de.adoc +9 -12
- data/README-fr.adoc +9 -12
- data/README-jp.adoc +10 -13
- data/README-zh_CN.adoc +9 -12
- data/README.adoc +33 -18
- data/asciidoctor.gemspec +2 -9
- data/data/locale/attributes-fr.adoc +2 -2
- data/data/locale/attributes-th.adoc +23 -0
- data/data/locale/attributes-vi.adoc +23 -0
- data/data/stylesheets/asciidoctor-default.css +54 -53
- data/data/stylesheets/coderay-asciidoctor.css +9 -9
- data/lib/asciidoctor/abstract_block.rb +11 -9
- data/lib/asciidoctor/abstract_node.rb +9 -8
- data/lib/asciidoctor/block.rb +6 -6
- data/lib/asciidoctor/cli/invoker.rb +1 -2
- data/lib/asciidoctor/cli/options.rb +25 -25
- data/lib/asciidoctor/convert.rb +1 -0
- data/lib/asciidoctor/converter/docbook5.rb +20 -22
- data/lib/asciidoctor/converter/html5.rb +112 -94
- data/lib/asciidoctor/converter/manpage.rb +61 -52
- data/lib/asciidoctor/converter/template.rb +12 -13
- data/lib/asciidoctor/converter.rb +6 -4
- data/lib/asciidoctor/core_ext/hash/merge.rb +1 -1
- data/lib/asciidoctor/document.rb +39 -41
- data/lib/asciidoctor/extensions.rb +20 -12
- 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 +172 -189
- data/lib/asciidoctor/path_resolver.rb +3 -3
- data/lib/asciidoctor/reader.rb +71 -72
- data/lib/asciidoctor/rx.rb +3 -2
- data/lib/asciidoctor/section.rb +7 -0
- data/lib/asciidoctor/substitutors.rb +101 -103
- 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 +14 -5
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +2 -1
- data/lib/asciidoctor/syntax_highlighter.rb +8 -11
- data/lib/asciidoctor/table.rb +18 -20
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/lib/asciidoctor.rb +7 -7
- data/man/asciidoctor.1 +26 -28
- data/man/asciidoctor.adoc +33 -27
- metadata +8 -62
@@ -21,7 +21,7 @@ class Converter::Html5Converter < Converter::Base
|
|
21
21
|
#latexmath: INLINE_MATH_DELIMITERS[:latexmath] + [false],
|
22
22
|
}).default = ['', '']
|
23
23
|
|
24
|
-
DropAnchorRx =
|
24
|
+
DropAnchorRx = %r(<(?:a\b[^>]*|/a)>)
|
25
25
|
StemBreakRx = / *\\\n(?:\\?\n)*|\n\n+/
|
26
26
|
if RUBY_ENGINE == 'opal'
|
27
27
|
# NOTE In JavaScript, ^ matches the start of the string when the m flag is not set
|
@@ -48,44 +48,45 @@ class Converter::Html5Converter < Converter::Base
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def convert node, transform = node.node_name, opts = nil
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
51
|
+
case transform
|
52
|
+
when 'inline_quoted' then convert_inline_quoted node
|
53
|
+
when 'paragraph' then convert_paragraph node
|
54
|
+
when 'inline_anchor' then convert_inline_anchor node
|
55
|
+
when 'section' then convert_section node
|
56
|
+
when 'listing' then convert_listing node
|
57
|
+
when 'literal' then convert_literal node
|
58
|
+
when 'ulist' then convert_ulist node
|
59
|
+
when 'olist' then convert_olist node
|
60
|
+
when 'dlist' then convert_dlist node
|
61
|
+
when 'admonition' then convert_admonition node
|
62
|
+
when 'colist' then convert_colist node
|
63
|
+
when 'embedded' then convert_embedded node
|
64
|
+
when 'example' then convert_example node
|
65
|
+
when 'floating_title' then convert_floating_title node
|
66
|
+
when 'image' then convert_image node
|
67
|
+
when 'inline_break' then convert_inline_break node
|
68
|
+
when 'inline_button' then convert_inline_button node
|
69
|
+
when 'inline_callout' then convert_inline_callout node
|
70
|
+
when 'inline_footnote' then convert_inline_footnote node
|
71
|
+
when 'inline_image' then convert_inline_image node
|
72
|
+
when 'inline_indexterm' then convert_inline_indexterm node
|
73
|
+
when 'inline_kbd' then convert_inline_kbd node
|
74
|
+
when 'inline_menu' then convert_inline_menu node
|
75
|
+
when 'open' then convert_open node
|
76
|
+
when 'page_break' then convert_page_break node
|
77
|
+
when 'preamble' then convert_preamble node
|
78
|
+
when 'quote' then convert_quote node
|
79
|
+
when 'sidebar' then convert_sidebar node
|
80
|
+
when 'stem' then convert_stem node
|
81
|
+
when 'table' then convert_table node
|
82
|
+
when 'thematic_break' then convert_thematic_break node
|
83
|
+
when 'verse' then convert_verse node
|
84
|
+
when 'video' then convert_video node
|
85
|
+
when 'document' then convert_document node
|
86
|
+
when 'toc' then convert_toc node
|
87
|
+
when 'pass' then convert_pass node
|
88
|
+
when 'audio' then convert_audio node
|
89
|
+
else; super
|
89
90
|
end
|
90
91
|
end
|
91
92
|
|
@@ -350,9 +351,10 @@ MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
|
|
350
351
|
stitle = section.captioned_title
|
351
352
|
elsif section.numbered && slevel <= sectnumlevels
|
352
353
|
if slevel < 2 && node.document.doctype == 'book'
|
353
|
-
|
354
|
+
case section.sectname
|
355
|
+
when 'chapter'
|
354
356
|
stitle = %(#{(signifier = node.document.attributes['chapter-signifier']) ? "#{signifier} " : ''}#{section.sectnum} #{section.title})
|
355
|
-
|
357
|
+
when 'part'
|
356
358
|
stitle = %(#{(signifier = node.document.attributes['part-signifier']) ? "#{signifier} " : ''}#{section.sectnum nil, ':'} #{section.title})
|
357
359
|
else
|
358
360
|
stitle = %(#{section.sectnum} #{section.title})
|
@@ -383,9 +385,10 @@ MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
|
|
383
385
|
title = node.captioned_title
|
384
386
|
elsif node.numbered && level <= (doc_attrs['sectnumlevels'] || 3).to_i
|
385
387
|
if level < 2 && node.document.doctype == 'book'
|
386
|
-
|
388
|
+
case node.sectname
|
389
|
+
when 'chapter'
|
387
390
|
title = %(#{(signifier = doc_attrs['chapter-signifier']) ? "#{signifier} " : ''}#{node.sectnum} #{node.title})
|
388
|
-
|
391
|
+
when 'part'
|
389
392
|
title = %(#{(signifier = doc_attrs['part-signifier']) ? "#{signifier} " : ''}#{node.sectnum nil, ':'} #{node.title})
|
390
393
|
else
|
391
394
|
title = %(#{node.sectnum} #{node.title})
|
@@ -513,16 +516,16 @@ Your browser does not support the audio tag.
|
|
513
516
|
result = []
|
514
517
|
id_attribute = node.id ? %( id="#{node.id}") : ''
|
515
518
|
|
516
|
-
|
519
|
+
case node.style
|
517
520
|
when 'qanda'
|
518
|
-
['qlist', 'qanda', node.role]
|
521
|
+
classes = ['qlist', 'qanda', node.role]
|
519
522
|
when 'horizontal'
|
520
|
-
['hdlist', node.role]
|
523
|
+
classes = ['hdlist', node.role]
|
521
524
|
else
|
522
|
-
['dlist', node.style, node.role]
|
523
|
-
end
|
525
|
+
classes = ['dlist', node.style, node.role]
|
526
|
+
end
|
524
527
|
|
525
|
-
class_attribute = %( class="#{classes.join ' '}")
|
528
|
+
class_attribute = %( class="#{classes.compact.join ' '}")
|
526
529
|
|
527
530
|
result << %(<div#{id_attribute}#{class_attribute}>)
|
528
531
|
result << %(<div class="title">#{node.title}</div>) if node.title?
|
@@ -578,12 +581,11 @@ Your browser does not support the audio tag.
|
|
578
581
|
terms.each do |dt|
|
579
582
|
result << %(<dt#{dt_style_attribute}>#{dt.text}</dt>)
|
580
583
|
end
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
end
|
584
|
+
next unless dd
|
585
|
+
result << '<dd>'
|
586
|
+
result << %(<p>#{dd.text}</p>) if dd.text?
|
587
|
+
result << dd.content if dd.blocks?
|
588
|
+
result << '</dd>'
|
587
589
|
end
|
588
590
|
result << '</dl>'
|
589
591
|
end
|
@@ -624,16 +626,18 @@ Your browser does not support the audio tag.
|
|
624
626
|
target = node.attr 'target'
|
625
627
|
width_attr = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
|
626
628
|
height_attr = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : ''
|
627
|
-
if ((node.attr? 'format', 'svg') || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE
|
628
|
-
|
629
|
-
if svg
|
629
|
+
if ((node.attr? 'format', 'svg') || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE
|
630
|
+
if node.option? 'inline'
|
630
631
|
img = (read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
|
631
|
-
elsif
|
632
|
-
fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri
|
632
|
+
elsif node.option? 'interactive'
|
633
|
+
fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri node.attr 'fallback'}" alt="#{encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
|
633
634
|
img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{width_attr}#{height_attr}>#{fallback}</object>)
|
635
|
+
else
|
636
|
+
img = %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
|
634
637
|
end
|
638
|
+
else
|
639
|
+
img = %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
|
635
640
|
end
|
636
|
-
img ||= %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
|
637
641
|
img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>) if node.attr? 'link'
|
638
642
|
id_attr = node.id ? %( id="#{node.id}") : ''
|
639
643
|
classes = ['imageblock']
|
@@ -759,8 +763,8 @@ Your browser does not support the audio tag.
|
|
759
763
|
logger.error 'partintro block can only be used when doctype is book and must be a child of a book part. Excluding block content.'
|
760
764
|
''
|
761
765
|
else
|
762
|
-
|
763
|
-
|
766
|
+
id_attr = node.id ? %( id="#{node.id}") : ''
|
767
|
+
title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : ''
|
764
768
|
%(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) ? " #{role}" : ''}">
|
765
769
|
#{title_el}<div class="content">
|
766
770
|
#{node.content}
|
@@ -857,20 +861,19 @@ Your browser does not support the audio tag.
|
|
857
861
|
if (stripes = node.attr 'stripes', nil, 'table-stripes')
|
858
862
|
classes << %(stripes-#{stripes})
|
859
863
|
end
|
860
|
-
|
864
|
+
style_attribute = ''
|
861
865
|
if (autowidth = node.option? 'autowidth') && !(node.attr? 'width')
|
862
866
|
classes << 'fit-content'
|
863
867
|
elsif (tablewidth = node.attr 'tablepcwidth') == 100
|
864
868
|
classes << 'stretch'
|
865
869
|
else
|
866
|
-
|
870
|
+
style_attribute = %( style="width: #{tablewidth}%;")
|
867
871
|
end
|
868
872
|
classes << (node.attr 'float') if node.attr? 'float'
|
869
873
|
if (role = node.role)
|
870
874
|
classes << role
|
871
875
|
end
|
872
876
|
class_attribute = %( class="#{classes.join ' '}")
|
873
|
-
style_attribute = styles.empty? ? '' : %( style="#{styles.join ' '}")
|
874
877
|
|
875
878
|
result << %(<table#{id_attribute}#{class_attribute}#{style_attribute}>)
|
876
879
|
result << %(<caption class="title">#{node.captioned_title}</caption>) if node.title?
|
@@ -1033,12 +1036,14 @@ Your browser does not support the audio tag.
|
|
1033
1036
|
end
|
1034
1037
|
start_anchor = (node.attr? 'start') ? %(#at=#{node.attr 'start'}) : ''
|
1035
1038
|
delimiter = ['?']
|
1039
|
+
target, hash = (node.attr 'target').split '/', 2
|
1040
|
+
hash_param = (hash ||= node.attr 'hash') ? %(#{delimiter.pop || '&'}h=#{hash}) : ''
|
1036
1041
|
autoplay_param = (node.option? 'autoplay') ? %(#{delimiter.pop || '&'}autoplay=1) : ''
|
1037
1042
|
loop_param = (node.option? 'loop') ? %(#{delimiter.pop || '&'}loop=1) : ''
|
1038
1043
|
muted_param = (node.option? 'muted') ? %(#{delimiter.pop || '&'}muted=1) : ''
|
1039
1044
|
%(<div#{id_attribute}#{class_attribute}>#{title_element}
|
1040
1045
|
<div class="content">
|
1041
|
-
<iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//player.vimeo.com/video/#{
|
1046
|
+
<iframe#{width_attribute}#{height_attribute} src="#{asset_uri_scheme}//player.vimeo.com/video/#{target}#{hash_param}#{autoplay_param}#{loop_param}#{muted_param}#{start_anchor}" frameborder="0"#{(node.option? 'nofullscreen') ? '' : (append_boolean_attribute 'allowfullscreen', xml)}></iframe>
|
1042
1047
|
</div>
|
1043
1048
|
</div>)
|
1044
1049
|
when 'youtube'
|
@@ -1074,7 +1079,7 @@ Your browser does not support the audio tag.
|
|
1074
1079
|
target, playlist = target.split ',', 2
|
1075
1080
|
if (playlist ||= (node.attr 'playlist'))
|
1076
1081
|
# INFO playlist bar doesn't appear in Firefox unless showinfo=1 and modestbranding=1
|
1077
|
-
list_param = %(&playlist=#{playlist})
|
1082
|
+
list_param = %(&playlist=#{target},#{playlist})
|
1078
1083
|
else
|
1079
1084
|
# NOTE for loop to work, playlist must be specified; use VIDEO_ID if there's no explicit playlist
|
1080
1085
|
list_param = has_loop_param ? %(&playlist=#{target}) : ''
|
@@ -1178,40 +1183,49 @@ Your browser does not support the video tag.
|
|
1178
1183
|
end
|
1179
1184
|
|
1180
1185
|
def convert_inline_image node
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1186
|
+
target = node.target
|
1187
|
+
if (type = node.type || 'image') == 'icon'
|
1188
|
+
if (icons = node.document.attr 'icons') == 'font'
|
1189
|
+
i_class_attr_val = %(fa fa-#{target})
|
1190
|
+
i_class_attr_val = %(#{i_class_attr_val} fa-#{node.attr 'size'}) if node.attr? 'size'
|
1191
|
+
if node.attr? 'flip'
|
1192
|
+
i_class_attr_val = %(#{i_class_attr_val} fa-flip-#{node.attr 'flip'})
|
1193
|
+
elsif node.attr? 'rotate'
|
1194
|
+
i_class_attr_val = %(#{i_class_attr_val} fa-rotate-#{node.attr 'rotate'})
|
1195
|
+
end
|
1196
|
+
attrs = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : ''
|
1197
|
+
img = %(<i class="#{i_class_attr_val}"#{attrs}></i>)
|
1198
|
+
elsif icons
|
1199
|
+
attrs = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
|
1200
|
+
attrs = %(#{attrs} height="#{node.attr 'height'}") if node.attr? 'height'
|
1201
|
+
attrs = %(#{attrs} title="#{node.attr 'title'}") if node.attr? 'title'
|
1202
|
+
img = %(<img src="#{node.icon_uri target}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
|
1203
|
+
else
|
1204
|
+
img = %([#{node.alt}])
|
1185
1205
|
end
|
1186
|
-
title_attr = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : ''
|
1187
|
-
img = %(<i class="#{class_attr_val}"#{title_attr}></i>)
|
1188
|
-
elsif type == 'icon' && !(node.document.attr? 'icons')
|
1189
|
-
img = %([#{node.alt}])
|
1190
1206
|
else
|
1191
|
-
|
1192
|
-
attrs =
|
1193
|
-
|
1194
|
-
|
1195
|
-
if
|
1207
|
+
attrs = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : ''
|
1208
|
+
attrs = %(#{attrs} height="#{node.attr 'height'}") if node.attr? 'height'
|
1209
|
+
attrs = %(#{attrs} title="#{node.attr 'title'}") if node.attr? 'title'
|
1210
|
+
if ((node.attr? 'format', 'svg') || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE
|
1211
|
+
if node.option? 'inline'
|
1196
1212
|
img = (read_svg_contents node, target) || %(<span class="alt">#{node.alt}</span>)
|
1197
|
-
elsif
|
1198
|
-
fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri
|
1213
|
+
elsif node.option? 'interactive'
|
1214
|
+
fallback = (node.attr? 'fallback') ? %(<img src="#{node.image_uri node.attr 'fallback'}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>) : %(<span class="alt">#{node.alt}</span>)
|
1199
1215
|
img = %(<object type="image/svg+xml" data="#{node.image_uri target}"#{attrs}>#{fallback}</object>)
|
1216
|
+
else
|
1217
|
+
img = %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
|
1200
1218
|
end
|
1219
|
+
else
|
1220
|
+
img = %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
|
1201
1221
|
end
|
1202
|
-
img ||= %(<img src="#{type == 'icon' ? (node.icon_uri target) : (node.image_uri target)}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
|
1203
1222
|
end
|
1204
1223
|
img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>) if node.attr? 'link'
|
1224
|
+
class_attr_val = type
|
1205
1225
|
if (role = node.role)
|
1206
|
-
|
1207
|
-
class_attr_val = %(#{type} #{node.attr 'float'} #{role})
|
1208
|
-
else
|
1209
|
-
class_attr_val = %(#{type} #{role})
|
1210
|
-
end
|
1226
|
+
class_attr_val = (node.attr? 'float') ? %(#{class_attr_val} #{node.attr 'float'} #{role}) : %(#{class_attr_val} #{role})
|
1211
1227
|
elsif node.attr? 'float'
|
1212
|
-
class_attr_val = %(#{
|
1213
|
-
else
|
1214
|
-
class_attr_val = type
|
1228
|
+
class_attr_val = %(#{class_attr_val} #{node.attr 'float'})
|
1215
1229
|
end
|
1216
1230
|
%(<span class="#{class_attr_val}">#{img}</span>)
|
1217
1231
|
end
|
@@ -1325,8 +1339,12 @@ Your browser does not support the video tag.
|
|
1325
1339
|
end
|
1326
1340
|
|
1327
1341
|
# NOTE adapt to older converters that relied on unprefixed method names
|
1328
|
-
def method_missing id, *
|
1329
|
-
!((name = id.to_s).start_with? 'convert_') && (handles? name) ? (send %(convert_#{name}), *
|
1342
|
+
def method_missing id, *args
|
1343
|
+
!((name = id.to_s).start_with? 'convert_') && (handles? name) ? (send %(convert_#{name}), *args) : super
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
def respond_to_missing? id, *options
|
1347
|
+
!((name = id.to_s).start_with? 'convert_') && (handles? name)
|
1330
1348
|
end
|
1331
1349
|
end
|
1332
1350
|
end
|
@@ -23,7 +23,7 @@ class Converter::ManPageConverter < Converter::Base
|
|
23
23
|
LeadingPeriodRx = /^\./
|
24
24
|
EscapedMacroRx = /^(?:#{ESC}\\c\n)?#{ESC}\.((?:URL|MTO) "#{CC_ANY}*?" "#{CC_ANY}*?" )( |[^\s]*)(#{CC_ANY}*?)(?: *#{ESC}\\c)?$/
|
25
25
|
MalformedEscapedMacroRx = /(#{ESC}\\c) (#{ESC}\.(?:URL|MTO) )/
|
26
|
-
MockMacroRx =
|
26
|
+
MockMacroRx = %r(</?(#{ESC}\\[^>]+)>)
|
27
27
|
EmDashCharRefRx = /—(?:​)?/
|
28
28
|
EllipsisCharRefRx = /…(?:​)?/
|
29
29
|
WrappedIndentRx = /#{CG_BLANK}*#{LF}#{CG_BLANK}*/
|
@@ -419,15 +419,7 @@ allbox tab(:);'
|
|
419
419
|
end
|
420
420
|
row_text[row_index] << %(T{#{LF}.sp#{LF})
|
421
421
|
cell_halign = (cell.attr 'halign', 'left').chr
|
422
|
-
if tsec == :
|
423
|
-
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
424
|
-
row_header[row_index][cell_index] << %(#{cell_halign}tB)
|
425
|
-
else
|
426
|
-
row_header[row_index][cell_index + 1] ||= []
|
427
|
-
row_header[row_index][cell_index + 1] << %(#{cell_halign}tB)
|
428
|
-
end
|
429
|
-
row_text[row_index] << %(#{manify cell.text, whitespace: :normalize}#{LF})
|
430
|
-
elsif tsec == :body
|
422
|
+
if tsec == :body
|
431
423
|
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
432
424
|
row_header[row_index][cell_index] << %(#{cell_halign}t)
|
433
425
|
else
|
@@ -443,7 +435,7 @@ allbox tab(:);'
|
|
443
435
|
cell_content = manify cell.content.join, whitespace: :normalize
|
444
436
|
end
|
445
437
|
row_text[row_index] << %(#{cell_content}#{LF})
|
446
|
-
|
438
|
+
else # tsec == :head || tsec == :foot
|
447
439
|
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
448
440
|
row_header[row_index][cell_index] << %(#{cell_halign}tB)
|
449
441
|
else
|
@@ -587,8 +579,16 @@ allbox tab(:);'
|
|
587
579
|
%(#{ESC_BS}c#{LF}#{ESC_FS}#{macro} "#{target}" "#{text}" )
|
588
580
|
when :xref
|
589
581
|
unless (text = node.text)
|
590
|
-
refid = node.attributes['refid']
|
591
|
-
|
582
|
+
if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid = node.attributes['refid']] || (refid.nil_or_empty? ? (top = get_root_document node) : nil))
|
583
|
+
if (@resolving_xref ||= (outer = true)) && outer && (text = ref.xreftext node.attr 'xrefstyle', nil, true)
|
584
|
+
text = uppercase_pcdata text if ref.context === :section && ref.level < 2 && text == ref.title
|
585
|
+
else
|
586
|
+
text = top ? '[^top]' : %([#{refid}])
|
587
|
+
end
|
588
|
+
@resolving_xref = nil if outer
|
589
|
+
else
|
590
|
+
text = %([#{refid}])
|
591
|
+
end
|
592
592
|
end
|
593
593
|
text
|
594
594
|
when :ref, :bibref
|
@@ -664,13 +664,12 @@ allbox tab(:);'
|
|
664
664
|
end
|
665
665
|
|
666
666
|
def self.write_alternate_pages mannames, manvolnum, target
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
end
|
667
|
+
return unless mannames && mannames.size > 1
|
668
|
+
mannames.shift
|
669
|
+
manvolext = %(.#{manvolnum})
|
670
|
+
dir, basename = ::File.split target
|
671
|
+
mannames.each do |manname|
|
672
|
+
::File.write ::File.join(dir, %(#{manname}#{manvolext})), %(.so #{basename}), mode: FILE_WRITE_MODE
|
674
673
|
end
|
675
674
|
end
|
676
675
|
|
@@ -679,7 +678,7 @@ allbox tab(:);'
|
|
679
678
|
def append_footnotes result, node
|
680
679
|
if node.footnotes? && !(node.attr? 'nofootnotes')
|
681
680
|
result << '.SH "NOTES"'
|
682
|
-
node.footnotes.
|
681
|
+
node.footnotes.each do |fn|
|
683
682
|
result << %(.IP [#{fn.index}])
|
684
683
|
# NOTE restore newline in escaped macro that gets removed by normalize_text in substitutor
|
685
684
|
if (text = fn.text).include? %(#{ESC}\\c #{ESC}.)
|
@@ -713,37 +712,40 @@ allbox tab(:);'
|
|
713
712
|
else
|
714
713
|
str = str.tr_s WHITESPACE, ' '
|
715
714
|
end
|
716
|
-
str = str
|
717
|
-
gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' }
|
718
|
-
gsub(EllipsisCharRefRx, '...')
|
719
|
-
gsub(LeadingPeriodRx, '\\\&.')
|
720
|
-
# drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
|
721
|
-
|
722
|
-
|
723
|
-
gsub('
|
724
|
-
gsub('&
|
725
|
-
gsub('
|
726
|
-
gsub('&#
|
727
|
-
gsub('&#
|
728
|
-
gsub('&#
|
729
|
-
gsub('&#
|
730
|
-
gsub('&#
|
731
|
-
gsub(
|
732
|
-
gsub('&#
|
733
|
-
gsub('&#
|
734
|
-
gsub(
|
735
|
-
gsub('&#
|
736
|
-
gsub('&#
|
737
|
-
gsub('&#
|
738
|
-
gsub('&#
|
739
|
-
gsub('&#
|
740
|
-
gsub('&#
|
741
|
-
gsub('
|
742
|
-
gsub('
|
743
|
-
gsub(
|
744
|
-
gsub(
|
745
|
-
gsub(
|
746
|
-
|
715
|
+
str = str
|
716
|
+
.gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' } # literal backslash (not a troff escape sequence)
|
717
|
+
.gsub(EllipsisCharRefRx, '...') # horizontal ellipsis
|
718
|
+
.gsub(LeadingPeriodRx, '\\\&.') # leading . is used in troff for macro call or other formatting; replace with \&.
|
719
|
+
.gsub(EscapedMacroRx) do # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
|
720
|
+
(rest = $3.lstrip).empty? ? %(.#{$1}"#{$2}") : %(.#{$1}"#{$2.rstrip}"#{LF}#{rest})
|
721
|
+
end
|
722
|
+
.gsub('-', '\-')
|
723
|
+
.gsub('<', '<')
|
724
|
+
.gsub('>', '>')
|
725
|
+
.gsub('+', '+') # plus sign; alternately could use \c(pl
|
726
|
+
.gsub(' ', '\~') # non-breaking space
|
727
|
+
.gsub('©', '\(co') # copyright sign
|
728
|
+
.gsub('®', '\(rg') # registered sign
|
729
|
+
.gsub('™', '\(tm') # trademark sign
|
730
|
+
.gsub('°', '\(de') # degree sign
|
731
|
+
.gsub(' ', ' ') # thin space
|
732
|
+
.gsub('–', '\(en') # en dash
|
733
|
+
.gsub(EmDashCharRefRx, '\(em') # em dash
|
734
|
+
.gsub('‘', '\(oq') # left single quotation mark
|
735
|
+
.gsub('’', '\(cq') # right single quotation mark
|
736
|
+
.gsub('“', '\(lq') # left double quotation mark
|
737
|
+
.gsub('”', '\(rq') # right double quotation mark
|
738
|
+
.gsub('←', '\(<-') # leftwards arrow
|
739
|
+
.gsub('→', '\(->') # rightwards arrow
|
740
|
+
.gsub('⇐', '\(lA') # leftwards double arrow
|
741
|
+
.gsub('⇒', '\(rA') # rightwards double arrow
|
742
|
+
.gsub('​', '\:') # zero width space
|
743
|
+
.gsub('&', '&') # literal ampersand (NOTE must take place after any other replacement that includes &)
|
744
|
+
.gsub('\'', '\*(Aq') # apostrophe / neutral single quote
|
745
|
+
.gsub(MockMacroRx, '\1') # mock boundary
|
746
|
+
.gsub(ESC_BS, '\\') # unescape troff backslash (NOTE update if more escapes are added)
|
747
|
+
.gsub(ESC_FS, '.') # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
|
748
|
+
.rstrip # strip trailing space
|
747
749
|
opts[:append_newline] ? %(#{str}#{LF}) : str
|
748
750
|
end
|
749
751
|
|
@@ -754,5 +756,12 @@ allbox tab(:);'
|
|
754
756
|
def enclose_content node
|
755
757
|
node.content_model == :compound ? node.content : %(.sp#{LF}#{manify node.content, whitespace: :normalize})
|
756
758
|
end
|
759
|
+
|
760
|
+
def get_root_document node
|
761
|
+
while (node = node.document).nested?
|
762
|
+
node = node.parent_document
|
763
|
+
end
|
764
|
+
node
|
765
|
+
end
|
757
766
|
end
|
758
767
|
end
|
@@ -40,13 +40,13 @@ class Converter::TemplateConverter < Converter::Base
|
|
40
40
|
@caches = { scans: {}, templates: {} }
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
end
|
43
|
+
class << self
|
44
|
+
attr_reader :caches
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
def clear_caches
|
47
|
+
@caches[:scans].clear
|
48
|
+
@caches[:templates].clear
|
49
|
+
end
|
50
50
|
end
|
51
51
|
|
52
52
|
def initialize backend, template_dirs, opts = {}
|
@@ -134,12 +134,10 @@ class Converter::TemplateConverter < Converter::Base
|
|
134
134
|
#
|
135
135
|
# Returns the Tilt template object
|
136
136
|
def register name, template
|
137
|
-
|
137
|
+
if (template_cache = @caches[:templates])
|
138
138
|
template_cache[template.file] = template
|
139
|
-
else
|
140
|
-
template
|
141
139
|
end
|
142
|
-
|
140
|
+
@templates[name] = template
|
143
141
|
end
|
144
142
|
|
145
143
|
private
|
@@ -155,6 +153,7 @@ class Converter::TemplateConverter < Converter::Base
|
|
155
153
|
engine = @engine
|
156
154
|
@template_dirs.each do |template_dir|
|
157
155
|
# FIXME need to think about safe mode restrictions here
|
156
|
+
# Ruby 2.3 requires the extra brackets around the path_resolver.system_path method call
|
158
157
|
next unless ::File.directory?(template_dir = (path_resolver.system_path template_dir))
|
159
158
|
|
160
159
|
if engine
|
@@ -186,8 +185,8 @@ class Converter::TemplateConverter < Converter::Base
|
|
186
185
|
else
|
187
186
|
@templates.update scan_dir(template_dir, pattern, @caches[:templates])
|
188
187
|
end
|
189
|
-
nil
|
190
188
|
end
|
189
|
+
nil
|
191
190
|
end
|
192
191
|
|
193
192
|
# Internal: Scan the specified directory for template files matching pattern and instantiate
|
@@ -197,7 +196,7 @@ class Converter::TemplateConverter < Converter::Base
|
|
197
196
|
def scan_dir template_dir, pattern, template_cache = nil
|
198
197
|
result, helpers = {}, nil
|
199
198
|
# Grab the files in the top level of the directory (do not recurse)
|
200
|
-
::Dir.glob(pattern).
|
199
|
+
::Dir.glob(pattern).keep_if {|match| ::File.file? match }.each do |file|
|
201
200
|
if (basename = ::File.basename file) == 'helpers.rb'
|
202
201
|
helpers = file
|
203
202
|
next
|
@@ -262,7 +261,7 @@ class Converter::TemplateConverter < Converter::Base
|
|
262
261
|
[::Tilt::ErubiTemplate, {}]
|
263
262
|
elsif name == 'erubis'
|
264
263
|
Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby
|
265
|
-
[::Tilt::ErubisTemplate,
|
264
|
+
[::Tilt::ErubisTemplate, engine_class: ::Erubis::FastEruby]
|
266
265
|
else
|
267
266
|
raise ::ArgumentError, %(Unknown ERB implementation: #{name})
|
268
267
|
end
|
@@ -42,7 +42,7 @@ module Asciidoctor
|
|
42
42
|
# puts Asciidoctor.convert_file 'sample.adoc', safe: :safe
|
43
43
|
module Converter
|
44
44
|
autoload :CompositeConverter, %(#{__dir__}/converter/composite)
|
45
|
-
autoload :TemplateConverter, %(#{__dir__}/converter/template)
|
45
|
+
autoload :TemplateConverter, %(#{__dir__}/converter/template) unless RUBY_ENGINE == 'opal'
|
46
46
|
|
47
47
|
# Public: The String backend name that this converter is handling.
|
48
48
|
attr_reader :backend
|
@@ -366,15 +366,17 @@ module Converter
|
|
366
366
|
# into - The Class into which the {Converter} module is being included.
|
367
367
|
#
|
368
368
|
# Returns nothing.
|
369
|
-
|
369
|
+
def self.included into
|
370
370
|
into.send :include, BackendTraits
|
371
371
|
into.extend Config
|
372
|
-
end
|
372
|
+
end
|
373
|
+
private_class_method :included # use separate declaration for Ruby 2.0.x
|
373
374
|
|
374
375
|
# An abstract base class for defining converters that can be used to convert {AbstractNode} objects in a parsed
|
375
376
|
# AsciiDoc document to a backend format such as HTML or DocBook.
|
376
377
|
class Base
|
377
|
-
include
|
378
|
+
include Logging
|
379
|
+
include Converter
|
378
380
|
|
379
381
|
# Public: Converts an {AbstractNode} by delegating to a method that matches the transform value.
|
380
382
|
#
|
@@ -3,6 +3,6 @@
|
|
3
3
|
# NOTE use `send :prepend` to be nice to Ruby 2.0
|
4
4
|
Hash.send :prepend, (Module.new do
|
5
5
|
def merge *args
|
6
|
-
(len = args.length) < 1 ?
|
6
|
+
(len = args.length) < 1 ? dup : (len > 1 ? args.inject(self) {|acc, arg| acc.merge arg } : (super args[0]))
|
7
7
|
end
|
8
8
|
end) if (Hash.instance_method :merge).arity == 1
|