Oh My Fish Powerline

Jun 1, 2016


Oh-my-fish powerline

There is a very nice app for theming my favourite shell - fish shell - called Oh-my-fish

To install it run:

curl -L https://github.com/oh-my-fish/oh-my-fish/raw/master/bin/install | fish

Then you can use omf app to install themes

omf install [themeName]

It will modify your ~/.config/fish/config.fish and registr own fish_prompt function.

I modified popular Agnoster theme to my liking.

My ~/.config/fish/config.fish:

# Theme config
set -g theme_display_user yes
set -g theme_hide_hostname yes
set -g default_user root

# Make xfce4-terminal support 256 colors
export TERM=xterm-256color

# Disable default greeting
set fish_greeting

My ~/.config/fish/functions/fish_prompt.fish:

# name: Agnoster
# agnoster's Theme - https://gist.github.com/3712874
# A Powerline-inspired theme for FISH
#
# # README
#
# In order for this theme to render correctly, you will need a
# [Powerline-patched font](https://gist.github.com/1595572).

## Set this options in your config.fish (if you want to :])
# set -g theme_display_user yes
# set -g theme_hide_hostname yes
# set -g theme_hide_hostname no
# set -g default_user your_normal_user



set -g current_bg NONE
set segment_separator \uE0B0
set right_segment_separator \uE0B2
# ===========================
# Helper methods
# ===========================

set -g __fish_git_prompt_showdirtystate 'yes'
set -g __fish_git_prompt_char_dirtystate ' ±'
set -g __fish_git_prompt_char_cleanstate ''

function parse_git_dirty
  set -l submodule_syntax
  set submodule_syntax "--ignore-submodules=dirty"
  set git_dirty (command git status --porcelain $submodule_syntax  2> /dev/null)
  if [ -n "$git_dirty" ]
    if [ $__fish_git_prompt_showdirtystate = "yes" ]
      echo -n "$__fish_git_prompt_char_dirtystate"
    end
  else
    if [ $__fish_git_prompt_showdirtystate = "yes" ]
      echo -n "$__fish_git_prompt_char_cleanstate"
    end
  end
end


# ===========================
# Segments functions
# ===========================

function prompt_segment -d "Function to draw a segment"
  set -l bg
  set -l fg
  if [ -n "$argv[1]" ]
    set bg $argv[1]
  else
    set bg normal
  end
  if [ -n "$argv[2]" ]
    set fg $argv[2]
  else
    set fg normal
  end
  if [ "$current_bg" != 'NONE' -a "$argv[1]" != "$current_bg" ]
    set_color -b $bg
    set_color $current_bg
    echo -n "$segment_separator "
    set_color -b $bg
    set_color $fg
  else
    set_color -b $bg
    set_color $fg
    echo -n " "
  end
  set current_bg $argv[1]
  if [ -n "$argv[3]" ]
    echo -n -s $argv[3] " "
  end
end

function prompt_finish -d "Close open segments"
  if [ -n $current_bg ]
    set_color -b normal
    set_color $current_bg
    echo -n "$segment_separator "
  end
  set -g current_bg NONE
end

# ===========================
# Theme components
# ===========================

#############################
# => Command duration segment
#############################

function prompt_cmd_duration -d 'Displays the elapsed time of last command'
  set -l seconds ''
  set -l minutes ''
  set -l hours ''
  set -l days ''
  # Only if command duration is set  
  if set -q CMD_DURATION
    set -l cmd_duration (expr $CMD_DURATION / 1000)
    if [ $cmd_duration -gt 0 ]
      set seconds (expr $cmd_duration \% 68400 \% 3600 \% 60)'s'
      if [ $cmd_duration -ge 60 ]
        set minutes (expr $cmd_duration \% 68400 \% 3600 / 60)'m'
      end
      if [ $cmd_duration -ge 3600 ]
        set hours (expr $cmd_duration \% 68400 / 3600)'h'
      end
      if [ $cmd_duration -ge 68400 ]
        set days (expr $cmd_duration / 68400)'d'
      end
      prompt_segment black red "$days$hours$minutes$seconds"
    end
  end
end

function prompt_virtual_env -d "Display Python virtual environment"
  if test "$VIRTUAL_ENV"
    prompt_segment white black (basename $VIRTUAL_ENV)
  end
end

function prompt_user -d "Display current user if different from $default_user"
  if [ "$theme_display_user" = "yes" ]
    if [ "$USER" != "$default_user" -o -n "$SSH_CLIENT" ]
      set USER (whoami)
      get_hostname
      if [ $HOSTNAME_PROMPT ]
        set USER_PROMPT $USER@$HOSTNAME_PROMPT
      else
        set USER_PROMPT $USER
      end
      prompt_segment CB4B16 black $USER_PROMPT
    else
      set USER (whoami)
      get_hostname
      if [ $HOSTNAME_PROMPT ]
        set USER_PROMPT $USER@$HOSTNAME_PROMPT
      else
        set USER_PROMPT $USER
      end
      prompt_segment CB4B16 black $USER_PROMPT
    end
  else
    get_hostname
    if [ $HOSTNAME_PROMPT ]
      prompt_segment CB4B16 black $HOSTNAME_PROMPT
    end
  end
end

function get_hostname -d "Set current hostname to prompt variable $HOSTNAME_PROMPT if connected via SSH"
  set -g HOSTNAME_PROMPT ""
  if [ "$theme_hide_hostname" = "no" -o \( "$theme_hide_hostname" != "yes" -a -n "$SSH_CLIENT" \) ]
    set -g HOSTNAME_PROMPT (hostname)
  end
end

function prompt_dir -d "Display the current directory"
  prompt_segment black yellow (prompt_pwd)
end


function prompt_hg -d "Display mercurial state"
  set -l branch
  set -l state
  if command hg id >/dev/null 2>&1
    if command hg prompt >/dev/null 2>&1
      set branch (command hg prompt "{branch}")
      set state (command hg prompt "{status}")
      set branch_symbol \uE0A0
      if [ "$state" = "!" ]
        prompt_segment red white "$branch_symbol $branch ±"
      else if [ "$state" = "?" ]
          prompt_segment yellow black "$branch_symbol $branch ±"
        else
          prompt_segment green black "$branch_symbol $branch"
      end
    end
  end
end


function prompt_git -d "Display the current git state"
  set -l ref
  set -l dirty
  if command git rev-parse --is-inside-work-tree >/dev/null 2>&1
    set dirty (parse_git_dirty)
    set ref (command git symbolic-ref HEAD 2> /dev/null)
    if [ $status -gt 0 ]
      set -l branch (command git show-ref --head -s --abbrev |head -n1 2> /dev/null)
      set ref "➦ $branch"
    end
    set branch_symbol \uE0A0
    set -l branch (echo $ref | sed  "s-refs/heads/-$branch_symbol -")
    if [ "$dirty" != "" ]
      prompt_segment yellow black "$branch$dirty"
    else
      prompt_segment green black "$branch$dirty"
    end
  end
end


function prompt_svn -d "Display the current svn state"
  set -l ref
  if command svn ls . >/dev/null 2>&1
    set branch (svn_get_branch)
    set branch_symbol \uE0A0
    set revision (svn_get_revision)
    prompt_segment green black "$branch_symbol $branch:$revision"
  end
end

function svn_get_branch -d "get the current branch name"
  svn info 2> /dev/null | awk -F/ \
      '/^URL:/ { \
        for (i=0; i<=NF; i++) { \
          if ($i == "branches" || $i == "tags" ) { \
            print $(i+1); \
            break;\
          }; \
          if ($i == "trunk") { print $i; break; } \
        } \
      }'
end

function svn_get_revision -d "get the current revision number"
  svn info 2> /dev/null | sed -n 's/Revision:\ //p'
end


function prompt_status -d "the symbols for a non zero exit status, root and background jobs"
    
    if [ $RETVAL -ne 0 ]
      prompt_segment black red "✘ $RETVAL"
    end

    # if superuser (uid == 0)
    #set -l uid (id -u $USER)
    #if [ $uid -eq 0 ]
    #  prompt_segment black yellow "⚡"
    #end

    # Jobs display
    if [ (jobs -l | wc -l) -gt 0 ]
      prompt_segment black cyan "⚙"
    end

end

function prompt_root -d "the symbols for root"

    # if superuser (uid == 0)
    set -l uid (id -u $USER)
    if [ $uid -eq 0 ]
      prompt_segment CB4B16 black "⚡"
    end

end

# ===========================
# Apply theme
# ===========================

function fish_prompt
  set -g RETVAL $status
# prompt_virtual_env
  prompt_user
  prompt_dir
  type -q hg;  and prompt_hg
  type -q git; and prompt_git
  type -q svn; and prompt_svn
  prompt_cmd_duration
  prompt_status
# prompt_root
  prompt_finish
end

And finally I added own ~/.config/fish/functions/fish_right_prompt.fish:

function prompt_finish_right -d "Close open right segments"
  set_color -b normal
  set_color black
  echo -n "$right_segment_separator"

	set_color -b black 
	set_color yellow
	echo -n " "
	date "+%H:%M:%S %d/%m/%Y"
	echo -n " "
	set_color normal


end

# ===========================
# Apply theme
# ===========================

function fish_right_prompt -d "Write out the right prompt"
	prompt_finish_right
end

To support this config for root user too you need to run following commands (replace [username] for your own)

cd /root/.config/
ln -s /home/[username]/.config/omf/ omf
mkdir /root/.config/fish/functions
cd /root/.config/fish/functions
ln -s /home/[username]/.local/share/omf/themes/agnoster/fish_prompt.fish fish_prompt.fish

Here is updated config of prompt ~/.config/fish/functions/fish_prompt.fish which plays nicely with cool-retro-term app.

# name: Agnoster
# agnoster's Theme - https://gist.github.com/3712874
# A Powerline-inspired theme for FISH
#
# # README
#
# In order for this theme to render correctly, you will need a
# [Powerline-patched font](https://gist.github.com/1595572).

## Set this options in your config.fish (if you want to :])
# set -g theme_display_user yes
# set -g theme_hide_hostname yes
# set -g theme_hide_hostname no
# set -g default_user your_normal_user



set -g current_bg NONE
set segment_separator \uE0B0
#set segment_separator \u25B6
set right_segment_separator \uE0B2
# ===========================
# Helper methods
# ===========================

set -g __fish_git_prompt_showdirtystate 'yes'
set -g __fish_git_prompt_char_dirtystate ' ±'
set -g __fish_git_prompt_char_cleanstate ''

function parse_git_dirty
  set -l submodule_syntax
  set submodule_syntax "--ignore-submodules=dirty"
  set git_dirty (command git status --porcelain $submodule_syntax  2> /dev/null)
  if [ -n "$git_dirty" ]
    if [ $__fish_git_prompt_showdirtystate = "yes" ]
      echo -n "$__fish_git_prompt_char_dirtystate"
    end
  else
    if [ $__fish_git_prompt_showdirtystate = "yes" ]
      echo -n "$__fish_git_prompt_char_cleanstate"
    end
  end
end


# ===========================
# Segments functions
# ===========================

function prompt_segment -d "Function to draw a segment"
  set -l bg
  set -l fg
  if [ -n "$argv[1]" ]
    set bg $argv[1]
  else
    set bg normal
  end
  if [ -n "$argv[2]" ]
    set fg $argv[2]
  else
    set fg normal
  end
  if [ "$current_bg" != 'NONE' -a "$argv[1]" != "$current_bg" ]
    set_color -b $bg
    set_color $current_bg
    echo -n "$segment_separator "
    set_color -b $bg
    set_color $fg
  else
    set_color -b $bg
    set_color $fg
    echo -n " "
  end
  set current_bg $argv[1]
  if [ -n "$argv[3]" ]
    echo -n -s $argv[3] " "
  end
end

function prompt_finish -d "Close open segments"
  if [ -n $current_bg ]
    set_color -b normal
    set_color $current_bg
    echo -n "$segment_separator "
  end
  set -g current_bg NONE
  # reset cursor color
  set_color normal
end

# ===========================
# Theme components
# ===========================

#############################
# => Command duration segment
#############################

function prompt_cmd_duration -d 'Displays the elapsed time of last command'
  set -l seconds ''
  set -l minutes ''
  set -l hours ''
  set -l days ''
  # Only if command duration is set  
  if set -q CMD_DURATION
    set -l cmd_duration (expr $CMD_DURATION / 1000)
    if [ $cmd_duration -gt 0 ]
      set seconds (expr $cmd_duration \% 68400 \% 3600 \% 60)'s'
      if [ $cmd_duration -ge 60 ]
        set minutes (expr $cmd_duration \% 68400 \% 3600 / 60)'m'
      end
      if [ $cmd_duration -ge 3600 ]
        set hours (expr $cmd_duration \% 68400 / 3600)'h'
      end
      if [ $cmd_duration -ge 68400 ]
        set days (expr $cmd_duration / 68400)'d'
      end
      prompt_segment black green "$days$hours$minutes$seconds"
    end
  end
end

function prompt_virtual_env -d "Display Python virtual environment"
  if test "$VIRTUAL_ENV"
    prompt_segment white black (basename $VIRTUAL_ENV)
  end
end

function prompt_user -d "Display current user if different from $default_user"
  if [ "$theme_display_user" = "yes" ]
    if [ "$USER" != "$default_user" -o -n "$SSH_CLIENT" ]
      set USER (whoami)
      get_hostname
      if [ $HOSTNAME_PROMPT ]
        set USER_PROMPT $USER@$HOSTNAME_PROMPT
      else
        set USER_PROMPT $USER
      end
      prompt_segment CB4B16 black $USER_PROMPT
    else
      set USER (whoami)
      get_hostname
      if [ $HOSTNAME_PROMPT ]
        set USER_PROMPT $USER@$HOSTNAME_PROMPT
      else
        set USER_PROMPT $USER
      end
      prompt_segment red black $USER_PROMPT
    end
  else
    get_hostname
    if [ $HOSTNAME_PROMPT ]
      prompt_segment CB4B16 black $HOSTNAME_PROMPT
    end
  end
end

function get_hostname -d "Set current hostname to prompt variable $HOSTNAME_PROMPT if connected via SSH"
  set -g HOSTNAME_PROMPT ""
  if [ "$theme_hide_hostname" = "no" -o \( "$theme_hide_hostname" != "yes" -a -n "$SSH_CLIENT" \) ]
    set -g HOSTNAME_PROMPT (hostname)
  end
end

function prompt_dir -d "Display the current directory"
  prompt_segment AC8C01 black (prompt_pwd)
end


function prompt_hg -d "Display mercurial state"
  set -l branch
  set -l state
  if command hg id >/dev/null 2>&1
    if command hg prompt >/dev/null 2>&1
      set branch (command hg prompt "{branch}")
      set state (command hg prompt "{status}")
      set branch_symbol \uE0A0
      if [ "$state" = "!" ]
        prompt_segment red white "$branch_symbol $branch ±"
      else if [ "$state" = "?" ]
          prompt_segment AC8C01 black "$branch_symbol $branch ±"
        else
          prompt_segment green black "$branch_symbol $branch"
      end
    end
  end
end


function prompt_git -d "Display the current git state"
  set -l ref
  set -l dirty
  if command git rev-parse --is-inside-work-tree >/dev/null 2>&1
    set dirty (parse_git_dirty)
    set ref (command git symbolic-ref HEAD 2> /dev/null)
    if [ $status -gt 0 ]
      set -l branch (command git show-ref --head -s --abbrev |head -n1 2> /dev/null)
      set ref "➦ $branch"
    end
    set branch_symbol \uE0A0
    set -l branch (echo $ref | sed  "s-refs/heads/-$branch_symbol -")
    if [ "$dirty" != "" ]
      prompt_segment E9B96E black "$branch$dirty"
    else
      prompt_segment green black "$branch$dirty"
    end
  end
end


function prompt_svn -d "Display the current svn state"
  set -l ref
  if command svn ls . >/dev/null 2>&1
    set branch (svn_get_branch)
    set branch_symbol \uE0A0
    set revision (svn_get_revision)
    prompt_segment green black "$branch_symbol $branch:$revision"
  end
end

function svn_get_branch -d "get the current branch name"
  svn info 2> /dev/null | awk -F/ \
      '/^URL:/ { \
        for (i=0; i<=NF; i++) { \
          if ($i == "branches" || $i == "tags" ) { \
            print $(i+1); \
            break;\
          }; \
          if ($i == "trunk") { print $i; break; } \
        } \
      }'
end

function svn_get_revision -d "get the current revision number"
  svn info 2> /dev/null | sed -n 's/Revision:\ //p'
end


function prompt_status -d "the symbols for a non zero exit status, root and background jobs"
    
    if [ $RETVAL -ne 0 ]
      prompt_segment red black "✘ $RETVAL"
    end

    # if superuser (uid == 0)
    #set -l uid (id -u $USER)
    #if [ $uid -eq 0 ]
    #  prompt_segment black yellow "⚡"
    #end

    # Jobs display
    if [ (jobs -l | wc -l) -gt 0 ]
      prompt_segment black cyan "⚙"
    end

end

function prompt_root -d "the symbols for root"

    # if superuser (uid == 0)
    set -l uid (id -u $USER)
    if [ $uid -eq 0 ]
      prompt_segment CB4B16 black "⚡"
    end

end

# ===========================
# Apply theme
# ===========================

function fish_prompt
  set -g RETVAL $status
# prompt_virtual_env
  prompt_user
  prompt_dir
# type -q hg;  and prompt_hg
  type -q git; and prompt_git
# type -q svn; and prompt_svn
  prompt_status
  prompt_cmd_duration
# prompt_root
  prompt_finish
end