Vim mappings for the win

I mostly work in source code hierarchies where for a given source file X.source the location of the file with the unit tests is tests/test_X.source and more often than not I need to do edit the unit tests after having opened the actual source file.

Being the geek that I am I *obviously* need to come up with some sort of optimisation or shortcut even if it takes 10x as long as stupidly typing in ":e tests/test_X.source" all the time :-)

Thankfully, the solution in vim turns out to be quite straightforward. The following mapping (conveniently added to your $HOME/.vimrc file) will open the unit test file when you type %%

nnoremap %% :e =escape(expand("%:h")."/tests/test_".expand("%:t"), "")^M

Please note that the last bit ("^M") is just one character (the Enter key) that you can get by typing ^V followed by the Enter key.

I guess what I should really do is write a configurable vim plugin that opens arbitrary files/locations based on the current buffer/location. Oh well, so much to do and so little time :P

Tool of the year!

I have been suffering from the multiple clipboards “feature” under X-Windows/Gnome for quite a while and finally found a solution: parcellite.

Install it, run it, right-click on the icon, select “preferences” from the menu, check “Use Primary (Selection)” and “Synchronize clipboards” in the “Behavior” tab.

.. and enjoy life again :-)

Combining ack-grep and xargs

Gotta love the command line..

I use ack-grep a lot and really, really like it. Kudos to the author and to the maintainer who takes care of the ubuntu package :-)

Sometimes though I was missing grep‘s --exclude feature that allows me to ignore certain paths while searching.

There are occasions where I e.g. want to see calls to a certain function in the code base but I am not interested in tests. Today I found an (embarrassingly) easy way to get that behaviour using xargs:

$ find . -name \*.py | grep -v tests/ | xargs ack-grep -C 3 -w 'Message\('

The snippet above first accumulates the paths of interests, then filters them and finally lets ack-grep loose on them.

Ta-da! There you go :-)

Determine order of execution by (re-)sequencing your source code files

Introduction

At times you’ll want to determine the order in which code is executed by naming the source code files correspondingly. This “trick” is particularly popular in server software and operating systems development.

Here’s a “random example” of file sequencing (found on a Debian system):

  1 /etc/rc2.d# ls -la | head
  2 total 12
  3 drwxr-xr-x 2 root root 4096 May 14 16:59 ./
  4 drwxr-xr-x 152 root root 8192 May 15 05:51 ../
  5 lrwxrwxrwx 1 root root 18 Mar 9 2003 S10sysklogd -> ../init.d/sysklogd*
  6 lrwxrwxrwx 1 root root 15 Mar 9 2003 S11klogd -> ../init.d/klogd*
  7 lrwxrwxrwx 1 root root 13 Apr 13 22:38 S14ppp -> ../init.d/ppp*
  8 lrwxrwxrwx 1 root root 17 Apr 25 15:31 S15dnsmasq -> ../init.d/dnsmasq*
  9 lrwxrwxrwx 1 root root 14 Mar 29 2003 S20alsa -> ../init.d/alsa*
 10 lrwxrwxrwx 1 root root 16 Apr 30 11:13 S20cupsys -> ../init.d/cupsys*
 11 lrwxrwxrwx 1 root root 18 Mar 12 16:45 S20darkstat -> ../init.d/darkstat*

The resequence.py tool (syntax highlighted code here) helps you to maintain such collections of files.

By the way, if you are writing Python code that needs to find and manipulate files you may also want to check out the scriptutil.py module described in this article.

Usage examples

Using the shell commands below I am creating 3 randomly named files in the files sub-directory (lines 3-5).

  1 bbox33:resequence $ for n in `jot -r -c 15 a z | rs -g 0 5`; do touch files/$n; done
  2 bbox33:resequence $ find . -type f | grep -v swp
  3 ./files/emnuw
  4 ./files/nnrln
  5 ./files/qkmbe
  6 ./resequence.py

The resequence.py tool invoked without any command line arguments will merely print a help text which is considered a security feature :-)

  7 bbox33:resequence $ python resequence.py
  8 resequence.py: a tool to rename a set of numbered files so that they
  9 are 10 "slots" apart.
 10 
 11 resequence.py [-n] [-p path] [-v]
 12 
 13     -c cmd  | --cmd cmd   : rename command to use (default: 'mv')
 14     -n      | --noaction  : no action, just show what would be done
 15     -p path | --path path : path where the files reside
 16     -v      | --verbose   : verbose output
 17 
 18 For help use --help

When invoked with the -n (“no action”) command line argument, the tool will only print a summary of what needs to be done but will not take any action.

 19 bbox33:resequence $ python resequence.py -n -p files
 20 mv files/emnuw files/010-emnuw
 21 mv files/nnrln files/020-nnrln
 22 mv files/qkmbe files/030-qkmbe

When run with the -v command line argument, the tool will actually rename files as needed and show what is being done (since it is invoked in “verbose” mode).

 23 bbox33:resequence $ python resequence.py -v -p files
 24 running: 'mv files/emnuw files/010-emnuw'
 25 running: 'mv files/nnrln files/020-nnrln'
 26 running: 'mv files/qkmbe files/030-qkmbe'

Here I am adding one more file (see lines 27 and 32)..

 27 bbox33:resequence $ touch files/another
 28 bbox33:resequence $ find . -type f | grep -v swp
 29 ./files/010-emnuw
 30 ./files/020-nnrln
 31 ./files/030-qkmbe
 32 ./files/another
 33 ./resequence.py

.. and calling the tool to show me what needs to be done (line 34) and to actually do the job (line 36).

 34 bbox33:resequence $ python resequence.py -n -p files
 35 mv files/another files/040-another
 36 bbox33:resequence $ python resequence.py -v -p files
 37 ok: files/010-emnuw
 38 ok: files/020-nnrln
 39 ok: files/030-qkmbe
 40 running: 'mv files/another files/040-another'

In the example below I am creating another file (see lines 41 and 46) that’s inserted in the existing sequence ..

 41 bbox33:resequence $ touch files/035-xxx
 42 bbox33:resequence $ find . -type f | grep -v swp
 43 ./files/010-emnuw
 44 ./files/020-nnrln
 45 ./files/030-qkmbe
 46 ./files/035-xxx
 47 ./files/040-another
 48 ./resequence.py

.. and, again, running the tool to rename the files as needed (line 52).

 49 bbox33:resequence $ python resequence.py -n -p files
 50 mv files/035-xxx files/040-xxx
 51 mv files/040-another files/050-another
 52 bbox33:resequence $ python resequence.py -v -p files
 53 ok: files/010-emnuw
 54 ok: files/020-nnrln
 55 ok: files/030-qkmbe
 56 running: 'mv files/035-xxx files/040-xxx'
 57 running: 'mv files/040-another files/050-another'

Enjoy!