#
# Garrett Zsh Theme for Prezto
# Created with modified code by Chauncey Garrett
# @vrtcl1dvoshun
# (ver.2013.09.30.23.32.46)
#
# A prompt full of information when you need it and absent when you don't.
#
# This prompt has the following features:
# * change prompt color when uid is root
# * change host color when on ssh
# * display full or truncated hostname on ssh
# * determine the number of background jobs
# * report the present working directory
# * report return codes
# * report local time
# * report the terminal line number
# * report git status, git remote status, git prompt info and git SHA information
# * indicate vi-mode
# * notifications for commands taking longer than x time
#
# Features may be disabled and rearranged as desired by using the corresponding tokens.
#
#
# Load dependencies
#
pmodload 'helper'
#
# PROMPT | prompt_garrett_help
# - prompt configuration help
# TODO not even remotely finished...
#
function prompt_garrett_help()
{
cat <<'EOF'
This prompt is configurable via styles:
Context: :prompt:garrett
Colors (red green yellow blue magenta cyan white grey):
color_user | The color for user@host. Defaults to 'green'
root_color | The color for the hostname for root. Defaults to 'red'
color_prompt | The color for everything else. Defaults to ''
Path (path type - possible values):
ratio - use COLUMNS/ratio to clip the path. Default.
fixed - use a fixed maximum lenght.
subdir - clip by number of subdirectories.
full - show the full path
Path length styles:
ratio | the ratio for the 'ratio' path style, funnily enough. Defaults to 6.
length | the maximum length for the 'fixed' path style. Defaults to 20.
subdir | the number of subdirs to show for the 'subdir' path style. Defaults to 3.
You can set styles in the current terminal to test things out, values will be updated.
EOF
}
#
# PROMPT | Preview
# - display a preview of the prompt
# TODO not ready
#
function prompt_garrett_preview
{
if (( $# > 0 ))
then
prompt_preview_theme 'garrett' "$@"
else
prompt_preview_theme 'garrett' # red green blue
fi
}
#
# PROMPT | prompt_garrett_pwd
# - format the pwd display
#
function prompt_garrett_pwd
{
local pwd="${PWD/#$HOME/~}"
if [[ "$pwd" == (#m)[/~] ]]
then
current_dir="${color_pwd}$MATCH"
unset MATCH
else
current_dir="${color_pwd}${${${(@j:/:M)${(@s:/:)pwd}##.#?}:h}%/}/${pwd:t}"
fi
}
#
# PROMPT | prompt_garrett_number_jobs
# - determine the number of background jobs
#
function prompt_garrett_number_jobs
{
number_jobs="%(1j.${color_prompt}J:${cyan}%j.) "
}
#
# Notifications
# - notify of command completion after x amount of time has passed
#
function prompt_garrett_notification_precmd
{
# trigger a notification after x time has elapsed
DELAY_AFTER_NOTIFICATION=1
# determine x time elapsed
start=${PREEXEC_TIME:-$(date +'%s')}
stop=$(date +'%s')
let elapsed=$stop-$start
# notify!
if [ $elapsed -gt $DELAY_AFTER_NOTIFICATION ]
then # x time has passed, so notify!
if [[ "$OSTYPE" == darwin* ]] && (( $+commands[terminal-notifier] ))
then
terminal-notifier -title "${PREEXEC_CMD:-Some command}" -message "required $elapsed s" -sound Tink
# growlnotify -n "Terminal" -m "Took $elapsed s" ${PREEXEC_CMD:-Some command}
else
tput bel
fi
fi
}
#
# PROMPT | prompt_garrett_chpwd
# - a function which is executed whenever the directory is changed
#
function prompt_garrett_chpwd
{
emulate -L zsh # TODO can't remember why this is necessary...
ls # list the contents of the new directory
}
#
# PROMPT | prompt_garrett_preexec
# - functions that are called before command execution
#
function prompt_garrett_preexec
{
# Define timer and cmd for notification
export PREEXEC_TIME=$(date +'%s')
export PREEXEC_CMD="\$ $1"
# Ensure terminal code isn't colored from prompt
print -n "$reset_color"
}
#
# PROMPT | prompt_garrett_precmd
# - functions that are called before each prompt is displayed
#
function prompt_garrett_precmd
{
setopt LOCAL_OPTIONS
unsetopt XTRACE KSH_ARRAYS
# Show number of background jobs
prompt_garrett_number_jobs
# Format PWD
prompt_garrett_pwd
# Trigger a notification after x time has elapsed
eval prompt_garrett_notification_precmd
# Get ruby info
if (( $+functions[ruby-info] ))
then
ruby-info
fi
# Get git repository info
if (( $+functions[git-info] ))
then
git-info
fi
#
# Add a line to prompt for visibility
#
# Determine the width
local prompt_width_term
(( prompt_width_term= ${COLUMNS} - 1 ))
# Determine the length needed for prompt_space
# NOTE: Be sure not to include the ${(e)prompt_space} portion or it won't work
local prompt_line1="${altchar_upper_left_corner}( ${current_dir}${git_info[remote_status]}${git_info[prompt_info]}${git_info[local_status]}${git_info[sha]} )( ${ruby_info[version]}${location} )${altchar_upper_right_corner}"
local zero='%([BSUbfksu]|([FB]|){*})'
local prompt_width_line1=${#${(S%%)prompt_line1//$~zero/}}
# Calc the padding
local prompt_space_padding
(( prompt_space_padding= ${prompt_width_term} - ${prompt_width_line1} ))
# Add the correct number of characters
local prompt_space_character="${altchar_padding}"
eval prompt_space="${color_prompt}\${(l.${prompt_space_padding}..${prompt_space_character}.)}"
# Prompt line 1
print
print -P '${altchar_enable}${color_prompt}${altchar_upper_left_corner}( ${current_dir}${git_info[remote_status]}${git_info[prompt_info]}${git_info[local_status]}${git_info[sha]} ${color_prompt})${altchar_enter}${(e)prompt_space}${altchar_leave}( ${ruby_info[version]}${location}${color_prompt} )${altchar_upper_right_corner}'
}
#
# PROMPT | prompt_garrett_setup
# - finally, configure the prompt
#
function prompt_garrett_setup
{
# Load necessary modules
setopt LOCAL_OPTIONS
unsetopt XTRACE KSH_ARRAYS
prompt_opts=(cr percent subst)
# Add hooks for calling preexec, precmd & chpwd
autoload -Uz add-zsh-hook
add-zsh-hook preexec prompt_garrett_preexec
add-zsh-hook precmd prompt_garrett_precmd
add-zsh-hook chpwd prompt_garrett_chpwd
#
# Colors
#
# Alias the colors
[[ -z $(functions colors) ]] && autoload -U colors && colors
for color in black red green yellow blue magenta cyan white grey
do
eval $color='%F{${(L)color}}'
eval ${color}_BOLD='%B{${(L)color}}'
done
# Color scheme
eval color_pwd=\$\{${2:-'blue'}\}
# eval color_pwd=${2:-'${blue}'}
eval color_line_number=${5:-'${magenta}'}
eval color_time=${6:-'${green}'}
eval color_git_branch=${7:-'${green}'}
eval color_git_sha=${8:-'${yellow}'}
eval color_ruby_version=${8:-'${yellow}'}
# Determine prompt, user and host colors
if [[ "$EUID" = "0" ]] || [[ "$USER" = 'root' ]]
then # root user
# set colors
eval color_user=${3:-'${red}'}
eval color_host=${3:-'${red}'}
eval color_prompt=${3:-'${red}'}
# set style
eval user='%S${color_user}%n%s'
eval host='${color_host}%m' # hostname up to first . (dot) (use %M for full hostname)
eval location='${user}${cyan}@${host}' # user@host.name
elif [[ -n "$SSH_CLIENT" || -n "$SSH2_CLIENT" ]]
then # on SSH
# set colors
eval color_user=${3:-'${green}'}
eval color_host=${3:-'${yellow}'}
eval color_prompt=${3:-'${yellow}'}
# set style
eval user='%S${color_user}%n%s'
eval host='${color_host}%m' # hostname up to first . (dot) (use %M for full hostname)
eval location='${user}${cyan}@${host}' # user@host.name
else # normal user
# set colors
eval color_user=${1:-'${green}'}
eval color_host=${1:-'${green}'}
eval color_prompt=${1:-'${grey}'}
# set style
eval user=''
eval host='${color_host}%m' # hostname up to first . (dot) (use %M for full hostname)
eval location='${user}${cyan}@${host}' # user@host.name
fi
#
# Report return code
#
eval return_code='%(?..${red}%? ⏎ ) '
#
# Report local time
#
eval current_time='${green}%T' # 24 hour time format
# eval current_time='${green}%*' # 24 hour time format, second precise
# eval current_time='${green}%t' # AM/PM time format
# Keep the time updated
# schedprompt()
# {
# emulate -L zsh
# zmodload -i zsh/sched
# # Remove existing event, so that multiple calls to "schedprompt" work OK (you could put one in precmd to push the timer 30 seconds into the future, for example.)
# integer i=${"${(@)zsh_scheduled_events#*:*:}"[(i)schedprompt]}
# (( i )) && sched -$i
# # Test that zle is running before calling the widget (recommended to avoid error messages). Otherwise it updates on entry to zle, so there's no loss.
# zle && zle reset-prompt
# # This ensures we're not too far off the start of the minute
# sched +1 schedprompt
# }
# schedprompt
#
# Report terminal line number
#
eval line_number='${green}+${magenta}%!'
#
# Report git info
# NOTE: listed in order in which the information will appear in the prompt
#
# Git verbose data (commit counts, etc.)
# zstyle ':prezto:module:git:info' verbose 'yes'
# Git prompt info
zstyle ':prezto:module:git:info:branch' format "${cyan} λ${color_prompt}:${green}%b"
zstyle ':prezto:module:git:info:remote' format ""
zstyle ':prezto:module:git:info:action' format "${yellow} %s"
zstyle ':prezto:module:git:info:position' format "${red} %p"
# Git commit SHA
zstyle ':prezto:module:git:info:commit' format "${yellow} %.7c"
# Git remote status
zstyle ':prezto:module:git:info:behind' format "${magenta} ⬇ "
zstyle ':prezto:module:git:info:ahead' format "${magenta} ⬆ "
zstyle ':prezto:module:git:info:diverged' format "${magenta} ⥮"
zstyle ':prezto:module:git:info:stashed' format "${cyan} ✭"
# Git local status
zstyle ':prezto:module:git:info:clean' format ""
zstyle ':prezto:module:git:info:dirty' format "${color_prompt} |"
zstyle ':prezto:module:git:info:added' format "${green} ✚"
zstyle ':prezto:module:git:info:deleted' format "${red} ✗"
zstyle ':prezto:module:git:info:modified' format "${blue} ✱"
zstyle ':prezto:module:git:info:renamed' format "${magenta} ➜"
zstyle ':prezto:module:git:info:unmerged' format "${yellow} ═"
zstyle ':prezto:module:git:info:untracked' format "${white} ◼"
# Git prompt styles
zstyle ':prezto:module:git:info:keys' format \
'prompt_info' "%b" \
'rprompt' "[%R]" \
'local_status' "%C%D%a%d%m%r%U%u" \
'remote_status' "%B%A%S" \
'sha' "%c" \
#
# Report ruby version
# %v | ruby version
#
zstyle ':prezto:module:ruby:info:version' format "${yellow}ruby:%v "
#
# Vim mode indicator
#
zstyle ':prezto:module:editor:info:keymap:primary' format "${red}❱%(?.${color_prompt}.${red})❱❱ "
zstyle ':prezto:module:editor:info:keymap:alternate' format "${red}❰%(?.${color_prompt}.${red})❰❰ "
# zstyle ':prezto:module:editor:info:keymap:primary:insert' format "${red}I "
zstyle ':prezto:module:editor:info:keymap:primary:overwrite' format "${red}♺ "
zstyle ':prezto:module:editor:info:completing' format "${red}..."
#
# Use the extended character set, if available
#
typeset -A altchar
set -A altchar ${(s..)terminfo[acsc]}
altchar_enable="%{$terminfo[enacs]%}"
altchar_enter="%{$terminfo[smacs]%}"
altchar_leave="%{$terminfo[rmacs]%}"
altchar_padding=${altchar[q]:--}
altchar_upper_left_corner=%{$terminfo[smacs]%}${altchar[l]:--}${altchar[q]:--}%{$terminfo[rmacs]%}
altchar_lower_left_corner=%{$terminfo[smacs]%}${altchar[m]:--}${altchar[q]:--}%{$terminfo[rmacs]%}
altchar_upper_right_corner=%{$terminfo[smacs]%}${altchar[q]:--}${altchar[k]:--}%{$terminfo[rmacs]%}
altchar_lower_right_corner=%{$terminfo[smacs]%}${altchar[q]:--}${altchar[j]:--}%{$terminfo[rmacs]%}
#
# Finally!
#
# | PROMPT | Left
# | RPROMPT | Right
# | PROMPT2 | Continuation
# | PROMPT3 | Selection
# | PROMPT4 | Execution trace
# | SPROMPT | Autocorrection
# | SUDO_PS1 | Backup root prompt
#
if (( $SHLVL == 1 ))
then
export PROMPT='${altchar_enable}${color_prompt}${altchar_lower_left_corner}${editor_info[keymap]}'
else
export PROMPT='${color_prompt}${altchar_lower_left_corner}( ${cyan}$SHLVL ${color_prompt}) ${editor_info[keymap]}'
fi
export RPROMPT='${editor_info[alternate]}${editor_info[overwrite]}${return_code}${number_jobs}${line_number} ${current_time} %(?.${color_prompt}.${red})❰${color_prompt}${altchar_lower_right_corner}'
export PROMPT2='${color_prompt}%_ ${editor_info[keymap]}'
export PROMPT3='${yellow}#? '
export PROMPT4='${blue}$0${color_prompt}@${yellow}%i+ '
export SPROMPT='
${color_prompt}Correct ${red}%R${color_prompt} to ${green}%r${color_prompt} ? [nyae] '
export SUDO_PS1="\[\e[31;1;46m\][\u] \w \$\[\e[0m\] "
}
prompt_garrett_setup "$@"