asciidoctor 0.0.7 → 0.0.9
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.
- data/Gemfile +2 -0
- data/README.asciidoc +35 -26
- data/Rakefile +9 -6
- data/asciidoctor.gemspec +27 -8
- data/bin/asciidoctor +1 -1
- data/lib/asciidoctor.rb +351 -63
- data/lib/asciidoctor/abstract_block.rb +218 -0
- data/lib/asciidoctor/abstract_node.rb +249 -0
- data/lib/asciidoctor/attribute_list.rb +211 -0
- data/lib/asciidoctor/backends/base_template.rb +99 -0
- data/lib/asciidoctor/backends/docbook45.rb +510 -0
- data/lib/asciidoctor/backends/html5.rb +585 -0
- data/lib/asciidoctor/block.rb +27 -254
- data/lib/asciidoctor/callouts.rb +117 -0
- data/lib/asciidoctor/debug.rb +7 -4
- data/lib/asciidoctor/document.rb +229 -77
- data/lib/asciidoctor/inline.rb +29 -0
- data/lib/asciidoctor/lexer.rb +1330 -502
- data/lib/asciidoctor/list_item.rb +33 -34
- data/lib/asciidoctor/reader.rb +305 -142
- data/lib/asciidoctor/renderer.rb +115 -19
- data/lib/asciidoctor/section.rb +100 -189
- data/lib/asciidoctor/substituters.rb +468 -0
- data/lib/asciidoctor/table.rb +499 -0
- data/lib/asciidoctor/version.rb +1 -1
- data/test/attributes_test.rb +301 -87
- data/test/blocks_test.rb +568 -0
- data/test/document_test.rb +221 -24
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +1 -0
- data/test/fixtures/include-file.asciidoc +1 -0
- data/test/fixtures/tip.gif +0 -0
- data/test/headers_test.rb +411 -43
- data/test/lexer_test.rb +265 -45
- data/test/links_test.rb +144 -3
- data/test/lists_test.rb +2252 -74
- data/test/paragraphs_test.rb +21 -30
- data/test/preamble_test.rb +24 -0
- data/test/reader_test.rb +248 -12
- data/test/renderer_test.rb +22 -0
- data/test/substitutions_test.rb +414 -0
- data/test/tables_test.rb +484 -0
- data/test/test_helper.rb +70 -6
- data/test/text_test.rb +30 -6
- metadata +64 -10
- data/lib/asciidoctor/render_templates.rb +0 -317
- data/lib/asciidoctor/string.rb +0 -12
@@ -0,0 +1,468 @@
|
|
1
|
+
# Public: Methods to perform substitutions on lines of AsciiDoc text. This module
|
2
|
+
# is intented to be mixed-in to Section and Block to provide operations for performing
|
3
|
+
# the necessary substitutions.
|
4
|
+
module Asciidoctor
|
5
|
+
module Substituters
|
6
|
+
|
7
|
+
COMPOSITE_SUBS = {
|
8
|
+
:none => [],
|
9
|
+
:normal => [:specialcharacters, :quotes, :attributes, :replacements, :macros, :post_replacements],
|
10
|
+
:verbatim => [:specialcharacters, :callouts]
|
11
|
+
}
|
12
|
+
|
13
|
+
SUB_OPTIONS = COMPOSITE_SUBS.keys + COMPOSITE_SUBS[:normal]
|
14
|
+
|
15
|
+
# Internal: A String Array of passthough (unprocessed) text captured from this block
|
16
|
+
attr_reader :passthroughs
|
17
|
+
|
18
|
+
# Public: Apply the specified substitutions to the lines of text
|
19
|
+
#
|
20
|
+
# lines - The lines of text to process. Can be a String or a String Array
|
21
|
+
# subs - The substitutions to perform. Can be a Symbol or a Symbol Array (default: COMPOSITE_SUBS[:normal])
|
22
|
+
#
|
23
|
+
# returns Either a String or String Array, whichever matches the type of the first argument
|
24
|
+
def apply_subs(lines, subs = COMPOSITE_SUBS[:normal])
|
25
|
+
if subs.nil?
|
26
|
+
subs = []
|
27
|
+
elsif subs.is_a? Symbol
|
28
|
+
subs = [subs]
|
29
|
+
end
|
30
|
+
|
31
|
+
if !subs.empty?
|
32
|
+
# QUESTION is this most efficient operation?
|
33
|
+
subs = subs.map {|key|
|
34
|
+
COMPOSITE_SUBS.has_key?(key) ? COMPOSITE_SUBS[key] : key
|
35
|
+
}.flatten
|
36
|
+
end
|
37
|
+
|
38
|
+
return lines if subs.empty?
|
39
|
+
|
40
|
+
multiline = lines.is_a?(Array)
|
41
|
+
text = multiline ? lines.join : lines
|
42
|
+
|
43
|
+
passthroughs = subs.include?(:macros)
|
44
|
+
text = extract_passthroughs(text) if passthroughs
|
45
|
+
|
46
|
+
subs.each {|type|
|
47
|
+
case type
|
48
|
+
when :specialcharacters
|
49
|
+
text = sub_specialcharacters(text)
|
50
|
+
when :quotes
|
51
|
+
text = sub_quotes(text)
|
52
|
+
when :attributes
|
53
|
+
text = sub_attributes(text.lines.entries).join
|
54
|
+
when :replacements
|
55
|
+
text = sub_replacements(text)
|
56
|
+
when :macros
|
57
|
+
text = sub_macros(text)
|
58
|
+
when :callouts
|
59
|
+
text = sub_callouts(text)
|
60
|
+
when :post_replacements
|
61
|
+
text = sub_post_replacements(text)
|
62
|
+
else
|
63
|
+
puts "asciidoctor: WARNING: unknown substitution type #{type}"
|
64
|
+
end
|
65
|
+
}
|
66
|
+
text = restore_passthroughs(text) if passthroughs
|
67
|
+
|
68
|
+
multiline ? text.lines.entries : text
|
69
|
+
end
|
70
|
+
|
71
|
+
# Public: Apply normal substitutions.
|
72
|
+
#
|
73
|
+
# lines - The lines of text to process. Can be a String or a String Array
|
74
|
+
#
|
75
|
+
# returns - A String with normal substitutions performed
|
76
|
+
def apply_normal_subs(lines)
|
77
|
+
apply_subs(lines.is_a?(Array) ? lines.join : lines)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Public: Apply substitutions for titles.
|
81
|
+
#
|
82
|
+
# title - The String title to process
|
83
|
+
#
|
84
|
+
# returns - A String with title substitutions performed
|
85
|
+
def apply_title_subs(title)
|
86
|
+
apply_subs(title, [:specialcharacters, :quotes, :replacements, :macros, :attributes, :post_replacements])
|
87
|
+
end
|
88
|
+
|
89
|
+
# Public: Apply substitutions for titles
|
90
|
+
#
|
91
|
+
# lines - A String Array containing the lines of text process
|
92
|
+
#
|
93
|
+
# returns - A String with literal (verbatim) substitutions performed
|
94
|
+
def apply_literal_subs(lines)
|
95
|
+
if @document.attr('basebackend') == 'html' && attr('style') == 'source' &&
|
96
|
+
@document.attr('source-highlighter') == 'coderay' && attr?('language')
|
97
|
+
sub_callouts(highlight_source(lines.join))
|
98
|
+
else
|
99
|
+
apply_subs(lines.join, COMPOSITE_SUBS[:verbatim])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Public: Apply substitutions for header metadata and attribute assignments
|
104
|
+
#
|
105
|
+
# text - String containing the text process
|
106
|
+
#
|
107
|
+
# returns - A String with header substitutions performed
|
108
|
+
def apply_header_subs(text)
|
109
|
+
apply_subs(text, [:specialcharacters, :attributes])
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: Apply substitutions for passthrough text
|
113
|
+
#
|
114
|
+
# lines - A String Array containing the lines of text process
|
115
|
+
#
|
116
|
+
# returns - A String Array with passthrough substitutions performed
|
117
|
+
def apply_passthrough_subs(lines)
|
118
|
+
if attr? 'subs'
|
119
|
+
subs = resolve_subs(attr('subs'))
|
120
|
+
else
|
121
|
+
subs = [:attributes, :macros]
|
122
|
+
end
|
123
|
+
apply_subs(lines.join, subs)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Internal: Extract the passthrough text from the document for reinsertion after processing.
|
127
|
+
#
|
128
|
+
# text - The String from which to extract passthrough fragements
|
129
|
+
#
|
130
|
+
# returns - The text with the passthrough region substituted with placeholders
|
131
|
+
def extract_passthroughs(text)
|
132
|
+
result = text.dup
|
133
|
+
|
134
|
+
result.gsub!(REGEXP[:pass_macro]) {
|
135
|
+
# alias match for Ruby 1.8.7 compat
|
136
|
+
m = $~
|
137
|
+
# honor the escape
|
138
|
+
if m[0].start_with? '\\'
|
139
|
+
next m[0][1..-1]
|
140
|
+
end
|
141
|
+
|
142
|
+
if m[1] == '$$'
|
143
|
+
subs = [:specialcharacters]
|
144
|
+
elsif !m[3].nil? && !m[3].empty?
|
145
|
+
subs = resolve_subs(m[3])
|
146
|
+
else
|
147
|
+
subs = []
|
148
|
+
end
|
149
|
+
|
150
|
+
@passthroughs << {:text => m[2] || m[4].gsub('\]', ']'), :subs => subs}
|
151
|
+
index = @passthroughs.size - 1
|
152
|
+
"\x0#{index}\x0"
|
153
|
+
} unless !(result.include?('+++') || result.include?('$$') || result.include?('pass:'))
|
154
|
+
|
155
|
+
result.gsub!(REGEXP[:pass_lit]) {
|
156
|
+
# alias match for Ruby 1.8.7 compat
|
157
|
+
m = $~
|
158
|
+
|
159
|
+
# honor the escape
|
160
|
+
if m[2].start_with? '\\'
|
161
|
+
next "#{m[1]}#{m[2][1..-1]}"
|
162
|
+
end
|
163
|
+
|
164
|
+
@passthroughs << {:text => m[3], :subs => [:specialcharacters], :literal => true}
|
165
|
+
index = @passthroughs.size - 1
|
166
|
+
"#{m[1]}\x0#{index}\x0"
|
167
|
+
} unless !result.include?('`')
|
168
|
+
|
169
|
+
result
|
170
|
+
end
|
171
|
+
|
172
|
+
# Internal: Restore the passthrough text by reinserting into the placeholder positions
|
173
|
+
#
|
174
|
+
# text - The String text into which to restore the passthrough text
|
175
|
+
#
|
176
|
+
# returns The String text with the passthrough text restored
|
177
|
+
def restore_passthroughs(text)
|
178
|
+
return text if @passthroughs.nil? || @passthroughs.empty? || !text.include?("\x0")
|
179
|
+
|
180
|
+
text.gsub(REGEXP[:pass_placeholder]) {
|
181
|
+
pass = @passthroughs[$1.to_i];
|
182
|
+
text = apply_subs(pass[:text], pass.fetch(:subs, []))
|
183
|
+
pass[:literal] ? Inline.new(self, :quoted, text, :type => :monospaced).render : text
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
# Public: Substitute special characters (i.e., encode XML)
|
188
|
+
#
|
189
|
+
# Special characters are defined in the Asciidoctor::SPECIAL_CHARS Array constant
|
190
|
+
#
|
191
|
+
# text - The String text to process
|
192
|
+
#
|
193
|
+
# returns The String text with special characters replaced
|
194
|
+
def sub_specialcharacters(text)
|
195
|
+
# this syntax only available in Ruby 1.9
|
196
|
+
#text.gsub(SPECIAL_CHARS_PATTERN, SPECIAL_CHARS)
|
197
|
+
|
198
|
+
text.gsub(SPECIAL_CHARS_PATTERN) { SPECIAL_CHARS[$&] }
|
199
|
+
end
|
200
|
+
|
201
|
+
# Public: Substitute quoted text (includes emphasis, strong, monospaced, etc)
|
202
|
+
#
|
203
|
+
# text - The String text to process
|
204
|
+
#
|
205
|
+
# returns The String text with quoted text rendered using the backend templates
|
206
|
+
def sub_quotes(text)
|
207
|
+
result = text.dup
|
208
|
+
|
209
|
+
QUOTE_SUBS.each {|type, scope, pattern|
|
210
|
+
result.gsub!(pattern) { transform_quoted_text($~, type, scope) }
|
211
|
+
}
|
212
|
+
|
213
|
+
result
|
214
|
+
end
|
215
|
+
|
216
|
+
# Public: Substitute replacement characters (e.g., copyright, trademark, etc)
|
217
|
+
#
|
218
|
+
# text - The String text to process
|
219
|
+
#
|
220
|
+
# returns The String text with the replacement characters substituted
|
221
|
+
def sub_replacements(text)
|
222
|
+
result = text.dup
|
223
|
+
|
224
|
+
REPLACEMENTS.each {|pattern, replacement|
|
225
|
+
result.gsub!(pattern, replacement)
|
226
|
+
}
|
227
|
+
|
228
|
+
result
|
229
|
+
end
|
230
|
+
|
231
|
+
# Public: Substitute attribute references
|
232
|
+
#
|
233
|
+
# Attribute references are in the format {name}.
|
234
|
+
#
|
235
|
+
# If an attribute referenced in the line is missing, the line is dropped.
|
236
|
+
#
|
237
|
+
# text - The String text to process
|
238
|
+
#
|
239
|
+
# returns The String text with the attribute references replaced with attribute values
|
240
|
+
#--
|
241
|
+
# NOTE it's necessary to perform this substitution line-by-line
|
242
|
+
# so that a missing key doesn't wipe out the whole block of data
|
243
|
+
def sub_attributes(data)
|
244
|
+
return data if data.nil? || data.empty?
|
245
|
+
|
246
|
+
# normalizes data type to an array (string becomes single-element array)
|
247
|
+
lines = Array(data)
|
248
|
+
|
249
|
+
result = lines.map {|line|
|
250
|
+
reject = false
|
251
|
+
subject = line.dup
|
252
|
+
subject.gsub!(REGEXP[:attr_ref]) {
|
253
|
+
if !$1.empty? || !$3.empty?
|
254
|
+
"{#$2}"
|
255
|
+
elsif document.attributes.has_key? $2
|
256
|
+
document.attributes[$2]
|
257
|
+
elsif INTRINSICS.has_key? $2
|
258
|
+
INTRINSICS[$2]
|
259
|
+
else
|
260
|
+
Asciidoctor.debug { "Missing attribute: #$2, line marked for removal" }
|
261
|
+
reject = true
|
262
|
+
break '{undefined}'
|
263
|
+
end
|
264
|
+
} if subject.include?('{')
|
265
|
+
|
266
|
+
!reject ? subject : nil
|
267
|
+
}.compact
|
268
|
+
|
269
|
+
data.is_a?(String) ? result.join : result
|
270
|
+
end
|
271
|
+
|
272
|
+
# Public: Substitute inline macros (e.g., links, images, etc)
|
273
|
+
#
|
274
|
+
# Replace inline macros, which may span multiple lines, in the provided text
|
275
|
+
#
|
276
|
+
# text - The String text to process
|
277
|
+
#
|
278
|
+
# returns The String with the inline macros rendered using the backend templates
|
279
|
+
def sub_macros(text)
|
280
|
+
return text if text.nil? || text.empty?
|
281
|
+
|
282
|
+
result = text.dup
|
283
|
+
|
284
|
+
# inline images, image:target.ext[Alt]
|
285
|
+
result.gsub!(REGEXP[:image_macro]) {
|
286
|
+
# alias match for Ruby 1.8.7 compat
|
287
|
+
m = $~
|
288
|
+
# honor the escape
|
289
|
+
if m[0].start_with? '\\'
|
290
|
+
next m[0][1..-1]
|
291
|
+
end
|
292
|
+
target = sub_attributes(m[1])
|
293
|
+
@document.register(:images, target)
|
294
|
+
attrs = parse_attributes(m[2], ['alt', 'width', 'height'])
|
295
|
+
if !attrs.has_key?('alt') || attrs['alt'].empty?
|
296
|
+
attrs['alt'] = File.basename(target, File.extname(target))
|
297
|
+
end
|
298
|
+
Inline.new(self, :image, nil, :target => target, :attributes => attrs).render
|
299
|
+
} unless !result.include?('image:')
|
300
|
+
|
301
|
+
# inline urls, target[text] (optionally prefixed with link: and optionally surrounded by <>)
|
302
|
+
result.gsub!(REGEXP[:link_inline]) {
|
303
|
+
# alias match for Ruby 1.8.7 compat
|
304
|
+
m = $~
|
305
|
+
# honor the escape
|
306
|
+
if m[2].start_with? '\\'
|
307
|
+
next "#{m[1]}#{m[2][1..-1]}#{m[3]}"
|
308
|
+
# not a valid macro syntax w/o trailing square brackets
|
309
|
+
# we probably shouldn't even get here...our regex is doing too much
|
310
|
+
elsif m[1] == 'link:' && m[3].nil?
|
311
|
+
next m[0]
|
312
|
+
end
|
313
|
+
prefix = (m[1] != 'link:' ? m[1] : '')
|
314
|
+
target = m[2]
|
315
|
+
# strip the <> around the link
|
316
|
+
if prefix.end_with? '<'
|
317
|
+
prefix = prefix[0..-5]
|
318
|
+
end
|
319
|
+
if target.end_with? '>'
|
320
|
+
target = target[0..-5]
|
321
|
+
end
|
322
|
+
@document.register(:links, target)
|
323
|
+
text = !m[3].nil? ? sub_attributes(m[3].gsub('\]', ']')) : ''
|
324
|
+
"#{prefix}#{Inline.new(self, :anchor, (!text.empty? ? text : target), :type => :link, :target => target).render}"
|
325
|
+
} unless !result.include?('http')
|
326
|
+
|
327
|
+
# inline link macros, link:target[text]
|
328
|
+
result.gsub!(REGEXP[:link_macro]) {
|
329
|
+
# alias match for Ruby 1.8.7 compat
|
330
|
+
m = $~
|
331
|
+
# honor the escape
|
332
|
+
if m[0].start_with? '\\'
|
333
|
+
next m[0][1..-1]
|
334
|
+
end
|
335
|
+
target = m[1]
|
336
|
+
@document.register(:links, target)
|
337
|
+
text = sub_attributes(m[2].gsub('\]', ']'))
|
338
|
+
Inline.new(self, :anchor, (!text.empty? ? text : target), :type => :link, :target => target).render
|
339
|
+
} unless !result.include?('link:')
|
340
|
+
|
341
|
+
result.gsub!(REGEXP[:xref_macro]) {
|
342
|
+
# alias match for Ruby 1.8.7 compat
|
343
|
+
m = $~
|
344
|
+
# honor the escape
|
345
|
+
if m[0].start_with? '\\'
|
346
|
+
next m[0][1..-1]
|
347
|
+
end
|
348
|
+
if !m[1].nil?
|
349
|
+
id, reftext = m[1].split(',', 2)
|
350
|
+
id.sub!(/^("|)(.*)\1$/, '\2')
|
351
|
+
reftext.sub!(/^("|)(.*)\1$/m, '\2') unless reftext.nil?
|
352
|
+
else
|
353
|
+
id = m[2]
|
354
|
+
reftext = !m[3].empty? ? m[3] : nil
|
355
|
+
end
|
356
|
+
Inline.new(self, :anchor, reftext, :type => :xref, :target => id).render
|
357
|
+
}
|
358
|
+
|
359
|
+
result.gsub!(REGEXP[:anchor_macro]) {
|
360
|
+
# alias match for Ruby 1.8.7 compat
|
361
|
+
m = $~
|
362
|
+
# honor the escape
|
363
|
+
if m[0].start_with? '\\'
|
364
|
+
next m[0][1..-1]
|
365
|
+
end
|
366
|
+
id, reftext = m[1].split(',')
|
367
|
+
id.sub!(/^("|)(.*)\1$/, '\2')
|
368
|
+
if reftext.nil?
|
369
|
+
reftext = "[#{id}]"
|
370
|
+
else
|
371
|
+
reftext.sub!(/^("|)(.*)\1$/m, '\2')
|
372
|
+
end
|
373
|
+
# NOTE the reftext should also match what's in our references dic
|
374
|
+
if !@document.references[:ids].has_key? id
|
375
|
+
Asciidoctor.debug { "Missing reference for anchor #{id}" }
|
376
|
+
end
|
377
|
+
Inline.new(self, :anchor, reftext, :type => :ref, :target => id).render
|
378
|
+
} unless !result.include?('[[')
|
379
|
+
|
380
|
+
result
|
381
|
+
end
|
382
|
+
|
383
|
+
# Public: Substitute callout references
|
384
|
+
#
|
385
|
+
# text - The String text to process
|
386
|
+
#
|
387
|
+
# returns The String with the callout references rendered using the backend templates
|
388
|
+
def sub_callouts(text)
|
389
|
+
text.gsub(REGEXP[:callout_render]) {
|
390
|
+
# alias match for Ruby 1.8.7 compat
|
391
|
+
m = $~
|
392
|
+
# honor the escape
|
393
|
+
if m[0].start_with? '\\'
|
394
|
+
next "<#{m[1]}>"
|
395
|
+
end
|
396
|
+
Inline.new(self, :callout, m[1], :id => document.callouts.read_next_id).render
|
397
|
+
}
|
398
|
+
end
|
399
|
+
|
400
|
+
# Public: Substitute post replacements
|
401
|
+
#
|
402
|
+
# text - The String text to process
|
403
|
+
#
|
404
|
+
# returns The String with the post replacements rendered using the backend templates
|
405
|
+
def sub_post_replacements(text)
|
406
|
+
text.gsub(REGEXP[:line_break]) { Inline.new(self, :break, $1, :type => :line).render }
|
407
|
+
end
|
408
|
+
|
409
|
+
# Internal: Transform (render) a quoted text region
|
410
|
+
#
|
411
|
+
# match - The MatchData for the quoted text region
|
412
|
+
# type - The quoting type (single, double, strong, emphasis, monospaced, etc)
|
413
|
+
# scope - The scope of the quoting (constrained or unconstrained)
|
414
|
+
#
|
415
|
+
# returns The rendered text for the quoted text region
|
416
|
+
def transform_quoted_text(match, type, scope)
|
417
|
+
if match[0].start_with? '\\'
|
418
|
+
match[0][1..-1]
|
419
|
+
elsif scope == :constrained
|
420
|
+
"#{match[1]}#{Inline.new(self, :quoted, match[3], :type => type, :attributes => parse_attributes(match[2])).render}"
|
421
|
+
else
|
422
|
+
Inline.new(self, :quoted, match[2], :type => type, :attributes => parse_attributes(match[1])).render
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# Internal: Parse the attributes in the attribute line
|
427
|
+
#
|
428
|
+
# attrline - A String of unprocessed attributes (key/value pairs)
|
429
|
+
# posattrs - The keys for positional attributes
|
430
|
+
#
|
431
|
+
# returns nil if attrline is nil, an empty Hash if attrline is empty, otherwise a Hash of parsed attributes
|
432
|
+
def parse_attributes(attrline, posattrs = ['role'])
|
433
|
+
return nil if attrline.nil?
|
434
|
+
return {} if attrline.empty?
|
435
|
+
|
436
|
+
AttributeList.new(attrline, self).parse(posattrs)
|
437
|
+
end
|
438
|
+
|
439
|
+
# Internal: Resolve the list of comma-delimited subs against the possible options.
|
440
|
+
#
|
441
|
+
# subs - A comma-delimited String of substitution aliases
|
442
|
+
#
|
443
|
+
# returns An Array of Symbols representing the substitution operation
|
444
|
+
def resolve_subs(subs)
|
445
|
+
candidates = subs.split(',').map {|sub| sub.strip.to_sym}
|
446
|
+
resolved = candidates & SUB_OPTIONS
|
447
|
+
if (invalid = candidates - resolved).size > 0
|
448
|
+
puts "asciidoctor: WARNING: invalid passthrough macro substitution operation#{invalid.size > 1 ? 's' : ''}: #{invalid * ', '}"
|
449
|
+
end
|
450
|
+
resolved
|
451
|
+
end
|
452
|
+
|
453
|
+
# Public: Highlight the source code if a source highlighter is defined
|
454
|
+
# on the document, otherwise return the text unprocessed
|
455
|
+
#
|
456
|
+
# source - the source code String to highlight
|
457
|
+
#
|
458
|
+
# returns the highlighted source code, if a source highlighter is defined
|
459
|
+
# on the document, otherwise the unprocessed text
|
460
|
+
def highlight_source(source)
|
461
|
+
Asciidoctor.require_library 'coderay'
|
462
|
+
::CodeRay::Duo[attr('language', 'text').to_sym, :html, {
|
463
|
+
:css => @document.attr('coderay-css', 'class').to_sym,
|
464
|
+
:line_numbers => (attr?('linenums') ? @document.attr('coderay-linenums-mode', 'table').to_sym : nil),
|
465
|
+
:line_number_anchors => false}].highlight(source).chomp
|
466
|
+
end
|
467
|
+
end
|
468
|
+
end
|