From 0831d2b0f839f8dfc2dcd39387597b4f89a5ac0a Mon Sep 17 00:00:00 2001 From: Robin Dupret Date: Sun, 22 Dec 2013 13:53:53 +0100 Subject: [PATCH] Add support for the Rouge syntax highlighter By setting the `highlighter` setting to `rouge` you can now easily highlight your code with it instead of relying on Pygments. However, Jekyll doesn't depend on Rouge explicitly, you will need to install it or add it to your Gemfile. The documentation has been updated accordingly. --- History.markdown | 5 ++-- features/site_configuration.feature | 8 ++++++ jekyll.gemspec | 1 + .../converters/markdown/redcarpet_parser.rb | 26 ++++++++++++++++--- lib/jekyll/tags/highlight.rb | 18 +++++++++++++ site/_config.yml | 2 +- site/docs/configuration.md | 6 ++--- site/docs/installation.md | 6 ++--- site/docs/posts.md | 4 +-- site/docs/templates.md | 17 ++++++++---- site/docs/troubleshooting.md | 4 +-- test/test_redcarpet.rb | 16 ++++++++++++ 12 files changed, 92 insertions(+), 21 deletions(-) diff --git a/History.markdown b/History.markdown index 3b633a7c..6988a787 100644 --- a/History.markdown +++ b/History.markdown @@ -1,12 +1,13 @@ ## HEAD ### Major Enhancements - * Rename the `pygments` option to `highlighter` * Add gem-based plugin whitelist to safe mode (#1657) * Replace the commander command line parser with a more robust solution for our needs called `mercenary` (#1706) * Remove support for Ruby 1.8.x (#1780) * Move to jekyll/jekyll from mojombo/jekyll (#1817) + * Rename the `pygments` option to `highlighter` (#1859) + * Provide support for the Rouge syntax highlighter (#1859) ### Minor Enhancements * Move the EntryFilter class into the Jekyll module to avoid polluting the @@ -25,7 +26,7 @@ ### Development Fixes * Add a link to the site in the README.md file (#1795) * Add in History and site changes from `v1-stable` branch (#1836) - * Fix the `highlight` tag feature + * Fix the `highlight` tag feature (#1859) ### Site Enhancements * Document Kramdown's GFM parser option (#1791) diff --git a/features/site_configuration.feature b/features/site_configuration.feature index 50d0fff1..6d3ea647 100644 --- a/features/site_configuration.feature +++ b/features/site_configuration.feature @@ -98,6 +98,14 @@ Feature: Site configuration And I should see "Hello world!" in "_site/index.html" And I should see "class=\"highlight\"" in "_site/index.html" + Scenario: Highlight code with rouge + Given I have an "index.html" page that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}" + And I have a configuration file with "highlighter" set to "rouge" + When I run jekyll + Then the _site directory should exist + And I should see "Hello world!" in "_site/index.html" + And I should see "class=\"highlight\"" in "_site/index.html" + Scenario: Set time and no future dated posts Given I have a _layouts directory And I have a page layout that contains "Page Layout: {{ site.posts.size }} on {{ site.time | date: "%Y-%m-%d" }}" diff --git a/jekyll.gemspec b/jekyll.gemspec index 1b1f4ef2..e62e5380 100644 --- a/jekyll.gemspec +++ b/jekyll.gemspec @@ -52,6 +52,7 @@ Gem::Specification.new do |s| s.add_development_dependency('activesupport', '~> 3.2.13') s.add_development_dependency('jekyll_test_plugin') s.add_development_dependency('jekyll_test_plugin_malicious') + s.add_development_dependency('rouge', '~> 1.0') # = MANIFEST = s.files = %w[ diff --git a/lib/jekyll/converters/markdown/redcarpet_parser.rb b/lib/jekyll/converters/markdown/redcarpet_parser.rb index 9e96c35e..7ad33dd2 100644 --- a/lib/jekyll/converters/markdown/redcarpet_parser.rb +++ b/lib/jekyll/converters/markdown/redcarpet_parser.rb @@ -5,7 +5,7 @@ module Jekyll module CommonMethods def add_code_tags(code, lang) - code = code.sub(/
/, "
")
+            code = code.sub(//, "
")
             code = code.sub(/<\/pre>/,"
") end end @@ -22,7 +22,7 @@ module Jekyll end end - module WithoutPygments + module WithoutHighlighting require 'cgi' include CommonMethods @@ -37,6 +37,22 @@ module Jekyll end end + module WithRouge + include CommonMethods + + def block_code(code, lang) + require 'rouge' + + lexer = Rouge::Lexer.find_fancy(lang, code) || Rouge::Lexers::PlainText + formatter = Rouge::Formatters::HTML.new + + output = "
" + output << add_code_tags(formatter.render(lexer.lex(code)), lang) + output << "
" + end + end + + def initialize(config) require 'redcarpet' @config = config @@ -48,9 +64,13 @@ module Jekyll Class.new(Redcarpet::Render::HTML) do include WithPygments end + when 'rouge' + Class.new(Redcarpet::Render::HTML) do + include WithRouge + end else Class.new(Redcarpet::Render::HTML) do - include WithoutPygments + include WithoutHighlighting end end rescue LoadError diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb index a20e90c0..eb6bf5a3 100644 --- a/lib/jekyll/tags/highlight.rb +++ b/lib/jekyll/tags/highlight.rb @@ -44,6 +44,8 @@ eos case context.registers[:site].highlighter when 'pygments' render_pygments(context, super) + when 'rouge' + render_rouge(context, super) else render_codehighlighter(context, super) end @@ -65,6 +67,22 @@ eos return output end + def render_rouge(context, code) + require 'rouge' + + linenos = @options.keys.include?('linenos') + lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText + formatter = Rouge::Formatters::HTML.new(line_numbers: linenos) + + output = context["highlighter_prefix"] || "" + output << "
" + output << add_code_tags(formatter.render(lexer.lex(code)), @lang) + output << "
" + output << context["highlighter_suffix"] if context["highlighter_suffix"] + + return output + end + def render_codehighlighter(context, code) #The div is required because RDiscount blows ass <<-HTML diff --git a/site/_config.yml b/site/_config.yml index f14c4e05..fc1fd46d 100644 --- a/site/_config.yml +++ b/site/_config.yml @@ -1,4 +1,4 @@ -pygments: true +highlight: pygments relative_permalinks: false gauges_id: 503c5af6613f5d0f19000027 permalink: /news/:year/:month/:day/:title/ diff --git a/site/docs/configuration.md b/site/docs/configuration.md index df93d9c6..8740d987 100644 --- a/site/docs/configuration.md +++ b/site/docs/configuration.md @@ -288,7 +288,7 @@ encoding: nil future: true show_drafts: nil limit_posts: 0 -pygments: true +highlighter: pygments relative_permalinks: true @@ -362,7 +362,7 @@ Jekyll handles two special Redcarpet extensions: # ...ruby code ``` - With both fenced code blocks and pygments enabled, this will statically highlight the code; without pygments, it will add a `class="LANGUAGE"` attribute to the `` element, which can be used as a hint by various JavaScript code highlighting libraries. + With both fenced code blocks and highlighter enabled, this will statically highlight the code; without any syntax highlighter, it will add a `class="LANGUAGE"` attribute to the `` element, which can be used as a hint by various JavaScript code highlighting libraries. - `smart` --- This pseudo-extension turns on SmartyPants, which converts straight quotes to curly quotes and runs of hyphens to em (`---`) and en (`--`) dashes. All other extensions retain their usual names from Redcarpet, and no renderer options aside from `smart` can be specified in Jekyll. [A list of available extensions can be found in the Redcarpet README file.][redcarpet_extensions] Make sure you're looking at the README for the right version of Redcarpet: Jekyll currently uses v2.2.x, and extensions like `footnotes` and `highlight` weren't added until after version 3.0.0. The most commonly used extensions are: @@ -380,4 +380,4 @@ In addition to the defaults mentioned above, you can also turn on recognition of For example, in your `_config.yml`: kramdown: - input: GFM \ No newline at end of file + input: GFM diff --git a/site/docs/installation.md b/site/docs/installation.md index 8fb82a0a..977e9d9c 100644 --- a/site/docs/installation.md +++ b/site/docs/installation.md @@ -66,9 +66,9 @@ Check out [the extras page](../extras/) for more information.
ProTip™: Enable Syntax Highlighting

If you’re the kind of person who is using Jekyll, then chances are you’ll - want to enable syntax highlighting using Pygments. You should really - check out how to do - that before you go any further. + want to enable syntax highlighting using Pygments or Rouge. You should + really check out how to + do that before you go any further.

diff --git a/site/docs/posts.md b/site/docs/posts.md index 88036bdb..73899a3b 100644 --- a/site/docs/posts.md +++ b/site/docs/posts.md @@ -139,8 +139,8 @@ your `excerpt_separator` to `""`. ## Highlighting code snippets Jekyll also has built-in support for syntax highlighting of code snippets using -Pygments, and including a code snippet in any post is easy. Just use the -dedicated Liquid tag as follows: +either Pygments or [Rouge](https://github.com/jayferd/rouge), and including a +code snippet in any post is easy. Just use the dedicated Liquid tag as follows: {% highlight text %} {% raw %}{% highlight ruby %}{% endraw %} diff --git a/site/docs/templates.md b/site/docs/templates.md index 7cf2a865..236aaaea 100644 --- a/site/docs/templates.md +++ b/site/docs/templates.md @@ -232,8 +232,14 @@ These parameters are available via Liquid in the include: Jekyll has built in support for syntax highlighting of [over 100 languages](http://pygments.org/languages/) thanks to -[Pygments](http://pygments.org/). To use Pygments, you must have Python installed on your -system and set `pygments` to `true` in your site's configuration file. +[Pygments](http://pygments.org/). To use Pygments, you must have Python installed +on your system and set `highlighter` to `pygments` in your site's configuration +file. + +Alternatively, you can use [Rouge](https://github.com/jayferd/rouge) to highlight +your code snippets. It doesn't support as many languages as Pygments does but +it should fit in most cases and it's written in pure Ruby ; you don't need Python +on your system! To render a code block with syntax highlighting, surround your code as follows: @@ -249,8 +255,9 @@ end The argument to the `highlight` tag (`ruby` in the example above) is the language identifier. To find the appropriate identifier to use for the language -you want to highlight, look for the “short name” on the [Lexers -page](http://pygments.org/docs/lexers/). +you want to highlight, look for the “short name” on the [Pygments' Lexers +page](http://pygments.org/docs/lexers/) or the [Rouge +wiki](https://github.com/jayferd/rouge/wiki/List-of-supported-languages-and-lexers). #### Line numbers @@ -290,7 +297,7 @@ will generate the correct permalink URL for the post you specify. {% endraw %} {% endhighlight %} -If you organize your posts in subdirectories, you need to include subdirectory +If you organize your posts in subdirectories, you need to include subdirectory path to the post: {% highlight text %} diff --git a/site/docs/troubleshooting.md b/site/docs/troubleshooting.md index e481af6b..c27c1665 100644 --- a/site/docs/troubleshooting.md +++ b/site/docs/troubleshooting.md @@ -123,8 +123,8 @@ bug](http://aaronqian.com/articles/2009/04/07/redcloth-ate-my-notextile.html) and will hopefully be fixed for 4.2. You can still use 4.1.9, but the test suite requires that 4.1.0 be installed. If you use a version of RedCloth that does not have the notextile tag, you may notice that -syntax highlighted blocks from Pygments are not formatted correctly, -among other things. If you’re seeing this just install 4.1.0. +syntax highlighted blocks from Pygments or Rouge are not formatted +correctly, among other things. If you’re seeing this just install 4.1.0. ### Liquid diff --git a/test/test_redcarpet.rb b/test/test_redcarpet.rb index c8354c4b..dabcd62c 100644 --- a/test/test_redcarpet.rb +++ b/test/test_redcarpet.rb @@ -42,6 +42,22 @@ puts "Hello world" end end + context "with rouge enabled" do + setup do + @markdown = Converters::Markdown.new @config.merge({ 'highlighter' => 'rouge' }) + end + + should "render fenced code blocks with syntax highlighting" do + assert_equal "
puts \"Hello world\"\n
", @markdown.convert( + <<-EOS +```ruby +puts "Hello world" +``` + EOS + ).strip + end + end + context "without any highlighter" do setup do @markdown = Converters::Markdown.new @config.merge({ 'highlighter' => nil })