Opening Files with Line Numbers in Emacs
Long ago I shared my EmacsClient setup. The short of it was that I always have Emacs running and set $EDITOR in such a way that things like git commit
open a new frame in my existing session. I also had a simple Bash alias that let me open any file in a frame as well:
alias ec="$EMACSCLIENT -c -n"
Where $EMACSCLIENT
is the path to emacsclient
on whatever system I’m on, -c
is to create a new frame for the file, and -n
to tell emacsclient
to exit immediately instead of waiting for me to finish editing.
This has served me well for years. However, there’s one bit of laziness I’ve been wanting to implement. Handling filenames (or file paths) that include line numbers, i.e. filename.rb:123. It’s common for error messages to be spit out in the form of:
./lib/something/somefile.rb:126:in `some_method'
Likewise, test frameworks like rspec will report failing tests in the form of:
./spec/something/somefile_spec.rb:152
If I want to look at that error, I need to select the filename without the line number, paste it to open the file and then go to line 126. Being lazy, I wanted a way to do that in one step. Fortunately, EmacsClient supports opening a file at a given line by adding “+linenumber” to the command line:
emacsclient -c -n +126 lib/something/somefile.rb
I can take advantage of this by replacing my ec
alias with a
function and adding a bit of smarts.
function ec () {
if [[ $1 =~ (.*):([0-9]+)$ ]]; then
$EMACSCLIENT -c -n "+${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}"
else
$EMACSCLIENT -c -n "$@"
fi
}
The if
statement uses a Bash Regular Expression to test if the file
path ends in a colon followed by numbers. If so, it captures the file
path in $BASH_REMATCH[1]
and the line number in $BASH_REMATCH[2]
($BASH_REMATCH[0]
is the everything that matched without regard to
the parentheses). It then adds the +
option to the command line and
follows that with the value of $BASH_REMATCH[2]
and uses
$BASH_REMATCH[1]
for the file path.
If there isn’t a match, it simply uses the argument for the filename, as it always has.
Laziness and Bash functions for the win!
Comments