## # Prompt that can be customized through vcs_info # autoload -Uz add-zle-hook-widget add-zsh-hook vcs_info # Standardized exit codes. See `man 3 sysexits`. if [[ ${(t)sysexits} != *readonly* ]]; then # Avoid error in case this has been set already. readonly -ga sysexits=( USAGE DATAERR NOINPUT NOUSER NOHOST UNAVAILABLE SOFTWARE OSERR OSFILE CANTCREAT IOERR TEMPFAIL PROTOCOL NOPERM CONFIG ) fi # Prompt segments readonly -gHA _prompt_vcs_defaults=( start:chpwd $'\n%B%F{blue}%~%%b%f/\n' start:left $'%%(?,%F{green},%F{red}%v%k\n%B%%S)%#%%b%f%%s ' start:right '%B%F{blue}%n%b%f%k@%F{magenta}%m%f' start:staged '%B%F{green}+%b%f' start:unstaged '%B%F{red}*%b%f' start:action '%B%F{red}%a%%b%f' start:branch '%B%F{cyan}%b%%b%f' start:repo '|%B%F{blue}%r%%b%f' cont:indent ' ' cont:left '' cont:right '%F{red}%^%f' ) prompt_vcs_help() { print -r -- \ "This prompt theme can by customized by copy-pasting any of the code below to your .zshrc file and editing it there:' # For each of these, # * the first string is used for \$PS1 after changing dirs, # * the second string is used for \$PS1 otherwise, and # * the third string is used for \$RPS1 and updated asynchronously. # In these, %v expands to the name (if any) & number of the last exit code. zstyle ':vcs_info:*:prompt_vcs:*' nvcsformats \ "${${:-$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]}//'%%'/%}" \ "${_prompt_vcs_defaults[start:left]//'%%'/%}" \ "${_prompt_vcs_defaults[start:right]//'%%'/%}" zstyle ':vcs_info:*:prompt_vcs:*' formats \\ ${(q+):-$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]} \\ ${(q+)_prompt_vcs_defaults[start:left]} \\ ${(q+):-%u%c$_prompt_vcs_defaults[start:branch]$_prompt_vcs_defaults[start:repo]} zstyle ':vcs_info:*:prompt_vcs:*' actionformats \\ ${(q+):-$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]} \\ ${(q+)_prompt_vcs_defaults[start:left]} \\ ${(q+):-%u%c$_prompt_vcs_defaults[start:action]$_prompt_vcs_defaults[start:repo]} # These set the values of %c and %u, respectively: zstyle ':vcs_info:*:prompt_vcs:*' stagedstr ${(q+)_prompt_vcs_defaults[start:staged]} zstyle ':vcs_info:*:prompt_vcs:*' unstagedstr ${(q+)_prompt_vcs_defaults[start:unstaged]} For more info on the config above, see http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html and the end of http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#vcs_005finfo-Configuration" } # Sets a style if it hasn't been set yet. _prompt_vcs_zstyle() { local -a val zstyle -g val "$1" "$2" (( $#val )) || zstyle "$@" } _prompt_vcs_info() { _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' max-exports 3 # Default is 2. _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' nvcsformats \ "${${:-$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]}//'%%'/%}" \ "${_prompt_vcs_defaults[start:left]//'%%'/%}" \ "${_prompt_vcs_defaults[start:right]//'%%'/%}" _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' formats \ "$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]" \ "$_prompt_vcs_defaults[start:left]" \ "%u%c$_prompt_vcs_defaults[start:branch]$_prompt_vcs_defaults[start:repo]" _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' actionformats \ "$_prompt_vcs_defaults[start:chpwd]$_prompt_vcs_defaults[start:left]" \ "$_prompt_vcs_defaults[start:left]" \ "%u%c$_prompt_vcs_defaults[start:action]$_prompt_vcs_defaults[start:repo]" _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' stagedstr \ "$_prompt_vcs_defaults[start:staged]" _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' unstagedstr \ "$_prompt_vcs_defaults[start:unstaged]" vcs_info prompt_vcs # Call with namespace. print -rNC1 -- \ "${(q+)vcs_info_msg_0_}" "${(q+)vcs_info_msg_1_}" "${(q+)vcs_info_msg_2_}" } prompt_vcs_chpwd() { emulate -L zsh local -i fd=-1; local -a reply exec {fd}< <( # Fetch only staged changes at this point, for performance reasons. _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-staged-changes yes _prompt_vcs_info ) IFS=$'\0' read -Aru "$fd" typeset -ga _prompt_vcs_info_msg_=( "${(@Q)reply}" ) exec {fd}<&- PS1="$_prompt_vcs_info_msg_[1]" RPS1="$_prompt_vcs_info_msg_[3]" } prompt_vcs_precmd() { local exitstatus=$? # Exit status of last command emulate -L zsh # Assign human-friendly exit status string to %v. psvar[1]= case $exitstatus in ( <128-> ) psvar[1]="SIG$signals[exitstatus-127] " ;| ( <64-78> ) psvar[1]="EX_$sysexits[exitstatus-63] " ;| ( <1-> ) psvar[1]+="($exitstatus)" ;; # No need to show EX_OK. esac } prompt_vcs_line-init() { emulate -L zsh case $CONTEXT in start ) # (R)PS1 # Asynchronously check for unstaged changes. Do this here & not in # precmd, so you can press Enter on an empty line to update VCS info. local -i fd=-1 exec {fd}< <( _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-changes yes _prompt_vcs_info print -r -- "$PWD" ) # Add callback. Needs to be a widget, so we can refresh the prompt. zle -Fw "$fd" prompt_vcs_fd-handler ;; cont ) # (R)PS2 # Indent left continuation prompt for each open shell construct. local fmt="$_prompt_vcs_defaults[cont:indent]" local -a indent=( '%('{1..$(( COLUMNS / ${(m)#fmt} ))}"_,$fmt,)" ) PS2="${(j::)indent}$_prompt_vcs_defaults[cont:left]" RPS2="$_prompt_vcs_defaults[cont:right]" ;; esac } # Callback widget function for our async fetch of unstaged VCS changes prompt_vcs_fd-handler() { emulate -L zsh local -i fd=$1; local sig=$2; local -a reply { zle -F "$fd" # Detach ourselves, so we don't get called more than once. [[ $sig != (|hup) ]] && return # Error occured IFS=$'\0' read -Aru "$fd" [[ $reply[-1] != $PWD ]] && return # Abort if the info is not for the current dir. } always { exec {fd}<&- } shift -p reply typeset -ga _prompt_vcs_info_msg_=( "${(@Q)reply}" ) RPS1="$_prompt_vcs_info_msg_[3]" zle .reset-prompt } prompt_vcs_line-finish() { emulate -L zsh PS1="$_prompt_vcs_info_msg_[2]" } prompt_vcs_setup() { prompt_opts=( cr percent sp ) # Tell promptinit which options to set. PS4=$'# ?=%(?,%F{green},%B%F{red}%S)%?%b%f%s e=%e %F{green}%1N%f:%I %(1_,%F{yellow}%K{black}%_%f%k ,)' SPROMPT='Correct %B%F{red}%U%R%b%f%u to %B%F{green}%r%b%f? [%Sy%ses|%Sn%so|%Se%sdit|%Sa%sbort] ' PROMPT_EOL_MARK='%S%F{cyan}%#%s%f' zle_highlight=( isearch:fg=black,bg=yellow special:fg=cyan,bold region:bg=blue suffix:bg=blue paste:none ) add-zsh-hook chpwd prompt_vcs_chpwd add-zsh-hook precmd prompt_vcs_precmd add-zle-hook-widget line-init prompt_vcs_line-init add-zle-hook-widget line-finish prompt_vcs_line-finish zle -N prompt_vcs_fd-handler # Callback widget for async VCS update. prompt_vcs_chpwd } prompt_vcs_setup "$@"