Migrating from ZSH to Fish
I've always been using ZSH + Oh My Zsh for my shell configuration, which I have been happy with. But I recently got the urge to try out something new, and I decided to try out fish as it includes many useful features without needing extra configuration. It also has a sweet name.
A note on Fish
Fish is not POSIX compliant, meaning you cannot use it to run your regular bash scripts. Fish-programs has to be written using the fish syntax, which seems easy enough to learn. I do little bash scripting for my regular workflow, and I plan on using fish solely as an interactive shell, so I do not think I will notice this very much
Installation
I used homebrew for a quick and easy installation:
brew install fish
I then added fish to my list of known shells, and used chsh
to set fish as default. After doing these steps, I had to sign out and back in again.
sudo bash -c 'echo $(which fish) >> /etc/shells'
chsh -s $(which fish)
I also had to use the fish_add_path
command for fish to recognize programs installed by homebrew:
fish_add_path /opt/homebrew/bin
Configuring fish
As I mentioned earlier, fish is very useable without any configuration, which I like. I, therefor, have decided to keep my config as clean as possible, without relying on any plugins.
The first thing I did was to set the fuck
alias, and disable the autosuggestion by default, as I found it distracting. I did this in .config/fish/config.fish
.
# ~/.config/fish/config.fish
thefuck --alias | source
set -g fish_autosuggestion_enabled 0
I then found a pretty greeting-function and modified it a bit to only print the greeting for large windows that open in ~
, as I do not want it cluttering the screen while I'm working on something.
# ~/.config/fish/functions/fish_greeting.fish
function fish_greeting
if test $LINES -gt 25; and [ (pwd) = $HOME ]
echo ' '(set_color F00)'___
___======____='(set_color FF7F00)'-'(set_color FF0)'-'(set_color FF7F00)'-='(set_color F00)')
/T \_'(set_color FF0)'--='(set_color FF7F00)'=='(set_color F00)') '(set_color red)(whoami)'@'(hostname)'
[ \ '(set_color FF7F00)'('(set_color FF0)'0'(set_color FF7F00)') '(set_color F00)'\~ \_'(set_color FF0)'-='(set_color FF7F00)'='(set_color F00)')'(set_color yellow)' Uptime: '(set_color white)(uptime | sed 's/.*up \([^,]*\), .*/\1/')(set_color red)'
\ / )J'(set_color FF7F00)'~~ \\'(set_color FF0)'-='(set_color F00)') IP Address: '(set_color white)(ipconfig getifaddr en0)(set_color red)'
\\\\___/ )JJ'(set_color FF7F00)'~'(set_color FF0)'~~ '(set_color F00)'\) '(set_color yellow)'Version: '(set_color white)(echo $FISH_VERSION)(set_color red)'
\_____/JJJ'(set_color FF7F00)'~~'(set_color FF0)'~~ '(set_color F00)'\\
'(set_color FF7F00)'/ '(set_color FF0)'\ '(set_color FF0)', \\'(set_color F00)'J'(set_color FF7F00)'~~~'(set_color FF0)'~~ '(set_color FF7F00)'\\
(-'(set_color FF0)'\)'(set_color F00)'\='(set_color FF7F00)'|'(set_color FF0)'\\\\\\'(set_color FF7F00)'~~'(set_color FF0)'~~ '(set_color FF7F00)'L_'(set_color FF0)'_
'(set_color FF7F00)'('(set_color F00)'\\'(set_color FF7F00)'\\) ('(set_color FF0)'\\'(set_color FF7F00)'\\\)'(set_color F00)'_ '(set_color FF0)'\=='(set_color FF7F00)'__
'(set_color F00)'\V '(set_color FF7F00)'\\\\'(set_color F00)'\) =='(set_color FF7F00)'=_____ '(set_color FF0)'\\\\\\\\'(set_color FF7F00)'\\\\
'(set_color F00)'\V) \_) '(set_color FF7F00)'\\\\'(set_color FF0)'\\\\JJ\\'(set_color FF7F00)'J\)
'(set_color F00)'/'(set_color FF7F00)'J'(set_color FF0)'\\'(set_color FF7F00)'J'(set_color F00)'T\\'(set_color FF7F00)'JJJ'(set_color F00)'J)
(J'(set_color FF7F00)'JJ'(set_color F00)'| \UUU)
(UU)'(set_color normal)
end
end
I also customized the default prompt. I took inspiration from the prompt I had been using from Oh My Zsh (avit), and created a similar looking one for fish:
# ~/.config/fish/functions/fish_prompt.fish
function _git_branch_name
echo (command git symbolic-ref HEAD 2> /dev/null | sed -e 's|^refs/heads/||')
end
function _git_is_dirty
echo (command git status -s --ignore-submodules=dirty 2> /dev/null)
end
function fish_prompt
set -l last_status $status
set -l cyan (set_color cyan)
set -l yellow (set_color yellow)
set -l red (set_color red)
set -l blue (set_color blue)
set -l green (set_color green)
set -l normal (set_color normal)
set -l cwd $blue(pwd | sed "s:^$HOME:~:")
# Add a newline before new prompts
echo -e ''
if set -q VIRTUAL_ENV
echo -n -s (set_color -b cyan black) '[' (basename "$VIRTUAL_ENV") ']' $normal ' '
end
echo -n -s $cwd $normal
if [ (_git_branch_name) ]
set -l git_branch (_git_branch_name)
if [ (_git_is_dirty) ]
set git_info $green $git_branch $red " ✗" $normal
else
set git_info $green $git_branch ' ✔'
end
echo -n -s ' ' $git_info $normal
end
set -l prompt_color $red
if test $last_status = 0
set prompt_color $normal
end
echo -e ''
echo -n -s "$normal▶ "
end
Neovim configuration
I installed fish grammar for treesitter to get syntax highlighting in Neovim. I also had to install ripgrep from homebrew to get telescope live grep working.
:TSinstall fish
brew install ripgrep
Thoughts
I've been using fish for the past couple of days now, and I have to say that I like it alot. After configuring everything, I've noticed how fast the prompt appears compared to Oh My Zsh. I've also been really impressed with fish_config
, which let's you do some configuration from a web interface. This was really useful when deciding on colors for my prompt. I've also been liking the prevd
and nextd
commands which are mapped to alt + left/right arrow
. I also really like that ctrl+c
is shown after terminating stuff.
If you want to copy my setup, feel free to check out my dotfiles!