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
@@ -570,17 +570,18 @@ class Reader
570
570
  #
571
571
  # data - A String Array or String of source data to be normalized.
572
572
  # opts - A Hash of options to control how lines are prepared.
573
- # :normalize - Enables line normalization, which coerces the encoding to UTF-8 and removes trailing whitespace
574
- # (optional, default: false).
573
+ # :normalize - Enables line normalization, which coerces the encoding to UTF-8 and removes trailing whitespace;
574
+ # :rstrip removes all trailing whitespace; :chomp removes trailing newline only (optional, not set).
575
575
  #
576
576
  # Returns A String Array of source lines. If the source data is an Array, this method returns a copy.
577
577
  def prepare_lines data, opts = {}
578
- if opts[:normalize]
579
- ::Array === data ? (Helpers.prepare_source_array data) : (Helpers.prepare_source_string data)
578
+ if (normalize = opts[:normalize])
579
+ trim_end = normalize == :chomp ? false : true
580
+ ::Array === data ? (Helpers.prepare_source_array data, trim_end) : (Helpers.prepare_source_string data, trim_end)
580
581
  elsif ::Array === data
581
582
  data.drop 0
582
583
  elsif data
583
- data.split LF, -1
584
+ data.chomp.split LF, -1
584
585
  else
585
586
  []
586
587
  end
@@ -717,7 +718,7 @@ class PreprocessorReader < Reader
717
718
  end
718
719
 
719
720
  # effectively fill the buffer
720
- if (@lines = prepare_lines data, normalize: true, condense: false, indent: attributes['indent']).empty?
721
+ if (@lines = prepare_lines data, normalize: @process_lines || :chomp, condense: @process_lines, indent: attributes['indent']).empty?
721
722
  pop_include
722
723
  else
723
724
  # FIXME we eventually want to handle leveloffset without affecting the lines
@@ -1060,7 +1061,13 @@ class PreprocessorReader < Reader
1060
1061
  return inc_path
1061
1062
  end
1062
1063
 
1064
+ if (enc = parsed_attrs['encoding']) && (::Encoding.find enc rescue nil)
1065
+ (read_mode_params = read_mode.split ':')[1] = enc
1066
+ read_mode = read_mode_params.join ':'
1067
+ end unless RUBY_ENGINE_OPAL
1068
+
1063
1069
  inc_linenos = inc_tags = nil
1070
+ # NOTE attrlist is nil if missing from include directive
1064
1071
  if attrlist
1065
1072
  if parsed_attrs.key? 'lines'
1066
1073
  inc_linenos = []
@@ -1148,7 +1155,7 @@ class PreprocessorReader < Reader
1148
1155
  active_tag, select = tag_stack.empty? ? [nil, base_select] : tag_stack[-1]
1149
1156
  elsif inc_tags.key? this_tag
1150
1157
  include_cursor = create_include_cursor inc_path, expanded_target, inc_lineno
1151
- if (idx = tag_stack.rindex {|key, _| key == this_tag })
1158
+ if (idx = tag_stack.rindex {|key,| key == this_tag })
1152
1159
  idx == 0 ? tag_stack.shift : (tag_stack.delete_at idx)
1153
1160
  logger.warn message_with_context %(mismatched end tag (expected '#{active_tag}' but found '#{this_tag}') at line #{inc_lineno} of include #{target_type}: #{inc_path}), source_location: cursor, include_location: include_cursor
1154
1161
  else
@@ -269,7 +269,7 @@ module Asciidoctor
269
269
  #
270
270
  # NOTE we only have to check as far as the blank character because we know it means non-whitespace follows.
271
271
  # IMPORTANT if this regexp does not agree with the regexp for each list type, the parser will hang.
272
- AnyListRx = %r(^(?:[ \t]*(?:-|\*\**|\.\.*|\u2022|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!//[^/])[ \t]*[^ \t]#{CC_ANY}*?(?::::{0,2}|;;)(?:$|[ \t])|<?\d+>[ \t]))
272
+ AnyListRx = %r(^(?:[ \t]*(?:-|\*\**|\.\.*|\u2022|\d+\.|[a-zA-Z]\.|[IVXivx]+\))[ \t]|(?!//[^/])[ \t]*[^ \t]#{CC_ANY}*?(?::::{0,2}|;;)(?:$|[ \t])|<(?:\d+|\.)>[ \t]))
273
273
 
274
274
  # Matches an unordered list item (one level for hyphens, up to 5 levels for asterisks).
275
275
  #
@@ -469,7 +469,7 @@ module Asciidoctor
469
469
  # footnoteref:[id,text] (legacy)
470
470
  # footnoteref:[id] (legacy)
471
471
  #
472
- InlineFootnoteMacroRx = /\\?footnote(?:(ref):|:([#{CC_WORD}-]+)?)\[(?:|(#{CC_ALL}*?[^\\]))\]/m
472
+ InlineFootnoteMacroRx = /\\?footnote(?:(ref):|:([#{CC_WORD}-]+)?)\[(?:|(#{CC_ALL}*?[^\\]))\](?!<\/a>)/m
473
473
 
474
474
  # Matches an image or icon inline macro.
475
475
  #
@@ -514,9 +514,10 @@ module Asciidoctor
514
514
  # https://github.com[GitHub]
515
515
  # <https://github.com>
516
516
  # link:https://github.com[]
517
+ # "https://github.com[]"
517
518
  #
518
519
  # FIXME revisit! the main issue is we need different rules for implicit vs explicit
519
- InlineLinkRx = %r((^|link:|#{CG_BLANK}|&lt;|[>\(\)\[\];])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*([^\s.,\[\]<]))(?:\[(|#{CC_ALL}*?[^\\])\])?)m
520
+ InlineLinkRx = %r((^|link:|#{CG_BLANK}|&lt;|[>\(\)\[\];"'])(\\?(?:https?|file|ftp|irc)://[^\s\[\]<]*([^\s.,\[\]<]))(?:\[(|#{CC_ALL}*?[^\\])\])?)m
520
521
 
521
522
  # Match a link or e-mail inline macro.
522
523
  #
@@ -551,7 +552,7 @@ module Asciidoctor
551
552
  # menu:View[Page Style > No Style]
552
553
  # menu:View[Page Style, No Style]
553
554
  #
554
- InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))?\]/m
555
+ InlineMenuMacroRx = /\\?menu:(#{CG_WORD}|[#{CC_WORD}&][^\n\[]*[^\s\[])\[ *(?:|(#{CC_ALL}*?[^\\]))\]/m
555
556
 
556
557
  # Matches an implicit menu inline macro.
557
558
  #
@@ -542,14 +542,17 @@ module Substitutors
542
542
  end
543
543
 
544
544
  prefix, suffix = $1, ''
545
- # 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[])
546
546
  if $4
547
547
  prefix = '' if prefix == 'link:'
548
548
  text = $4
549
549
  else
550
- # invalid macro syntax (link: prefix w/o trailing square brackets)
551
- # FIXME we probably shouldn't even get here...our regex is doing too much
552
- 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
553
556
  text = ''
554
557
  case $3
555
558
  when ')'
@@ -591,7 +594,8 @@ module Substitutors
591
594
  unless text.empty?
592
595
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
593
596
  if !doc.compat_mode && (text.include? '=')
594
- 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, ''
595
599
  link_opts[:id] = attrs['id']
596
600
  end
597
601
 
@@ -637,7 +641,8 @@ module Substitutors
637
641
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
638
642
  if mailto
639
643
  if !doc.compat_mode && (text.include? ',')
640
- 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, ''
641
646
  link_opts[:id] = attrs['id']
642
647
  if attrs.key? 2
643
648
  if attrs.key? 3
@@ -648,7 +653,8 @@ module Substitutors
648
653
  end
649
654
  end
650
655
  elsif !doc.compat_mode && (text.include? '=')
651
- 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, ''
652
658
  link_opts[:id] = attrs['id']
653
659
  end
654
660
 
@@ -739,8 +745,8 @@ module Substitutors
739
745
  refid = $2
740
746
  if (text = $3)
741
747
  text = text.gsub ESC_R_SB, R_SB if text.include? R_SB
742
- # NOTE if an equal sign (=) is present, parse text as attributes
743
- 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? '=')
744
750
  end
745
751
  end
746
752
 
@@ -804,7 +810,7 @@ module Substitutors
804
810
  # handles: id (in compat mode or when natural xrefs are disabled)
805
811
  elsif doc.compat_mode || !Compliance.natural_xrefs
806
812
  refid, target = fragment, %(##{fragment})
807
- 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]
808
814
  # handles: id
809
815
  elsif doc.catalog[:refs][fragment]
810
816
  refid, target = fragment, %(##{fragment})
@@ -843,19 +849,17 @@ module Substitutors
843
849
  end
844
850
 
845
851
  if id
846
- 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
847
856
  text = restore_passthroughs(normalize_text text, true, true)
848
857
  index = doc.counter('footnote-number')
849
858
  doc.register(:footnotes, Document::Footnote.new(index, id, text))
850
859
  type, target = :ref, nil
851
860
  else
852
- if (footnote = doc.footnotes.find {|candidate| candidate.id == id })
853
- index, text = footnote.index, footnote.text
854
- else
855
- logger.warn %(invalid footnote reference: #{id})
856
- index, text = nil, id
857
- end
858
- type, target, id = :xref, id, nil
861
+ logger.warn %(invalid footnote reference: #{id})
862
+ index, text = nil, id
859
863
  end
860
864
  elsif text
861
865
  text = restore_passthroughs(normalize_text text, true, true)
@@ -917,7 +921,7 @@ module Substitutors
917
921
  # use sub since it might be behind a line comment
918
922
  $&.sub RS, ''
919
923
  else
920
- 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
921
925
  end
922
926
  end
923
927
  end
@@ -945,7 +949,7 @@ module Substitutors
945
949
  if (linenums_mode = (attr? 'linenums') ? (doc_attrs[%(#{syntax_hl_name}-linenums-mode)] || :table).to_sym : nil)
946
950
  start_line_number = 1 if (start_line_number = (attr 'start', 1).to_i) < 1
947
951
  end
948
- 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'
949
953
 
950
954
  highlighted, source_offset = syntax_hl.highlight self, source, (attr 'language'),
951
955
  callouts: callout_marks,
@@ -968,9 +972,10 @@ module Substitutors
968
972
  #
969
973
  # source - The String source.
970
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)
971
976
  #
972
977
  # Returns an [Array] of unique, sorted line numbers.
973
- def resolve_lines_to_highlight source, spec
978
+ def resolve_lines_to_highlight source, spec, start = nil
974
979
  lines = []
975
980
  spec = spec.delete ' ' if spec.include? ' '
976
981
  ((spec.include? ',') ? (spec.split ',') : (spec.split ';')).map do |entry|
@@ -981,21 +986,22 @@ module Substitutors
981
986
  if (delim = (entry.include? '..') ? '..' : ((entry.include? '-') ? '-' : nil))
982
987
  from, delim, to = entry.partition delim
983
988
  to = (source.count LF) + 1 if to.empty? || (to = to.to_i) < 0
984
- line_nums = (from.to_i..to).to_a
985
- if negate
986
- lines -= line_nums
987
- else
988
- lines.concat line_nums
989
- end
990
- else
991
989
  if negate
992
- lines.delete entry.to_i
990
+ lines -= (from.to_i..to).to_a
993
991
  else
994
- lines << entry.to_i
992
+ lines |= (from.to_i..to).to_a
995
993
  end
994
+ elsif negate
995
+ lines.delete entry.to_i
996
+ elsif !lines.include?(line = entry.to_i)
997
+ lines << line
996
998
  end
997
999
  end
998
- 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
999
1005
  end
1000
1006
 
1001
1007
  # Public: Extract the passthrough text from the document for reinsertion after processing.
@@ -1321,10 +1327,23 @@ module Substitutors
1321
1327
 
1322
1328
  private
1323
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
+
1324
1343
  # Internal: Extract the callout numbers from the source to prepare it for syntax highlighting.
1325
1344
  def extract_callouts source
1326
1345
  callout_marks = {}
1327
- lineno = 0
1346
+ autonum = lineno = 0
1328
1347
  last_lineno = nil
1329
1348
  callout_rx = (attr? 'line-comment') ? CalloutExtractRxMap[attr 'line-comment'] : CalloutExtractRx
1330
1349
  # extract callout marks, indexed by line number
@@ -1336,7 +1355,7 @@ module Substitutors
1336
1355
  # use sub since it might be behind a line comment
1337
1356
  $&.sub RS, ''
1338
1357
  else
1339
- (callout_marks[lineno] ||= []) << [$1, $4]
1358
+ (callout_marks[lineno] ||= []) << [$1 || ($3 == '--' ? ['<!--', '-->'] : nil), $4 == '.' ? (autonum += 1).to_s : $4]
1340
1359
  last_lineno = lineno
1341
1360
  ''
1342
1361
  end
@@ -1358,15 +1377,15 @@ module Substitutors
1358
1377
  else
1359
1378
  preamble = ''
1360
1379
  end
1361
- autonum = lineno = 0
1380
+ lineno = 0
1362
1381
  preamble + ((source.split LF, -1).map do |line|
1363
1382
  if (conums = callout_marks.delete lineno += 1)
1364
1383
  if conums.size == 1
1365
- guard, conum = conums[0]
1366
- %(#{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})
1367
1386
  else
1368
- %(#{line}#{conums.map do |guard_it, conum_it|
1369
- 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
1370
1389
  end.join ' '})
1371
1390
  end
1372
1391
  else
@@ -20,7 +20,7 @@ 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
  #
@@ -28,6 +28,7 @@ module SyntaxHighlighter
28
28
  def docinfo? location; end
29
29
 
30
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).
33
34
  # doc - The Document in which this syntax highlighter is being used.
@@ -139,7 +140,7 @@ module SyntaxHighlighter
139
140
  # name - The String name of the syntax highlighter to create.
140
141
  # backend - The String name of the backend for which this syntax highlighter is being used (default: 'html5').
141
142
  # opts - A Hash of options providing information about the context in which this syntax highlighter is used:
142
- # :doc - The Document for which this syntax highlighter was created.
143
+ # :document - The Document for which this syntax highlighter was created.
143
144
  #
144
145
  # Returns a [SyntaxHighlighter] instance for the specified name.
145
146
  def create name, backend = 'html5', opts = {}
@@ -235,9 +236,11 @@ module SyntaxHighlighter
235
236
  def format node, lang, opts
236
237
  class_attr_val = opts[:nowrap] ? %(#{@pre_class} highlight nowrap) : %(#{@pre_class} highlight)
237
238
  if (transform = opts[:transform])
238
- pre = { 'class' => class_attr_val }
239
- code = lang ? { 'data-lang' => lang } : {}
240
- 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
241
244
  %(<pre#{pre.map {|k, v| %[ #{k}="#{v}"] }.join}><code#{code.map {|k, v| %[ #{k}="#{v}"] }.join}>#{node.content}</code></pre>)
242
245
  else
243
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