From 172e2a886fcb499fd1f0712836721366dc66cb74 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 --- 0001-Add-customizable-vcs-prompt-theme.patch | 499 +++++++++++++++++++ Functions/Prompts/prompt_vcs_setup | 227 +++++++++ 2 files changed, 726 insertions(+) create mode 100644 0001-Add-customizable-vcs-prompt-theme.patch create mode 100644 Functions/Prompts/prompt_vcs_setup diff --git a/0001-Add-customizable-vcs-prompt-theme.patch b/0001-Add-customizable-vcs-prompt-theme.patch new file mode 100644 index 000000000..fde38a197 --- /dev/null +++ b/0001-Add-customizable-vcs-prompt-theme.patch @@ -0,0 +1,499 @@ +From 1d557059a1ae35be86f17832526198abde8d949d 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 + +--- + 0001-Add-customizable-vcs-prompt-theme.txt | 245 +++++++++++++++++++++ + Functions/Prompts/prompt_vcs_setup | 227 +++++++++++++++++++ + 2 files changed, 472 insertions(+) + create mode 100644 0001-Add-customizable-vcs-prompt-theme.txt + create mode 100644 Functions/Prompts/prompt_vcs_setup + +diff --git a/0001-Add-customizable-vcs-prompt-theme.txt b/0001-Add-customizable-vcs-prompt-theme.txt +new file mode 100644 +index 000000000..980f4a317 +--- /dev/null ++++ b/0001-Add-customizable-vcs-prompt-theme.txt +@@ -0,0 +1,245 @@ ++From 1d34a81c3b09228deaf9de599e42611ec4fe21dd 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 | 226 +++++++++++++++++++++++++++++ ++ 1 file changed, 226 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..218e6a5e2 ++--- /dev/null +++++ b/Functions/Prompts/prompt_vcs_setup ++@@ -0,0 +1,226 @@ +++## +++# 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 name 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)" +++ ;; +++ 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 ++ +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 + 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