Sublime, urxvt, and nose-progressive
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:
#!/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 exec
s 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.