beforeRunningCommand nop bundleUUID B7BC3FFD-6E4B-11D9-91AF-000D93589AF6 command #!/usr/bin/env ruby -wKU require 'iconv' SUPPORT = ENV['TM_SUPPORT_PATH'] DIALOG = SUPPORT + '/bin/tm_dialog' ENV['PATH'] = %x{sh -c '. "$BASH_ENV"; echo $PATH'} require SUPPORT + '/lib/escape' require SUPPORT + '/lib/plist' require SUPPORT + '/lib/exit_codes' search_text = STDIN.read def found?(executable) ENV['PATH'].split(/:/).find do |dir| File.executable?(File.join(dir, executable)) end end # convert between UTF-8 and Mac Roman encoding macroman = Iconv.new('macroman', 'utf-8') utf8 = Iconv.new('utf-8', 'macroman') ## these commands are tried in order # lbdb is The Little Brother's Database # http://www.spinnaker.de/lbdb/ # it can search Mutt's alias files, abook, LDAP directories, etc. # contacts searches the Address Book. # http://gnufoo.org/contacts/ # It returns only one email address for each person. # Both lbdb and contacts can be easily installed with MacPorts: # http://www.macports.org/ # The fallback option is querying Address Book with AppleScript. # Unlike lbdb and contacts, it requires Address Book to be open. COMMANDS = [ ['lbdbq', proc do %x{lbdbq "#{search_text}" | tail -n +2}.map do |line| line.split(/\t/)[0..1].map {|f| f.strip}.reverse end end ], ['contacts', proc do %x{contacts -Ss -f "%n:%e" "#{macroman.iconv(search_text)}" | tail -n +2}.map do |line| line.chomp.split(/:/).map {|field| utf8.iconv(field)} end end ], ['osascript', proc do %x{osascript <<END tell application "Address Book" set matchList to {} repeat with oneID in (get id of every person whose name contains "#{search_text}") set oneID to contents of oneID set dataList to (get every email of person id oneID) repeat with oneValue in dataList copy (name of person id oneID & tab & value of oneValue) to end of matchList end repeat end repeat end tell set AppleScript's text item delimiters to ASCII character 10 return items of matchList as string END }.map {|line| line.chomp.split(/\t/)} end ], ] matches = COMMANDS.find {|command| found? command.first }.last.call names = matches.map do |name, email| {'title' => "#{name} (#{email})", 'email' => "#{name} <#{email}>"} if email end.compact TextMate.exit_show_tool_tip "No matches found" if names.empty? TextMate.exit_replace_text names[0]['email'] if names.length == 1 plist = { 'menuItems' => names }.to_plist res = PropertyList::load(`#{e_sh DIALOG} -up #{e_sh plist}`) TextMate.exit_discard unless res.has_key? 'selectedMenuItem' print res['selectedMenuItem']['email'] fallbackInput word input selection keyEquivalent ^@A name Find Email Address in Address Book output replaceSelectedText uuid 575C4CAF-71B1-4F92-886B-8D89E0D0EFDD