class TextUtils::CodeHighlighter < TextUtils::Processor
# highlights code inside of ... code ...
def call data, env
require 'nokogiri'
snippets = {}
# processign html :code tags
data = data.gsub /()(.+?)(<\/code\s*>)/im do
node = Nokogiri::HTML($1 + $3).css('code').first
language = node.attributes['lang'].try(:value) || node.attributes['language'].try(:value)
code = $2
if language and code
attributes = {}; node.attributes.each{|name, value| attributes[name] = value.value}
code = colorize code, language, attributes
cut_snippet snippets, code
else
$&
end
end
# processign markdown ``` tags
data = data.gsub /^```\s*([a-z\-_0-9]+)\s*\n(.+?)^```\s*$/im do
language, code = $1, $2
if language and code
code = colorize code, language, {language: language}
cut_snippet snippets, code
else
$&
end
end
data = call_next data, env
restore_snippet snippets, data
end
protected
# temporarilly removing all highlighted code from html to prevent it's beed damaged by next processors
def cut_snippet snippets, code
key = "CODESNIPPET#{snippets.size}"
snippets[key] = code
key
end
# inserting cutted code back to html
def restore_snippet snippets, data
data = data.gsub /(CODESNIPPET[0-9]+)/ do |key|
snippets[key]
end
data
end
def colorize code, language, attributes
require 'albino'
code = Albino.colorize(code, language.to_sym)
code = "\n#{code}\n
"
code = rewrite_styles code
end
# adding prefix 'hl_' to all class names
def rewrite_styles html
node = Nokogiri::HTML(html).css('code').first
node.css("*").each do |e|
classes = e.attribute 'class'
if classes and classes.value
classes = classes.value.strip.split(/\s+/).collect{|c| "hl_#{c}"}.join(' ')
e['class'] = classes
end
end
node.to_s
end
end