asciidoctor 2.0.10 → 2.0.11

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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +89 -5
  3. data/LICENSE +1 -1
  4. data/README-de.adoc +4 -4
  5. data/README-fr.adoc +4 -4
  6. data/README-jp.adoc +4 -4
  7. data/README-zh_CN.adoc +6 -6
  8. data/README.adoc +14 -10
  9. data/asciidoctor.gemspec +3 -3
  10. data/data/locale/attributes-ar.adoc +4 -3
  11. data/data/locale/attributes-bg.adoc +4 -3
  12. data/data/locale/attributes-ca.adoc +6 -5
  13. data/data/locale/attributes-cs.adoc +4 -3
  14. data/data/locale/attributes-da.adoc +6 -5
  15. data/data/locale/attributes-de.adoc +4 -4
  16. data/data/locale/attributes-en.adoc +4 -4
  17. data/data/locale/attributes-es.adoc +6 -5
  18. data/data/locale/attributes-fa.adoc +4 -3
  19. data/data/locale/attributes-fi.adoc +4 -3
  20. data/data/locale/attributes-fr.adoc +6 -5
  21. data/data/locale/attributes-hu.adoc +4 -3
  22. data/data/locale/attributes-id.adoc +4 -3
  23. data/data/locale/attributes-it.adoc +4 -3
  24. data/data/locale/attributes-ja.adoc +4 -3
  25. data/data/locale/{attributes-kr.adoc → attributes-ko.adoc} +4 -3
  26. data/data/locale/attributes-nb.adoc +4 -3
  27. data/data/locale/attributes-nl.adoc +4 -3
  28. data/data/locale/attributes-nn.adoc +4 -3
  29. data/data/locale/attributes-pl.adoc +8 -7
  30. data/data/locale/attributes-pt.adoc +6 -5
  31. data/data/locale/attributes-pt_BR.adoc +6 -5
  32. data/data/locale/attributes-ro.adoc +4 -3
  33. data/data/locale/attributes-ru.adoc +6 -5
  34. data/data/locale/attributes-sr.adoc +4 -4
  35. data/data/locale/attributes-sr_Latn.adoc +4 -4
  36. data/data/locale/attributes-sv.adoc +4 -4
  37. data/data/locale/attributes-tr.adoc +4 -3
  38. data/data/locale/attributes-uk.adoc +6 -5
  39. data/data/locale/attributes-zh_CN.adoc +4 -3
  40. data/data/locale/attributes-zh_TW.adoc +4 -3
  41. data/data/stylesheets/asciidoctor-default.css +22 -20
  42. data/lib/asciidoctor.rb +33 -7
  43. data/lib/asciidoctor/abstract_block.rb +9 -4
  44. data/lib/asciidoctor/abstract_node.rb +16 -6
  45. data/lib/asciidoctor/attribute_list.rb +59 -67
  46. data/lib/asciidoctor/cli/invoker.rb +2 -0
  47. data/lib/asciidoctor/cli/options.rb +3 -3
  48. data/lib/asciidoctor/convert.rb +167 -162
  49. data/lib/asciidoctor/converter.rb +13 -12
  50. data/lib/asciidoctor/converter/docbook5.rb +3 -7
  51. data/lib/asciidoctor/converter/html5.rb +59 -42
  52. data/lib/asciidoctor/converter/manpage.rb +12 -11
  53. data/lib/asciidoctor/converter/template.rb +3 -0
  54. data/lib/asciidoctor/document.rb +23 -38
  55. data/lib/asciidoctor/extensions.rb +2 -2
  56. data/lib/asciidoctor/helpers.rb +17 -9
  57. data/lib/asciidoctor/load.rb +101 -101
  58. data/lib/asciidoctor/parser.rb +26 -23
  59. data/lib/asciidoctor/path_resolver.rb +14 -12
  60. data/lib/asciidoctor/reader.rb +14 -7
  61. data/lib/asciidoctor/rx.rb +5 -4
  62. data/lib/asciidoctor/substitutors.rb +57 -38
  63. data/lib/asciidoctor/syntax_highlighter.rb +8 -5
  64. data/lib/asciidoctor/syntax_highlighter/coderay.rb +1 -1
  65. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +12 -4
  66. data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
  67. data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -3
  68. data/lib/asciidoctor/syntax_highlighter/rouge.rb +15 -7
  69. data/lib/asciidoctor/table.rb +49 -20
  70. data/lib/asciidoctor/version.rb +1 -1
  71. data/man/asciidoctor.1 +6 -6
  72. data/man/asciidoctor.adoc +3 -3
  73. metadata +8 -8
@@ -85,23 +85,24 @@ module Converter
85
85
  # Public: Derive backend traits (basebackend, filetype, outfilesuffix, htmlsyntax) from the given backend.
86
86
  #
87
87
  # backend - the String backend from which to derive the traits
88
+ # basebackend - the String basebackend to use in favor of deriving one from the backend (optional, default: nil)
88
89
  #
89
90
  # Returns the backend traits for the given backend as a [Hash].
90
- def self.derive_backend_traits backend
91
+ def self.derive_backend_traits backend, basebackend = nil
91
92
  return {} unless backend
92
- if (t_outfilesuffix = DEFAULT_EXTENSIONS[(t_basebackend = backend.sub TrailingDigitsRx, '')])
93
- t_filetype = t_outfilesuffix.slice 1, t_outfilesuffix.length
93
+ if (outfilesuffix = DEFAULT_EXTENSIONS[(basebackend ||= backend.sub TrailingDigitsRx, '')])
94
+ filetype = outfilesuffix.slice 1, outfilesuffix.length
94
95
  else
95
- t_outfilesuffix = %(.#{t_filetype = t_basebackend})
96
+ outfilesuffix = %(.#{filetype = basebackend})
96
97
  end
97
- t_filetype == 'html' ?
98
- { basebackend: t_basebackend, filetype: t_filetype, htmlsyntax: 'html', outfilesuffix: t_outfilesuffix } :
99
- { basebackend: t_basebackend, filetype: t_filetype, outfilesuffix: t_outfilesuffix }
98
+ filetype == 'html' ?
99
+ { basebackend: basebackend, filetype: filetype, htmlsyntax: 'html', outfilesuffix: outfilesuffix } :
100
+ { basebackend: basebackend, filetype: filetype, outfilesuffix: outfilesuffix }
100
101
  end
101
102
 
102
103
  module BackendTraits
103
104
  def basebackend value = nil
104
- value ? (backend_traits[:basebackend] = value) : backend_traits[:basebackend]
105
+ value ? ((backend_traits value)[:basebackend] = value) : backend_traits[:basebackend]
105
106
  end
106
107
 
107
108
  def filetype value = nil
@@ -128,15 +129,15 @@ module Converter
128
129
  @backend_traits = value || {}
129
130
  end
130
131
 
131
- def backend_traits
132
- @backend_traits ||= Converter.derive_backend_traits @backend
132
+ def backend_traits basebackend = nil
133
+ @backend_traits ||= Converter.derive_backend_traits @backend, basebackend
133
134
  end
134
135
 
135
136
  alias backend_info backend_traits
136
137
 
137
138
  # Deprecated: Use {Converter.derive_backend_traits} instead.
138
- def self.derive_backend_traits backend
139
- Converter.derive_backend_traits backend
139
+ def self.derive_backend_traits backend, basebackend = nil
140
+ Converter.derive_backend_traits backend, basebackend
140
141
  end
141
142
  end
142
143
 
@@ -371,9 +371,7 @@ class Converter::DocBook5Converter < Converter::Base
371
371
  has_body = false
372
372
  result = []
373
373
  pgwide_attribute = (node.option? 'pgwide') ? ' pgwide="1"' : ''
374
- if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
375
- frame = 'topbot'
376
- end
374
+ frame = 'topbot' if (frame = node.attr 'frame', 'all', 'table-frame') == 'ends'
377
375
  grid = node.attr 'grid', nil, 'table-grid'
378
376
  result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{frame}" rowsep="#{['none', 'cols'].include?(grid) ? 0 : 1}" colsep="#{['none', 'rows'].include?(grid) ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', 'table-orientation') ? ' orient="land"' : ''}>)
379
377
  if (node.option? 'unbreakable')
@@ -401,12 +399,10 @@ class Converter::DocBook5Converter < Converter::Base
401
399
  rows.each do |row|
402
400
  result << '<row>'
403
401
  row.each do |cell|
404
- halign_attribute = (cell.attr? 'halign') ? %( align="#{cell.attr 'halign'}") : ''
405
- valign_attribute = (cell.attr? 'valign') ? %( valign="#{cell.attr 'valign'}") : ''
406
402
  colspan_attribute = cell.colspan ? %( namest="col_#{colnum = cell.column.attr 'colnumber'}" nameend="col_#{colnum + cell.colspan - 1}") : ''
407
403
  rowspan_attribute = cell.rowspan ? %( morerows="#{cell.rowspan - 1}") : ''
408
404
  # NOTE <entry> may not have whitespace (e.g., line breaks) as a direct descendant according to DocBook rules
409
- entry_start = %(<entry#{halign_attribute}#{valign_attribute}#{colspan_attribute}#{rowspan_attribute}>)
405
+ entry_start = %(<entry align="#{cell.attr 'halign'}" valign="#{cell.attr 'valign'}"#{colspan_attribute}#{rowspan_attribute}>)
410
406
  if tsec == :head
411
407
  cell_content = cell.text
412
408
  else
@@ -487,7 +483,7 @@ class Converter::DocBook5Converter < Converter::Base
487
483
  when :link
488
484
  %(<link xl:href="#{node.target}">#{node.text}</link>)
489
485
  when :bibref
490
- %(<anchor#{common_attributes node.id, nil, "[#{node.reftext || node.id}]"}/>#{text})
486
+ %(<anchor#{common_attributes node.id, nil, (text = "[#{node.reftext || node.id}]")}/>#{text})
491
487
  else
492
488
  logger.warn %(unknown anchor type: #{node.type.inspect})
493
489
  nil
@@ -21,15 +21,15 @@ class Converter::Html5Converter < Converter::Base
21
21
  #latexmath: INLINE_MATH_DELIMITERS[:latexmath] + [false],
22
22
  }).default = ['', '']
23
23
 
24
- DropAnchorRx = /<(?:a[^>+]+|\/a)>/
24
+ DropAnchorRx = /<(?: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
28
- SvgPreambleRx = /^#{CC_ALL}*?(?=<svg\b)/
29
- SvgStartTagRx = /^<svg[^>]*>/
28
+ SvgPreambleRx = /^#{CC_ALL}*?(?=<svg[\s>])/
29
+ SvgStartTagRx = /^<svg(?:\s[^>]*)?>/
30
30
  else
31
- SvgPreambleRx = /\A.*?(?=<svg\b)/m
32
- SvgStartTagRx = /\A<svg[^>]*>/
31
+ SvgPreambleRx = /\A.*?(?=<svg[\s>])/m
32
+ SvgStartTagRx = /\A<svg(?:\s[^>]*)?>/
33
33
  end
34
34
  DimensionAttributeRx = /\s(?:width|height|style)=(["'])#{CC_ANY}*?\1/
35
35
 
@@ -96,6 +96,7 @@ class Converter::Html5Converter < Converter::Base
96
96
  end
97
97
  cdn_base_url = %(#{asset_uri_scheme}//cdnjs.cloudflare.com/ajax/libs)
98
98
  linkcss = node.attr? 'linkcss'
99
+ max_width_attr = (node.attr? 'max-width') ? %( style="max-width: #{node.attr 'max-width'};") : ''
99
100
  result = ['<!DOCTYPE html>']
100
101
  lang_attribute = (node.attr? 'nolang') ? '' : %( lang="#{node.attr 'lang', 'en'}")
101
102
  result << %(<html#{@xml_mode ? ' xmlns="http://www.w3.org/1999/xhtml"' : ''}#{lang_attribute}>)
@@ -138,7 +139,7 @@ class Converter::Html5Converter < Converter::Base
138
139
  result << %(<link rel="stylesheet" href="#{node.normalize_web_path((node.attr 'stylesheet'), (node.attr 'stylesdir', ''))}"#{slash}>)
139
140
  else
140
141
  result << %(<style>
141
- #{node.read_asset node.normalize_system_path((node.attr 'stylesheet'), (node.attr 'stylesdir', '')), warn_on_failure: true, label: 'stylesheet'}
142
+ #{node.read_contents (node.attr 'stylesheet'), start: (node.attr 'stylesdir'), warn_on_failure: true, label: 'stylesheet'}
142
143
  </style>)
143
144
  end
144
145
  end
@@ -152,8 +153,8 @@ class Converter::Html5Converter < Converter::Base
152
153
  end
153
154
  end
154
155
 
155
- if (syntax_hl = node.syntax_highlighter) && (syntax_hl.docinfo? :head)
156
- result << (syntax_hl.docinfo :head, node, cdn_base_url: cdn_base_url, linkcss: linkcss, self_closing_tag_slash: slash)
156
+ if (syntax_hl = node.syntax_highlighter)
157
+ result << (syntax_hl_docinfo_head_idx = result.size)
157
158
  end
158
159
 
159
160
  unless (docinfo_content = node.docinfo).empty?
@@ -161,29 +162,27 @@ class Converter::Html5Converter < Converter::Base
161
162
  end
162
163
 
163
164
  result << '</head>'
164
- body_attrs = node.id ? [%(id="#{node.id}")] : []
165
+ id_attr = node.id ? %( id="#{node.id}") : ''
165
166
  if (sectioned = node.sections?) && (node.attr? 'toc-class') && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
166
167
  classes = [node.doctype, (node.attr 'toc-class'), %(toc-#{node.attr 'toc-position', 'header'})]
167
168
  else
168
169
  classes = [node.doctype]
169
170
  end
170
171
  classes << node.role if node.role?
171
- body_attrs << %(class="#{classes.join ' '}")
172
- body_attrs << %(style="max-width: #{node.attr 'max-width'};") if node.attr? 'max-width'
173
- result << %(<body #{body_attrs.join ' '}>)
172
+ result << %(<body#{id_attr} class="#{classes.join ' '}">)
174
173
 
175
174
  unless (docinfo_content = node.docinfo :header).empty?
176
175
  result << docinfo_content
177
176
  end
178
177
 
179
178
  unless node.noheader
180
- result << '<div id="header">'
179
+ result << %(<div id="header"#{max_width_attr}>)
181
180
  if node.doctype == 'manpage'
182
181
  result << %(<h1>#{node.doctitle} Manual Page</h1>)
183
182
  if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
184
183
  result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
185
184
  <div id="toctitle">#{node.attr 'toc-title'}</div>
186
- #{convert_outline node}
185
+ #{node.converter.convert node, 'outline'}
187
186
  </div>)
188
187
  end
189
188
  result << (generate_manname_section node) if node.attr? 'manpurpose'
@@ -216,19 +215,19 @@ class Converter::Html5Converter < Converter::Base
216
215
  if sectioned && (node.attr? 'toc') && (node.attr? 'toc-placement', 'auto')
217
216
  result << %(<div id="toc" class="#{node.attr 'toc-class', 'toc'}">
218
217
  <div id="toctitle">#{node.attr 'toc-title'}</div>
219
- #{convert_outline node}
218
+ #{node.converter.convert node, 'outline'}
220
219
  </div>)
221
220
  end
222
221
  end
223
222
  result << '</div>'
224
223
  end
225
224
 
226
- result << %(<div id="content">
225
+ result << %(<div id="content"#{max_width_attr}>
227
226
  #{node.content}
228
227
  </div>)
229
228
 
230
229
  if node.footnotes? && !(node.attr? 'nofootnotes')
231
- result << %(<div id="footnotes">
230
+ result << %(<div id="footnotes"#{max_width_attr}>
232
231
  <hr#{slash}>)
233
232
  node.footnotes.each do |footnote|
234
233
  result << %(<div class="footnote" id="_footnotedef_#{footnote.index}">
@@ -239,7 +238,7 @@ class Converter::Html5Converter < Converter::Base
239
238
  end
240
239
 
241
240
  unless node.nofooter
242
- result << '<div id="footer">'
241
+ result << %(<div id="footer"#{max_width_attr}>)
243
242
  result << '<div id="footer-text">'
244
243
  result << %(#{node.attr 'version-label'} #{node.attr 'revnumber'}#{br}) if node.attr? 'revnumber'
245
244
  result << %(#{node.attr 'last-update-label'} #{node.attr 'docdatetime'}) if (node.attr? 'last-update-label') && !(node.attr? 'reproducible')
@@ -250,8 +249,15 @@ class Converter::Html5Converter < Converter::Base
250
249
  # JavaScript (and auxiliary stylesheets) loaded at the end of body for performance reasons
251
250
  # See http://www.html5rocks.com/en/tutorials/speed/script-loading/
252
251
 
253
- if syntax_hl && (syntax_hl.docinfo? :footer)
254
- result << (syntax_hl.docinfo :footer, node, cdn_base_url: cdn_base_url, linkcss: linkcss, self_closing_tag_slash: slash)
252
+ if syntax_hl
253
+ if syntax_hl.docinfo? :head
254
+ result[syntax_hl_docinfo_head_idx] = syntax_hl.docinfo :head, node, cdn_base_url: cdn_base_url, linkcss: linkcss, self_closing_tag_slash: slash
255
+ else
256
+ result.delete_at syntax_hl_docinfo_head_idx
257
+ end
258
+ if syntax_hl.docinfo? :footer
259
+ result << (syntax_hl.docinfo :footer, node, cdn_base_url: cdn_base_url, linkcss: linkcss, self_closing_tag_slash: slash)
260
+ end
255
261
  end
256
262
 
257
263
  if node.attr? 'stem'
@@ -275,7 +281,7 @@ MathJax.Hub.Config({
275
281
  })
276
282
  MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
277
283
  MathJax.InputJax.AsciiMath.postfilterHooks.Add(function (data, node) {
278
- if ((node = data.script.parentNode) && (node = node.parentNode) && node.classList.contains('stemblock')) {
284
+ if ((node = data.script.parentNode) && (node = node.parentNode) && node.classList.contains("stemblock")) {
279
285
  data.math.root.display = "block"
280
286
  }
281
287
  return data
@@ -311,7 +317,7 @@ MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
311
317
  if node.sections? && (node.attr? 'toc') && (toc_p = node.attr 'toc-placement') != 'macro' && toc_p != 'preamble'
312
318
  result << %(<div id="toc" class="toc">
313
319
  <div id="toctitle">#{node.attr 'toc-title'}</div>
314
- #{convert_outline node}
320
+ #{node.converter.convert node, 'outline'}
315
321
  </div>)
316
322
  end
317
323
 
@@ -628,9 +634,7 @@ Your browser does not support the audio tag.
628
634
  end
629
635
  end
630
636
  img ||= %(<img src="#{node.image_uri target}" alt="#{encode_attribute_value node.alt}"#{width_attr}#{height_attr}#{@void_element_slash}>)
631
- if node.attr? 'link'
632
- img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>)
633
- end
637
+ img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>) if node.attr? 'link'
634
638
  id_attr = node.id ? %( id="#{node.id}") : ''
635
639
  classes = ['imageblock']
636
640
  classes << (node.attr 'float') if node.attr? 'float'
@@ -689,8 +693,8 @@ Your browser does not support the audio tag.
689
693
  open, close = BLOCK_MATH_DELIMITERS[style = node.style.to_sym]
690
694
  if (equation = node.content)
691
695
  if style == :asciimath && (equation.include? LF)
692
- br = %(<br#{@void_element_slash}>#{LF})
693
- equation = equation.gsub(StemBreakRx) { %(#{close}#{br * ($&.count LF)}#{open}) }
696
+ br = %(#{LF}<br#{@void_element_slash}>)
697
+ equation = equation.gsub(StemBreakRx) { %(#{close}#{br * (($&.count LF) - 1)}#{LF}#{open}) }
694
698
  end
695
699
  unless (equation.start_with? open) && (equation.end_with? close)
696
700
  equation = %(#{open}#{equation}#{close})
@@ -796,7 +800,7 @@ Your browser does not support the audio tag.
796
800
  toc = %(
797
801
  <div id="toc" class="#{doc.attr 'toc-class', 'toc'}">
798
802
  <div id="toctitle">#{doc.attr 'toc-title'}</div>
799
- #{convert_outline doc}
803
+ #{doc.converter.convert doc, 'outline'}
800
804
  </div>)
801
805
  else
802
806
  toc = ''
@@ -848,7 +852,8 @@ Your browser does not support the audio tag.
848
852
  def convert_table node
849
853
  result = []
850
854
  id_attribute = node.id ? %( id="#{node.id}") : ''
851
- classes = ['tableblock', %(frame-#{node.attr 'frame', 'all', 'table-frame'}), %(grid-#{node.attr 'grid', 'all', 'table-grid'})]
855
+ frame = 'ends' if (frame = node.attr 'frame', 'all', 'table-frame') == 'topbot'
856
+ classes = ['tableblock', %(frame-#{frame}), %(grid-#{node.attr 'grid', 'all', 'table-grid'})]
852
857
  if (stripes = node.attr 'stripes', nil, 'table-stripes')
853
858
  classes << %(stripes-#{stripes})
854
859
  end
@@ -934,7 +939,7 @@ Your browser does not support the audio tag.
934
939
 
935
940
  %(<div#{id_attr} class="#{role}">
936
941
  <div#{title_id_attr} class="title">#{title}</div>
937
- #{convert_outline doc, toclevels: levels}
942
+ #{doc.converter.convert doc, 'outline', toclevels: levels}
938
943
  </div>)
939
944
  end
940
945
 
@@ -1089,7 +1094,7 @@ Your browser does not support the audio tag.
1089
1094
  time_anchor = (start_t || end_t) ? %(#t=#{start_t || ''}#{end_t ? ",#{end_t}" : ''}) : ''
1090
1095
  %(<div#{id_attribute}#{class_attribute}>#{title_element}
1091
1096
  <div class="content">
1092
- <video src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{width_attribute}#{height_attribute}#{poster_attribute}#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'nocontrols') ? '' : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : ''}#{preload_attribute}>
1097
+ <video src="#{node.media_uri(node.attr 'target')}#{time_anchor}"#{width_attribute}#{height_attribute}#{poster_attribute}#{(node.option? 'autoplay') ? (append_boolean_attribute 'autoplay', xml) : ''}#{(node.option? 'muted') ? (append_boolean_attribute 'muted', xml) : ''}#{(node.option? 'nocontrols') ? '' : (append_boolean_attribute 'controls', xml)}#{(node.option? 'loop') ? (append_boolean_attribute 'loop', xml) : ''}#{preload_attribute}>
1093
1098
  Your browser does not support the video tag.
1094
1099
  </video>
1095
1100
  </div>
@@ -1107,8 +1112,13 @@ Your browser does not support the video tag.
1107
1112
  attrs = node.role ? %( class="#{node.role}") : ''
1108
1113
  unless (text = node.text)
1109
1114
  refid = node.attributes['refid']
1110
- if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid])
1111
- text = (ref.xreftext node.attr('xrefstyle', nil, true)) || %([#{refid}])
1115
+ if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid]) && (@resolving_xref ||= (outer = true)) && outer
1116
+ if !(text = ref.xreftext node.attr 'xrefstyle', nil, true)
1117
+ text = %([#{refid}])
1118
+ elsif text.include? '<a'
1119
+ text = text.gsub DropAnchorRx, ''
1120
+ end
1121
+ @resolving_xref = nil
1112
1122
  else
1113
1123
  text = %([#{refid}])
1114
1124
  end
@@ -1144,8 +1154,10 @@ Your browser does not support the video tag.
1144
1154
  elsif node.document.attr? 'icons'
1145
1155
  src = node.icon_uri("callouts/#{node.text}")
1146
1156
  %(<img src="#{src}" alt="#{node.text}"#{@void_element_slash}>)
1157
+ elsif ::Array === (guard = node.attributes['guard'])
1158
+ %(&lt;!--<b class="conum">(#{node.text})</b>--&gt;)
1147
1159
  else
1148
- %(#{node.attributes['guard']}<b class="conum">(#{node.text})</b>)
1160
+ %(#{guard}<b class="conum">(#{node.text})</b>)
1149
1161
  end
1150
1162
  end
1151
1163
 
@@ -1186,9 +1198,7 @@ Your browser does not support the video tag.
1186
1198
  end
1187
1199
  img ||= %(<img src="#{type == 'icon' ? (node.icon_uri target) : (node.image_uri target)}" alt="#{encode_attribute_value node.alt}"#{attrs}#{@void_element_slash}>)
1188
1200
  end
1189
- if node.attr? 'link'
1190
- img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>)
1191
- end
1201
+ img = %(<a class="image" href="#{node.attr 'link'}"#{(append_link_constraint_attrs node).join}>#{img}</a>) if node.attr? 'link'
1192
1202
  if (role = node.role)
1193
1203
  if node.attr? 'float'
1194
1204
  class_attr_val = %(#{type} #{node.attr 'float'} #{role})
@@ -1252,15 +1262,22 @@ Your browser does not support the video tag.
1252
1262
 
1253
1263
  # NOTE expose read_svg_contents for Bespoke converter
1254
1264
  def read_svg_contents node, target
1255
- if (svg = node.read_contents target, start: (node.document.attr 'imagesdir'), normalize: true, label: 'SVG')
1265
+ if (svg = node.read_contents target, start: (node.document.attr 'imagesdir'), normalize: true, label: 'SVG', warn_if_empty: true)
1266
+ return if svg.empty?
1256
1267
  svg = svg.sub SvgPreambleRx, '' unless svg.start_with? '<svg'
1257
- old_start_tag = new_start_tag = nil
1268
+ old_start_tag = new_start_tag = start_tag_match = nil
1258
1269
  # NOTE width, height and style attributes are removed if either width or height is specified
1259
1270
  ['width', 'height'].each do |dim|
1260
1271
  if node.attr? dim
1261
- new_start_tag = (old_start_tag = (svg.match SvgStartTagRx)[0]).gsub DimensionAttributeRx, '' unless new_start_tag
1262
- # QUESTION should we add px since it's already the default?
1263
- new_start_tag = %(#{new_start_tag.chop} #{dim}="#{node.attr dim}px">)
1272
+ unless new_start_tag
1273
+ next if (start_tag_match ||= (svg.match SvgStartTagRx) || :no_match) == :no_match
1274
+ new_start_tag = (old_start_tag = start_tag_match[0]).gsub DimensionAttributeRx, ''
1275
+ end
1276
+ unless (dim_val = node.attr dim).end_with? '%'
1277
+ # QUESTION should we add px since it's already the default?
1278
+ dim_val += 'px'
1279
+ end
1280
+ new_start_tag = %(#{new_start_tag.chop} #{dim}="#{dim_val}">)
1264
1281
  end
1265
1282
  end
1266
1283
  svg = %(#{new_start_tag}#{svg[old_start_tag.length..-1]}) if new_start_tag
@@ -15,7 +15,7 @@ class Converter::ManPageConverter < Converter::Base
15
15
  ESC_BS = %(#{ESC}\\) # escaped backslash (indicates troff formatting sequence)
16
16
  ESC_FS = %(#{ESC}.) # escaped full stop (indicates troff macro)
17
17
 
18
- LiteralBackslashRx = /(?:\A|[^#{ESC}])\\/
18
+ LiteralBackslashRx = /\A\\|(#{ESC})?\\/
19
19
  LeadingPeriodRx = /^\./
20
20
  EscapedMacroRx = /^(?:#{ESC}\\c\n)?#{ESC}\.((?:URL|MTO) "#{CC_ANY}*?" "#{CC_ANY}*?" )( |[^\s]*)(#{CC_ANY}*?)(?: *#{ESC}\\c)?$/
21
21
  MockBoundaryRx = /<\/?BOUNDARY>/
@@ -247,7 +247,9 @@ r lw(\n(.lu*75u/100u).'
247
247
  result << %(.sp
248
248
  .if n .RS 4
249
249
  .nf
250
+ .fam C
250
251
  #{manify node.content, whitespace: :preserve}
252
+ .fam
251
253
  .fi
252
254
  .if n .RE)
253
255
  result.join LF
@@ -261,7 +263,9 @@ r lw(\n(.lu*75u/100u).'
261
263
  result << %(.sp
262
264
  .if n .RS 4
263
265
  .nf
266
+ .fam C
264
267
  #{manify node.content, whitespace: :preserve}
268
+ .fam
265
269
  .fi
266
270
  .if n .RE)
267
271
  result.join LF
@@ -284,15 +288,16 @@ r lw(\n(.lu*75u/100u).'
284
288
  .B #{manify node.title}
285
289
  .br) if node.title?
286
290
 
291
+ start = (node.attr 'start', 1).to_i
287
292
  node.items.each_with_index do |item, idx|
288
293
  result << %(.sp
289
294
  .RS 4
290
295
  .ie n \\{\\
291
- \\h'-04' #{idx + 1}.\\h'+01'\\c
296
+ \\h'-04' #{numeral = idx + start}.\\h'+01'\\c
292
297
  .\\}
293
298
  .el \\{\\
294
299
  . sp -1
295
- . IP " #{idx + 1}." 4.2
300
+ . IP " #{numeral}." 4.2
296
301
  .\\}
297
302
  #{manify item.text, whitespace: :normalize})
298
303
  result << item.content if item.blocks?
@@ -580,11 +585,7 @@ allbox tab(:);'
580
585
  when :xref
581
586
  unless (text = node.text)
582
587
  refid = node.attributes['refid']
583
- if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid])
584
- text = (ref.xreftext node.attr('xrefstyle', nil, true)) || %([#{refid}])
585
- else
586
- text = %([#{refid}])
587
- end
588
+ text = %([#{refid}]) unless AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid]) && (@resolving_xref ||= outer = true) && outer && (text = ref.xreftext node.attr 'xrefstyle', nil, true)
588
589
  end
589
590
  text
590
591
  when :ref, :bibref
@@ -699,7 +700,8 @@ allbox tab(:);'
699
700
  str = str.tr_s WHITESPACE, ' '
700
701
  end
701
702
  str = str.
702
- gsub(LiteralBackslashRx, '\&(rs'). # literal backslash (not a troff escape sequence)
703
+ gsub(LiteralBackslashRx) { $1 ? $& : '\\(rs' }. # literal backslash (not a troff escape sequence)
704
+ gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
703
705
  gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
704
706
  # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
705
707
  gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#$1"#$2") : %(.#$1"#$2"#{LF}#{rest}) }.
@@ -717,13 +719,12 @@ allbox tab(:);'
717
719
  gsub('&#8217;', '\(cq'). # right single quotation mark
718
720
  gsub('&#8220;', '\(lq'). # left double quotation mark
719
721
  gsub('&#8221;', '\(rq'). # right double quotation mark
720
- gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
721
722
  gsub('&#8592;', '\(<-'). # leftwards arrow
722
723
  gsub('&#8594;', '\(->'). # rightwards arrow
723
724
  gsub('&#8656;', '\(lA'). # leftwards double arrow
724
725
  gsub('&#8658;', '\(rA'). # rightwards double arrow
725
726
  gsub('&#8203;', '\:'). # zero width space
726
- gsub('&amp;','&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
727
+ gsub('&amp;', '&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
727
728
  gsub('\'', '\(aq'). # apostrophe-quote
728
729
  gsub(MockBoundaryRx, ''). # mock boundary
729
730
  gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
@@ -257,6 +257,9 @@ class Converter::TemplateConverter < Converter::Base
257
257
  if !name || name == 'erb'
258
258
  require 'erb' unless defined? ::ERB.version
259
259
  [::Tilt::ERBTemplate, {}]
260
+ elsif name == 'erubi'
261
+ Helpers.require_library 'erubi' unless defined? ::Erubis::Engine
262
+ [::Tilt::ErubiTemplate, {}]
260
263
  elsif name == 'erubis'
261
264
  Helpers.require_library 'erubis' unless defined? ::Erubis::FastEruby
262
265
  [::Tilt::ErubisTemplate, { engine_class: ::Erubis::FastEruby }]
@@ -326,7 +326,7 @@ class Document < AbstractBlock
326
326
  @sourcemap = options[:sourcemap]
327
327
  @timings = options.delete :timings
328
328
  @path_resolver = PathResolver.new
329
- initialize_extensions = (defined? ::Asciidoctor::Extensions) ? true : nil
329
+ initialize_extensions = (defined? ::Asciidoctor::Extensions) || (options.key? :extensions) ? ::Asciidoctor::Extensions : nil
330
330
  @extensions = nil # initialize furthur down if initialize_extensions is true
331
331
  options[:standalone] = options[:header_footer] if (options.key? :header_footer) && !(options.key? :standalone)
332
332
  end
@@ -339,51 +339,36 @@ class Document < AbstractBlock
339
339
  (@options = options).freeze
340
340
 
341
341
  attrs = @attributes
342
- #attrs['encoding'] = 'UTF-8'
343
- attrs['sectids'] = ''
344
- attrs['toc-placement'] = 'auto'
342
+ attrs['attribute-undefined'] = Compliance.attribute_undefined
343
+ attrs['attribute-missing'] = Compliance.attribute_missing
344
+ attrs.update DEFAULT_ATTRIBUTES
345
+ # TODO if lang attribute is set, @safe mode < SafeMode::SERVER, and !parent_doc,
346
+ # load attributes from data/locale/attributes-<lang>.adoc
347
+
345
348
  if standalone
346
- attrs['copycss'] = ''
347
349
  # sync embedded attribute with :standalone option value
348
350
  attr_overrides['embedded'] = nil
351
+ attrs['copycss'] = ''
352
+ attrs['iconfont-remote'] = ''
353
+ attrs['stylesheet'] = ''
354
+ attrs['webfonts'] = ''
349
355
  else
350
- attrs['notitle'] = ''
351
356
  # sync embedded attribute with :standalone option value
352
357
  attr_overrides['embedded'] = ''
358
+ if (attr_overrides.key? 'showtitle') && (attr_overrides.keys & %w(notitle showtitle))[-1] == 'showtitle'
359
+ attr_overrides['notitle'] = { nil => '', false => '@', '@' => false}[attr_overrides['showtitle']]
360
+ elsif attr_overrides.key? 'notitle'
361
+ attr_overrides['showtitle'] = { nil => '', false => '@', '@' => false}[attr_overrides['notitle']]
362
+ else
363
+ attrs['notitle'] = ''
364
+ end
353
365
  end
354
- attrs['stylesheet'] = ''
355
- attrs['webfonts'] = ''
356
- attrs['prewrap'] = ''
357
- attrs['attribute-undefined'] = Compliance.attribute_undefined
358
- attrs['attribute-missing'] = Compliance.attribute_missing
359
- attrs['iconfont-remote'] = ''
360
-
361
- # language strings
362
- # TODO load these based on language settings
363
- attrs['caution-caption'] = 'Caution'
364
- attrs['important-caption'] = 'Important'
365
- attrs['note-caption'] = 'Note'
366
- attrs['tip-caption'] = 'Tip'
367
- attrs['warning-caption'] = 'Warning'
368
- attrs['example-caption'] = 'Example'
369
- attrs['figure-caption'] = 'Figure'
370
- #attrs['listing-caption'] = 'Listing'
371
- attrs['table-caption'] = 'Table'
372
- attrs['toc-title'] = 'Table of Contents'
373
- #attrs['preface-title'] = 'Preface'
374
- attrs['section-refsig'] = 'Section'
375
- attrs['part-refsig'] = 'Part'
376
- attrs['chapter-refsig'] = 'Chapter'
377
- attrs['appendix-caption'] = attrs['appendix-refsig'] = 'Appendix'
378
- attrs['untitled-label'] = 'Untitled'
379
- attrs['version-label'] = 'Version'
380
- attrs['last-update-label'] = 'Last updated'
381
366
 
382
367
  attr_overrides['asciidoctor'] = ''
383
368
  attr_overrides['asciidoctor-version'] = ::Asciidoctor::VERSION
384
369
 
385
370
  attr_overrides['safe-mode-name'] = (safe_mode_name = SafeMode.name_for_value @safe)
386
- attr_overrides["safe-mode-#{safe_mode_name}"] = ''
371
+ attr_overrides[%(safe-mode-#{safe_mode_name})] = ''
387
372
  attr_overrides['safe-mode-level'] = @safe
388
373
 
389
374
  # the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc Python
@@ -505,10 +490,10 @@ class Document < AbstractBlock
505
490
  ::AsciidoctorJ::Extensions::ExtensionRegistry === ext_registry)
506
491
  @extensions = ext_registry.activate self
507
492
  end
508
- elsif ::Proc === (ext_block = options[:extensions])
493
+ elsif (ext_block = options[:extensions]).nil?
494
+ @extensions = Extensions::Registry.new.activate self unless Extensions.groups.empty?
495
+ elsif ::Proc === ext_block
509
496
  @extensions = Extensions.create(&ext_block).activate self
510
- elsif !Extensions.groups.empty?
511
- @extensions = Extensions::Registry.new.activate self
512
497
  end
513
498
  end
514
499
 
@@ -772,7 +757,7 @@ class Document < AbstractBlock
772
757
  end
773
758
 
774
759
  def notitle
775
- !@attributes.key?('showtitle') && @attributes.key?('notitle')
760
+ @attributes.key? 'notitle'
776
761
  end
777
762
 
778
763
  def noheader