Report abuse


			
# codecloth.rb
# By Nathan Weizenbaum (http://nex3.leeweiz.net)
# MIT License (http://www.opensource.org/licenses/mit-license.php)
#
# Integrating CodeRay syntax highlighting with RedCloth.
# Check out http://nex3.leeweiz.net/posts/31-a-solution-to-the-syntax-highlighting-problem

require 'rubygems'
require 'redcloth'
require 'coderay'

module CodeCloth
  HTML_OPTIONS = { :wrap => :div }

  def self.included(other)
    other::BASIC_TAGS['span'] = ['class']
    other::BASIC_TAGS['div'] = ['class']
    other::BASIC_TAGS['codeclothpre'] = nil

    other::DEFAULT_RULES.insert 0, :block_syntax_set

    other.send :alias_method, :to_html_without_syntax, :to_html
    other.send :alias_method, :to_html, :to_html_with_syntax

    other.send :alias_method, :initialize_without_scanner, :initialize
    other.send :alias_method, :initialize, :initialize_with_scanner
  end

  def initialize_with_scanner(*whatever)
    initialize_without_scanner(*whatever)
    @scanner = CodeRay::Scanners['plain']
  end

  def block_syntax_set(text)
    return nil if text[0] != ?$
    syntax, rest = text.split "\n", 2

    syntax.slice! 0
    syntax.strip!
    syntax.downcase!

    scanner = CodeRay::Scanners[syntax.empty? ? 'plain' : syntax]

    if rest.nil?
      @scanner = scanner
      text.replace('')
    else
      text.replace rest.gsub(/^#{'\s' * rest.index(/[^\s]/)}/, '')
      blocks text, true
      syntaxify text, scanner
    end
  end

  def to_html_with_syntax(*whatever)
    unescape_pre syntaxify(syntaxify_manual_html(to_html_without_syntax(*whatever)), @scanner)
  end

  private

  SYNTAXLESS_CODE_RE = /
(?:)?(.*?)(?:<\/code>)?<\/pre>/m

  def syntaxify(text, scanner)
    text.gsub!(SYNTAXLESS_CODE_RE) do
      escape_pre scanner.new($1).tokenize.html(HTML_OPTIONS)
    end
    text
  end

  MANUAL_HTML_RE = /^\$([^\n]+)\n(#{SYNTAXLESS_CODE_RE})/

  def syntaxify_manual_html(text)
    text.gsub!(MANUAL_HTML_RE) do
      syntaxify $2, CodeRay::Scanners[$1.strip.downcase]
    end
    text
  end

  def escape_pre(text)
    text.gsub(/<(\/?)pre>/, '<\1codeclothpre>')
  end

  def unescape_pre(text)
    text.gsub(/<(\/?)codeclothpre>/, '<\1pre>')
  end
end

RedCloth.send :include, CodeCloth