Syntax highlight with Rouge in Jekyll

Syntax highlight with Rouge in Jekyll

better styling the code blocks

Overview

While using Markdown in Jekyll, it’s easy to insert any code blocks into blog posts. But we need a step further to make them fancy.

By default, Jekyll was integrated with Rouge - a pure Ruby syntax highlighter which supports over 100 languages. Since Rouge themes are compatible with Pygments’s stylesheets, it’s nice for us to choose a favourable style from availabe Pygments themes.1

Install Rouge

Once you have installed Jekyll, Rouge is already included as dependencies.

If you’re still using Jekyll 2, it’s also quick and painless to install Rouge. Just open your favourite command line tool and enter the following command:

gem install rouge

Then, in your _config.yml, set Rouge as your syntax highlighter:

highlighter: rouge

Theme and colour

Rouge will help to render the code snippets in your Markdown posts into pre and code tags in the generated HTML pages. The further step is style these HTML elements using CSS.

In Jekyll’s official document: stylesheets for syntax highlighting, there is an example stylesheet (syntax.css) you can use.

Besides that, Rouge is 100% compatible with Pygments’s stylesheets, you can choose one of those Pygments themes and use it on your site.

You can preview the Pygments predefined styles at http://pygments.org/demo/. Input some sample codes, and choose the correct language.

Adjust the Style to preview the rendered HTML snippet. Once you found your favourite style, download the demo file. The CSS styles in the downloaded file are we needed.

Since Pygments stylesheet uses .demo-highlight as the class name in the demo file, and Rouge uses .highlight instead. You need to replace all the .demo-highlight with .highlight and put those CSS styles into your stylesheet file.

Implement

Highlight code blocks in Jekyll posts is very easy, just wrap the code snippets in Markdown files like this:

{% highlight ruby linenos %}
...
...
{% endhighlight %}

In this way of using Liquid tag highlight, you can add language identifier (here is ruby) or its supported aliases (rb for Ruby). All supported language by Rouge can be found at List of supported languages and lexers - Rouge Wiki. Also, the always-up-to-date list of supporting language can be found by running the command: bundle exec rougify list.2

If you don’t need the line numbers, you can simply use fenced_code_blocks style in Markdown files just with triple backticks like this:

```rb
your code here
```
Ads by Google

Example

For example, this snippet of Ruby code:

def show
  puts "Outputting a very lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong line"
  @widget = Widget(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @widget }
  end
end

Just using the following markups in the Markdown file:

```rb
def show
  puts "Outputting a very lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong line"
  @widget = Widget(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @widget }
  end
end
```

To display the line numbers, like:

1
2
3
4
5
6
7
8
def show
  puts "Outputting a very lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong line"
  @widget = Widget(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @widget }
  end
end

You need to use the highlight liquid tag with linenos explicitly in the Markdown files:

{% highlight ruby linenos %}
def show
  puts "Outputting a very lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong lo-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-ong line"
  @widget = Widget(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.json { render json: @widget }
  end
end
{% endhighlight %}

The fenced_code_blocks (triple backticks style) is the most simple and recommended way for code highlights. But it defaults without line numbers. Here we can configure kramdown to show line number for the triple backticks code block. In the Jekyll’s _config.yml, config like this:

markdown: kramdown
highlighter: rouge
kramdown:
  input: GFM
  syntax_highlighter_opts:
    default_lang: html
    css_class: 'highlight'
    span:
      line_numbers: false
    block:
      line_numbers: true
      start_line: 1

Now, all your code blocks will have line numbers if you use fenced_code_blocks styled markups. For those code blocks that you don’t want to show the line numbers, just switch to Liquid highlight tags.

Alternative Themes

Like dark themes? Have a look at the Pygments Syntax Highlighting themes page. Preview a list of dark Pygments themes and download one from https://github.com/StylishThemes/Syntax-Themes/tree/master/pygments/css-github.

Aside from the Pygments’ styles, Sunil Sarolkar has created a series of pre-defined Rouge themes. Here is a Rouge Theme Preview Page that allows you to have a feel on these themes. Then, download your favourable one from https://github.com/spsarolkar/rouge-theme-preview/tree/gh-pages/css.

Or, if you like my code highlight style just shown in this post, you can get the SCSS from the gist: https://gist.github.com/flinhong/f37f0271bcada97b383bf9f81d8942e7. Don’t forget to include the converted css on required pages…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// define variables
$code-bg:  #2e3e4e;
$tea:      #ecebe7;
$gray-200: #e9ecef;
$gray-500: #adb5bd;
$gray-800: #343a40;

$font-family-monospace: 'Ubuntu Mono', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'Noto Serif SC', 'STSong', monospace;

figure.highlight,
pre.highlight {
    padding: 1rem 1.5rem;
    margin: 1.5rem 0;
    overflow: auto;
    line-height: 1.4rem;
    position: relative;
}

.highlighter-rouge {
    font-weight: 300;
    position: relative;
}

p code.highlighter-rouge,
p kbd {
    color: #cc6666;
    font-size: 1rem;
    background-color: lighten($tea, 5%);
    padding: 2px 4px;
    border-radius: 2px;
    word-break: break-word;
}

kbd {
    border: 1px solid $gray-800;
    border-radius: 4px;
}

/* "data-lang" should be injected by JavaScript */
/*
figure.highlight::before,
div.highlighter-rouge::before {
    font-family: $font-family-monospace;
    content: attr(data-lang);
    font-size: .9rem;
    color: $gray-200;
    position: absolute;
    display: block;
    height: 1rem;
    right: .5rem;
    z-index: 5;
}

figure.highlight::before {
    margin-top: -1rem;
}
*/

.rouge-table .code pre {
    overflow: hidden;
}

.rouge-table .code pre {
    overflow: hidden;
}

table.rouge-table,
table.rouge-table tr,
table.rouge-table td,
table.rouge-table pre {
    border: 0;
    padding: 0;
    margin: 0;
}

table.rouge-table td.gutter {
    padding-right: .5rem;
    border-right: 1px solid $gray-500;
}

table.rouge-table td.code {
    padding-left: .5rem;
}

figure pre {
    margin-bottom: 0;
}

.lineno {
    text-align: right;
}

/* Base16 Tomorrow Dark by Chris Kempson; https://github.com/idleberg */
.highlight,
.highlight pre,
.highlight table {
    background: $code-bg;
    color: $gray-200;
    border-radius: 4px;
    font-size: 1rem;
}

.highlight .hll { background-color: #373b41 }
.highlight .c { color: #969896 } /* Comment */
.highlight .err { color: #cc6666 } /* Error */
.highlight .k { color: #b294bb } /* Keyword */
.highlight .l { color: #de935f } /* Literal */
.highlight .n, .highlight .h { color: #ffffff } /* Name */
.highlight .o { color: #8abeb7 } /* Operator */
.highlight .p { color: #ffffff } /* Punctuation */
.highlight .cm { color: #969896 } /* Comment.Multiline */
.highlight .cp { color: #969896 } /* Comment.Preproc */
.highlight .c1 { color: #969896 } /* Comment.Single */
.highlight .cs { color: #969896 } /* Comment.Special */
.highlight .gd { color: #cc6666 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #b5bd68 } /* Generic.Inserted */
.highlight .gp { color: #969896; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */
.highlight .kc { color: #b294bb } /* Keyword.Constant */
.highlight .kd { color: #b294bb } /* Keyword.Declaration */
.highlight .kn { color: #8abeb7 } /* Keyword.Namespace */
.highlight .kp { color: #b294bb } /* Keyword.Pseudo */
.highlight .kr { color: #b294bb } /* Keyword.Reserved */
.highlight .kt { color: #f0c674 } /* Keyword.Type */
.highlight .ld { color: #b5bd68 } /* Literal.Date */
.highlight .m { color: #de935f } /* Literal.Number */
.highlight .s { color: #b5bd68 } /* Literal.String */
.highlight .na { color: #81a2be } /* Name.Attribute */
.highlight .nb { color: #ffffff } /* Name.Builtin */
.highlight .nc { color: #f0c674 } /* Name.Class */
.highlight .no { color: #cc6666 } /* Name.Constant */
.highlight .nd { color: #8abeb7 } /* Name.Decorator */
.highlight .ni { color: #ffffff } /* Name.Entity */
.highlight .ne { color: #cc6666 } /* Name.Exception */
.highlight .nf { color: #81a2be } /* Name.Function */
.highlight .nl { color: #ffffff } /* Name.Label */
.highlight .nn { color: #f0c674 } /* Name.Namespace */
.highlight .nx { color: #81a2be } /* Name.Other */
.highlight .py { color: #ffffff } /* Name.Property */
.highlight .nt { color: #8abeb7 } /* Name.Tag */
.highlight .nv { color: #cc6666 } /* Name.Variable */
.highlight .ow { color: #8abeb7 } /* Operator.Word */
.highlight .w { color: #ffffff } /* Text.Whitespace */
.highlight .mf { color: #de935f } /* Literal.Number.Float */
.highlight .mh { color: #de935f } /* Literal.Number.Hex */
.highlight .mi { color: #de935f } /* Literal.Number.Integer */
.highlight .mo { color: #de935f } /* Literal.Number.Oct */
.highlight .sb { color: #b5bd68 } /* Literal.String.Backtick */
.highlight .sc { color: #ffffff } /* Literal.String.Char */
.highlight .sd { color: #969896 } /* Literal.String.Doc */
.highlight .s2 { color: #b5bd68 } /* Literal.String.Double */
.highlight .se { color: #de935f } /* Literal.String.Escape */
.highlight .sh { color: #b5bd68 } /* Literal.String.Heredoc */
.highlight .si { color: #de935f } /* Literal.String.Interpol */
.highlight .sx { color: #b5bd68 } /* Literal.String.Other */
.highlight .sr { color: #b5bd68 } /* Literal.String.Regex */
.highlight .s1 { color: #b5bd68 } /* Literal.String.Single */
.highlight .ss { color: #b5bd68 } /* Literal.String.Symbol */
.highlight .bp { color: #ffffff } /* Name.Builtin.Pseudo */
.highlight .vc { color: #cc6666 } /* Name.Variable.Class */
.highlight .vg { color: #cc6666 } /* Name.Variable.Global */
.highlight .vi { color: #cc6666 } /* Name.Variable.Instance */
.highlight .il { color: #de935f } /* Literal.Number.Integer.Long */

Thanks to @undavide for the feedbacks on the variable definitions.

The font-face in use in this post is actually the IBM Plex Mono, from Google Fonts.

Conclusion

Both configurations and stylings are covered in this post. I think it’s clean now for highlight code blocks using build-in Rouge in Jekyll. If you have any further issues with code highlight in Jekyll, welcome to leave your comment for discussion.

THE END
Ads by Google

林宏

Frank Lin, PhD

Hey, there! This is Frank Lin (@flinhong), one of the 1.41 billion . This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Using Liquid in Jekyll - Live with Demos

Web Notes

2016.08.20

Using Liquid in Jekyll - Live with Demos

Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.

Setup an IKEv2 server with strongSwan

Tutorials

2020.01.09

Setup an IKEv2 server with strongSwan

IKEv2, or Internet Key Exchange v2, is a protocol that allows for direct IPSec tunnelling between two points. In IKEv2 implementations, IPSec provides encryption for the network traffic. IKEv2 is natively supported on some platforms (OS X 10.11+, iOS 9.1+, and Windows 10) with no additional applications necessary, and it handles client hiccups quite smoothly.

Hands on IBM Cloud Functions with CLI

Tools

2020.10.20

Hands on IBM Cloud Functions with CLI

IBM Cloud CLI allows complete management of the Cloud Functions system. You can use the Cloud Functions CLI plugin-in to manage your code snippets in actions, create triggers, and rules to enable your actions to respond to events, and bundle actions into packages.

TOC

Ads by Google