Luke Melia

software dev

October 3, 2007

Clickable Ruby Stacktraces with iTerm & TextMate

UPDATED: Rev'd the script to strip out "stupid rails /../ crap". Thanks, Ryan.

When I'm working in Ruby on my delightful new MacBook, I sometimes miss a feature of VisualStudio: the ability to double-click a line of a stacktrace in a test failure and open that file and line number in the editor.

I started thinking about how it might be possible at RubyEast on Friday, and tonight I hacked something together that works for TextMate and iTerm, my tools of choice. Here's the scoop:

iTerm has a feature where you can Command-Click a URL in terminal window and "follow" it using the app registered for that protocol. TextMate has a txmt:// URL scheme that lets you open files in textmate.

I wrote a ruby script that filters input to convert stacktrace lines to the txmt::// format. So here is a normal test failure (without processing through the filter):

CODE:
  1. $ /usr/local/bin/ruby -I.:lib:test -rtest/unit -e "%w[test/unit/some_test.rb].each { |f| require f }"               
  2. Loaded suite -e
  3. Started
  4. .....F...
  5. Finished in 0.128739 seconds.
  6.  
  7.   1) Failure:
  8. test_spec {Someone, in general, } 006 [should say something](Someone, in general, )
  9.     [/Users/lmelia/devprojects/secret/config/../vendor/plugins/test_spec_on_rails/lib/test/spec/rails/test_spec_ext.rb:6:in `equal'
  10.      ./test/unit/blog_entry_factory_test.rb:68:in `test_spec {Someone, in general, } 006 [should say something]'
  11.      /Users/lmelia/devprojects/secret/config/../vendor/gems/mocha-0.5.3/lib/mocha/test_case_adapter.rb:19:in `__send__'
  12.      /Users/lmelia/devprojects/secret/config/../vendor/gems/mocha-0.5.3/lib/mocha/test_case_adapter.rb:19:in `run']:
  13. <"Someone's clever response goes where?"> expected but was
  14. <"Someone's clever response goes here.">.
  15.  
  16. 9 tests, 11 assertions, 1 failures, 0 errors
  17. $

And here it is running through the textmate_urls Ruby script:

CODE:
  1. $ /usr/local/bin/ruby -I.:lib:test -rtest/unit -e "%w[test/unit/blog_entry_factory_test.rb].each { |f| require f }" | textmate_urls
  2. Loaded suite -e
  3. Started
  4. .....F...
  5. Finished in 0.111423 seconds.
  6.  
  7.   1) Failure:
  8. test_spec {Someone, in general, } 006 [should say something](Someone, in general, )
  9.     [txmt://open?url=file:///Users/lmelia/devprojects/secret/vendor/plugins/test_spec_on_rails/lib/test/spec/rails/test_spec_ext.rb&line=6 :in `equal'
  10.      txmt://open?url=file:///Users/lmelia/devprojects/secret/test/unit/blog_entry_factory_test.rb&line=68 :in `test_spec {Someone, in general, } 006 [should say something]'
  11.      txmt://open?url=file:///Users/lmelia/devprojects/secret/config/../vendor/gems/mocha-0.5.3/lib/mocha/test_case_adapter.rb&line=19 :in `__send__'
  12.      txmt://open?url=file:///Users/lmelia/devprojects/secret/config/../vendor/gems/mocha-0.5.3/lib/mocha/test_case_adapter.rb&line=19 :in `run']:
  13. <"Someone's clever response goes where?"> expected but was
  14. <"Someone's clever response goes here.">.
  15.  
  16. 9 tests, 11 assertions, 1 failures, 0 errors
  17. $

Now I can mouseover any of the stacktrace lines above, hold down command and click, and I'm automatically switched to TextMate with the specified file and line showing.

Yay!

My next step is to figure out how best to integrate it with autotest. If you have ideas, please leave a comment!

Here's the script:

RUBY:
  1. #!/usr/local/bin/ruby -ws
  2. #
  3. # textmate_urls - by Luke Melia <luke@lukemelia.com>
  4. #
  5. # usage:
  6. #  test.rb | textmate_urls
  7.  
  8. ############################################################
  9.  
  10. class TextmateUrls
  11.  
  12.   def self.urlize
  13.     trap 'INT' do exit 1 end
  14.     TextmateUrls.new.urlize
  15.   end
  16.  
  17.   ##
  18.   # Scans input looking for stacktrace lines and rewrite them with textmate urls in the output
  19.  
  20.   def urlize(input=ARGF, output=$stdout)
  21.     cwd = `pwd`.chomp #remember the current working directory to rewrite relative paths in the stacktrace
  22.     old_sync = output.sync
  23.     output.sync = true
  24.     while line = input.gets
  25.       case line
  26.         when %r{(^[a-z_]+\([A-Za-z]+\)) \[\.?(/?.*):(\d+)\]:}
  27.           line = "#{$1}\ntxmt://open?url=file://#{File.join(cwd, $2)}&line=#{$3}"
  28.           line.gsub!(%r|/[^/]+/\.\./|, '/')
  29.         when %r{^\s*(\[?)(/.+):(\d+):(.*)$} # a stacktrace line
  30.           line = "#{$1}txmt://open?url=file://#{$2}&line=#{$3} #{$4}"
  31.           line.gsub!(%r|/[^/]+/\.\./|, '/')
  32.         when %r{^\s*(\[?)\.?(/?.+):(\d+):(in .*)$} # a stacktrace line with a relative file reference
  33.           line = "#{$1}txmt://open?url=file://#{File.join(cwd, $2)}&line=#{$3} #{$4}"
  34.           line.gsub!(%r|/[^/]+/\.\./|, '/')
  35.       end
  36.       output.puts line
  37.     end
  38.     output.sync = old_sync
  39.   end
  40. end
  41.  
  42. TextmateUrls.urlize

Happy stack-walking!

5 Responses to “Clickable Ruby Stacktraces with iTerm & TextMate”

  1. a gravatar Reinier Balt chimed in:

    you get this for free when using Netbeans :-)

  2. a gravatar Ryan Davis chimed in:

    Reinier: yeah, but then he'd be running netbeans. My guess is textmate + iterm + rails + the rest of the OS runs within the memory footprint of netbeans...

    Luke: while I'm glad you now have clickable links, isn't there some way to keep them readable? Maybe even cleaning them up even more over your default (remove full paths and the stupid rails /../ crap)?

    I've got all that and autotest integration and more within emacs. It truly is helpful.

  3. a gravatar Bryan Helmkamp chimed in:

    The same thing works in Leopard's Terminal.app. If you right click a link, you can choose "Open URL". I confirmed this works for txmt:// URLs.

  4. a gravatar Chip chimed in:

    I am new to RoR and this has helped me immensely when using autotest. I am trying to figure out how to hook this into the browser's stack trace. If anyone has any suggestions, please let me know.

    Thanks again for this killer script!

  5. a gravatar Dr Nic chimed in:

    Did you ever get this hooked into autotest?

Leave a Reply

LukeMelia.com created 1999. ··· Luke Melia created 1976. ··· Live With Passion!