#!/usr/bin/env ruby -w # encoding: utf-8 # if we are not called directly from TM (e.g. JavaScript) the caller # should ensure that RUBYLIB is set properly $: << "#{ENV["TM_SUPPORT_PATH"]}/lib" if ENV.has_key? "TM_SUPPORT_PATH" LINKED_RI = "#{ENV["TM_BUNDLE_SUPPORT"]}/bin/linked_ri.rb" require "exit_codes" require "ui" require "web_preview" require "erb" include ERB::Util RI_EXE = [ ENV['TM_RUBY_RI'], 'qri', 'ri' ].find { |cmd| !cmd.to_s.empty? && (File.executable?(cmd) || ENV['PATH'].split(':').any? { |dir| File.executable? File.join(dir, cmd) }) ? cmd : false } term = ARGV.shift # first escape for use in the shell, then escape for use in a JS string def e_js_sh(str) (e_sh str).gsub("\\", "\\\\\\\\") end def link_methods(prefix, methods) methods.split(/(,\s*)/).map do |match| match[0] == ?, ? match : "#{match}" end.join end def htmlize_ri_output(text, term) text = text.gsub(/&/, '&').gsub(/, '<') text.sub!(/\A(-+\s+Class: )(.*)$\n*/) do "
"
end
text.sub!(/\A(-+\s+)(([A-Z_]\w*::)*[A-Z_]\w*)((#|::|\.).*)$/) do
method = $4
namespace = $2.split("::")
linked = (0...namespace.size).map do |i|
"#{namespace[i]}"
end
"#{linked.join("::")}#{method}
\n"
end
text.sub!(/^(Includes:\s+-+\s+)(.+?)([ \t]*\n[ \t]*\n|\s*\Z)/m) do
head, meths, foot = $1, $2, $3
head + meths.gsub(/([A-Z_]\w*)\(([^)]*)\)/) do |match|
"#{$1}(" +
link_methods("#{$1}#", $2) + ")"
end + foot
end
text.sub!(/^(Class methods:\s+-+\s+)(.+?)([ \t]*\n[ \t]*\n|\s*\Z)/m) do
$1 + link_methods("#{term}::", $2) + $3
end
text.sub!(/^(Instance methods:\s+-+\s+)(.+?)([ \t]*\n[ \t]*\n|\s*\Z)/m) do
$1 + link_methods("#{term}#", $2) + $3
end
text.gsub!(/(?:\n+-+$)?\n+([\w\s]+)[:.]$\n-+\n+/, "\n\n\\1
\n")
text.gsub!(/^-+$/, '
')
text.chomp + "
"
end
def ri(term)
documentation = `#{e_sh LINKED_RI} '#{term}' 'js' 2>&1` \
rescue "ri Command Error.
"
if documentation =~ /\ACouldn't open the index/
TextMate.exit_show_tool_tip(
"Index needed by #{RI_EXE} not found.\n" +
"You may need to run:\n\n" +
" fastri-server -b"
)
elsif documentation =~ /\ACouldn't initialize DRb and locate the Ring server./
TextMate.exit_show_tool_tip("Your fastri-server is not running.")
elsif documentation =~ /Nothing known about /
TextMate.exit_show_tool_tip(documentation)
elsif documentation.sub!(/\A>>\s*/, "")
choices = documentation.split
choice = TextMate::UI.menu(choices)
exit if choice.nil?
ri(choices[choice])
else
[term, documentation]
end
end
mode = ARGV.shift
if mode.nil? then
term = STDIN.read.strip
if term.empty?
term = TextMate::UI.request_string( :title => "Ruby Documentation Search",
:prompt => "Enter a term to search for:",
:button1 => "search")
end
TextMate.exit_show_tool_tip("Please select a term to look up.") if term.empty?
term, documentation = ri(term)
html_header("Documentation for ‘#{term}’", "RDoc", <<-HTML)
HTML
puts <<-HTML
#{documentation}
HTML
html_footer
TextMate.exit_show_html
elsif mode == 'js' then
documentation = `#{e_sh RI_EXE} -T -f plain #{e_sh term}` \
rescue "ri Command Error.
"
if documentation =~ /\A(?:\s*More than one method matched|-+\s+Multiple choices)/
methods = documentation.split(/\n[ \t]*\n/).last.
strip.split(/(?:,\s*|\n)/).map { |m| m[/\S+/] }.compact
documentation = ">> #{methods.join(' ')}"
else
documentation = htmlize_ri_output(documentation, term)
end
puts documentation
end