Syntax Highlighting in Rails
Your Rails driven website has the need to display some code. It’s not good enough to just get proper indentation, you’d like to have some decent syntax highlighting. Maybe something like following.
def foo(bar)
"Hello #{bar}"
end
foo("World")
There’s a great ruby gem called Rouge that makes this process quite easy for us. What is Rouge?
Rouge is a pure-ruby syntax highlighter. It can highlight over 60 languages, and output HTML or ANSI 256-color text. Its HTML output is compatible with stylesheets designed for pygments.
Pretty cool, let’s get going.
Install Rouge Gem
First, we need to add the Rouge gem to our Gemfile
# Gemfile
gem 'rouge', '~> 1.10'
After you’ve added the Rouge gem go ahead and run bundle install
. Good to go? Okay, let’s move on.
Configuration
There are two parts main parts to the configuration. The first part is the lexing and formatting of your desired code block. The second part is the style (think CSS) you want to give to the now formatted code.
Lexing and Formatting
Create the initializer rouge_highlighter.rb
so we can reuse the same formatter and lexer throughout our application.
# config/initializers/rouge_highlighter.rb
module RougeHighlighter
class Highlight
def initialize
@formatter = Rouge::Formatters::HTML.new(css_class: 'highlight')
@lexer = Rouge::Lexers::Shell.new
end
def render(source)
@formatter.format(@lexer.lex(source))
end
end
::HighlightSource = Highlight.new
end
We create a simple Ruby module to house a class and a top-level namespace.
The @formatter
variable we’re setting is going to ensure our provided source code is going to be wrapped in a .highlight
class. It will wrap our code like this:
<pre class="highlight">
<code>
...
</code>
</pre>
This is important to take note of because we need to provide the .highlight
scope when dealing with our styling a little later.
We’re going to end up using the render
method in a helper for our application. So, open up app/helpers/application_helper.rb
and add the following.
# app/helpers/application_helper.rb
module ApplicationHelper
...
def syntax_highlight(text)
# Initialized in config/initializers/rouge_highlighter.rb
html = HighlightSource.render(text)
html.html_safe
end
...
end
Pretty slick. Now we can simply call the syntax_highlight
method anywhere we want some highlighted code. But, before we do that we need to make sure there is some CSS to back it up.
Styles (CSS)
In order to have the styles that make all this work look pretty we need to create a new file called _rouge.scss.erb
. It’s a little weird to see erb
at the end of a scss
file, but remember Rails interprets from right to left so adding that suffix gives us the some dynamic abilities.
// app/assets/stylesheets/_rouge.scss.erb
<%= Rouge::Themes::Github.render(:scope => '.highlight') %>
.highlight {
border-radius:4px;
background: #f2f2f2;
margin-bottom:1rem;
padding:1rem;
}
In the first line we’ve allowed Rouge to spit out some styles while telling it we’d like to namespace it to the .highlight
class. Rouge comes with several predefined themes you can choose from. Here we’ve chosen a Github-like theme for our syntax highlighting. We also added a little of our own styling as well.
_rouge.scss.erb` should be compiled automatically if you’ve stuck with the initial Rails setup in `application.css
Yay, We’re Setup
Everything should be setup and ready to go now. You can go to any view you’d like and print out some pretty code. I’ll put some HTML in an external file I can read from later.
<!-- public/example.html -->
<div class="row">
<div class="col-sm-3">...</div>
<div class="col-sm-3">...</div>
<div class="col-sm-3">...</div>
</div>
Then, in an example view I’m choosing to call highlight.html.erb
I render out our nicely formatted code.
<% # app/views/static_pages/highlight.html.erb %>
<h1>Syntax Highlighting with Rouge</h1>
<p>Below is a very simple example of some syntax highlighting.</p>
<%= syntax_highlight(File.read(Rails.root + "public/example.html")) %>
All done.
Summary
This example just shows how to get syntax highlighting applied to an external file which, to be honest, isn’t extremely useful. It does, however, demonstrate the steps to get going. If you’re writing a blog or something similar you probably want something a little more dynamic. If you’re a regular Github user you’re probably comfortable writing in Markdown. We can easily combine Rouge with Redcarpet and do this all with a Markdown parser. I plan on coming back around and showing how to do that. Until then, enjoy your new highlighted code!
Example Repo
If you want to see everything working together you can clone this Leaving Harbor repo over on Github and poke around in an actual working environment.