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
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
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
- Increased performance.
- This becomes noticeable after a couple hundred or so in my testing.
- Clean history. Using
abbrmeans 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.
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 a
somethingfunctionally equivalent to
something 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.
somethingand have it expanded into
something elseafter pressing space or semicolon (but not return). The new hotness.
somethingfunctionally equivalent to one or more
something elses, and optionally permute data that are being worked on with (
alias is itself just an alias for a
function that blindly
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
Choosing the right one
Here is how I picture the use cases:
aliaswill not be used.
abbrwill be employed as the new
alias; it will shorten phrases where we don’t need to do anything special with
functionis for everything else; for when an
argvand/or is complex/abstract enough to warrant a
Fish has a mechanism in place for
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
here’s a fun fact. I heard on the
(yes, a pun) that using the fish-style
alias syntax is more performant than
= 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'
Time for the straight dope. First up - simple and obvious choice:
abbr --add g 'git'
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
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
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
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
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 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
abbrs? 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
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?
- 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.