#!/usr/bin/env ruby -rcgi # By Henrik Nyh 2007-06-26 # Free to modify and redistribute with credit. # # Updated to use with ack by Pedro Melo 2008-05-26 # Support for TM_SELECTED_FILES by Corey Jewett 2008-05-30 # # 2008-08-11 (melo): Added flag ':' you must start your query with a : to # search only in the "selected files". I added this because using the # selected files ends up not being something that I commonly do. # # # **NOTE WELL**: TextMate does not inherit your PATH, so if you this # command does not find it define the environment variable # TM_ACK_COMMAND_PATH in your Preferences > Advanced > Shell Variables with # the full path of your copy of the ack command. # %w{ui web_preview escape textmate tm/process}.each { |lib| require "%s/lib/%s" % [ENV['TM_SUPPORT_PATH'], lib] } ack_cmd=ENV['TM_ACK_COMMAND_PATH'] || ENV['TM_ACK'] || 'ack' TextMate.require_cmd(ack_cmd) NAME = "Search in Project with ack" HEAD = <<-HTML HTML RESIZE_TABLE = <<-HTML HTML def ellipsize_path(path) path.sub(/^(.{30})(.{10,})(.{30})$/) { "#$1?#$3" } end def escape(string) CGI.escapeHTML(string) end def bail(message) puts <<-HTML

#{ message }

HTML html_footer exit end directory = ENV['TM_PROJECT_DIRECTORY'] || ( ENV['TM_FILEPATH'] && File.dirname(ENV['TM_FILEPATH']) ) puts html_head( :window_title => NAME, :page_title => NAME, :sub_title => directory || "Error", :html_head => HEAD ) bail("Not in a saved file") unless directory query = TextMate::UI.request_string(:title => "Search in Project with ack", :prompt => "Find this:", :default => %x{pbpaste -pboard find}) bail("Search aborted") unless query if query[0,1] == ':' query[0,1] = '' use_selected_files = true else use_selected_files = false end IO.popen('pbcopy -pboard find', 'w') { |copy| copy.print query } puts <<-HTML

Searching for #{ escape(query) }

HTML if use_selected_files selected_files=TextMate.selected_files end if selected_files command = [ack_cmd, "-H", '--', query, selected_files] puts <<-HTML

Search limited to #{ escape(selected_files.join(' ')) }

HTML else Dir.chdir(directory) command = [ack_cmd, '--', query] end puts <<-HTML HTML # Used to highlight matches query_re = Regexp.new( Regexp.escape(CGI.escapeHTML(query)), Regexp::IGNORECASE) last_path = path = i = nil err = "" alternate = true lines = 0 TextMate::Process.run(command, :interactive_input => false) do |line, type| case type when :err err << line when :out lines = lines + 1 line.gsub!(/^([^:]+):(\d+):(.*)$/) do relative_path, line_number, content = $1, $2, $3.strip relative_path.sub!(directory + "/", '') if selected_files path = directory + '/' + relative_path url = "txmt://open/?url=file://#{path}&line=#{line_number}" fname = "%s:%s" % [ellipsize_path(relative_path), line_number]; fname = ":%s" % [ line_number ] if (path == last_path); content = escape(content). # Highlight keywords gsub(query_re) { %{#$&} }. # Ellipsize before, between and after keywords gsub(%r{(^[^<]{25}|[^<]{15})([^<]{20,})([^<]{15}?#$3} end <<-HTML HTML end puts line last_path = path end end if lines # A paragraph inside the table ends up at the top even though it's output # at the end. Something of a hack :) puts <<-HTML

#{lines} matching line#{lines==1 ? '' : 's'}:

#{RESIZE_TABLE} HTML else puts <<-HTML HTML end if $? != 0 TextMate::UI.alert(:critical, "Search In Project With Ack Error", err) TextMate.exit_discard end # TODO: see how to detect command not found in ruby and suggest using # TM_ACK_COMMAND_PATH to solve it puts <<-HTML
#{ fname } #{ content }
No results.
HTML html_footer TextMate.exit_show_html