Mazzarolo MatteoMazzarolo Matteo

Setting up my fish shell from scratch on macOS

By Mazzarolo Matteo


I just got a new MacBook and couldn't remember how to set up the fish shell the way I like ๐Ÿคท.

Below you can find my notes on setting it up from scratch on macOS.

Setup

Install fish

Run the following command to install fish using Homebrew:

brew install fish

Set fish as the default shell

Run the following command to add fish to the list of available shells and set it as the default shell:

echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fish
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fish

Make fish recognize Homebrew's binaries

Add the Homebrew's binaries to the list of fish known binaries (otherwise it won't run commands installed with brew) with the following command:

fish_add_path "/opt/homebrew/bin/"
fish_add_path "/opt/homebrew/bin/"

Create completition files

Parse manual pages installed on the system and attempt to create completion files in the fish configuration directory with the following command:

fish_update_completions

Customizations

Install fisher and fisher plugins:

curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
fisher install jethrokuan/z
fisher install jethrokuan/z
brew install fzf && fisher install patrickf1/fzf.fish
brew install fzf && fisher install patrickf1/fzf.fish
fisher install rstacruz/fish-npm-global
fisher install rstacruz/fish-npm-global
fisher install jorgebucaran/nvm.fish
fisher install jorgebucaran/nvm.fish

Change the fish shell prompt (color/theme)

Add the following to ~/.config/fish/functions/fish_prompt.fish to change the fish theme:

function fish_prompt
    set -l pointer_color red
    test $status = 0; and set pointer_color yellow
 
    set -q __fish_git_prompt_showupstream
    or set -g __fish_git_prompt_showupstream auto
 
    if not set -q VIRTUAL_ENV_DISABLE_PROMPT
        set -g VIRTUAL_ENV_DISABLE_PROMPT true
    end
 
    set_color yellow
    printf '%s' $USER
    set_color normal
    printf ' in '
 
    set_color $fish_color_cwd
    printf '%s' (prompt_pwd --dir-length=0)
    set_color normal
 
    # git
    set_color white -d
    set -l prompt_git (fish_git_prompt '%s')
    test -n "$prompt_git"
    and printf ' %s' $prompt_git
    set_color normal
 
    # Line 2
    echo
    set_color $pointer_color
    printf 'ยป '
    set_color normal
end
function fish_prompt
    set -l pointer_color red
    test $status = 0; and set pointer_color yellow
 
    set -q __fish_git_prompt_showupstream
    or set -g __fish_git_prompt_showupstream auto
 
    if not set -q VIRTUAL_ENV_DISABLE_PROMPT
        set -g VIRTUAL_ENV_DISABLE_PROMPT true
    end
 
    set_color yellow
    printf '%s' $USER
    set_color normal
    printf ' in '
 
    set_color $fish_color_cwd
    printf '%s' (prompt_pwd --dir-length=0)
    set_color normal
 
    # git
    set_color white -d
    set -l prompt_git (fish_git_prompt '%s')
    test -n "$prompt_git"
    and printf ' %s' $prompt_git
    set_color normal
 
    # Line 2
    echo
    set_color $pointer_color
    printf 'ยป '
    set_color normal
end

Allow restarting the shell by running fish

Back in the day, with zsh I was used to restart the shell by running zsh. To do the same with fish, create a new funcion ~/.config/fish/functions/fish.fish:

# A way to reload the shell ร  la "zsh"
function fish
  source ~/.config/fish/config.fish
end
# A way to reload the shell ร  la "zsh"
function fish
  source ~/.config/fish/config.fish
end

To print a new line after any command create a new function ~/.config/fish/functions/postexec_newline.fish:

# Print a new line after any command
# https://stackoverflow.com/a/70644608
function postexec_newline --on-event fish_postexec
   echo
end
# Print a new line after any command
# https://stackoverflow.com/a/70644608
function postexec_newline --on-event fish_postexec
   echo
end

Tweak the config file

Here's my ~/.config/fish/config.fish file.
Protip: when running/customizing external programs in the config file it is a good practice to check if the program executable is available (with if type -q COMMAND_NAME) to avoid errors.

if status is-interactive
    # Commands to run in interactive sessions can go here
end
 
# Disable the fish greeting message
set fish_greeting ""
 
# Print a new line after any command
source ~/.config/fish/functions/postexec_newline.fish
 
# Setup brew
eval "$(/opt/homebrew/bin/brew shellenv)"
 
# Clear line on CTRL + C
# Sometimes it still doesn't work well enough on node.js scripts :(
bind --preset \cC 'cancel-commandline'
 
# Auto-switch nvm version on cd
# Requires a ~/.node-version file with a valid node version
# https://github.com/jorgebucaran/nvm.fish/pull/186
if type -q nvm
  function __nvm_auto --on-variable PWD
  nvm use --silent 2>/dev/null # Comment out the silent flag for debugging
  end
  __nvm_auto
end
 
# Pyenv setup
# Requires `brew install pyenv`
if type -q pyenv
  status --is-interactive; and source (pyenv init -|psub)
end
 
# `ls` โ†’ `ls -laG` abbreviation
abbr -a -g ls ls -laG
 
# `ls` โ†’ `exa` abbreviation
# Requires `brew install exa`
if type -q exa
  abbr --add -g ls 'exa --long --classify --all --header --git --no-user --tree --level 1'
end
 
# `cat` โ†’ `bat` abbreviation
# Requires `brew install bat`
if type -q bat
  abbr --add -g cat 'bat'
end
 
# `rm` โ†’ `trash` abbreviation (moves files to the trash instead of deleting them)
# Requires `brew install trash`
if type -q trash
  abbr --add -g rm 'trash'
end
if status is-interactive
    # Commands to run in interactive sessions can go here
end
 
# Disable the fish greeting message
set fish_greeting ""
 
# Print a new line after any command
source ~/.config/fish/functions/postexec_newline.fish
 
# Setup brew
eval "$(/opt/homebrew/bin/brew shellenv)"
 
# Clear line on CTRL + C
# Sometimes it still doesn't work well enough on node.js scripts :(
bind --preset \cC 'cancel-commandline'
 
# Auto-switch nvm version on cd
# Requires a ~/.node-version file with a valid node version
# https://github.com/jorgebucaran/nvm.fish/pull/186
if type -q nvm
  function __nvm_auto --on-variable PWD
  nvm use --silent 2>/dev/null # Comment out the silent flag for debugging
  end
  __nvm_auto
end
 
# Pyenv setup
# Requires `brew install pyenv`
if type -q pyenv
  status --is-interactive; and source (pyenv init -|psub)
end
 
# `ls` โ†’ `ls -laG` abbreviation
abbr -a -g ls ls -laG
 
# `ls` โ†’ `exa` abbreviation
# Requires `brew install exa`
if type -q exa
  abbr --add -g ls 'exa --long --classify --all --header --git --no-user --tree --level 1'
end
 
# `cat` โ†’ `bat` abbreviation
# Requires `brew install bat`
if type -q bat
  abbr --add -g cat 'bat'
end
 
# `rm` โ†’ `trash` abbreviation (moves files to the trash instead of deleting them)
# Requires `brew install trash`
if type -q trash
  abbr --add -g rm 'trash'
end