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" +
+ "x = " +
+ "1\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")