things julia likes about fish
(there's a little more in this blog post from 2017)
In 10 years of using fish I have never found a single thing I wanted to configure. It just works the way I want. My fish config file just has:
- environment variables
- aliases
- the occasional
direnv hook fish | source
to integrate a tool like direnv
As I type, it’ll automatically suggest (in light grey) a command that I ran recently. I can press the right arrow key to accept the completion, or keep typing to ignore it.
Here’s what that looks like in practice: (in this example I just typed the “v” key and it guessed that I want to run the previous vim command again)
One of my favourite subtle autocomplete features is how fish handles autocompleting commands that contain paths in them. For example, if I run:
$ ls blah.txt
that command will only be autocompleted in directories that contain blah.txt
-- it won't show up in a different directory. (here's a short comment about how it works)
I honestly didn't understand exactly how this worked for 10 years, it just feels like fish is magically able to suggest the right commands.
If I copy and paste multiple lines, bash will run them all, like this:
[bork@grapefruit linux-playground (main)]$ echo hi
hi
[bork@grapefruit linux-playground (main)]$ touch blah
[bork@grapefruit linux-playground (main)]$ echo hi
hi
Fish will paste them all at a single prompt, so that I can press Enter if I actually want to run them. Much less scary.
bork@grapefruit ~/work/> echo hi
touch blah
echo hi
If I run ls
and press tab, it'll display all the filenames in a nice grid. I can use either Tab, Shift+Tab, or the arrow keys to navigate the grid.
Also, I can tab complete from the middle of a filename -- if the filename starts with a weird character, I can always just type something in the middle and press tab.
Here's what the tab completion looks like:
bork@grapefruit ~/work/> ls
api/ blah.py fly.toml README.md
blah Dockerfile frontend/ test_websocket.sh
I honestly don't complete things other than filenames very much so I can't speak to that, but I've found the experience of tab completing filenames to be very good.
it includes everything I want:
- username
- hostname
- git integration
- status of last command exit (if the last command failed)
The default prompt looks something like this (though there are colours):
bork@grapefruit ~/w/homepage (main) [SIGINT]>
In bash, the maximum history size is 500 by default (????). Also, by default, commands don't get added to your history until you end your session.
In fish:
- the default history size is 256,000 commands. I don't see any reason I'd ever need more.
- Commands are added to the history continuously as you run them: if you open a new tab, everything you've run is immediately available to you
- New commands don't get added to the history of existing terminals though, that would be weird, but they're there if you open a new terminal
(I think I'm not doing the best job explaining how the history works here)
Minor thing but fish disables Ctrl+S. It's a feature that I've never wanted and I'm happy to not have it.
I have mixed feelings about this one, but in Fish you can use fish_add_path /opt/whatever/bin
to add a path to your PATH, globally, permanently, across
all open shell sessions. This can get a bit confusing if you forget where
those PATH entries are configured but overall I think I appreciate it.
By default commands that don't exist are highlighted in red, like this:
I find the loop syntax in fish a lot easier to type than the bash syntax. It looks like this:
for i in *.yaml
echo $i
end
Related to loops: you can edit multiline commands much more easily (just use the arrow keys!) unlike in bash
This might just be me, but I really appreciate that fish has the Ctrl+left arrow
/ Ctrl+right arrow
keyboard shortcut by default for moving between
words when writing a command
Sometimes tools don't have instructions for integrating them with fish which is annoying, but:
- I've found this has gotten better over the last 10 years as fish has gotten more popular
- If I need to run a POSIX shell command real quick, I can always just run
bash
orzsh
- I've gotten much better over the years at translating simple commands to fish syntax when I need to
My biggest day-to-day to annoyance is probably that for whatever reason I've still not
gotten used to fish's syntax for setting environment variables, I get confused
about set
vs set -x
.
Changing my default shell to fish is always a little annoying, I occasionally get myself into a situation where
- I install fish somewhere
- I add the new fish location to
/etc/shells
as an allowed shell - I change my shell with
chsh
- at some point months/years later I reinstall fish in a different location for some reason and remove the old one
- oh no!!! I have no valid shell! I can't open a new terminal tab anymore!
This has never been a major issue because I always have a terminal open somewhere where I can fix the problem and rescue myself, but it's a bit alarming.