asciidoctor 2.0.15 → 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 +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
|