108 lines
4.2 KiB
Ruby
108 lines
4.2 KiB
Ruby
require 'pygments'
|
|
require 'fileutils'
|
|
require 'digest/md5'
|
|
|
|
PYGMENTS_CACHE_DIR = File.expand_path('../../.pygments-cache', __FILE__)
|
|
FileUtils.mkdir_p(PYGMENTS_CACHE_DIR)
|
|
|
|
module HighlightCode
|
|
def self.highlight(str, lang)
|
|
lang = 'ruby' if lang == 'ru'
|
|
lang = 'objc' if lang == 'm'
|
|
lang = 'perl' if lang == 'pl'
|
|
lang = 'yaml' if lang == 'yml'
|
|
str = pygments(str, lang).match(/<pre>(.+)<\/pre>/m)[1].to_s.gsub(/ *$/, '') #strip out divs <div class="highlight">
|
|
tableize_code(str, lang)
|
|
end
|
|
|
|
def self.pygments(code, lang)
|
|
if defined?(PYGMENTS_CACHE_DIR)
|
|
path = File.join(PYGMENTS_CACHE_DIR, "#{lang}-#{Digest::MD5.hexdigest(code)}.html")
|
|
if File.exist?(path)
|
|
highlighted_code = File.read(path)
|
|
else
|
|
begin
|
|
highlighted_code = Pygments.highlight(code, :lexer => lang, :formatter => 'html', :options => {:encoding => 'utf-8', :startinline => true})
|
|
rescue MentosError
|
|
raise "Pygments can't parse unknown language: #{lang}."
|
|
end
|
|
File.open(path, 'w') {|f| f.print(highlighted_code) }
|
|
end
|
|
else
|
|
highlighted_code = Pygments.highlight(code, :lexer => lang, :formatter => 'html', :options => {:encoding => 'utf-8', :startinline => true})
|
|
end
|
|
highlighted_code
|
|
end
|
|
def self.tableize_code (str, lang = '')
|
|
table = '<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers">'
|
|
code = ''
|
|
str.lines.each_with_index do |line,index|
|
|
table += "<span class='line-number'>#{index+1}</span>\n"
|
|
code += "<span class='line'>#{line}</span>"
|
|
end
|
|
table += "</pre></td><td class='code'><pre><code class='#{lang}'>#{code}</code></pre></td></tr></table></div>"
|
|
end
|
|
end
|
|
|
|
#------------------------------------------------------------------------------#
|
|
# INTERIM BUGFIX FOR: https://github.com/imathis/octopress/issues/704
|
|
# an upstream solution is in the works but, as of 2012-08-29, the pygment.rb
|
|
# gem has yet to incorporate necessary changes and release a new gem:
|
|
# https://github.com/tmm1/pygments.rb/issues/10
|
|
#
|
|
# The ForcePython2 module below tries to ensure that, when the 'python' command
|
|
# is executed, it always returns an interpreter for version 2.* of python,
|
|
# regardless of what the system-wide default version of python is. When the
|
|
# system-wide version of python is not 2.* and a compatible version is found,
|
|
# a .pygments-cache/python-bin/python symlink is created which points to the
|
|
# compatible version. The python-bin directory is then added to the PATH
|
|
# which gives priority to locally identified version.
|
|
#
|
|
module ForcePython2
|
|
class << self
|
|
def find_python2
|
|
(%w{python python2} + 10.downto(0).map{|v|"python2.#{v}"}).each do |cmd|
|
|
cmd_path = which_cmd(cmd) or next
|
|
return cmd_path if python_major_ver(cmd_path) == 2
|
|
end
|
|
nil
|
|
end
|
|
|
|
def python_major_ver(cmd_path)
|
|
%x{"#{cmd_path}" -c "import sys; print(sys.version_info.major)"}.to_i
|
|
end
|
|
|
|
def which_cmd(cmd)
|
|
# loosely based on cross-platform solution found on stack overflow:
|
|
# http://stackoverflow.com/questions/2108727/
|
|
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] # windows
|
|
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
|
cmd_paths = exts.map {|ext| "#{path}#{File::SEPARATOR}#{cmd}#{ext}" }
|
|
cmd_path = cmd_paths.find {|c| File.executable?(c) }
|
|
return cmd_path if cmd_path
|
|
end
|
|
nil
|
|
end
|
|
|
|
def force
|
|
# rewrite PATH to include local dir which might have python symlink
|
|
path = "#{PYGMENTS_CACHE_DIR}#{File::SEPARATOR}python-bin"
|
|
ENV['PATH'] = "#{path}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
|
|
|
|
# if 'python' command's version is 2.*, we're good
|
|
return if python_major_ver(which_cmd('python')) == 2
|
|
|
|
# not v2, search all our paths for a compatible version
|
|
if cmd_path = find_python2
|
|
# found a compatible version, make it stick w/ a symlink
|
|
sym_path = "#{path}#{File::SEPARATOR}python#{File.extname(cmd_path)}"
|
|
FileUtils.mkdir_p(path)
|
|
File.symlink(cmd_path, sym_path) rescue nil # don't care if unimplemented
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
ForcePython2::force unless ENV['FORCE_PYTHON2'] =~ /^(?:0|false|no)$/i
|