How to integrate Ultraviolet into Mephisto
I couldn’t find a theme I liked for CodeRay, and I wasn’t up for creating/modifying my own. I ended up finding a different syntax highlighter called Ultraviolet. It uses TextMate’s syntax files which is pretty cool. The code in this article is highlighted using the “lazy” theme.
Integrating Ultraviolet into Mephisto (or more specifically the filtered_column_code_macro plugin) can be done in 3 steps.
Step 1: Install Ultraviolet
I won’t get into too much detail here. You can follow the directions here: http://ultraviolet.rubyforge.org/.
Step 2: Hack filtered_column_code_macro
I consider this a dirty hack. Ideally, filtered_column_code_macro
would be written to give the user options to use either CodeRay or Ultraviolet. Kinda like how filtered_column
supports Markdown and Textile. This works for now…
Modify code_macro.rb to look like the following:
# plugins/filtered_column_code_macro/lib/code_macro.rb
require 'uv'
class CodeMacro < FilteredColumn::Macros::Base
DEFAULT_OPTIONS = {:wrap => :div, :line_numbers => :table, :tab_width => 2, :bold_every => 5, :hint => false, :line_number_start => 1}
def self.filter(attributes, inner_text = '', text = '')
# It's a whole lot easier to just set your attributes statically
# I think for most of us the only option we're gonna change is 'lang'
# refer to http://rd.cycnus.de/coderay/doc/classes/CodeRay/Encoders/HTML.html for more info
# use code_highlighter.css to change highlighting
# don't change, formats code so code_highlighter.css can be used
lang = attributes[:lang].blank? ? nil : attributes[:lang].to_sym
options = DEFAULT_OPTIONS.dup
# type of line number to print options: :inline, :table, :list, nil [default = :table]
# you can change the line_numbers default value but you will probably have to change the css too
options[:line_numbers] = attributes[:line_numbers].to_sym unless attributes[:line_numbers].blank?
# changes tab spacing [default = 2]
options[:tab_width] = attributes[:tab_width].to_i unless attributes[:tab_width].blank?
# bolds every 'X' line number
options[:bold_every] = attributes[:bold_every].to_i unless attributes[:bold_every].blank?
# use it if you want to can be :info, :info_long, :debug just debugging info in the tags
options[:hint] = attributes[:hint].to_sym unless attributes[:hint].blank?
# start with line number
options[:line_number_start] = attributes[:line_number_start].to_i unless attributes[:line_number_start].blank?
inner_text = inner_text.gsub(/\A\r?\n/, '').chomp
html = ""
begin
html = Uv.parse(inner_text, "xhtml", lang.to_s, false, "lazy")
rescue
unless lang.blank?
RAILS_DEFAULT_LOGGER.warn "UltraViolet Error: #{$!.message}"
RAILS_DEFAULT_LOGGER.debug $!.backtrace.join("\n")
end
html = "<pre><code>#{CGI.escapeHTML(inner_text)}</code></pre>"
end
"<div class=\"ultraviolet\">\n#{html}</div>\n"
end
end
Two things to note here:
- Don’t forget to
require 'uv'
at the top. We won’t be needing CodeRay here anymore. - Pay attention to the parameters passed to
Uv.parse
towards the bottom.
If you want to turn on line numbers, set the 4th parameter for Uv.parse
to true. If you want to use a different theme, place it’s name in the 5th parameter. Again, a dirty hack that should be configured by the user of this library, but this isn’t an article about best practices.
Step 3: Generate and include the CSS
Fire up irb and run the following:
>> require 'uv'
>> Uv.copy_files "xhtml", "PATH_TO_GENERATE_FILES"
This will create a css directory containing all of the TextMate themes. Copy the theme you want and include it in your layout.liquid:
<!-- layout.liquid -->
{{ 'lazy' | stylesheet : 'screen, projection' }}
That’s it! Using it works the same way as before by using the <macro:code lang="ruby">
tags. A list of supported languages can be found by running puts Uv.syntaxes.join( ", " )
in irb.