Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [RFC][PATCH] `newuser` prompt theme



Alright, attached is a new attempt at this patch. Hopefully, this version is more to your liking.

Changes:
* The primary prompt can now be configured completely through `zstyle ':vcs_info:*:prompt_vcs:*’` statements.
* Accordingly, I renamed the theme to `vcs`. (Naming is hard.)
* I removed customization of the secondary prompt.
* I removed the weird shenanigans with $vcs_info_msg_0_ between chpwd & precmd. (I think I must’ve been tired when I originally wrote that code. It makes no sense to me now.)
* I added plenty of comments everywhere.

My thanks to Daniel for his thorough review and to Bart & Mikael for their zstyle/vcs_info tips. :)

Question for Daniel: If you’re going to add sysexits(3) to PRINT_EXIT_VALUE anyway (workers/48564), should I just get rid of prompt_vcs_precmd()? Or do you think it still adds value?

From 172e2a886fcb499fd1f0712836721366dc66cb74 Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlon.richert@xxxxxxxxx>
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 <marlon.richert@xxxxxxxxx>
+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 <marlon.richert@xxxxxxxxx>
++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



Messages sorted by: Reverse Date, Date, Thread, Author