Merge pull request #1859 from robin850/rouge

This commit is contained in:
Matt Rogers 2013-12-30 22:45:07 -06:00
commit 012387396a
22 changed files with 168 additions and 64 deletions

View File

@ -7,6 +7,7 @@
* Remove support for Ruby 1.8.x (#1780)
* Move to jekyll/jekyll from mojombo/jekyll (#1817)
* Allow custom markdown processors (#1872)
* Provide support for the Rouge syntax highlighter (#1859)
### Minor Enhancements
* Move the EntryFilter class into the Jekyll module to avoid polluting the
@ -37,6 +38,7 @@
* Add in History and site changes from `v1-stable` branch (#1836)
* Testing additions on the Excerpt class (#1893)
* Update Kramdown to `~> 1.3` (#1894)
* Fix the `highlight` tag feature (#1859)
### Site Enhancements
* Document Kramdown's GFM parser option (#1791)

View File

@ -91,11 +91,19 @@ Feature: Site configuration
And I should see "<a href=\"http://google.com\">Google</a>" in "_site/index.html"
Scenario: Highlight code with pygments
Given I have an "index.html" file that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}"
And I have a configuration file with "pygments" set to "true"
Given I have an "index.html" page that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}"
When I run jekyll
Then the _site directory should exist
And I should see "puts 'Hello world!'" in "_site/index.html"
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

View File

@ -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.3')
# = MANIFEST =
s.files = %w[

View File

@ -24,12 +24,12 @@ module Jekyll
'limit_posts' => 0,
'lsi' => false,
'future' => true, # remove and make true just default
'pygments' => true,
'relative_permalinks' => true, # backwards-compatibility with < 1.0
# will be set to false once 2.0 hits
'markdown' => 'maruku',
'highlighter' => 'pygments',
'permalink' => 'date',
'baseurl' => '/',
'include' => ['.htaccess'],
@ -210,6 +210,16 @@ module Jekyll
config.delete('server_port')
end
if config.has_key? 'pygments'
Jekyll.logger.warn "Deprecation:", "The 'pygments' configuration option" +
" has been renamed to 'highlighter'. Please update your" +
" config file accordingly. The allowed values are 'rouge', " +
"'pygments' or null."
config['highlighter'] = 'pygments' if config['pygments']
config.delete('pygments')
end
%w[include exclude].each do |option|
if config.fetch(option, []).is_a?(String)
Jekyll.logger.warn "Deprecation:", "The '#{option}' configuration option" +

View File

@ -1,27 +1,27 @@
module Jekyll
class Converter < Plugin
# Public: Get or set the pygments prefix. When an argument is specified,
# Public: Get or set the highlighter prefix. When an argument is specified,
# the prefix will be set. If no argument is specified, the current prefix
# will be returned.
#
# pygments_prefix - The String prefix (default: nil).
# highlighter_prefix - The String prefix (default: nil).
#
# Returns the String prefix.
def self.pygments_prefix(pygments_prefix = nil)
@pygments_prefix = pygments_prefix if pygments_prefix
@pygments_prefix
def self.highlighter_prefix(highlighter_prefix = nil)
@highlighter_prefix = highlighter_prefix if highlighter_prefix
@highlighter_prefix
end
# Public: Get or set the pygments suffix. When an argument is specified,
# Public: Get or set the highlighter suffix. When an argument is specified,
# the suffix will be set. If no argument is specified, the current suffix
# will be returned.
#
# pygments_suffix - The String suffix (default: nil).
# highlighter_suffix - The String suffix (default: nil).
#
# Returns the String suffix.
def self.pygments_suffix(pygments_suffix = nil)
@pygments_suffix = pygments_suffix if pygments_suffix
@pygments_suffix
def self.highlighter_suffix(highlighter_suffix = nil)
@highlighter_suffix = highlighter_suffix if highlighter_suffix
@highlighter_suffix
end
# Initialize the converter.
@ -31,18 +31,18 @@ module Jekyll
@config = config
end
# Get the pygments prefix.
# Get the highlighter prefix.
#
# Returns the String prefix.
def pygments_prefix
self.class.pygments_prefix
def highlighter_prefix
self.class.highlighter_prefix
end
# Get the pygments suffix.
# Get the highlighter suffix.
#
# Returns the String suffix.
def pygments_suffix
self.class.pygments_suffix
def highlighter_suffix
self.class.highlighter_suffix
end
end
end

View File

@ -3,8 +3,8 @@ module Jekyll
class Markdown < Converter
safe true
pygments_prefix "\n"
pygments_suffix "\n"
highlighter_prefix "\n"
highlighter_suffix "\n"
def setup
return if @setup

View File

@ -22,7 +22,7 @@ module Jekyll
end
end
module WithoutPygments
module WithoutHighlighting
require 'cgi'
include CommonMethods
@ -37,19 +37,50 @@ module Jekyll
end
end
module WithRouge
require 'rouge'
require 'rouge/plugins/redcarpet'
if Rouge.version < '1.3.0'
abort "Please install Rouge 1.3.0 or greater and try running Jekyll again."
end
include Rouge::Plugins::Redcarpet
include CommonMethods
def block_code(code, lang)
code = "<pre>#{super}</pre>"
output = "<div class=\"highlight\">"
output << add_code_tags(code, lang)
output << "</div>"
end
protected
def rouge_formatter(opts = {})
Rouge::Formatters::HTML.new(opts.merge(wrap: false))
end
end
def initialize(config)
require 'redcarpet'
@config = config
@redcarpet_extensions = {}
@config['redcarpet']['extensions'].each { |e| @redcarpet_extensions[e.to_sym] = true }
@renderer ||= if @config['pygments']
@renderer ||= case @config['highlighter']
when 'pygments'
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

View File

@ -3,8 +3,8 @@ module Jekyll
class Textile < Converter
safe true
pygments_prefix '<notextile>'
pygments_suffix '</notextile>'
highlighter_prefix '<notextile>'
highlighter_suffix '</notextile>'
def setup
return if @setup

View File

@ -145,8 +145,8 @@ module Jekyll
info = { :filters => [Jekyll::Filters], :registers => { :site => self.site, :page => payload['page'] } }
# render and transform content (this becomes the final content of the object)
payload["pygments_prefix"] = converter.pygments_prefix
payload["pygments_suffix"] = converter.pygments_suffix
payload["highlighter_prefix"] = converter.highlighter_prefix
payload["highlighter_suffix"] = converter.highlighter_suffix
self.content = self.render_liquid(self.content,
payload,

View File

@ -9,8 +9,8 @@ module Jekyll
arg_is_present? args, "--auto", "The switch '--auto' has been replaced with '--watch'."
arg_is_present? args, "--no-auto", "To disable auto-replication, simply leave off \
the '--watch' switch."
arg_is_present? args, "--pygments", "The 'pygments' setting can only be set in \
your config files."
arg_is_present? args, "--pygments", "The 'pygments'settings has been removed in \
favour of 'highlighter'."
arg_is_present? args, "--paginate", "The 'paginate' setting can only be set in your \
config files."
arg_is_present? args, "--url", "The 'url' setting can only be set in your config files."

View File

@ -1,7 +1,7 @@
module Jekyll
class Site
attr_accessor :config, :layouts, :posts, :pages, :static_files,
:categories, :exclude, :include, :source, :dest, :lsi, :pygments,
:categories, :exclude, :include, :source, :dest, :lsi, :highlighter,
:permalink_style, :tags, :time, :future, :safe, :plugins, :limit_posts,
:show_drafts, :keep_files, :baseurl, :data, :file_read_opts, :gems
@ -13,7 +13,7 @@ module Jekyll
def initialize(config)
self.config = config.clone
%w[safe lsi pygments baseurl exclude include future show_drafts limit_posts keep_files gems].each do |opt|
%w[safe lsi highlighter baseurl exclude include future show_drafts limit_posts keep_files gems].each do |opt|
self.send("#{opt}=", config[opt])
end

View File

@ -41,8 +41,11 @@ eos
end
def render(context)
if context.registers[:site].pygments
case context.registers[:site].highlighter
when 'pygments'
render_pygments(context, super)
when 'rouge'
render_rouge(context, super)
else
render_codehighlighter(context, super)
end
@ -58,9 +61,28 @@ eos
@lang
)
output = context["pygments_prefix"] + output if context["pygments_prefix"]
output = output + context["pygments_suffix"] if context["pygments_suffix"]
output
output = context["highlighter_prefix"] + output if context["highlighter_prefix"]
output << context["highlighter_suffix"] if context["highlighter_suffix"]
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, wrap: false)
pre = "<pre>#{formatter.format(lexer.lex(code))}</pre>"
output = context["highlighter_prefix"] || ""
output << "<div class=\"highlight\">"
output << add_code_tags(pre, @lang)
output << "</div>"
output << context["highlighter_suffix"] if context["highlighter_suffix"]
return output
end
def render_codehighlighter(context, code)

View File

@ -1,3 +1,3 @@
name: Your New Jekyll Site
markdown: redcarpet
pygments: true
highlighter: pygments

View File

@ -1,4 +1,4 @@
pygments: true
highlight: pygments
relative_permalinks: false
gauges_id: 503c5af6613f5d0f19000027
permalink: /news/:year/:month/:day/:title/

View File

@ -288,7 +288,7 @@ encoding: nil
future: true
show_drafts: nil
limit_posts: 0
pygments: true
highlighter: pygments
relative_permalinks: true
@ -363,7 +363,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 `<code>` 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 `<code>` 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:

View File

@ -66,9 +66,10 @@ Check out [the extras page](../extras/) for more information.
<h5>ProTip™: Enable Syntax Highlighting</h5>
<p>
If youre the kind of person who is using Jekyll, then chances are youll
want to enable syntax highlighting using Pygments. You should really
<a href="../templates/#code_snippet_highlighting">check out how to do
that</a> before you go any further.
want to enable syntax highlighting using <a href="http://pygments.org/">Pygments</a>
or <a href="https://github.com/jayferd/rouge">Rouge</a>. You should really
<a href="../templates/#code_snippet_highlighting">check out how to
do that</a> before you go any farther.
</p>
</div>

View File

@ -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, and including a code snippet in any post is easy. Just
use the dedicated Liquid tag as follows:
{% highlight text %}
{% raw %}{% highlight ruby %}{% endraw %}

View File

@ -230,8 +230,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:
@ -247,8 +253,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
@ -288,7 +295,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 %}

View File

@ -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 youre seeing this just install 4.1.0.
syntax highlighted blocks from Pygments or Rouge are not formatted
correctly, among other things. If youre seeing this just install 4.1.0.
### Liquid

View File

@ -51,11 +51,12 @@ class TestConfiguration < Test::Unit::TestCase
context "#backwards_compatibilize" do
setup do
@config = Configuration[{
"auto" => true,
"watch" => true,
"server" => true,
"exclude" => "READ-ME.md, Gemfile,CONTRIBUTING.hello.markdown",
"include" => "STOP_THE_PRESSES.txt,.heloses, .git"
"auto" => true,
"watch" => true,
"server" => true,
"exclude" => "READ-ME.md, Gemfile,CONTRIBUTING.hello.markdown",
"include" => "STOP_THE_PRESSES.txt,.heloses, .git",
"pygments" => true,
}]
end
should "unset 'auto' and 'watch'" do
@ -78,6 +79,11 @@ class TestConfiguration < Test::Unit::TestCase
assert @config.backwards_compatibilize.has_key?("include")
assert_equal @config.backwards_compatibilize["include"], %w[STOP_THE_PRESSES.txt .heloses .git]
end
should "set highlighter to pygments" do
assert @config.has_key?("pygments")
assert !@config.backwards_compatibilize.has_key?("pygments")
assert_equal @config.backwards_compatibilize["highlighter"], "pygments"
end
end
context "#fix_common_issues" do
setup do

View File

@ -28,7 +28,7 @@ class TestRedcarpet < Test::Unit::TestCase
context "with pygments enabled" do
setup do
@markdown = Converters::Markdown.new @config.merge({ 'pygments' => true })
@markdown = Converters::Markdown.new @config.merge({ 'highlighter' => 'pygments' })
end
should "render fenced code blocks with syntax highlighting" do
@ -42,9 +42,25 @@ puts "Hello world"
end
end
context "with pygments disabled" do
context "with rouge enabled" do
setup do
@markdown = Converters::Markdown.new @config.merge({ 'pygments' => false })
@markdown = Converters::Markdown.new @config.merge({ 'highlighter' => 'rouge' })
end
should "render fenced code blocks with syntax highlighting" do
assert_equal "<div class=\"highlight\"><pre><code class=\"ruby language-ruby\" data-lang=\"ruby\"><span class=\"nb\">puts</span> <span class=\"s2\">\"Hello world\"</span>\n</code></pre></div>", @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 })
end
should "render fenced code blocks without syntax highlighting" do

View File

@ -6,7 +6,7 @@ class TestTags < Test::Unit::TestCase
def create_post(content, override = {}, converter_class = Jekyll::Converters::Markdown)
stub(Jekyll).configuration do
Jekyll::Configuration::DEFAULTS.deep_merge({'pygments' => true}).deep_merge(override)
Jekyll::Configuration::DEFAULTS.deep_merge({'highlighter' => 'pygments'}).deep_merge(override)
end
site = Site.new(Jekyll.configuration)
@ -16,8 +16,8 @@ class TestTags < Test::Unit::TestCase
info = { :filters => [Jekyll::Filters], :registers => { :site => site } }
@converter = site.converters.find { |c| c.class == converter_class }
payload = { "pygments_prefix" => @converter.pygments_prefix,
"pygments_suffix" => @converter.pygments_suffix }
payload = { "highlighter_prefix" => @converter.highlighter_prefix,
"highlighter_suffix" => @converter.highlighter_suffix }
@result = Liquid::Template.parse(content).render!(payload, info)
@result = @converter.convert(@result)