From 11f84b43e90854ae4c03aa072e110ec494da2d33 Mon Sep 17 00:00:00 2001 From: Marlon Richert Date: Thu, 10 Jun 2021 16:45:30 +0300 Subject: [PATCH] Add customizable `vcs` prompt theme --- Functions/Prompts/prompt_vcs_setup | 199 +++++++++++++++++++++++++++++ 1 file changed, 199 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..c2f2e6cde --- /dev/null +++ b/Functions/Prompts/prompt_vcs_setup @@ -0,0 +1,199 @@ +## +# Prompt that can be customized through vcs_info +# +zmodload -F zsh/system p:sysparams +autoload -Uz add-zle-hook-widget add-zsh-hook vcs_info + +# Prompt segments +# Normal %b and %(...) need extra % in vcs_info -- except in nvcsformats. +readonly -gHA _prompt_vcs_ps1_default=( + left $'%%(?,%F{green},%F{red})%#%%b%f%%s ' + right '%B%F{blue}%n%b%f%k@%F{magenta}%m%f' + chpwd $'\n%B%F{blue}%~%%b%f/\n' + staged '%B%F{green}+%b%f' + unstaged '%B%F{red}*%b%f' + action '%B%F{red}%a%%b%f' + branch '%B%F{cyan}%b%%b%f' + repo '|%B%F{blue}%r%%b%f' +) + +prompt_vcs_help() { + print -r -- \ +"Customizable prompt theme that includes VCS info for the current dir (for +example, git status) and asynchronously checks for repo changes. + +To customize it, copy-paste any of the code below to your .zshrc file and edit +it there: + + # For each of the following three entries: + # 1st string is the left prompt. + # 2nd string is the right prompt. + # 3rd string is printed whenever you change dirs (before the left prompt). + + # Normal prompt: + zstyle ':vcs_info:*:prompt_vcs:*' nvcsformats \\ + "${(q+)_prompt_vcs_ps1_default[left]//'%%'/%}" \\ + "${(q+)_prompt_vcs_ps1_default[right]//'%%'/%}" \\ + "${(q+)_prompt_vcs_ps1_default[chpwd]//'%%'/%}" + + # Prompt inside VCS repo: + zstyle ':vcs_info:*:prompt_vcs:*' formats \\ + ${(q+)_prompt_vcs_ps1_default[left]} \\ + ${(q+):-%u%c$_prompt_vcs_ps1_default[branch]$_prompt_vcs_ps1_default[repo]} \\ + ${(q+)_prompt_vcs_ps1_default[chpwd]} + + # Prompt during ongoing VCS action: + zstyle ':vcs_info:*:prompt_vcs:*' actionformats \\ + ${(q+)_prompt_vcs_ps1_default[left]} \\ + ${(q+):-%u%c$_prompt_vcs_ps1_default[action]$_prompt_vcs_ps1_default[repo]} \\ + ${(q+)_prompt_vcs_ps1_default[chpwd]} + + # These customize the values of %c and %u, respectively: + zstyle ':vcs_info:*:prompt_vcs:*' stagedstr ${(q+)_prompt_vcs_ps1_default[staged]} + zstyle ':vcs_info:*:prompt_vcs:*' unstagedstr ${(q+)_prompt_vcs_ps1_default[unstaged]} + +For more info on the settings 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_ps1_default[left]//'%%'/%}" \ + "${_prompt_vcs_ps1_default[right]//'%%'/%}" \ + "${_prompt_vcs_ps1_default[chpwd]//'%%'/%}" + + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' formats \ + "$_prompt_vcs_ps1_default[left]" \ + "%u%c$_prompt_vcs_ps1_default[branch]$_prompt_vcs_ps1_default[repo]" \ + "$_prompt_vcs_ps1_default[chpwd]" + + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' actionformats \ + "$_prompt_vcs_ps1_default[left]" \ + "%u%c$_prompt_vcs_ps1_default[action]$_prompt_vcs_ps1_default[repo]" \ + "$_prompt_vcs_ps1_default[chpwd]" + + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' stagedstr \ + "$_prompt_vcs_ps1_default[staged]" + + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' unstagedstr \ + "$_prompt_vcs_ps1_default[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 + + # Don't check for changes at this point, for performance reasons. + typeset -ga _prompt_vcs_info_msg_=( "${(0@Q)$( + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-changes no + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-staged-changes no + _prompt_vcs_info + )}" ) + PS1="$_prompt_vcs_info_msg_[1]" + RPS1="$_prompt_vcs_info_msg_[2]" + print -nPr -- "$_prompt_vcs_info_msg_[3]" +} + +# We need to use line-init instead of precmd, because any widget can +# potentially change the state of the repo or change dir without accepting or +# aborting the command line. +prompt_vcs_line-init() { + emulate -L zsh + + # Terminate any pending vcs_info request before starting a new one. + # Second test checks if fd is readable, to avoid this error being printed: + # failed to close file descriptor XX: bad file descriptor + if (( prompt_vcs_fd )) && { : <&$prompt_vcs_fd } 2>/dev/null; then + zle -F "$prompt_vcs_fd" 2> /dev/null + exec {prompt_vcs_fd}<&- + fi + if (( prompt_vcs_pid )); then + [[ -o monitor ]] && + (( prompt_vcs_pid *= -1 )) + kill -KILL $prompt_vcs_pid 2> /dev/null + fi + + # Asynchronously check for changes. + typeset -gH prompt_vcs_fd= + exec {prompt_vcs_fd}< <( + print -r -- $sysparams[pid] + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-changes yes + _prompt_vcs_zstyle ':vcs_info:*:prompt_vcs:*' check-for-staged-changes yes + _prompt_vcs_info + ) + typeset -gH prompt_vcs_pid= + read -u $prompt_vcs_fd -- prompt_vcs_pid + + # Add callback. Needs to be a widget, so we can refresh the prompt. + zle -Fw "$prompt_vcs_fd" prompt_vcs_fd-widget +} + +# Callback widget for our async fetch of VCS changes +zle -N prompt_vcs_fd-widget +prompt_vcs_fd-widget() { + emulate -L zsh + + (( $1 )) || + return 64 # EX_USAGE; see man 3 sysexits + + local -i fd=$1 + local -a reply + { + zle -F "$fd" # Detach ourselves, so we don't get called more than once. + + [[ -z $2 ]] || + return 74 # EX_IOERR + + IFS=$'\0' read -Aru "$fd" + typeset -gHa _prompt_vcs_info_msg_=( "${(@Q)reply}" ) + PS1="$_prompt_vcs_info_msg_[1]" + RPS1="$_prompt_vcs_info_msg_[2]" + zle .reset-prompt + } always { + exec {fd}<&- + } +} + +prompt_vcs_setup() { + prompt_opts=( cr percent sp ) # Tell promptinit which options to set. + + # Indent left continuation prompt for each open shell construct. + local -a indent=( '%('{1..36}'_, ,)' ) + PS2="${(j::)indent}" + RPS2='%F{yellow}# %^%f' + + PS4=$'#->%(?,%F{green},%B%F{red}%S)%?%b%f%s\t%e+%F{green}%1N%f:%I' + PS4+=' %(1_,%F{yellow}%K{black}%_%f%k ,)' + SPROMPT='Correct %B%F{red}%S%R%b%f%s to %B%F{green}%r%b%f?' + SPROMPT+=$'\n%{\e[2m%}%Uy%ues %Un%uo %Ue%udit %Ua%ubort%b ' + PROMPT_EOL_MARK='%F{cyan}%S%#%f%s' + zle_highlight=( + isearch:fg=black,bg=yellow + special:fg=cyan,bold + region:fg=white,bg=blue,bold + suffix:fg=white,bg=blue,bold + paste:bold + ) + + add-zsh-hook chpwd prompt_vcs_chpwd + add-zle-hook-widget line-init prompt_vcs_line-init + + prompt_vcs_chpwd +} + +prompt_vcs_setup "$@" -- 2.30.1 (Apple Git-130)