From a6079f3abd3be61f15858d50c811a6856cfb34f1 Mon Sep 17 00:00:00 2001
From: Tom Preston-Werner
Date: Tue, 20 Apr 2010 13:10:50 -0700
Subject: [PATCH] code highligting
---
lib/gollum.rb | 1 +
lib/gollum/albino.rb | 119 +++++++++++++++++++++++++++++++++++++++++++
lib/gollum/markup.rb | 43 ++++++++++++++++
test/test_markup.rb | 15 ++++++
4 files changed, 178 insertions(+)
create mode 100644 lib/gollum/albino.rb
diff --git a/lib/gollum.rb b/lib/gollum.rb
index 28a67d74..449f619e 100644
--- a/lib/gollum.rb
+++ b/lib/gollum.rb
@@ -7,6 +7,7 @@ require 'gollum/wiki'
require 'gollum/page'
require 'gollum/file'
require 'gollum/markup'
+require 'gollum/albino'
module Gollum
VERSION = '0.0.1'
diff --git a/lib/gollum/albino.rb b/lib/gollum/albino.rb
new file mode 100644
index 00000000..3e83bb05
--- /dev/null
+++ b/lib/gollum/albino.rb
@@ -0,0 +1,119 @@
+##
+# Wrapper for the Pygments command line tool, pygmentize.
+#
+# Pygments: http://pygments.org/
+#
+# Assumes pygmentize is in the path. If not, set its location
+# with Albino.bin = '/path/to/pygmentize'
+#
+# Use like so:
+#
+# @syntaxer = Albino.new('/some/file.rb', :ruby)
+# puts @syntaxer.colorize
+#
+# This'll print out an HTMLized, Ruby-highlighted version
+# of '/some/file.rb'.
+#
+# To use another formatter, pass it as the third argument:
+#
+# @syntaxer = Albino.new('/some/file.rb', :ruby, :bbcode)
+# puts @syntaxer.colorize
+#
+# You can also use the #colorize class method:
+#
+# puts Albino.colorize('/some/file.rb', :ruby)
+#
+# Another also: you get a #to_s, for somewhat nicer use in Rails views.
+#
+# ... helper file ...
+# def highlight(text)
+# Albino.new(text, :ruby)
+# end
+#
+# ... view file ...
+# <%= highlight text %>
+#
+# The default lexer is 'text'. You need to specify a lexer yourself;
+# because we are using STDIN there is no auto-detect.
+#
+# To see all lexers and formatters available, run `pygmentize -L`.
+#
+# Chris Wanstrath // chris@ozmm.org
+# GitHub // http://github.com
+#
+class Albino
+ @@bin = Rails.development? ? 'pygmentize' : '/usr/bin/pygmentize' rescue 'pygmentize'
+
+ def self.bin=(path)
+ @@bin = path
+ end
+
+ def self.colorize(*args)
+ new(*args).colorize
+ end
+
+ def initialize(target, lexer = :text, format = :html)
+ @target = File.exists?(target) ? File.read(target) : target rescue target
+ @options = { :l => lexer, :f => format, :O => 'encoding=utf-8' }
+ end
+
+ def execute(command)
+ output = ''
+ IO.popen(command, mode='r+') do |p|
+ p.write @target
+ p.close_write
+ output = p.read.strip
+ end
+ output
+ end
+
+ def colorize(options = {})
+ html = execute(@@bin + convert_options(options))
+ # Work around an RDiscount bug: http://gist.github.com/97682
+ html.to_s.sub(%r{\Z}, "\n")
+ end
+ alias_method :to_s, :colorize
+
+ def convert_options(options = {})
+ @options.merge(options).inject('') do |string, (flag, value)|
+ string + " -#{flag} #{value}"
+ end
+ end
+end
+
+if $0 == __FILE__
+ require 'rubygems'
+ require 'test/spec'
+ require 'mocha'
+ begin require 'redgreen'; rescue LoadError; end
+
+ context "Albino" do
+ setup do
+ @syntaxer = Albino.new(__FILE__, :ruby)
+ end
+
+ specify "defaults to text" do
+ syntaxer = Albino.new(__FILE__)
+ syntaxer.expects(:execute).with('pygmentize -f html -l text').returns(true)
+ syntaxer.colorize
+ end
+
+ specify "accepts options" do
+ @syntaxer.expects(:execute).with('pygmentize -f html -l ruby').returns(true)
+ @syntaxer.colorize
+ end
+
+ specify "works with strings" do
+ syntaxer = Albino.new('class New; end', :ruby)
+ assert_match %r(highlight), syntaxer.colorize
+ end
+
+ specify "aliases to_s" do
+ assert_equal @syntaxer.colorize, @syntaxer.to_s
+ end
+
+ specify "class method colorize" do
+ assert_equal @syntaxer.colorize, Albino.colorize(__FILE__, :ruby)
+ end
+ end
+end
diff --git a/lib/gollum/markup.rb b/lib/gollum/markup.rb
index 63206320..db9e39c3 100644
--- a/lib/gollum/markup.rb
+++ b/lib/gollum/markup.rb
@@ -14,6 +14,7 @@ module Gollum
@version = page.version.id
@dir = ::File.dirname(page.path)
@tagmap = {}
+ @codemap = {}
end
# Render the content with Gollum wiki syntax on top of the file's own
@@ -22,10 +23,18 @@ module Gollum
# Returns the formatted String content.
def render
data = extract_tags(@data)
+ data = extract_code(data)
data = GitHub::Markup.render(@name, data) rescue ''
data = process_tags(data)
+ data = process_code(data)
end
+ #########################################################################
+ #
+ # Tags
+ #
+ #########################################################################
+
# Extract all tags into the tagmap and replace with placeholders.
#
# data - The raw String data.
@@ -199,5 +208,39 @@ module Gollum
@wiki.file(path, @version)
end
end
+
+ #########################################################################
+ #
+ # Code
+ #
+ #########################################################################
+
+ # Extract all code blocks into the codemap and replace with placeholders.
+ #
+ # data - The raw String data.
+ #
+ # Returns the placeholder'd String data.
+ def extract_code(data)
+ data.gsub(/^``` ?(.+)\n(.+)\n```$/m) do
+ id = Digest::SHA1.hexdigest($2)
+ @codemap[id] = { :lang => $1, :code => $2 }
+ id
+ end
+ end
+
+ # Process all code from the codemap and replace the placeholders with the
+ # final HTML.
+ #
+ # data - The String data (with placeholders).
+ #
+ # Returns the marked up String data.
+ def process_code(data)
+ @codemap.each do |id, spec|
+ lang = spec[:lang]
+ code = spec[:code]
+ data.sub!(id, Albino.new(code, lang).colorize)
+ end
+ data
+ end
end
end
\ No newline at end of file
diff --git a/test/test_markup.rb b/test/test_markup.rb
index 1d5ce0eb..91eca0fd 100644
--- a/test/test_markup.rb
+++ b/test/test_markup.rb
@@ -134,6 +134,21 @@ context "Markup" do
assert_equal %{a Alpha b
\n}, output
end
+ test "code blocks" do
+ content = "a\n\n```ruby\nx = 1\n```\n\nb"
+ output = "a
\n\n
\n\nb
\n"
+
+ index = @wiki.repo.index
+ index.add("Bilbo-Baggins.md", content)
+ index.commit("Add alpha.jpg")
+
+ page = @wiki.page("Bilbo Baggins")
+ rendered = Gollum::Markup.new(page).render
+ assert_equal output, rendered
+ end
+
def relative_image(content, output)
index = @wiki.repo.index
index.add("greek/alpha.jpg", "hi")