asciidoctor 2.0.7 → 2.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.adoc +169 -7
  3. data/LICENSE +2 -1
  4. data/README-de.adoc +5 -15
  5. data/README-fr.adoc +4 -14
  6. data/README-jp.adoc +234 -186
  7. data/README-zh_CN.adoc +7 -17
  8. data/README.adoc +18 -18
  9. data/asciidoctor.gemspec +4 -4
  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 +33 -30
  42. data/lib/asciidoctor.rb +89 -791
  43. data/lib/asciidoctor/abstract_block.rb +19 -11
  44. data/lib/asciidoctor/abstract_node.rb +21 -15
  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 +14 -13
  50. data/lib/asciidoctor/converter/docbook5.rb +10 -26
  51. data/lib/asciidoctor/converter/html5.rb +62 -43
  52. data/lib/asciidoctor/converter/manpage.rb +13 -12
  53. data/lib/asciidoctor/converter/template.rb +6 -3
  54. data/lib/asciidoctor/document.rb +25 -41
  55. data/lib/asciidoctor/extensions.rb +3 -3
  56. data/lib/asciidoctor/helpers.rb +38 -39
  57. data/lib/asciidoctor/inline.rb +1 -1
  58. data/lib/asciidoctor/load.rb +101 -101
  59. data/lib/asciidoctor/parser.rb +30 -25
  60. data/lib/asciidoctor/path_resolver.rb +35 -25
  61. data/lib/asciidoctor/reader.rb +14 -7
  62. data/lib/asciidoctor/rx.rb +722 -0
  63. data/lib/asciidoctor/substitutors.rb +61 -39
  64. data/lib/asciidoctor/syntax_highlighter.rb +22 -8
  65. data/lib/asciidoctor/syntax_highlighter/coderay.rb +1 -1
  66. data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +12 -4
  67. data/lib/asciidoctor/syntax_highlighter/prettify.rb +7 -4
  68. data/lib/asciidoctor/syntax_highlighter/pygments.rb +2 -3
  69. data/lib/asciidoctor/syntax_highlighter/rouge.rb +15 -7
  70. data/lib/asciidoctor/table.rb +52 -23
  71. data/lib/asciidoctor/version.rb +1 -1
  72. data/man/asciidoctor.1 +6 -6
  73. data/man/asciidoctor.adoc +4 -3
  74. metadata +10 -9
@@ -422,7 +422,10 @@ module Substitutors
422
422
  end
423
423
  target = $1
424
424
  attrs = parse_attributes $2, posattrs, unescape_input: true
425
- doc.register :images, [target, (attrs['imagesdir'] = doc_attrs['imagesdir'])] unless type == 'icon'
425
+ unless type == 'icon'
426
+ doc.register :images, target
427
+ attrs['imagesdir'] = doc_attrs['imagesdir']
428
+ end
426
429
  attrs['alt'] ||= (attrs['default-alt'] = Helpers.basename(target, true).tr('_-', ' '))
427
430
  Inline.new(self, :image, nil, type: type, target: target, attributes: attrs).convert
428
431
  end
@@ -539,14 +542,17 @@ module Substitutors
539
542
  end
540
543
 
541
544
  prefix, suffix = $1, ''
542
- # NOTE if $4 is set, then we're looking at a formal macro
545
+ # NOTE if $4 is set, we're looking at a formal macro (e.g., https://example.org[])
543
546
  if $4
544
547
  prefix = '' if prefix == 'link:'
545
548
  text = $4
546
549
  else
547
- # invalid macro syntax (link: prefix w/o trailing square brackets)
548
- # FIXME we probably shouldn't even get here...our regex is doing too much
549
- next $& if prefix == 'link:'
550
+ # invalid macro syntax (link: prefix w/o trailing square brackets or enclosed in double quotes)
551
+ # FIXME we probably shouldn't even get here when the link: prefix is present; the regex is doing too much
552
+ case prefix
553
+ when 'link:', ?", ?'
554
+ next $&
555
+ end
550
556
  text = ''
551
557
  case $3
552
558
  when ')'
@@ -588,7 +594,8 @@ module Substitutors
588
594
  unless text.empty?
589
595
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
590
596
  if !doc.compat_mode && (text.include? '=')
591
- text = (attrs = (AttributeList.new text, self).parse)[1] || ''
597
+ # NOTE if an equals sign (=) is present, extract attributes from text
598
+ text, attrs = extract_attributes_from_text text, ''
592
599
  link_opts[:id] = attrs['id']
593
600
  end
594
601
 
@@ -634,7 +641,8 @@ module Substitutors
634
641
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
635
642
  if mailto
636
643
  if !doc.compat_mode && (text.include? ',')
637
- text = (attrs = (AttributeList.new text, self).parse)[1] || ''
644
+ # NOTE if a comma (,) is present, extract attributes from text
645
+ text, attrs = extract_attributes_from_text text, ''
638
646
  link_opts[:id] = attrs['id']
639
647
  if attrs.key? 2
640
648
  if attrs.key? 3
@@ -645,7 +653,8 @@ module Substitutors
645
653
  end
646
654
  end
647
655
  elsif !doc.compat_mode && (text.include? '=')
648
- text = (attrs = (AttributeList.new text, self).parse)[1] || ''
656
+ # NOTE if an equals sign (=) is present, extract attributes from text
657
+ text, attrs = extract_attributes_from_text text, ''
649
658
  link_opts[:id] = attrs['id']
650
659
  end
651
660
 
@@ -736,8 +745,8 @@ module Substitutors
736
745
  refid = $2
737
746
  if (text = $3)
738
747
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
739
- # NOTE if an equal sign (=) is present, parse text as attributes
740
- text = ((AttributeList.new text, self).parse_into attrs)[1] if !doc.compat_mode && (text.include? '=')
748
+ # NOTE if an equals sign (=) is present, extract attributes from text
749
+ text, attrs = extract_attributes_from_text text if !doc.compat_mode && (text.include? '=')
741
750
  end
742
751
  end
743
752
 
@@ -801,7 +810,7 @@ module Substitutors
801
810
  # handles: id (in compat mode or when natural xrefs are disabled)
802
811
  elsif doc.compat_mode || !Compliance.natural_xrefs
803
812
  refid, target = fragment, %(##{fragment})
804
- logger.info %(possible invalid reference: #{refid}) if logger.info? && doc.catalog[:refs][refid]
813
+ logger.info %(possible invalid reference: #{refid}) if logger.info? && !doc.catalog[:refs][refid]
805
814
  # handles: id
806
815
  elsif doc.catalog[:refs][fragment]
807
816
  refid, target = fragment, %(##{fragment})
@@ -840,19 +849,17 @@ module Substitutors
840
849
  end
841
850
 
842
851
  if id
843
- if text
852
+ if (footnote = doc.footnotes.find {|candidate| candidate.id == id })
853
+ index, text = footnote.index, footnote.text
854
+ type, target, id = :xref, id, nil
855
+ elsif text
844
856
  text = restore_passthroughs(normalize_text text, true, true)
845
857
  index = doc.counter('footnote-number')
846
858
  doc.register(:footnotes, Document::Footnote.new(index, id, text))
847
859
  type, target = :ref, nil
848
860
  else
849
- if (footnote = doc.footnotes.find {|candidate| candidate.id == id })
850
- index, text = footnote.index, footnote.text
851
- else
852
- logger.warn %(invalid footnote reference: #{id})
853
- index, text = nil, id
854
- end
855
- type, target, id = :xref, id, nil
861
+ logger.warn %(invalid footnote reference: #{id})
862
+ type, target, text, id = :xref, id, id, nil
856
863
  end
857
864
  elsif text
858
865
  text = restore_passthroughs(normalize_text text, true, true)
@@ -914,7 +921,7 @@ module Substitutors
914
921
  # use sub since it might be behind a line comment
915
922
  $&.sub RS, ''
916
923
  else
917
- Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, id: @document.callouts.read_next_id, attributes: { 'guard' => $1 }).convert
924
+ Inline.new(self, :callout, $4 == '.' ? (autonum += 1).to_s : $4, id: @document.callouts.read_next_id, attributes: { 'guard' => $1 || ($3 == '--' ? ['<!--', '-->'] : nil) }).convert
918
925
  end
919
926
  end
920
927
  end
@@ -942,7 +949,7 @@ module Substitutors
942
949
  if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil)
943
950
  start_line_number = 1 if (start_line_number = (attr 'start', 1).to_i) < 1
944
951
  end
945
- highlight_lines = resolve_lines_to_highlight source, (attr 'highlight') if attr? 'highlight'
952
+ highlight_lines = resolve_lines_to_highlight source, (attr 'highlight'), start_line_number if attr? 'highlight'
946
953
 
947
954
  highlighted, source_offset = syntax_hl.highlight self, source, (attr 'language'),
948
955
  callouts: callout_marks,
@@ -965,9 +972,10 @@ module Substitutors
965
972
  #
966
973
  # source - The String source.
967
974
  # spec - The lines specifier (e.g., "1-5, !2, 10" or "1..5;!2;10")
975
+ # start - The line number of the first line (optional, default: false)
968
976
  #
969
977
  # Returns an [Array] of unique, sorted line numbers.
970
- def resolve_lines_to_highlight source, spec
978
+ def resolve_lines_to_highlight source, spec, start = nil
971
979
  lines = []
972
980
  spec = spec.delete ' ' if spec.include? ' '
973
981
  ((spec.include? ',') ? (spec.split ',') : (spec.split ';')).map do |entry|
@@ -978,21 +986,22 @@ module Substitutors
978
986
  if (delim = (entry.include? '..') ? '..' : ((entry.include? '-') ? '-' : nil))
979
987
  from, delim, to = entry.partition delim
980
988
  to = (source.count LF) + 1 if to.empty? || (to = to.to_i) < 0
981
- line_nums = (from.to_i..to).to_a
982
989
  if negate
983
- lines -= line_nums
990
+ lines -= (from.to_i..to).to_a
984
991
  else
985
- lines.concat line_nums
986
- end
987
- else
988
- if negate
989
- lines.delete entry.to_i
990
- else
991
- lines << entry.to_i
992
+ lines |= (from.to_i..to).to_a
992
993
  end
994
+ elsif negate
995
+ lines.delete entry.to_i
996
+ elsif !lines.include?(line = entry.to_i)
997
+ lines << line
993
998
  end
994
999
  end
995
- lines.sort.uniq
1000
+ # If the start attribute is defined, then the lines to highlight specified by the provided spec should be relative to the start value.
1001
+ unless (shift = start ? start - 1 : 0) == 0
1002
+ lines = lines.map {|it| it - shift }
1003
+ end
1004
+ lines.sort
996
1005
  end
997
1006
 
998
1007
  # Public: Extract the passthrough text from the document for reinsertion after processing.
@@ -1318,10 +1327,23 @@ module Substitutors
1318
1327
 
1319
1328
  private
1320
1329
 
1330
+ # This method is used in cases when the attrlist can be mixed with the text of a macro.
1331
+ # If no attributes are detected aside from the first positional attribute, and the first positional
1332
+ # attribute matches the attrlist, then the original text is returned.
1333
+ def extract_attributes_from_text text, default_text = nil
1334
+ attrlist = (text.include? LF) ? (text.tr LF, ' ') : text
1335
+ if (resolved_text = (attrs = (AttributeList.new attrlist, self).parse)[1])
1336
+ # NOTE if resolved text remains unchanged, clear attributes and return unparsed text
1337
+ resolved_text == attrlist ? [text, attrs.clear] : [resolved_text, attrs]
1338
+ else
1339
+ [default_text, attrs]
1340
+ end
1341
+ end
1342
+
1321
1343
  # Internal: Extract the callout numbers from the source to prepare it for syntax highlighting.
1322
1344
  def extract_callouts source
1323
1345
  callout_marks = {}
1324
- lineno = 0
1346
+ autonum = lineno = 0
1325
1347
  last_lineno = nil
1326
1348
  callout_rx = (attr? 'line-comment') ? CalloutExtractRxMap[attr 'line-comment'] : CalloutExtractRx
1327
1349
  # extract callout marks, indexed by line number
@@ -1333,7 +1355,7 @@ module Substitutors
1333
1355
  # use sub since it might be behind a line comment
1334
1356
  $&.sub RS, ''
1335
1357
  else
1336
- (callout_marks[lineno] ||= []) << [$1, $4]
1358
+ (callout_marks[lineno] ||= []) << [$1 || ($3 == '--' ? ['<!--', '-->'] : nil), $4 == '.' ? (autonum += 1).to_s : $4]
1337
1359
  last_lineno = lineno
1338
1360
  ''
1339
1361
  end
@@ -1355,15 +1377,15 @@ module Substitutors
1355
1377
  else
1356
1378
  preamble = ''
1357
1379
  end
1358
- autonum = lineno = 0
1380
+ lineno = 0
1359
1381
  preamble + ((source.split LF, -1).map do |line|
1360
1382
  if (conums = callout_marks.delete lineno += 1)
1361
1383
  if conums.size == 1
1362
- guard, conum = conums[0]
1363
- %(#{line}#{Inline.new(self, :callout, conum == '.' ? (autonum += 1).to_s : conum, id: @document.callouts.read_next_id, attributes: { 'guard' => guard }).convert})
1384
+ guard, numeral = conums[0]
1385
+ %(#{line}#{Inline.new(self, :callout, numeral, id: @document.callouts.read_next_id, attributes: { 'guard' => guard }).convert})
1364
1386
  else
1365
- %(#{line}#{conums.map do |guard_it, conum_it|
1366
- Inline.new(self, :callout, conum_it == '.' ? (autonum += 1).to_s : conum_it, id: @document.callouts.read_next_id, attributes: { 'guard' => guard_it }).convert
1387
+ %(#{line}#{conums.map do |guard_it, numeral_it|
1388
+ Inline.new(self, :callout, numeral_it, id: @document.callouts.read_next_id, attributes: { 'guard' => guard_it }).convert
1367
1389
  end.join ' '})
1368
1390
  end
1369
1391
  else
@@ -20,19 +20,25 @@ module SyntaxHighlighter
20
20
  end
21
21
 
22
22
  # Public: Indicates whether this syntax highlighter has docinfo (i.e., markup) to insert into the output document at
23
- # the specified location.
23
+ # the specified location. Should be called by converter after main content has been converted.
24
24
  #
25
25
  # location - The Symbol representing the location slot (:head or :footer).
26
26
  #
27
27
  # Returns a [Boolean] indicating whether the docinfo method should be called for this location.
28
28
  def docinfo? location; end
29
29
 
30
- # Public: Generates docinfo markup to insert in the output document at the specified location.
30
+ # Public: Generates docinfo markup for this syntax highlighter to insert at the specified location in the output document.
31
+ # Should be called by converter after main content has been converted.
31
32
  #
32
33
  # location - The Symbol representing the location slot (:head or :footer).
34
+ # doc - The Document in which this syntax highlighter is being used.
35
+ # opts - A Hash of options that configure the syntax highlighting:
36
+ # :linkcss - A Boolean indicating whether the stylesheet should be linked instead of embedded (optional).
37
+ # :cdn_base_url - The String base URL for assets loaded from the CDN.
38
+ # :self_closing_tag_slash - The String '/' if the converter calling this method emits self-closing tags.
33
39
  #
34
40
  # Return the [String] markup to insert.
35
- def docinfo location
41
+ def docinfo location, doc, opts
36
42
  raise ::NotImplementedError, %(#{SyntaxHighlighter} subclass #{self.class} must implement the ##{__method__} method since #docinfo? returns true)
37
43
  end
38
44
 
@@ -100,15 +106,21 @@ module SyntaxHighlighter
100
106
  module Config
101
107
  # Public: Statically register the current class in the registry for the specified names.
102
108
  #
109
+ # names - one or more String or Symbol names with which to register the current class as a syntax highlighter
110
+ # implementation. Symbol arguments are coerced to Strings.
111
+ #
103
112
  # Returns nothing.
104
113
  def register_for *names
105
- SyntaxHighlighter.register self, *names
114
+ SyntaxHighlighter.register self, *(names.map {|name| name.to_s })
106
115
  end
107
116
  end
108
117
 
109
118
  module Factory
110
119
  # Public: Associates the syntax highlighter class or object with the specified names.
111
120
  #
121
+ # syntax_highlighter - the syntax highlighter implementation to register
122
+ # names - one or more String names with which to register this syntax highlighter implementation.
123
+ #
112
124
  # Returns nothing.
113
125
  def register syntax_highlighter, *names
114
126
  names.each {|name| registry[name] = syntax_highlighter }
@@ -128,7 +140,7 @@ module SyntaxHighlighter
128
140
  # name - The String name of the syntax highlighter to create.
129
141
  # backend - The String name of the backend for which this syntax highlighter is being used (default: 'html5').
130
142
  # opts - A Hash of options providing information about the context in which this syntax highlighter is used:
131
- # :doc - The Document for which this syntax highlighter was created.
143
+ # :document - The Document for which this syntax highlighter was created.
132
144
  #
133
145
  # Returns a [SyntaxHighlighter] instance for the specified name.
134
146
  def create name, backend = 'html5', opts = {}
@@ -224,9 +236,11 @@ module SyntaxHighlighter
224
236
  def format node, lang, opts
225
237
  class_attr_val = opts[:nowrap] ? %(#{@pre_class} highlight nowrap) : %(#{@pre_class} highlight)
226
238
  if (transform = opts[:transform])
227
- pre = { 'class' => class_attr_val }
228
- code = lang ? { 'data-lang' => lang } : {}
229
- transform[pre, code]
239
+ transform[(pre = { 'class' => class_attr_val }), (code = lang ? { 'data-lang' => lang } : {})]
240
+ # NOTE: make sure data-lang is the last attribute on the code tag to remain consistent with 1.5.x
241
+ if (lang = code.delete 'data-lang')
242
+ code['data-lang'] = lang
243
+ end
230
244
  %(<pre#{pre.map {|k, v| %[ #{k}="#{v}"] }.join}><code#{code.map {|k, v| %[ #{k}="#{v}"] }.join}>#{node.content}</code></pre>)
231
245
  else
232
246
  %(<pre class="#{class_attr_val}"><code#{lang ? %[ data-lang="#{lang}"] : ''}>#{node.content}</code></pre>)
@@ -32,7 +32,7 @@ class SyntaxHighlighter::CodeRayAdapter < SyntaxHighlighter::Base
32
32
  end
33
33
 
34
34
  def docinfo? location
35
- @requires_stylesheet && location == :footer
35
+ @requires_stylesheet && location == :head
36
36
  end
37
37
 
38
38
  def docinfo location, doc, opts
@@ -13,14 +13,22 @@ class SyntaxHighlighter::HighlightJsAdapter < SyntaxHighlighter::Base
13
13
  end
14
14
 
15
15
  def docinfo? location
16
- location == :footer
16
+ true
17
17
  end
18
18
 
19
19
  def docinfo location, doc, opts
20
20
  base_url = doc.attr 'highlightjsdir', %(#{opts[:cdn_base_url]}/highlight.js/#{HIGHLIGHT_JS_VERSION})
21
- %(<link rel="stylesheet" href="#{base_url}/styles/#{doc.attr 'highlightjs-theme', 'github'}.min.css"#{opts[:self_closing_tag_slash]}>
22
- <script src="#{base_url}/highlight.min.js"></script>
23
- #{(doc.attr? 'highlightjs-languages') ? ((doc.attr 'highlightjs-languages').split ',').map {|lang| %[<script src="#{base_url}/languages/#{lang.lstrip}.min.js"></script>\n] }.join : ''}<script>hljs.initHighlighting()</script>)
21
+ if location == :head
22
+ %(<link rel="stylesheet" href="#{base_url}/styles/#{doc.attr 'highlightjs-theme', 'github'}.min.css"#{opts[:self_closing_tag_slash]}>)
23
+ else # :footer
24
+ %(<script src="#{base_url}/highlight.min.js"></script>
25
+ #{(doc.attr? 'highlightjs-languages') ? ((doc.attr 'highlightjs-languages').split ',').map {|lang| %[<script src="#{base_url}/languages/#{lang.lstrip}.min.js"></script>\n] }.join : ''}<script>
26
+ if (!hljs.initHighlighting.called) {
27
+ hljs.initHighlighting.called = true
28
+ ;[].slice.call(document.querySelectorAll('pre.highlight > code')).forEach(function (el) { hljs.highlightBlock(el) })
29
+ }
30
+ </script>)
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -14,14 +14,17 @@ class SyntaxHighlighter::PrettifyAdapter < SyntaxHighlighter::Base
14
14
  end
15
15
 
16
16
  def docinfo? location
17
- location == :footer
17
+ true
18
18
  end
19
19
 
20
20
  def docinfo location, doc, opts
21
21
  base_url = doc.attr 'prettifydir', %(#{opts[:cdn_base_url]}/prettify/r298)
22
- prettify_theme_url = ((prettify_theme = doc.attr 'prettify-theme', 'prettify').start_with? 'http://', 'https://') ? prettify_theme : %(#{base_url}/#{prettify_theme}.min.css)
23
- %(<link rel="stylesheet" href="#{prettify_theme_url}"#{opts[:self_closing_tag_slash]}>
24
- <script src="#{base_url}/run_prettify.min.js"></script>)
22
+ if location == :head
23
+ prettify_theme_url = ((prettify_theme = doc.attr 'prettify-theme', 'prettify').start_with? 'http://', 'https://') ? prettify_theme : %(#{base_url}/#{prettify_theme}.min.css)
24
+ %(<link rel="stylesheet" href="#{prettify_theme_url}"#{opts[:self_closing_tag_slash]}>)
25
+ else # :footer
26
+ %(<script src="#{base_url}/run_prettify.min.js"></script>)
27
+ end
25
28
  end
26
29
  end
27
30
  end
@@ -5,8 +5,7 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
5
5
 
6
6
  def initialize *args
7
7
  super
8
- @requires_stylesheet = nil
9
- @style = nil
8
+ @requires_stylesheet = @style = nil
10
9
  end
11
10
 
12
11
  def highlight?
@@ -53,7 +52,7 @@ class SyntaxHighlighter::PygmentsAdapter < SyntaxHighlighter::Base
53
52
  end
54
53
 
55
54
  def docinfo? location
56
- @requires_stylesheet && location == :footer
55
+ @requires_stylesheet && location == :head
57
56
  end
58
57
 
59
58
  def docinfo location, doc, opts
@@ -13,8 +13,17 @@ class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
13
13
  end
14
14
 
15
15
  def highlight node, source, lang, opts
16
- lexer = (::Rouge::Lexer.find_fancy lang) || ::Rouge::Lexers::PlainText
17
- lexer_opts = lexer.tag == 'php' && !(node.option? 'mixed') ? { start_inline: true } : {}
16
+ if lang.include? '?'
17
+ # NOTE cgi-style options only properly supported in Rouge >= 2.1
18
+ if (lexer = ::Rouge::Lexer.find_fancy lang)
19
+ unless lexer.tag != 'php' || (node.option? 'mixed') || ((lexer_opts = lexer.options).key? 'start_inline')
20
+ lexer = lexer.class.new lexer_opts.merge 'start_inline' => true
21
+ end
22
+ end
23
+ elsif (lexer = ::Rouge::Lexer.find lang)
24
+ lexer = lexer.tag == 'php' && !(node.option? 'mixed') ? (lexer.new start_inline: true) : lexer.new
25
+ end if lang
26
+ lexer ||= ::Rouge::Lexers::PlainText.new
18
27
  @style ||= (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE
19
28
  if opts[:css_mode] == :class
20
29
  @requires_stylesheet = true
@@ -28,25 +37,24 @@ class SyntaxHighlighter::RougeAdapter < SyntaxHighlighter::Base
28
37
  if opts[:number_lines]
29
38
  formatter = RougeExt::Formatters::HTMLTable.new formatter, start_line: opts[:start_line_number]
30
39
  if opts[:callouts]
31
- return [(highlighted = formatter.format lexer.lex source, lexer_opts), (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
40
+ return [(highlighted = formatter.format lexer.lex source), (idx = highlighted.index CodeCellStartTagCs) ? idx + CodeCellStartTagCs.length : nil]
32
41
  end
33
42
  end
34
- formatter.format lexer.lex source, lexer_opts
43
+ formatter.format lexer.lex source
35
44
  end
36
45
 
37
46
  def format node, lang, opts
38
47
  if (query_idx = lang && (lang.index '?'))
39
48
  lang = lang.slice 0, query_idx
40
49
  end
41
- if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) &&
42
- (pre_style_attr_val = base_style @style)
50
+ if opts[:css_mode] != :class && (@style = (style = opts[:style]) && (style_available? style) || DEFAULT_STYLE) && (pre_style_attr_val = base_style @style)
43
51
  opts[:transform] = proc {|pre| pre['style'] = pre_style_attr_val }
44
52
  end
45
53
  super
46
54
  end
47
55
 
48
56
  def docinfo? location
49
- @requires_stylesheet && location == :footer
57
+ @requires_stylesheet && location == :head
50
58
  end
51
59
 
52
60
  def docinfo location, doc, opts
@@ -58,7 +58,7 @@ class Table < AbstractBlock
58
58
  @rows = Rows.new
59
59
  @columns = []
60
60
 
61
- @has_header_option = attributes['header-option'] ? true : false
61
+ @has_header_option = false
62
62
 
63
63
  # smells like we need a utility method here
64
64
  # to resolve an integer width from potential bogus input
@@ -78,10 +78,10 @@ class Table < AbstractBlock
78
78
  @attributes['orientation'] = 'landscape' if attributes['rotate-option']
79
79
  end
80
80
 
81
- # Internal: Returns whether the current row being processed is
82
- # the header row
81
+ # Internal: Returns the current state of the header option (true or :implicit) if
82
+ # the row being processed is (or is assumed to be) the header row, otherwise nil
83
83
  def header_row?
84
- @has_header_option && @rows.body.empty?
84
+ (val = @has_header_option) && @rows.body.empty? ? val : nil
85
85
  end
86
86
 
87
87
  # Internal: Creates the Column objects from the column spec
@@ -154,22 +154,19 @@ class Table < AbstractBlock
154
154
  # returns nothing
155
155
  def partition_header_footer(attrs)
156
156
  # set rowcount before splitting up body rows
157
- @attributes['rowcount'] = @rows.body.size
158
-
159
- num_body_rows = @rows.body.size
160
- if num_body_rows > 0 && @has_header_option
161
- head = @rows.body.shift
162
- num_body_rows -= 1
163
- # styles aren't applied to header row
164
- head.each {|c| c.style = nil }
165
- # QUESTION why does AsciiDoc use an array for head? is it
166
- # possible to have more than one based on the syntax?
167
- @rows.head = [head]
157
+ num_body_rows = @attributes['rowcount'] = (body = @rows.body).size
158
+
159
+ if num_body_rows > 0
160
+ if @has_header_option
161
+ @rows.head = [body.shift.map {|cell| cell.reinitialize true }]
162
+ num_body_rows -= 1
163
+ elsif @has_header_option.nil?
164
+ @has_header_option = false
165
+ body.unshift(body.shift.map {|cell| cell.reinitialize false })
166
+ end
168
167
  end
169
168
 
170
- if num_body_rows > 0 && attrs['footer-option']
171
- @rows.foot = [@rows.body.pop]
172
- end
169
+ @rows.foot = [body.pop] if num_body_rows > 0 && attrs['footer-option']
173
170
 
174
171
  nil
175
172
  end
@@ -232,14 +229,23 @@ class Table::Cell < AbstractBlock
232
229
  # Public: An alias to the parent block (which is always a Column)
233
230
  alias column parent
234
231
 
235
- # Internal: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
232
+ # Public: Returns the nested Document in an AsciiDoc table cell (only set when style is :asciidoc)
236
233
  attr_reader :inner_document
237
234
 
238
235
  def initialize column, cell_text, attributes = {}, opts = {}
239
236
  super column, :table_cell
237
+ @cursor = @reinitialize_args = nil
240
238
  @source_location = opts[:cursor].dup if @document.sourcemap
239
+ # NOTE: column is always set when parsing; may not be set when building table from the API
241
240
  if column
242
- cell_style = column.attributes['style'] unless (in_header_row = column.table.header_row?)
241
+ if (in_header_row = column.table.header_row?)
242
+ if in_header_row == :implicit && (cell_style = column.style || (attributes && attributes['style']))
243
+ @reinitialize_args = [column, cell_text, attributes && attributes.merge, opts] if cell_style == :asciidoc || cell_style == :literal
244
+ cell_style = nil
245
+ end
246
+ else
247
+ cell_style = column.style
248
+ end
243
249
  # REVIEW feels hacky to inherit all attributes from column
244
250
  update_attributes column.attributes
245
251
  end
@@ -306,8 +312,12 @@ class Table::Cell < AbstractBlock
306
312
  @content_model = :verbatim
307
313
  @subs = BASIC_SUBS
308
314
  else
309
- if normal_psv && (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
310
- Parser.catalog_inline_anchor $1, $2, self, opts[:cursor], @document
315
+ if normal_psv
316
+ if in_header_row
317
+ @cursor = opts[:cursor] # used in deferred catalog_inline_anchor call
318
+ else
319
+ catalog_inline_anchor cell_text, opts[:cursor]
320
+ end
311
321
  end
312
322
  @content_model = :simple
313
323
  @subs = NORMAL_SUBS
@@ -316,6 +326,25 @@ class Table::Cell < AbstractBlock
316
326
  @style = cell_style
317
327
  end
318
328
 
329
+ def reinitialize has_header
330
+ if has_header
331
+ @reinitialize_args = nil
332
+ elsif @reinitialize_args
333
+ return Table::Cell.new(*@reinitialize_args)
334
+ else
335
+ @style = @attributes['style']
336
+ end
337
+ catalog_inline_anchor if @cursor
338
+ self
339
+ end
340
+
341
+ def catalog_inline_anchor cell_text = @text, cursor = nil
342
+ cursor, @cursor = @cursor, nil unless cursor
343
+ if (cell_text.start_with? '[[') && LeadingInlineAnchorRx =~ cell_text
344
+ Parser.catalog_inline_anchor $1, $2, self, cursor, @document
345
+ end
346
+ end
347
+
319
348
  # Public: Get the String text of this cell with substitutions applied.
320
349
  #
321
350
  # Used for cells in the head row as well as text-only (non-AsciiDoc) cells in
@@ -339,7 +368,7 @@ class Table::Cell < AbstractBlock
339
368
 
340
369
  # Public: Handles the body data (tbody, tfoot), applying styles and partitioning into paragraphs
341
370
  #
342
- # This method should not be used for cells in the head row or that have the literal or verse style.
371
+ # This method should not be used for cells in the head row or that have the literal style.
343
372
  #
344
373
  # Returns the converted String for this Cell
345
374
  def content