From f11694bc0260de5d4572fdacb0f41fc748bd7155 Mon Sep 17 00:00:00 2001 From: Marlon Richert Date: Thu, 15 Apr 2021 23:28:56 +0300 Subject: [PATCH] Add customizable `vcs` prompt theme --- Functions/Prompts/prompt_vcs_setup | 227 +++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 Functions/Prompts/prompt_vcs_setup diff --git a/Functions/Prompts/prompt_vcs_setup b/Functions/Prompts/prompt_vcs_setup new file mode 100644 index 000000000..66f167f49 --- /dev/null +++ b/Functions/Prompts/prompt_vcs_setup @@ -0,0 +1,227 @@ +## +# 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 "$@" -- 2.31.1