splitbrain.org

electronic brain surgery since 2001

Fish Shell

I am using Bash as my shell for as long as I am using Linux.

Over the years I had customized it quite a lot by making my .bashrc load a whole bunch of scripts from a ~/.bashrc.d directory. It worked fine but of course there is only so much you can do with simple aliases and function definitions…

I saw many of my friends switch to zsh, but every time I looked into it I was overwhelmed by its configuration and I wasn't convinced by the “just use oh-my-zsh” argument.

Fish Shell When I stumbled on Fish I was intrigued by it's features and easy configuration approach. I gave it a few halfhearted tries in the past but having to port over my collection of accumulated Bash configs was always holding me back from switching for reals.

This weekend I finally got around to properly switch to Fish. Fish already has the same concept for customizing that I used in Bash by providing a ~/.config/fish/conf.d directory from which any .fish file is loaded automatically. So I spent some time to port over by bash scripts.

Initially I used ChatGPT to help me with the porting, but after a few scripts I quickly got the knack of it myself. It's different but not overly complicated.


Prompt Setup

I spent most of the time fiddling with my prompt setup. Here's what I got so far:

The left hand side shows:

  • The time when the prompt was shown. I sometimes uses this when I have to book my time at work and need to figure out when I started on a particular task.
  • The current user. Normally in green, but highlighted in red when I'm root
  • The hostname. White for the local machine, highlighted in magenta when on a remote host (this of course depends on me being logged into a machine with my fish setup)
  • The current path. Only the last three segments are shown in full, if it gets longer the initial segments are abbreviated.
  • The last non-zero return code is shown in red

Fish also supports a right hand side prompt. I configured this to show:

  • The currently activated Python virtual environment (if any)
  • The current git branch and dirty status (if any)

Finally there's a greeting message. Here I simply highlight if I working local or remotely again. I might add other info here later.

The code for all of this wasn't too terrible to come up with.

.config/fish/conf.d/30-prompt.fish
set -g VIRTUAL_ENV_DISABLE_PROMPT true
set -g __fish_git_prompt_showdirtystate true
set -g __fish_git_prompt_showcolorhints true
set -g __fish_git_prompt_showupstream auto
set -g __fish_git_prompt_char_stateseparator ''
 
function fish_prompt --description 'Write out the prompt'
    set -l last_pipestatus $pipestatus
    set -lx __fish_last_status $status # Export for __fish_print_pipestatus.
    set -l normal (set_color normal)
    set -q fish_color_status
    or set -g fish_color_status red
 
    # Get the current time in HHMM format
    set -l current_time (date '+%H%M')
    set -l time_color (set_color brblue)
 
    # Highlight root with bright red background
    set -l suffix '>'
    set -l user_color (set_color $fish_color_user)
    if fish_is_root_user
        set user_color $normal (set_color -b brred)
        set suffix '#'
    end
 
    # On remote connections color the host name
    set -l host_color $normal
    if set -q SSH_TTY
        set host_color $normal (set_color -b magenta)
    end
 
    # Write pipestatus
    set -l bold_flag --bold
    set -q __fish_prompt_status_generation; or set -g __fish_prompt_status_generation $status_generation
    if test $__fish_prompt_status_generation = $status_generation
        set bold_flag
    end
    set __fish_prompt_status_generation $status_generation
    set -l status_color (set_color $fish_color_status)
    set -l statusb_color (set_color $bold_flag $fish_color_status)
    set -l prompt_status (__fish_print_pipestatus "[" "]" "|" "$status_color" "$statusb_color" $last_pipestatus)
 
    echo -n -s $time_color $current_time $normal
    echo -n -s $user_color (whoami) $host_color '@' (prompt_hostname) ':' $normal
    echo -n -s (set_color $fish_color_cwd) (prompt_pwd --full-length-dirs 3) $normal
    echo -n -s $prompt_status
    echo -n -s $suffix " "
end
 
function fish_right_prompt --description 'Right side prompt for Python venv and Git'
    set -l normal (set_color normal)
 
    # Show active Python virtual environment, if any
    if set -q VIRTUAL_ENV
        set -l venv (basename "$VIRTUAL_ENV")
        set -l venv_color (set_color cyan)
        echo -n -s "($venv_color$venv$normal)"
    end
 
    # Show Git branch and status
    set -l git_info (fish_vcs_prompt)
    if test -n "$git_info"
        echo -n -s "$git_info"
    end
end
 
function fish_greeting
    set -l normal (set_color normal)
 
    set -l greeting_color (set_color cyan)
    set -l login_type "💻 Local session on"
 
    # Detect if logged in via SSH
    if set -q SSH_TTY
        set greeting_color (set_color brmagenta)
        set login_type "🔮 SSH session on"
    end
 
    # Get system information
    set -l host (prompt_hostname)  # Get system hostname
 
    # Display greeting with system information
    echo -e "$greeting_color$login_type $host$normal"
    echo
end

Daily Temp Dir

I am still using the daily temp dir mechanism I blogged about 17 years ago. Porting it to Fish was straight forward:

.config/fish/conf.d/80-tools.fish
# Daily temp dir
set -gx TD "$HOME/temp/$(date +'%Y-%m-%d')"
 
function td
    set td $TD
    if test -n "$argv[1]"
        set td "$HOME/temp/$(date -d "$argv[1] days" +'%Y-%m-%d')"
    else
        ln -s -f -T $td "$HOME/temp/00-today"
    end
    mkdir -p $td
    cd $td
end