mythmon

Sublime, urxvt, and nose-progressive

Posted on 2013-04-24 in
  • coding
  • ,
  • dotfiles
  • ,
  • sublime
  • ,
  • urxvt
  • ,
  • nose-progressive
  • , and
  • python
.

For many of my projects I use the excellent nose-progressive for running tests. Among other features, it prints out lines that are intended to be helpful to jump straight to the code that caused the error. This works well for some workflows, but not mine. Here is an example of nose-progressive's output:

Reusing old database "test_kitsune". Set env var FORCE_DB=1 if you need fresh DBs.
Generating sample data from wiki...
Done!

FAIL: kitsune.apps.wiki.tests.test_models:DocumentTests.test_document_is_template
  vim +44 apps/wiki/tests/test_models.py  # test_document_is_template
    assert 0
AssertionError

1438 tests, 1 failure, 0 errors, 5 skips in 115.0s

In particular, note the line that begins vim +44 apps/wiki.... It is indicating the file and line number where the error occurred, and if I were to copy that line and execute it in my shell, it would launch vim with the right file and location. Not bad! It chose vim because that is what I have $EDITOR set to.

Unfortunately, even though my $EDITOR is set to vim, I use Sublime in my day to day editing tasks. I like to keep $EDITOR set to vim, because it tends to be used in places where I don't want to escalate to Sublime, but in this case I really do want the GUI editor.. This feature of nose-progressive doesn't help me much.

So how can I get nose-progressive to be helpful? In the recent 1.5 release of nose-progressive, a feature to customize this line was added. Promising. Additionally, I use urxvt as my terminal, and with some configuring, it can open links when they are clicked on. A plan is beginning to form.

Configuring nose-progressive

First, I made nose-progressive output a line that will indicate that Sublime should be used to open the file, not vim. A quick trip to the documentation taught me that I can set the environment variable $NOSE_PROGRESSIVE_EDITOR_SHORTCUT_TEMPLATE to a template string to

{dim_format}subl://{path}:{line_number}{normal}{function_format}{hash_if_function}{function}{normal}

Quite a mouthful, but it gets the job done. This format string will print something visually resembling the old line, but with a custom format. In action, it looks like this:

Reusing old database "test_kitsune". Set env var FORCE_DB=1 if you need fresh DBs.

FAIL: kitsune.apps.wiki.tests.test_models:DocumentTests.test_document_is_template
  subl:///home/mythmon/src/kitsune/apps/wiki/tests/test_models.py:44  # test_document_is_template
    assert 0
AssertionError

1 test, 1 failure, 0 errors in 0.0s

Awesome! Now to get the terminal to respond.

Configuring urxvt

I use a package called urxvt-perls to add features like clickable links to my terminal. I tweaked it's config to look like this to make it recognize my custom Sublime links from above, as well as normal web links. This is the relevant snippet of my ~/.Xdefaults file:

URxvt.perl-ext-common: default,url-select
URxvt.url-select.launcher: urxvt_launcher
URxvt.url-select.underline: true
URxvt.url-select.button: 3
URxvt.matcher.pattern.1: \\b(subl://[^ ]+)\\b

Line by line: - url-select add-on is loaded. - Set the launcher script to urxvt_launcher. More on this in a second. - Underline links when they are detected. - Use the right mouse button to open links. - Add an additional pattern to search for to make clickable.

Now when normal web links (like http://www.grinchcentral.com/) are found, or my custom subl:// links are clicked, urxvt_launcher will be executed with the underlined text as $1.

The launcher

Bash is not my native language, but it seemed the appropriate tool for this job. I hacked together this script:

1
2
3
4
5
6
7
8
#!/bin/bash

if [[ $1 == 'subl://'* ]]; then
    path=$(echo $1 | sed -e 's|^subl://([^ :]+)(:(\d+))?|\1 :\2|')
    exec subl $path
else
    exec browser $1
fi

This seems to do the trick. If the "url" starts with the string subl://, then it extracts a url and a line number from the argument, and then execs sublime with that information. Otherwise, it runs another script, browser, which is simply a symlink for whatever browser I'm using at the moment.

All of this combined together make nice, clickable links to exactly what line of code is breaking my tests. Time will tell if this is useful but if nothing else, it is quite neat.