My ZSH Config (.zshrc)

January 14, 2016

I spent the last few weeks setting up ZSH the way I want it. I’m pretty happy with the result, so I figured I’d share.

If you just want to download it and skip the explanation below, here’s the github link.

Screenshot

Pictures are worth a thousand words, so here’s what it looks like:

 

console

There are a bunch of other things not pictured, like colored grep results, the prompt turns red if you’re root, and all of the sweet interactive stuff that ZSH offers.

Summary

My .zshrc is made up of a handful of files:

I also use a custom font, which is necessary for the pretty prompt. The “powerline” fonts are edited to include a few special characters that can make your prompt look sweeter. If you don’t have these characters edited into your font, my prompt won’t look right on your system. You can get my font here: DejaVu Sans Mono (Powerline).

Download Everything

Here’s an easy-to-download zip that has all of the files enclosed: config.zip

File Stucture / Setup

I put most of my config files in “.config” in my home directory, and create symlinks to them. On most of my computers, “.config” links to a dropbox folder, so I get immediate updates. Here are two screenshots which might make things more clear:

dir-structure1

dir-structure2

~/.ssh/config is a hard link to ~/.config/.ssh/config, because SSH is picky about ownership and permissions on that file.

Why don’t I use .oh-my-zsh?

I don’t like that it is large and does a bunch of stuff I don’t need. It’s great, but I wanted more control and less mess.

Limitations

There are probably a bunch more, but these are the main things that jump out at me.

Why use ZSH instead of BASH

Because it’s better. It feels just like bash, but it does a lot of things in better ways. There are plenty of posts out in the wild about this topic. I haven’t found one good reason to run bash instead of zsh.

Update October 10, 2016

I removed the timestamp after commands. It was causing a small delay after every command which was annoying.

.zshrc

# Written by Josh Hartwell
# Borrowed from a lot of places, especially .oh-my-zsh
# Version 3 - 2016/08/20

local ZSH_CONF=$HOME/.zsh                      # Define the place I store all my zsh config stuff
local ZSH_CACHE=$ZSH_CONF/cache                # for storing files like history and zcompdump 
local LOCAL_ZSHRC=$HOME/.zshlocal/.zshrc       # Allow the local machine to have its own overriding zshrc if it wants it

# Load external config files and tools
   source $ZSH_CONF/functions.zsh              # Load misc functions. Done in a seperate file to keep this from getting too long and ugly
   source $ZSH_CONF/spectrum.zsh               # Make nice colors available
   source $ZSH_CONF/prompts.zsh                # Setup our PS1, PS2, etc.
   source $ZSH_CONF/termsupport.zsh            # Set terminal window title and other terminal-specific things

# Set important shell variables
   export EDITOR=vim                           # Set default editor
   export WORDCHARS=''                         # This is the oh-my-zsh default, I think I'd like it to be a bit different 
   export PAGER=less                           # Set default pager
   export LESS="-R"                            # Set the default options for less 
   export LANG="en_US.UTF-8"                   # I'm not sure who looks at this, but I know it's good to set in general
   
# Misc
   setopt ZLE                                  # Enable the ZLE line editor, which is default behavior, but to be sure
   declare -U path                             # prevent duplicate entries in path
   eval $(dircolors $ZSH_CONF/dircolors)       # Uses custom colors for LS, as outlined in dircolors
   LESSHISTFILE="/dev/null"                    # Prevent the less hist file from being made, I don't want it
   umask 002                                   # Default permissions for new files, subract from 777 to understand
   setopt NO_BEEP                              # Disable beeps
   setopt AUTO_CD                              # Sends cd commands without the need for 'cd'
   setopt MULTI_OS                             # Can pipe to mulitple outputs
   unsetopt NO_HUP                             # Kill all child processes when we exit, don't leave them running
   setopt INTERACTIVE_COMMENTS                 # Allows comments in interactive shell.
   setopt RC_EXPAND_PARAM                      # Abc{$cool}efg where $cool is an array surrounds all array variables individually
   unsetopt FLOW_CONTROL                       # Ctrl+S and Ctrl+Q usually disable/enable tty input. This disables those inputs
   setopt LONG_LIST_JOBS                       # List jobs in the long format by default. (I don't know what this does but it sounds good)
   setopt vi                                   # Make the shell act like vi if i hit escape

# ZSH History 
   alias history='fc -fl 1'
   HISTFILE=$ZSH_CACHE/history                 # Keep our home directory neat by keeping the histfile somewhere else
   SAVEHIST=10000                              # Big history
   HISTSIZE=10000                              # Big history
   setopt EXTENDED_HISTORY                     # Include more information about when the command was executed, etc
   setopt APPEND_HISTORY                       # Allow multiple terminal sessions to all append to one zsh command history
   setopt HIST_FIND_NO_DUPS                    # When searching history don't display results already cycled through twice
   setopt HIST_EXPIRE_DUPS_FIRST               # When duplicates are entered, get rid of the duplicates first when we hit $HISTSIZE 
   setopt HIST_IGNORE_SPACE                    # Don't enter commands into history if they start with a space
   setopt HIST_VERIFY                          # makes history substitution commands a bit nicer. I don't fully understand
   setopt SHARE_HISTORY                        # Shares history across multiple zsh sessions, in real time
   setopt HIST_IGNORE_DUPS                     # Do not write events to history that are duplicates of the immediately previous event
   setopt INC_APPEND_HISTORY                   # Add commands to history as they are typed, don't wait until shell exit
   setopt HIST_REDUCE_BLANKS                   # Remove extra blanks from each command line being added to history

# ZSH Auto Completion
   # Figure out the short hostname
   if [[ "$OSTYPE" = darwin* ]]; then          
      # OS X's $HOST changes with dhcp, etc., so use ComputerName if possible.
      SHORT_HOST=$(scutil --get ComputerName 2>/dev/null) || SHORT_HOST=${HOST/.*/}
   else
      SHORT_HOST=${HOST/.*/}
   fi

   #the auto complete dump is a cache file where ZSH stores its auto complete data, for faster load times
   local ZSH_COMPDUMP="$ZSH_CACHE/acdump-${SHORT_HOST}-${ZSH_VERSION}"  #where to store autocomplete data

   autoload -U compinit                                    # Autoload auto completion
   compinit -i -d "${ZSH_COMPDUMP}"                        # Init auto completion; tell where to store autocomplete dump
   zstyle ':completion:*' menu select                      # Have the menu highlight as we cycle through options
   zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'     # Case-insensitive (uppercase from lowercase) completion
   setopt COMPLETE_IN_WORD                                 # Allow completion from within a word/phrase
   setopt ALWAYS_TO_END                                    # When completing from the middle of a word, move cursor to end of word
   setopt MENU_COMPLETE                                    # When using auto-complete, put the first option on the line immediately
   setopt COMPLETE_ALIASES                                 # Turn on completion for aliases as well
   setopt LIST_ROWS_FIRST                                  # Cycle through menus horizontally instead of vertically

# Globbing
   setopt NO_CASE_GLOB                         # Case insensitive globbing
   setopt EXTENDED_GLOB                        # Allow the powerful zsh globbing features, see link:
   # http://www.refining-linux.org/archives/37/ZSH-Gem-2-Extended-globbing-and-expansion/
   setopt NUMERIC_GLOB_SORT                    # Sort globs that expand to numbers numerically, not by letter (i.e. 01 2 03)
   
# Aliases
   git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%C(bold blue)<%an>%Creset' --abbrev-commit" 

   alias -g ...='../..'
   alias -g ....='../../..'
   alias -g .....='../../../..'
   alias -g ......='../../../../..'
   alias -g .......='../../../../../..'
   alias -g ........='../../../../../../..'
   
   alias ls="ls -h --color='auto'"
   alias lsa='ls -a'
   alias ll='ls -l'
   alias la='ls -la'
   alias cdl=changeDirectory; function changeDirectory { cd $1 ; la }

   alias md='mkdir -p'
   alias rd='rmdir'

   # Search running processes. Usage: psg 
   alias psg="ps aux $( [[ -n "$(uname -a | grep CYGWIN )" ]] && echo '-W') | grep -i $1"

   # Copy with a progress bar
   alias cpv="rsync -poghb --backup-dir=/tmp/rsync -e /dev/null --progress --" 

   alias d='dirs -v | head -10'                      # List the last ten directories we've been to this session, no duplicates

   alias google='web_search google'                  # Note: websearch function is loaded in function file, see above
   alias ddg='web_search ddg'
   alias github='web_search github'
   alias wiki='web_search ddg \!w'
   alias news='web_search ddg \!n'
   alias youtube='web_search ddg \!yt'
   alias map='web_search ddg \!m'
   alias image='web_search ddg \!i'

# Key Bindings
   bindkey "^K" kill-whole-line                      # [Ctrl-K] erase whole line
   bindkey '^[[1;5C' forward-word                    # [Ctrl-RightArrow] - move forward one word
   bindkey '^[[1;5D' backward-word                   # [Ctrl-LeftArrow] - move backward one word                    
   bindkey '^?' backward-delete-char                 # [Backspace] - delete backward
   bindkey "${terminfo[kdch1]}" delete-char          # [Delete] - delete forward
   bindkey '\e[2~' overwrite-mode                    # [Insert] - toggles overwrite mode                  
   bindkey "${terminfo[kpp]}" up-line-or-history     # [PageUp] - Up a line of history
   bindkey "${terminfo[knp]}" down-line-or-history   # [PageDown] - Down a line of history
   bindkey "^[[A" history-search-backward            # start typing + [Up-Arrow] - fuzzy find history forward  
   bindkey "^[[B" history-search-forward             # start typing + [Down-Arrow] - fuzzy find history backward
   bindkey '\e[H' beginning-of-line                  # Note: this works on cygwin/mintty, may not work on other systems 
   bindkey '\e[F' end-of-line                        # Note: this works on cygwin/mintty, may not work on other systems
   bindkey "\e\e" sudo-command-line                  # [Esc] [Esc] - insert "sudo" at beginning of line
      zle -N sudo-command-line
      sudo-command-line() {
            [[ -z $BUFFER ]] && zle up-history
            if [[ $BUFFER == sudo\ * ]]; then
                  LBUFFER="${LBUFFER#sudo }"
            else
                  LBUFFER="sudo $LBUFFER"
            fi
      }
      
# Setup grep to be a bit more nice
  # check if 'x' grep argument available
   grep-flag-available() {
         echo | grep $1 "" >/dev/null 2>&1
   }

   local GREP_OPTIONS=""

   # color grep results
   if grep-flag-available --color=auto; then
         GREP_OPTIONS+=" --color=auto"
   fi

   # ignore VCS folders (if the necessary grep flags are available)
   local VCS_FOLDERS="{.bzr,CVS,.git,.hg,.svn}"

   if grep-flag-available --exclude-dir=.cvs; then
         GREP_OPTIONS+=" --exclude-dir=$VCS_FOLDERS"
   elif grep-flag-available --exclude=.cvs; then
         GREP_OPTIONS+=" --exclude=$VCS_FOLDERS"
   fi

   # export grep settings
   alias grep="grep $GREP_OPTIONS"

   # clean up
   unfunction grep-flag-available

# Allow local zsh settings (superseding anything in here) in case I want something specific for certain machines
  if [[ -r $LOCAL_ZSHRC ]]; then
    source $LOCAL_ZSHRC
  fi

functions.zsh

# intellegently extract archives based on extension. 
function extract {  
   
   file=$1
   dir=$2

   if [[ -n $dir ]]; then
      mkdir -p $dir; 
      echo Extracting $1 into $2 ...
   else 
      echo Extracting $1 ...
   fi

   if [[ ! -f $1 ]] ; then
      echo "'$1' is not a valid file"
   else
      case $1 in
         *.tar.bz2)   
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar xjvf $1 $dc" 
             echo $cmd
             eval ${cmd}
             ;;   
         *.tar.gz)    
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar xzvf $1 $dc"; 
             echo $cmd;
             eval ${cmd}
             ;;
         *.tar)       
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar vxf $1 $dc";
             echo $cmd;
             eval ${cmd}
             ;;
         *.tbz2)      
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar xjvf $1 $dc";
             echo $cmd; 
             eval ${cmd}
             ;;  
         *.tgz) 
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar xzf $1 $dc"; 
             echo $cmd; 
             eval ${cmd} 
             ;;    
         *.bz2)       
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar jf $1 $dc"; 
             echo $cmd; 
             eval ${cmd} 
             ;;     
         *.zip)       
             if [[ -n $dir ]]; then dc="-d $dir"; fi
             cmd="unzip $1 $dc"; 
             echo $cmd; 
             eval ${cmd}
             ;;
         *.gz)
             if [[ -n $dir ]]; then dc="-C $dir"; fi
             cmd="tar zf $1 $dc"; 
             echo $cmd; 
             eval ${cmd}
             ;;
         *.7z)        
             #TODO dir
             cmd="7z x -o$dir $1"; 
             echo $cmd; 
             eval ${cmd} 
             ;;
         *.rar)       
             #TODO Dir
             cmd="unrar x $1 $dir";
             echo $cmd;
             eval ${cmd}
             ;;
         *)           
            echo "'$1' cannot be extracted via extract()" 
            ;;
         esac
   fi
}

# Make a directory and cd into it
function take {
	mkdir -p $1
	cd $1
}

# web_search from terminal
function web_search() {
  emulate -L zsh

  # define search engine URLS
  typeset -A urls
  urls=(
    google      "https://www.google.com/search?q="
    ddg         "https://www.duckduckgo.com/?q="
    github      "https://github.com/search?q="
  )

  # check whether the search engine is supported
  if [[ -z "$urls[$1]" ]]; then
    echo "Search engine $1 not supported."
    return 1
  fi

  # search or go to main page depending on number of arguments passed
  if [[ $# -gt 1 ]]; then
    # build search url:
    # join arguments passed with '+', then append to search engine URL
    url="${urls[$1]}${(j:+:)@[2,-1]}"
  else
    # build main page url:
    # split by '/', then rejoin protocol (1) and domain (2) parts with '//'
    url="${(j://:)${(s:/:)urls[$1]}[1,2]}"
  fi

  open_command "$url"
}

#use generalized open command
function open_command() {
  emulate -L zsh
  setopt shwordsplit

  local open_cmd

  # define the open command
  case "$OSTYPE" in
    darwin*)  open_cmd='open' ;;
    cygwin*)  open_cmd='cygstart' ;;
    linux*)   open_cmd='xdg-open' ;;
    msys*)    open_cmd='start ""' ;;
    *)        echo "Platform $OSTYPE not supported"
              return 1
              ;;
  esac

  # don't use nohup on OSX
  if [[ "$OSTYPE" == darwin* ]]; then
    $open_cmd "$@" &>/dev/null
  else
    nohup $open_cmd "$@" &>/dev/null
  fi
}

# Show dots while waiting for tab-completion
expand-or-complete-with-dots() {
	# toggle line-wrapping off and back on again
	[[ -n "$terminfo[rmam]" && -n "$terminfo[smam]" ]] && echoti rmam
	print -Pn "%{%F{red}......%f%}"
	[[ -n "$terminfo[rmam]" && -n "$terminfo[smam]" ]] && echoti smam

	zle expand-or-complete
	zle redisplay
}
zle -N expand-or-complete-with-dots
bindkey "^I" expand-or-complete-with-dots

spectrum.zsh

# A script to make using 256 colors in zsh less painful.
# P.C. Shyamshankar <sykora@lucentbeing.com>
# Copied from http://github.com/sykora/etc/blob/master/zsh/functions/spectrum/

autoload -U colors && colors
export LSCOLORS="Gxfxcxdxbxegedabagacad"

typeset -AHg FX FG BG

FX=(
  reset     "%{%}"
  bold      "%{%}" no-bold      "%{%}"
  italic    "%{%}" no-italic    "%{%}"
  underline "%{%}" no-underline "%{%}"
  blink     "%{%}" no-blink     "%{%}"
  reverse   "%{%}" no-reverse   "%{%}"
)

for color in {000..255}; do
  FG[$color]="%{[38;5;${color}m%}"
  BG[$color]="%{[48;5;${color}m%}"
done


ZSH_SPECTRUM_TEXT=${ZSH_SPECTRUM_TEXT:-Arma virumque cano Troiae qui primus ab oris}

# Show all 256 colors with color number
function spectrum_ls() {
for code in {000..255}; do
  print -P -- "$code: %{$FG[$code]%}$ZSH_SPECTRUM_TEXT%{$reset_color%}"
done
}

# Show all 256 colors where the background is set to specific color
function spectrum_bls() {
for code in {000..255}; do
  print -P -- "$code: %{$BG[$code]%}$ZSH_SPECTRUM_TEXT%{$reset_color%}"
done
}

prompts.zsh

#/usr/bin/zsh
#/usr/bin/zsh
#if we're in a situation where we don't want colors
#these variables aren't initialized and
#so they don't have any impact on prompt definitions

if [[ "$TERM" != "dumb" ]]; then
  local reset="%{$reset_color%}"
  local fg_text="$FG[232]"
  local fg_black="$FG[232]"
  local bg_black="$BG[232]"
  local fg_error="$FG[124]"

  local fg_time="$FG[232]" 
  local bg_time="$BG[027]"
	
  local name=027;       local fg_name="$FG[$name]";      local bg_name="$BG[$name]"
  local comp=070;       local fg_comp="$FG[$comp]";      local bg_comp="$BG[$comp]"
  local dir=117;        local fg_dir="$FG[$dir]";        local bg_dir="$BG[$dir]" 
  local git=105;        local fg_git="$FG[$git]";        local bg_git="$BG[$git]"
  local bar=240;        local fg_bar="$FG[$bar]";        local bg_bar="$BG[$bar]"
  local jobs=117;       local fg_jobs="$FG[$jobs]";      local bg_jobs="$BG[$jobs]"
  local clock=249;      local fg_clock="$FG[$clock]";    local bg_clock="$BG[$clock]"
    
  local prompt=166
  local prompt_root=124
  local fg_prompt="%(!.$FG[$prompt_root].$FG[$prompt])"
  local bg_prompt="%(!.$BG[$prompt_root].$BG[$prompt])"
  
  local git_icon=""
  local split="$FX[no-bold]$FX[bold]"
  #local split="$FX[no-bold] $FX[bold]"
  local spad=" "  
  local indicator="$split"

else
  local indicator=">"

fi

local newline=$'\n'                                  #inlining $'\n' doesn't work for some reason
local return_status="%(?. .$fg_error ✖$newline)"     #Setup the return status indicator
ZLE_RPROMPT_INDENT=0                                 #get rid of the indent on the right-prompt
setopt prompt_subst                                  #make sure we get color substitution

#now setup the prompts


#first setup the main prompt. This can get a little tricky..
#All this fancy stuff is just to get rid of an extra newline when you first open a prompt window
local line_one='$return_status'
local line_two='$FX[bold]$fg_text$bg_name$spad%n$spad$fg_name$bg_comp$split$fg_text$spad@%m$spad$fg_comp$bg_dir$split$fg_text$spad%~$spad$fg_dir$(git_status)$bg_bar$split%E'
local line_three='$reset$bg_prompt$spad$reset$fg_prompt$indicator$reset '


autoload -U add-zsh-hook  # We need this for the hooks we call later on
add-zsh-hook precmd updatePrompt
add-zsh-hook preexec checkForClears

function updatePrompt() {
   if [[ -z $newPrompt || $newPrompt == "true" ]]; then
      PROMPT="$line_two$newline$line_three$reset"
      newPrompt="false"

   elif [[ $newPrompt == "false" ]]; then
      PROMPT="$line_one$newline$line_two$newline$line_three"    
   fi 

   if [[ -n $lastCommand ]]; then
      unset $lastCommand
   fi
}

function checkForClears() {
   if [[ $1 =~ "^ *clear" ]]; then  #TODO I would like to check for "reset" here as well, but it causes bugs
      newPrompt="true"
   fi
}


#Now setup the rest of the prompts. This is more direct

RPROMPT='$FX[bold]$fg_black$(jobs_status)$FX[no-bold]$reset' 

PROMPT2='$reset$bg_prompt %_$spad$reset$fg_prompt$indicator$reset '

RPROMPT2=''

PROMPT3='$reset$bg_prompt ?#$spad$reset$fg_prompt$indicator$reset '

PROMPT4='$reset$bg_prompt +%N:%i$spad$reset$fg_prompt$indicator$reset '

SPROMPT="zsh: correct '%R' to '%r' [nyae]?" #this is the default, and I like it

TIMEFMT=`echo "$newline$fg_time$bg_time$FX[bold] %J  %*Es (%P cpu) $reset" | sed -e 's/%{//g' -e 's/%}//g'`

#tells us how many jobs are in the background
function jobs_status() {
   count=$((jobs -s) | wc -l)
   if [[ $count -ne "0" ]]; then
      echo "$bg_jobs$split$fg_text $count $fg_jobs"
   else 
      echo " "
   fi
}

function git_status() {
  ref=$(git symbolic-ref HEAD 2> /dev/null) 
    if [[ -z $ref ]]; then
    echo ""
  else 
     echo "$bg_git$split$fg_text $git_icon ${ref#refs/heads/}$(git_icons) $fg_git"
  fi
}

function git_icons() {
  #TODO: https://git-scm.com/docs/git-status
  #use these statuses to make more information
  local git_status="$(git status --porcelain 2> /dev/null)"
  if [[ -n "$git_status" ]]; then
    echo "*"
  fi

}


#Cool utf characters: λ ✔ ✓ ✘ ✢ ➤ ✖ ❯ ❮ ✚ ✹ ➜ ═ ✭ 

#Got this from ze-best-zsh-theme. Look at it in more detail
#function git_prompt_info {
#  local ref=$(=git symbolic-ref HEAD 2> /dev/null)
#  local gitst="$(=git status 2> /dev/null)"
#
#  if [[ -f .git/MERGE_HEAD ]]; then
#    if [[ ${gitst} =~ "unmerged" ]]; then
#      gitstatus=" %{$fg[red]%}unmerged%{$reset_color%}"
#    else
#      gitstatus=" %{$fg[green]%}merged%{$reset_color%}"
#    fi
#  elif [[ ${gitst} =~ "Changes to be committed" ]]; then
#    gitstatus=" %{$fg[blue]%}!%{$reset_color%}"
#  elif [[ ${gitst} =~ "use \"git add" ]]; then
#    gitstatus=" %{$fg[red]%}!%{$reset_color%}"
#  elif [[ -n `git checkout HEAD 2> /dev/null | grep ahead` ]]; then
#    gitstatus=" %{$fg[yellow]%}*%{$reset_color%}"
#  else
#    gitstatus=''
#  fi
#
#  if [[ -n $ref ]]; then
#    echo "%{$fg_bold[green]%}/${ref#refs/heads/}%{$reset_color%}$gitstatus"
#  fi
#}
# $bg_clock$split$spad$fg_text${timec}%D{%L:%M:%S %p} 

# This is how I did the after-prompt time stamp, but it makes things sluggish, so i dont like it

#autoload -U add-zsh-hook  # We need this for the hooks we call later on
#add-zsh-hook precmd updatePrompt
#add-zsh-hook preexec checkForClears

#function updatePrompt() {
#   if [[ -z $newPrompt || $newPrompt == "true" ]]; then
#      PROMPT="$line_two$newline$line_three$reset"
#      newPrompt="false"
#
#   elif [[ $newPrompt == "false" ]]; then
#      echo $(echo "$fg_clock$FX[bold]$bg_clock$fg_black $(date +"%I:%M:%S%P") $bg_black$fg_clock$FX[no-bold]"  | sed -e 's/%{//g' -e 's/%}//g')
#      PROMPT="$line_one$newline$line_two$newline$line_three"    
#
#   fi 
#
#   if [[ -n $lastCommand ]]; then
#      unset $lastCommand
#   fi
#}
#
#function checkForClears() {
#   if [[ $1 =~ "^ *clear" ]]; then  #TODO I would like to check for "reset" here as well, but it causes bugs
#      newPrompt="true"
#   fi
#}

termsupport.zsh

# Set terminal window and tab/icon title
#
# usage: title short_tab_title [long_window_title]
#
# See: http://www.faqs.org/docs/Linux-mini/Xterm-Title.html#ss3.1
# Fully supports screen, iterm, and probably most modern xterm and rxvt
# (In screen, only short_tab_title is used)
# Limited support for Apple Terminal (Terminal can't set window and tab separately)
function title {
  emulate -L zsh
  setopt prompt_subst

  [[ "$EMACS" == *term* ]] && return

  # if $2 is unset use $1 as default
  # if it is set and empty, leave it as is
  : ${2=$1}

  case "$TERM" in
    cygwin|xterm*|putty*|rxvt*|ansi)
      print -Pn "\e]2;$2:q\a" # set window name
      print -Pn "\e]1;$1:q\a" # set tab name
      ;;
    screen*)
      print -Pn "\ek$1:q\e\\" # set screen hardstatus
      ;;
    *)
      if [[ "$TERM_PROGRAM" == "iTerm.app" ]]; then
        print -Pn "\e]2;$2:q\a" # set window name
        print -Pn "\e]1;$1:q\a" # set tab name
      else
        # Try to use terminfo to set the title
        # If the feature is available set title
        if [[ -n "$terminfo[fsl]" ]] && [[ -n "$terminfo[tsl]" ]]; then
	  echoti tsl
	  print -Pn "$1"
	  echoti fsl
	fi
      fi
      ;;
  esac
}

ZSH_THEME_TERM_TAB_TITLE_IDLE="%15<..<%~%<<" #15 char left truncated PWD ZSH_THEME_TERM_TITLE_IDLE="%n@%m: %~" # Avoid duplication of directory in terminals with independent dir display if [[ "$TERM_PROGRAM" == Apple_Terminal ]]; then ZSH_THEME_TERM_TITLE_IDLE="%n@%m" fi # Runs before showing the prompt function omz_termsupport_precmd { emulate -L zsh if [[ "$DISABLE_AUTO_TITLE" == true ]]; then return fi title $ZSH_THEME_TERM_TAB_TITLE_IDLE $ZSH_THEME_TERM_TITLE_IDLE } # Runs before executing the command function omz_termsupport_preexec { emulate -L zsh setopt extended_glob if [[ "$DISABLE_AUTO_TITLE" == true ]]; then return fi # cmd name only, or if this is sudo or ssh, the next cmd local CMD=${1[(wr)^(*=*|sudo|ssh|mosh|rake|-*)]:gs/%/%%} local LINE="${2:gs/%/%%}" title '$CMD' '%100>...>$LINE%<<'
}

precmd_functions+=(omz_termsupport_precmd)
preexec_functions+=(omz_termsupport_preexec)


# Keep Apple Terminal.app's current working directory updated
# Based on this answer: http://superuser.com/a/315029
# With extra fixes to handle multibyte chars and non-UTF-8 locales

if [[ "$TERM_PROGRAM" == "Apple_Terminal" ]] && [[ -z "$INSIDE_EMACS" ]]; then
  # Emits the control sequence to notify Terminal.app of the cwd
  # Identifies the directory using a file: URI scheme, including
  # the host name to disambiguate local vs. remote paths.
  function update_terminalapp_cwd() {
    emulate -L zsh

    # Percent-encode the pathname.
    local URL_PATH="$(omz_urlencode -P $PWD)"
    [[ $? != 0 ]] && return 1

    # Undocumented Terminal.app-specific control sequence
    printf '\e]7;%s\a' "file://$HOST$URL_PATH"
  }

  # Use a precmd hook instead of a chpwd hook to avoid contaminating output
  precmd_functions+=(update_terminalapp_cwd)
  # Run once to get initial cwd set
  update_terminalapp_cwd
fi

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *