When An Alias Should Actually Be An Abbr
The short answer is: always.
I really appreciate how tmuxinator
handles completion and aliasing from a fish
shell. You type mux
, and when you hit space it expands into tmuxintor
. From
there you can hit tab to see the options at each step of the way.
I like it so much that I poked around in their
completion
script hoping to crib some gnarly methods and do the same thing with tmux
itself. Well, there are some custom methods therein, however the main feature I
want turns out to be built in to fish
already. It’s called abbr
.
Why !
alias?
- Increased performance.
- This becomes noticeable after a couple hundred or so in my testing.
- Clean history. Using
abbr
means other developers can understand your terminal history. So posting an issue to GitHub doesn’t require manual substitution of your aliases, and another developer won’t have trouble deciphering history on a remote that you worked on with your dotfiles in place. - Easy to use a shortcut that’s close to what you want and edit it.
- If your shortcut conflicts with another executable that you want to run, you can use the arrow keys to edit the expanded text, before fixing it in your dotfiles.
Here’s a four month long GitHub issue about how abbr
came to
be..
A Logical Separation of concerns
With the addition of abbr
, we now have three distinct types of functions to
choose from while programming our programming shortcuts–what? Why, yes, I do like
programming - where did you hear this?
The three types
alias
: Make asomething
functionally equivalent tosomething else
. This holds true if you press return, chain things together, pipe, redirect, and such. In recent versions of fish, context aware tab completion will work here too.abbr
: Typesomething
and have it expanded intosomething else
after pressing space or semicolon (but not return). The new hotness.function
: Makesomething
functionally equivalent to one or moresomething else
s, and optionally permute data that are being worked on with (argv
).
Strictly speaking, alias
is itself just an alias for a function
that blindly
accepts argv
and tacks them to the end of its something else
. But this
pattern is so prolific that it got its own name, so we will consider it unique
for today.
Choosing the right one
Here is how I picture the use cases:
alias
will not be used.abbr
will be employed as the newalias
; it will shorten phrases where we don’t need to do anything special withargv
.function
is for everything else; for when anabbr
permutesargv
and/or is complex/abstract enough to warrant a--description
.
performance notes
Fish has a mechanism in place for
lazily autoloading
custom function definitions. This can have a noticeable performance impact over
just defining them in your config.fish or init.fish or wherever. So it’s a good
idea to keep each function in its own, self-title file in
~/.config/fish/functions/
like so:
# in ~/.config/fish/functions/ll.fish
function ll
ls -lh $argv
end
In case I’m missing something and there is still a use case for alias
,
here’s a fun fact. I heard on the
net
(yes, a pun) that using the fish-style alias
syntax is more performant than
using the =
assignment operator due to an extra sed
call; this was, however,
back in 2013. I didn’t notice much of a difference here, but it’s an easy change
and using a default syntax is always preferred in my book. (Someday maybe: make
or find a fish->bash transpiler.)
alias l='ls'
# should be:
alias l 'ls'
Practical Examples
Time for the straight dope. First up - simple and obvious choice: git
.
abbr --add g 'git'
Type g<space>
and witness the magic. I mean dope,
Now, what if you want to replace a program with another program. I recently
switched to neovim, but for some reason it felt wrong not to type vim
. An
alias will do well here:
abbr --add vim 'nvim'
Note that abbr-ception will not work:
abbr --add v 'vim' # this will still be regular `vim`
What about setting default flags for programs that don’t allow such
configuration? Let’s say we want to default to the long-form ls
, with
classification indicators, but hide user and group info:
abbr ls 'ls -Fog'
The astute observer will note that I forgot to add the --add
here. Well, turns
out we don’t need
it.
And now, on to something more useful. Yes, it’s function time.
Normally naming things is the second most difficult part of computer science (next to cache invalidation), but this was rather easy to name:
function take
mkdir -p $argv;
cd $argv
end
take
is an amalgamation of touch
and mk
(make). It creates a directory and
changes into it. As an added bonus it leverages the -p
flag, which forces the
computer to create the entire path you pass it if it doesn’t exist.
The use case for functions basically starts here. There are multiple
non-sequential calls to argv
from multiple commands.
Here is a more worthy example:
function wait --description "Run a command after some time: wait <minutes> <command args>"
set minutes $argv[1]
set time_in_seconds (math "$minutes*60")
sleep $time_in_seconds; and eval "$argv[2..-1]"
end
Attempted DRYness, two counts
So I at this point, I now have a 261 line file full of abbr --add 'what have
you'
. My DRY senses be tinglin’. Isn’t there a way to neither type, nor look
at, a million abbr
s? Let’s find out.
Well, we can make a temporary helper function to shorten the abbr –add syntax.
function a
abbr --add $argv
end
# do abbrs...
a alias='echo "nope"'
# unset the function
# unset helper function
functions -e a
That’s still repetition though, and it’s confusing for anyone else. What
about a for loop? Fish doesn’t have hashes/dictionaries that I’m aware of, so I
tried reading in lines of a file and passing each one to an abbr
call:
while read -la line
echo "$line"
abbr "$line"
end < $HOME/.config/omf/aliases.load
This way, we can maintain an abbreviations file that purely has:
name 'command here'
another 'another command here'
Well, after 10 minutes of fish complaining “abbr: abbreviation cannot have
spaces in the key
” despite my best efforts to escape and slice/join the string,
I decided to cut my losses and stick with the default.
Someday I’ll learn to leave well enough alone. That will be a really boring day. The next day, I’ll start bothering well enough again.
What have we learned?
- Use
abbr
instead ofalias
. - Use
function
even more. - Fish really is friendly. Unless you want to program a dictionary.
- Don’t stay awake until 1am attempting to bypass built-in functionality of you shell, unless someone is paying you.