asciidoctor 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +107 -1
- data/LICENSE.adoc +1 -1
- data/README.adoc +155 -230
- data/Rakefile +2 -1
- data/bin/asciidoctor +5 -1
- data/data/stylesheets/asciidoctor-default.css +37 -29
- data/data/stylesheets/coderay-asciidoctor.css +3 -3
- data/features/text_formatting.feature +2 -0
- data/lib/asciidoctor.rb +46 -21
- data/lib/asciidoctor/abstract_block.rb +14 -8
- data/lib/asciidoctor/abstract_node.rb +77 -24
- data/lib/asciidoctor/attribute_list.rb +1 -1
- data/lib/asciidoctor/block.rb +2 -3
- data/lib/asciidoctor/cli/options.rb +14 -15
- data/lib/asciidoctor/converter/docbook45.rb +8 -8
- data/lib/asciidoctor/converter/docbook5.rb +25 -17
- data/lib/asciidoctor/converter/factory.rb +6 -1
- data/lib/asciidoctor/converter/html5.rb +159 -117
- data/lib/asciidoctor/converter/manpage.rb +671 -0
- data/lib/asciidoctor/converter/template.rb +24 -17
- data/lib/asciidoctor/document.rb +89 -47
- data/lib/asciidoctor/extensions.rb +22 -21
- data/lib/asciidoctor/helpers.rb +73 -16
- data/lib/asciidoctor/list.rb +26 -5
- data/lib/asciidoctor/parser.rb +179 -122
- data/lib/asciidoctor/path_resolver.rb +6 -10
- data/lib/asciidoctor/reader.rb +37 -34
- data/lib/asciidoctor/stylesheets.rb +16 -10
- data/lib/asciidoctor/substitutors.rb +98 -21
- data/lib/asciidoctor/table.rb +21 -17
- data/lib/asciidoctor/timings.rb +3 -3
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +155 -89
- data/man/asciidoctor.adoc +19 -11
- data/test/attributes_test.rb +86 -0
- data/test/blocks_test.rb +203 -15
- data/test/converter_test.rb +15 -2
- data/test/document_test.rb +290 -36
- data/test/extensions_test.rb +22 -3
- data/test/fixtures/circle.svg +8 -0
- data/test/fixtures/subs-docinfo.html +2 -0
- data/test/fixtures/subs.adoc +7 -0
- data/test/invoker_test.rb +25 -0
- data/test/links_test.rb +17 -0
- data/test/lists_test.rb +173 -0
- data/test/options_test.rb +2 -2
- data/test/paragraphs_test.rb +2 -2
- data/test/parser_test.rb +56 -13
- data/test/reader_test.rb +35 -3
- data/test/sections_test.rb +59 -0
- data/test/substitutions_test.rb +53 -14
- data/test/tables_test.rb +158 -2
- data/test/test_helper.rb +7 -2
- metadata +22 -11
- data/benchmark/benchmark.rb +0 -129
- data/benchmark/sample-data/mdbasics.adoc +0 -334
- data/lib/asciidoctor/opal_ext.rb +0 -26
- data/lib/asciidoctor/opal_ext/comparable.rb +0 -38
- data/lib/asciidoctor/opal_ext/dir.rb +0 -13
- data/lib/asciidoctor/opal_ext/error.rb +0 -2
- data/lib/asciidoctor/opal_ext/file.rb +0 -145
@@ -303,7 +303,6 @@ class PathResolver
|
|
303
303
|
# any parent references resolved and self references removed and enforces
|
304
304
|
# that the resolved path be contained within the jail, if provided
|
305
305
|
def system_path target, start, jail = nil, opts = {}
|
306
|
-
recover = opts.fetch :recover, true
|
307
306
|
if jail
|
308
307
|
unless is_root? jail
|
309
308
|
raise ::SecurityError, %(Jail is not an absolute path: #{jail})
|
@@ -325,7 +324,7 @@ class PathResolver
|
|
325
324
|
return expand_path start
|
326
325
|
end
|
327
326
|
else
|
328
|
-
return system_path start, jail, jail
|
327
|
+
return system_path start, jail, jail, opts
|
329
328
|
end
|
330
329
|
end
|
331
330
|
|
@@ -343,7 +342,7 @@ class PathResolver
|
|
343
342
|
elsif is_root? start
|
344
343
|
start = posixfy start
|
345
344
|
else
|
346
|
-
start = system_path start, jail, jail
|
345
|
+
start = system_path start, jail, jail, opts
|
347
346
|
end
|
348
347
|
|
349
348
|
# both jail and start have been posixfied at this point
|
@@ -374,7 +373,7 @@ class PathResolver
|
|
374
373
|
if jail
|
375
374
|
if resolved_segments.length > jail_segments.length
|
376
375
|
resolved_segments.pop
|
377
|
-
elsif !recover
|
376
|
+
elsif !(recover ||= (opts.fetch :recover, true))
|
378
377
|
raise ::SecurityError, %(#{opts[:target_name] || 'path'} #{target} refers to location outside jail: #{jail} (disallowed in safe mode))
|
379
378
|
elsif !warned
|
380
379
|
warn %(asciidoctor: WARNING: #{opts[:target_name] || 'path'} has illegal reference to ancestor of jail, auto-recovering)
|
@@ -411,21 +410,18 @@ class PathResolver
|
|
411
410
|
|
412
411
|
unless start.nil_or_empty? || (is_web_root? target)
|
413
412
|
target = %(#{start}#{SLASH}#{target})
|
414
|
-
if (
|
415
|
-
uri_prefix = $~[0]
|
413
|
+
if (uri_prefix = Helpers.uri_prefix target)
|
416
414
|
target = target[uri_prefix.length..-1]
|
417
415
|
end
|
418
416
|
end
|
419
417
|
|
420
418
|
# use this logic instead if we want to normalize target if it contains a URI
|
421
419
|
#unless is_web_root? target
|
422
|
-
# if preserve_uri_target && (
|
423
|
-
# uri_prefix = $~[0]
|
420
|
+
# if preserve_uri_target && (uri_prefix = Helpers.uri_prefix target)
|
424
421
|
# target = target[uri_prefix.length..-1]
|
425
422
|
# elsif !start.nil_or_empty?
|
426
423
|
# target = %(#{start}#{SLASH}#{target})
|
427
|
-
# if (
|
428
|
-
# uri_prefix = $~[0]
|
424
|
+
# if (uri_prefix = Helpers.uri_prefix target)
|
429
425
|
# target = target[uri_prefix.length..-1]
|
430
426
|
# end
|
431
427
|
# end
|
data/lib/asciidoctor/reader.rb
CHANGED
@@ -438,7 +438,7 @@ class Reader
|
|
438
438
|
break_on_blank_lines = options[:break_on_blank_lines]
|
439
439
|
break_on_list_continuation = options[:break_on_list_continuation]
|
440
440
|
end
|
441
|
-
|
441
|
+
skip_comments = options[:skip_line_comments]
|
442
442
|
line_read = false
|
443
443
|
line_restored = false
|
444
444
|
|
@@ -466,7 +466,7 @@ class Reader
|
|
466
466
|
line_restored = true
|
467
467
|
end
|
468
468
|
else
|
469
|
-
unless
|
469
|
+
unless skip_comments && line.start_with?('//') && CommentLineRx =~ line
|
470
470
|
result << line
|
471
471
|
line_read = true
|
472
472
|
end
|
@@ -578,8 +578,8 @@ class PreprocessorReader < Reader
|
|
578
578
|
result.pop while (last = result[-1]) && last.empty?
|
579
579
|
end
|
580
580
|
|
581
|
-
if
|
582
|
-
Parser.
|
581
|
+
if opts[:indent]
|
582
|
+
Parser.adjust_indentation! result, opts[:indent], (@document.attr 'tabsize')
|
583
583
|
end
|
584
584
|
|
585
585
|
result
|
@@ -753,11 +753,14 @@ class PreprocessorReader < Reader
|
|
753
753
|
end
|
754
754
|
|
755
755
|
lhs = resolve_expr_val expr_match[1]
|
756
|
-
# regex enforces a restrict set of math-related operations
|
757
|
-
op = expr_match[2]
|
758
756
|
rhs = resolve_expr_val expr_match[3]
|
759
757
|
|
760
|
-
|
758
|
+
# regex enforces a restricted set of math-related operations
|
759
|
+
if (op = expr_match[2]) == '!='
|
760
|
+
skip = lhs.send :==, rhs
|
761
|
+
else
|
762
|
+
skip = !(lhs.send op.to_sym, rhs)
|
763
|
+
end
|
761
764
|
end
|
762
765
|
end
|
763
766
|
|
@@ -838,7 +841,7 @@ class PreprocessorReader < Reader
|
|
838
841
|
else
|
839
842
|
::File.join @dir, target
|
840
843
|
end
|
841
|
-
elsif
|
844
|
+
elsif Helpers.uriish? target
|
842
845
|
unless @document.attributes.has_key? 'allow-uri-read'
|
843
846
|
replace_line %(link:#{target}[])
|
844
847
|
return true
|
@@ -849,7 +852,7 @@ class PreprocessorReader < Reader
|
|
849
852
|
if @document.attributes.has_key? 'cache-uri'
|
850
853
|
# caching requires the open-uri-cached gem to be installed
|
851
854
|
# processing will be automatically aborted if these libraries can't be opened
|
852
|
-
Helpers.require_library 'open-uri/cached', 'open-uri-cached'
|
855
|
+
Helpers.require_library 'open-uri/cached', 'open-uri-cached' unless defined? ::OpenURI::Cache
|
853
856
|
elsif !::RUBY_ENGINE_OPAL
|
854
857
|
# autoload open-uri
|
855
858
|
::OpenURI
|
@@ -1126,65 +1129,65 @@ class PreprocessorReader < Reader
|
|
1126
1129
|
# Examples
|
1127
1130
|
#
|
1128
1131
|
# expr = '"value"'
|
1129
|
-
# resolve_expr_val
|
1132
|
+
# resolve_expr_val expr
|
1130
1133
|
# # => "value"
|
1131
1134
|
#
|
1132
1135
|
# expr = '"value'
|
1133
|
-
# resolve_expr_val
|
1136
|
+
# resolve_expr_val expr
|
1134
1137
|
# # => "\"value"
|
1135
1138
|
#
|
1136
1139
|
# expr = '"{undefined}"'
|
1137
|
-
# resolve_expr_val
|
1140
|
+
# resolve_expr_val expr
|
1138
1141
|
# # => ""
|
1139
1142
|
#
|
1140
1143
|
# expr = '{undefined}'
|
1141
|
-
# resolve_expr_val
|
1144
|
+
# resolve_expr_val expr
|
1142
1145
|
# # => nil
|
1143
1146
|
#
|
1144
1147
|
# expr = '2'
|
1145
|
-
# resolve_expr_val
|
1148
|
+
# resolve_expr_val expr
|
1146
1149
|
# # => 2
|
1147
1150
|
#
|
1148
1151
|
# @document.attributes['name'] = 'value'
|
1149
1152
|
# expr = '"{name}"'
|
1150
|
-
# resolve_expr_val
|
1153
|
+
# resolve_expr_val expr
|
1151
1154
|
# # => "value"
|
1152
1155
|
#
|
1153
1156
|
# Returns The value of the expression, coerced to the appropriate type
|
1154
|
-
def resolve_expr_val
|
1155
|
-
val
|
1156
|
-
|
1157
|
-
|
1158
|
-
if val.start_with?('"') && val.end_with?('"') ||
|
1159
|
-
val.start_with?('\'') && val.end_with?('\'')
|
1160
|
-
type = :string
|
1157
|
+
def resolve_expr_val val
|
1158
|
+
if ((val.start_with? '"') && (val.end_with? '"')) ||
|
1159
|
+
((val.start_with? '\'') && (val.end_with? '\''))
|
1160
|
+
quoted = true
|
1161
1161
|
val = val[1...-1]
|
1162
|
+
else
|
1163
|
+
quoted = false
|
1162
1164
|
end
|
1163
1165
|
|
1164
1166
|
# QUESTION should we substitute first?
|
1167
|
+
# QUESTION should we also require string to be single quoted (like block attribute values?)
|
1165
1168
|
if val.include? '{'
|
1166
|
-
val = @document.sub_attributes val
|
1169
|
+
val = @document.sub_attributes val, :attribute_missing => 'drop'
|
1167
1170
|
end
|
1168
1171
|
|
1169
|
-
|
1172
|
+
if quoted
|
1173
|
+
val
|
1174
|
+
else
|
1170
1175
|
if val.empty?
|
1171
|
-
|
1172
|
-
elsif val.strip.empty?
|
1173
|
-
val = ' '
|
1176
|
+
nil
|
1174
1177
|
elsif val == 'true'
|
1175
|
-
|
1178
|
+
true
|
1176
1179
|
elsif val == 'false'
|
1177
|
-
|
1178
|
-
elsif val.
|
1179
|
-
|
1180
|
+
false
|
1181
|
+
elsif val.rstrip.empty?
|
1182
|
+
' '
|
1183
|
+
elsif val.include? '.'
|
1184
|
+
val.to_f
|
1180
1185
|
else
|
1181
1186
|
# fallback to coercing to integer, since we
|
1182
1187
|
# require string values to be explicitly quoted
|
1183
|
-
val
|
1188
|
+
val.to_i
|
1184
1189
|
end
|
1185
1190
|
end
|
1186
|
-
|
1187
|
-
val
|
1188
1191
|
end
|
1189
1192
|
|
1190
1193
|
def include_processors?
|
@@ -6,7 +6,6 @@ module Asciidoctor
|
|
6
6
|
# QUESTION create method for user stylesheet?
|
7
7
|
class Stylesheets
|
8
8
|
DEFAULT_STYLESHEET_NAME = 'asciidoctor.css'
|
9
|
-
#DEFAULT_CODERAY_STYLE = 'asciidoctor'
|
10
9
|
DEFAULT_PYGMENTS_STYLE = 'default'
|
11
10
|
STYLESHEETS_DATA_PATH = ::File.join DATA_PATH, 'stylesheets'
|
12
11
|
|
@@ -45,9 +44,10 @@ class Stylesheets
|
|
45
44
|
#
|
46
45
|
# returns the [String] CodeRay stylesheet data
|
47
46
|
def coderay_stylesheet_data
|
48
|
-
# NOTE use the following
|
49
|
-
#
|
50
|
-
#
|
47
|
+
# NOTE use the following lines to load a built-in theme instead
|
48
|
+
# unless load_coderay.nil?
|
49
|
+
# ::CodeRay::Encoders[:html]::CSS.new(:default).stylesheet
|
50
|
+
# end
|
51
51
|
@coderay_stylesheet_data ||= ::IO.read(::File.join(STYLESHEETS_DATA_PATH, 'coderay-asciidoctor.css')).chomp
|
52
52
|
end
|
53
53
|
|
@@ -62,16 +62,19 @@ class Stylesheets
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def pygments_stylesheet_name style = nil
|
65
|
-
style
|
66
|
-
%(pygments-#{style}.css)
|
65
|
+
%(pygments-#{style || DEFAULT_PYGMENTS_STYLE}.css)
|
67
66
|
end
|
68
67
|
|
69
68
|
# Public: Generate the Pygments stylesheet with the specified style.
|
70
69
|
#
|
71
70
|
# returns the [String] Pygments stylesheet data
|
72
71
|
def pygments_stylesheet_data style = nil
|
73
|
-
|
74
|
-
|
72
|
+
if load_pygments
|
73
|
+
(@pygments_stylesheet_data ||= {})[style || DEFAULT_PYGMENTS_STYLE] ||=
|
74
|
+
::Pygments.css '.listingblock .pygments', :classprefix => 'tok-', :style => (style || DEFAULT_PYGMENTS_STYLE)
|
75
|
+
else
|
76
|
+
'/* Pygments styles disabled. Pygments is not available. */'
|
77
|
+
end
|
75
78
|
end
|
76
79
|
|
77
80
|
def embed_pygments_stylesheet style = nil
|
@@ -84,9 +87,12 @@ class Stylesheets
|
|
84
87
|
::File.open(::File.join(target_dir, pygments_stylesheet_name(style)), 'w') {|f| f.write pygments_stylesheet_data(style) }
|
85
88
|
end
|
86
89
|
|
90
|
+
#def load_coderay
|
91
|
+
# (defined? ::CodeRay) ? true : !(Helpers.require_library 'coderay', true, :ignore).nil?
|
92
|
+
#end
|
93
|
+
|
87
94
|
def load_pygments
|
88
|
-
Helpers.require_library 'pygments', 'pygments.rb'
|
89
|
-
{}
|
95
|
+
(defined? ::Pygments) ? true : !(Helpers.require_library 'pygments', 'pygments.rb', :ignore).nil?
|
90
96
|
end
|
91
97
|
end
|
92
98
|
end
|
@@ -80,7 +80,7 @@ module Substitutors
|
|
80
80
|
elsif subs == :normal
|
81
81
|
subs = SUBS[:normal]
|
82
82
|
elsif expand
|
83
|
-
if
|
83
|
+
if ::Symbol === subs
|
84
84
|
subs = COMPOSITE_SUBS[subs] || [subs]
|
85
85
|
else
|
86
86
|
effective_subs = []
|
@@ -98,7 +98,7 @@ module Substitutors
|
|
98
98
|
|
99
99
|
return source if subs.empty?
|
100
100
|
|
101
|
-
text = (multiline =
|
101
|
+
text = (multiline = ::Array === source) ? source * EOL : source
|
102
102
|
|
103
103
|
if (has_passthroughs = subs.include? :macros)
|
104
104
|
text = extract_passthroughs text
|
@@ -108,7 +108,7 @@ module Substitutors
|
|
108
108
|
subs.each do |type|
|
109
109
|
case type
|
110
110
|
when :specialcharacters
|
111
|
-
text =
|
111
|
+
text = sub_specialchars text
|
112
112
|
when :quotes
|
113
113
|
text = sub_quotes text
|
114
114
|
when :attributes
|
@@ -138,7 +138,7 @@ module Substitutors
|
|
138
138
|
#
|
139
139
|
# returns - A String with normal substitutions performed
|
140
140
|
def apply_normal_subs(lines)
|
141
|
-
apply_subs
|
141
|
+
apply_subs(::Array === lines ? lines * EOL : lines)
|
142
142
|
end
|
143
143
|
|
144
144
|
# Public: Apply substitutions for titles.
|
@@ -356,12 +356,12 @@ module Substitutors
|
|
356
356
|
# text - The String text to process
|
357
357
|
#
|
358
358
|
# returns The String text with special characters replaced
|
359
|
-
def
|
359
|
+
def sub_specialchars(text)
|
360
360
|
SUPPORTS_GSUB_RESULT_HASH ?
|
361
361
|
text.gsub(SPECIAL_CHARS_PATTERN, SPECIAL_CHARS) :
|
362
362
|
text.gsub(SPECIAL_CHARS_PATTERN) { SPECIAL_CHARS[$&] }
|
363
363
|
end
|
364
|
-
alias :
|
364
|
+
alias :sub_specialcharacters :sub_specialchars
|
365
365
|
|
366
366
|
# Public: Substitute quoted text (includes emphasis, strong, monospaced, etc)
|
367
367
|
#
|
@@ -448,7 +448,7 @@ module Substitutors
|
|
448
448
|
return data if data.nil_or_empty?
|
449
449
|
|
450
450
|
# normalizes data type to an array (string becomes single-element array)
|
451
|
-
if (string_data = String === data)
|
451
|
+
if (string_data = ::String === data)
|
452
452
|
data = [data]
|
453
453
|
end
|
454
454
|
|
@@ -520,7 +520,7 @@ module Substitutors
|
|
520
520
|
result << line unless reject || (reject_if_empty && line.empty?)
|
521
521
|
end
|
522
522
|
|
523
|
-
string_data ?
|
523
|
+
string_data ? result * EOL : result
|
524
524
|
end
|
525
525
|
|
526
526
|
# Public: Substitute inline macros (e.g., links, images, etc)
|
@@ -632,7 +632,7 @@ module Substitutors
|
|
632
632
|
# TODO this handling needs some cleanup
|
633
633
|
if (extensions = @document.extensions) && extensions.inline_macros? # && found[:macroish]
|
634
634
|
extensions.inline_macros.each do |extension|
|
635
|
-
result = result.gsub(extension.
|
635
|
+
result = result.gsub(extension.instance.regexp) {
|
636
636
|
# alias match for Ruby 1.8.7 compat
|
637
637
|
m = $~
|
638
638
|
# honor the escape
|
@@ -678,7 +678,7 @@ module Substitutors
|
|
678
678
|
@document.register(:images, target)
|
679
679
|
end
|
680
680
|
attrs = parse_attributes(raw_attrs, posattrs)
|
681
|
-
attrs['alt'] ||=
|
681
|
+
attrs['alt'] ||= Helpers.basename(target, true).tr('_-', ' ')
|
682
682
|
Inline.new(self, :image, nil, :type => type, :target => target, :attributes => attrs).convert
|
683
683
|
}
|
684
684
|
end
|
@@ -828,10 +828,10 @@ module Substitutors
|
|
828
828
|
end
|
829
829
|
|
830
830
|
if text.empty?
|
831
|
-
|
832
|
-
target.sub UriSniffRx, ''
|
831
|
+
if @document.attr? 'hide-uri-scheme'
|
832
|
+
text = target.sub UriSniffRx, ''
|
833
833
|
else
|
834
|
-
target
|
834
|
+
text = target
|
835
835
|
end
|
836
836
|
|
837
837
|
if attrs
|
@@ -1069,6 +1069,9 @@ module Substitutors
|
|
1069
1069
|
|
1070
1070
|
if id.include? '#'
|
1071
1071
|
path, fragment = id.split('#')
|
1072
|
+
# QUESTION perform this check and throw it back if it fails?
|
1073
|
+
#elsif (start_chr = id.chr) == '.' || start_chr == '/'
|
1074
|
+
# next m[0][1..-1]
|
1072
1075
|
else
|
1073
1076
|
path = nil
|
1074
1077
|
fragment = id
|
@@ -1318,8 +1321,7 @@ module Substitutors
|
|
1318
1321
|
return [] if subs.nil_or_empty?
|
1319
1322
|
candidates = nil
|
1320
1323
|
modifiers_present = SubModifierSniffRx =~ subs
|
1321
|
-
subs.split(',').each do |
|
1322
|
-
key = val.strip
|
1324
|
+
subs.tr(' ', '').split(',').each do |key|
|
1323
1325
|
modifier_operation = nil
|
1324
1326
|
if modifiers_present
|
1325
1327
|
if (first = key.chr) == '+'
|
@@ -1394,10 +1396,34 @@ module Substitutors
|
|
1394
1396
|
# process_callouts - a Boolean flag indicating whether callout marks should be substituted
|
1395
1397
|
#
|
1396
1398
|
# returns the highlighted source code, if a source highlighter is defined
|
1397
|
-
# on the document, otherwise the
|
1398
|
-
def highlight_source
|
1399
|
-
highlighter ||= @document.attributes['source-highlighter']
|
1400
|
-
|
1399
|
+
# on the document, otherwise the source with verbatim substituions applied
|
1400
|
+
def highlight_source source, process_callouts, highlighter = nil
|
1401
|
+
case (highlighter ||= @document.attributes['source-highlighter'])
|
1402
|
+
when 'coderay'
|
1403
|
+
unless (highlighter_loaded = defined? ::CodeRay) || @document.attributes['coderay-unavailable']
|
1404
|
+
if (Helpers.require_library 'coderay', true, :warn).nil?
|
1405
|
+
# prevent further attempts to load CodeRay
|
1406
|
+
@document.set_attr 'coderay-unavailable', true
|
1407
|
+
else
|
1408
|
+
highlighter_loaded = true
|
1409
|
+
end
|
1410
|
+
end
|
1411
|
+
when 'pygments'
|
1412
|
+
unless (highlighter_loaded = defined? ::Pygments) || @document.attributes['pygments-unavailable']
|
1413
|
+
if (Helpers.require_library 'pygments', 'pygments.rb', :warn).nil?
|
1414
|
+
# prevent further attempts to load Pygments
|
1415
|
+
@document.set_attr 'pygments-unavailable', true
|
1416
|
+
else
|
1417
|
+
highlighter_loaded = true
|
1418
|
+
end
|
1419
|
+
end
|
1420
|
+
else
|
1421
|
+
# unknown highlighting library (something is misconfigured if we arrive here)
|
1422
|
+
highlighter_loaded = false
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
return sub_source source, process_callouts unless highlighter_loaded
|
1426
|
+
|
1401
1427
|
lineno = 0
|
1402
1428
|
callout_on_last = false
|
1403
1429
|
if process_callouts
|
@@ -1428,13 +1454,21 @@ module Substitutors
|
|
1428
1454
|
end
|
1429
1455
|
|
1430
1456
|
linenums_mode = nil
|
1457
|
+
highlight_lines = nil
|
1431
1458
|
|
1432
1459
|
case highlighter
|
1433
1460
|
when 'coderay'
|
1461
|
+
if (linenums_mode = (attr? 'linenums') ? (@document.attributes['coderay-linenums-mode'] || :table).to_sym : nil)
|
1462
|
+
if attr? 'highlight', nil, false
|
1463
|
+
highlight_lines = resolve_lines_to_highlight(attr 'highlight', nil, false)
|
1464
|
+
end
|
1465
|
+
end
|
1434
1466
|
result = ::CodeRay::Duo[attr('language', :text, false).to_sym, :html, {
|
1435
1467
|
:css => (@document.attributes['coderay-css'] || :class).to_sym,
|
1436
|
-
:line_numbers =>
|
1437
|
-
:line_number_anchors => false
|
1468
|
+
:line_numbers => linenums_mode,
|
1469
|
+
:line_number_anchors => false,
|
1470
|
+
:highlight_lines => highlight_lines,
|
1471
|
+
:bold_every => false}].highlight source
|
1438
1472
|
when 'pygments'
|
1439
1473
|
lexer = ::Pygments::Lexer[attr('language', nil, false)] || ::Pygments::Lexer['text']
|
1440
1474
|
opts = { :cssclass => 'pyhl', :classprefix => 'tok-', :nobackground => true }
|
@@ -1442,6 +1476,11 @@ module Substitutors
|
|
1442
1476
|
opts[:noclasses] = true
|
1443
1477
|
opts[:style] = (@document.attributes['pygments-style'] || Stylesheets::DEFAULT_PYGMENTS_STYLE)
|
1444
1478
|
end
|
1479
|
+
if attr? 'highlight', nil, false
|
1480
|
+
unless (highlight_lines = resolve_lines_to_highlight(attr 'highlight', nil, false)).empty?
|
1481
|
+
opts[:hl_lines] = highlight_lines * ' '
|
1482
|
+
end
|
1483
|
+
end
|
1445
1484
|
if attr? 'linenums'
|
1446
1485
|
# TODO we could add the line numbers in ourselves instead of having to strip out the junk
|
1447
1486
|
# FIXME move these regular expressions into constants
|
@@ -1505,6 +1544,44 @@ module Substitutors
|
|
1505
1544
|
end
|
1506
1545
|
end
|
1507
1546
|
|
1547
|
+
# e.g., highlight="1-5, !2, 10" or highlight=1-5;!2,10
|
1548
|
+
def resolve_lines_to_highlight spec
|
1549
|
+
lines = []
|
1550
|
+
spec.delete(' ').split(DataDelimiterRx).map do |entry|
|
1551
|
+
negate = false
|
1552
|
+
if entry.start_with? '!'
|
1553
|
+
entry = entry[1..-1]
|
1554
|
+
negate = true
|
1555
|
+
end
|
1556
|
+
if entry.include? '-'
|
1557
|
+
s, e = entry.split '-', 2
|
1558
|
+
line_nums = (s.to_i..e.to_i).to_a
|
1559
|
+
if negate
|
1560
|
+
lines -= line_nums
|
1561
|
+
else
|
1562
|
+
lines.concat line_nums
|
1563
|
+
end
|
1564
|
+
else
|
1565
|
+
if negate
|
1566
|
+
lines.delete entry.to_i
|
1567
|
+
else
|
1568
|
+
lines << entry.to_i
|
1569
|
+
end
|
1570
|
+
end
|
1571
|
+
end
|
1572
|
+
lines.sort.uniq
|
1573
|
+
end
|
1574
|
+
|
1575
|
+
# Public: Apply verbatim substitutions on source (for use when highlighting is disabled).
|
1576
|
+
#
|
1577
|
+
# source - the source code String on which to apply verbatim substitutions
|
1578
|
+
# process_callouts - a Boolean flag indicating whether callout marks should be substituted
|
1579
|
+
#
|
1580
|
+
# returns the substituted source
|
1581
|
+
def sub_source source, process_callouts
|
1582
|
+
return process_callouts ? sub_callouts(sub_specialchars(source)) : sub_specialchars(source)
|
1583
|
+
end
|
1584
|
+
|
1508
1585
|
# Internal: Lock-in the substitutions for this block
|
1509
1586
|
#
|
1510
1587
|
# Looks for an attribute named "subs". If present, resolves the
|