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

[RFC][PATCH] `newuser` prompt theme



This is a new prompt theme that is intended to be used in a rewrite of `zsh-newuser-install` (see 47955 and descendants), but it should work well as a standalone theme, too. It includes an update to `promptinit` to handle ZLE hooks.

From eaa9bebe782489434ecb1d2841da4ee6cb03dcd3 Mon Sep 17 00:00:00 2001
From: Marlon Richert <marlon.richert@xxxxxxxxx>
Date: Tue, 13 Apr 2021 20:46:20 +0300
Subject: [PATCH] Add `newuser` prompt theme

---
 Functions/Prompts/prompt_newuser_setup | 197 +++++++++++++++++++++++++
 Functions/Prompts/promptinit           | 164 ++++++++++----------
 2 files changed, 284 insertions(+), 77 deletions(-)
 create mode 100644 Functions/Prompts/prompt_newuser_setup

diff --git a/Functions/Prompts/prompt_newuser_setup b/Functions/Prompts/prompt_newuser_setup
new file mode 100644
index 000000000..a4167a8c8
--- /dev/null
+++ b/Functions/Prompts/prompt_newuser_setup
@@ -0,0 +1,197 @@
+autoload -Uz add-zle-hook-widget add-zsh-hook vcs_info
+readonly -gHA _prompt_newuser_formats=(
+    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'
+)
+readonly -ga sysexits=(
+    USAGE
+    DATAERR
+    NOINPUT
+    NOUSER
+    NOHOST
+    UNAVAILABLE
+    SOFTWARE
+    OSERR
+    OSFILE
+    CANTCREAT
+    IOERR
+    TEMPFAIL
+    PROTOCOL
+    NOPERM
+    CONFIG
+)
+
+prompt_newuser_help() {
+  print -r -- \
+"To customize your prompt, copy-paste any of the following to your .zshrc file
+and edit it in there:
+
+  # Start prompt:
+  zstyle ':prompt:*:start' left     ${(q+)_prompt_newuser_formats[start:left]}
+  zstyle ':prompt:*:start' right    ${(q+)_prompt_newuser_formats[start:right]}
+
+  # Prepended to left side of start prompt if we changed dirs:
+  zstyle ':prompt:*:start' chpwd    ${(q+)_prompt_newuser_formats[start:chpwd]}
+
+  # Replaces right side of start prompt when in a repo:
+  zstyle ':prompt:*:start' unstaged ${(q+)_prompt_newuser_formats[start:unstaged]}
+  zstyle ':prompt:*:start' staged   ${(q+)_prompt_newuser_formats[start:staged]}
+  zstyle ':prompt:*:start' branch   ${(q+)_prompt_newuser_formats[start:branch]}
+  zstyle ':prompt:*:start' action   ${(q+)_prompt_newuser_formats[start:action]}
+  zstyle ':prompt:*:start' repo     ${(q+)_prompt_newuser_formats[start:repo]}
+
+  # Continuation prompt:
+  zstyle ':prompt:*:cont' left    ${(q+)_prompt_newuser_formats[cont:left]}
+  zstyle ':prompt:*:cont' right   ${(q+)_prompt_newuser_formats[cont:right]}
+
+  # Used to indent left side of continuation prompt:
+  zstyle ':prompt:*:cont' indent  ${(q+)_prompt_newuser_formats[cont:indent]}
+
+For an explanation of the % codes, 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";
+}
+
+prompt_newuser_format() {
+  local ctx=$1 arg fmt out
+  shift
+  for arg; do
+    zstyle -s :prompt:newuser:$ctx $arg fmt ||
+        fmt="$_prompt_newuser_formats[${ctx}:$arg]"
+    out+="$fmt"
+  done
+  print -r -- "$out"
+}
+
+prompt_newuser_chpwd() {
+  emulate -L zsh
+  unset vcs_info_msg_0_
+  PS1="$( prompt_newuser_format start chpwd left )"
+}
+
+prompt_newuser_precmd() {
+  local exitstatus=$?
+  emulate -L zsh
+
+  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
+
+  if ! [[ -v vcs_info_msg_0_ ]]; then
+    zstyle ':vcs_info:*' check-for-staged-changes yes
+    vcs_info
+    if [[ -n $vcs_info_msg_0_ ]]; then
+      RPS1="$vcs_info_msg_0_"
+    else
+      RPS1="$( prompt_newuser_format start right )"
+    fi
+  fi
+}
+
+prompt_newuser_line-init() {
+  emulate -L zsh
+
+  case $CONTEXT in
+    start )
+      local -i fd=-1
+      exec {fd}< <(
+        zstyle ':vcs_info:*' check-for-changes yes
+        vcs_info
+        print -rNC1 -- "$PWD" "${vcs_info_msg_0_}"
+      )
+      zle -Fw "$fd" prompt_newuser_async
+      ;;
+    cont )
+      local fmt="$( prompt_newuser_format cont indent )"
+      local -a indent=( '%('{1..$(( COLUMNS / ${(m)#fmt} ))}"_,$fmt,)" )
+      PS2="${(j::)indent}$( prompt_newuser_format cont left )"
+      RPS2="$( prompt_newuser_format cont right )"
+      ;;
+  esac
+}
+
+prompt_newuser_async() {
+  emulate -L zsh
+  {
+    zle -F "$1"
+
+    [[ $2 != (|hup) ]] &&
+        return
+
+    () {
+      local pwd null
+      IFS=$'\0' read -ru "$1" pwd vcs_info_msg_0_ null
+
+      [[ $pwd == $PWD ]]
+    } "$@" || return
+
+    if [[ -n $vcs_info_msg_0_ ]]; then
+      RPS1="$vcs_info_msg_0_"
+    else
+      RPS1="$( prompt_newuser_format start right )"
+    fi
+    zle .reset-prompt
+
+  } always {
+    exec {1}<&-
+  }
+}
+
+prompt_newuser_line-finish() {
+  emulate -L zsh
+  PS1="$( prompt_newuser_format start left )"
+}
+
+prompt_newuser_setup() {
+  prompt_opts=( cr percent sp )
+
+  zstyle -e ':vcs_info:*' formats '
+    reply=( "%u%c$( prompt_newuser_format start branch repo )" )
+  '
+  zstyle -e ':vcs_info:*' actionformats '
+    reply=( "%u%c$( prompt_newuser_format start action repo )" )
+  '
+  zstyle -e ':vcs_info:*' stagedstr '
+    reply=( "$( prompt_newuser_format start staged )" )
+  '
+  zstyle -e ':vcs_info:*' unstagedstr '
+    reply=( "$( prompt_newuser_format start unstaged )" )
+  '
+  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
+  )
+  zle -N prompt_newuser_async
+
+  add-zsh-hook chpwd  prompt_newuser_chpwd
+  add-zsh-hook precmd prompt_newuser_precmd
+  add-zle-hook-widget line-init   prompt_newuser_line-init
+  add-zle-hook-widget line-finish prompt_newuser_line-finish
+
+  prompt_newuser_chpwd
+}
+
+prompt_newuser_setup "$@"
diff --git a/Functions/Prompts/promptinit b/Functions/Prompts/promptinit
index 37d69f100..6d3c5272c 100644
--- a/Functions/Prompts/promptinit
+++ b/Functions/Prompts/promptinit
@@ -14,6 +14,8 @@ prompt_themes=()
 promptinit () {
   emulate -L zsh
   setopt extendedglob
+  autoload -Uz add-zsh-hook add-zle-hook-widget
+
   local ppath='' name theme
   local -a match mbegin mend
 
@@ -32,9 +34,6 @@ promptinit () {
     fi
   done
 
-  # To manipulate precmd and preexec hooks...
-  autoload -Uz add-zsh-hook
-
   # Variables common to all prompt styles
   prompt_newline=$'\n%{\r%}'
 }
@@ -113,80 +112,91 @@ Use prompt -h <theme> for help on specific themes.'
       ;;
   esac
   case "$opt" in
-    c) if [[ -n $prompt_theme ]]; then
-         print -n "Current prompt theme"
-         (( $#prompt_theme > 1 )) && print -n " with parameters"
-         print " is:\n  $prompt_theme"
-       else
-         print "Current prompt is not a theme."
-       fi
-       return
-       ;;
-    h) if [[ -n "$2" && -n $prompt_themes[(r)$2] ]]; then
-         if functions prompt_$2_setup >/dev/null; then
-           zstyle -t :prompt-theme cleanup
-           # The next line is a bit ugly.  It (perhaps unnecessarily)
-           # runs the prompt theme setup function to ensure that if
-           # the theme has a _help function that it's been autoloaded.
-           prompt_$2_setup
-         fi
-         if functions prompt_$2_help >/dev/null; then
-           print "Help for $2 theme:\n"
-           prompt_$2_help
-         else
-           print "No help available for $2 theme."
-         fi
-         print "\nType \`prompt -p $2' to preview the theme, \`prompt $2'"
-         print "to try it out, and \`prompt -s $2' to use it in future sessions."
-       else
-         print "$usage"
-       fi
-       ;;
-    l) print Currently available prompt themes:
-       print $prompt_themes
-       return
-       ;;
-    p) preview=( $prompt_themes )
-       (( $#* > 1 )) && preview=( "$@[2,-1]" )
-       for theme in $preview; do
-         [[ "$theme" == "$prompt_theme[*]" ]] && continue
-         prompt_preview_safely "$=theme"
-       done
-       print -P "%b%f%k"
-       ;;
-    s) print "Set and save not yet implemented.  Please ensure your ~/.zshrc"
-       print "contains something similar to the following:\n"
-       print "  autoload -Uz promptinit"
-       print "  promptinit"
-       print "  prompt $*[2,-1]"
-       shift
-       ;&
-    *) if [[ "$1" == 'random' ]]; then
-         local random_themes
-         if (( $#* == 1 )); then
-           random_themes=( $prompt_themes )
-         else
-           random_themes=( "$@[2,-1]" )
-         fi
-         local i=$(( ( $RANDOM % $#random_themes ) + 1 ))
-         argv=( "${=random_themes[$i]}" )
-       fi
-       if [[ -z "$1" || -z $prompt_themes[(r)$1] ]]; then
-         print "$usage"
-         return
-       fi
+    c )
+      if [[ -n $prompt_theme ]]; then
+        print -n "Current prompt theme"
+        (( $#prompt_theme > 1 )) && print -n " with parameters"
+        print " is:\n  $prompt_theme"
+      else
+        print "Current prompt is not a theme."
+      fi
+      return
+      ;;
+    h )
+      if [[ -n "$2" && -n $prompt_themes[(r)$2] ]]; then
+        if functions prompt_$2_setup >/dev/null; then
+          zstyle -t :prompt-theme cleanup
+          # The next line is a bit ugly.  It (perhaps unnecessarily)
+          # runs the prompt theme setup function to ensure that if
+          # the theme has a _help function that it's been autoloaded.
+          prompt_$2_setup
+        fi
+        if functions prompt_$2_help >/dev/null; then
+          print "Help for $2 theme:\n"
+          prompt_$2_help
+        else
+          print "No help available for $2 theme."
+        fi
+        print "\nType \`prompt -p $2' to preview the theme, \`prompt $2'"
+        print "to try it out, and \`prompt -s $2' to use it in future sessions."
+      else
+        print "$usage"
+      fi
+      ;;
+    l )
+      print Currently available prompt themes:
+      print $prompt_themes
+      return
+      ;;
+    p )
+      preview=( $prompt_themes )
+      (( $#* > 1 )) && preview=( "$@[2,-1]" )
+      for theme in $preview; do
+        [[ "$theme" == "$prompt_theme[*]" ]] && continue
+        prompt_preview_safely "$=theme"
+      done
+      print -P "%b%f%k"
+      ;;
+    s )
+      print "Set and save not yet implemented.  Please ensure your ~/.zshrc"
+      print "contains something similar to the following:\n"
+      print "  autoload -Uz promptinit"
+      print "  promptinit"
+      print "  prompt $*[2,-1]"
+      shift
+      ;&
+    * )
+      if [[ "$1" == 'random' ]]; then
+        local random_themes
+        if (( $#* == 1 )); then
+          random_themes=( $prompt_themes )
+        else
+          random_themes=( "$@[2,-1]" )
+        fi
+        local i=$(( ( $RANDOM % $#random_themes ) + 1 ))
+        argv=( "${=random_themes[$i]}" )
+      fi
+      if [[ -z "$1" || -z $prompt_themes[(r)$1] ]]; then
+        print "$usage"
+        return
+      fi
 
-       # Reset some commonly altered bits to the default
-       local hook
-       for hook in chpwd precmd preexec periodic zshaddhistory zshexit; do
-         add-zsh-hook -D "${hook}" "prompt_*_${hook}"
-       done
-       typeset -ga zle_highlight=( ${zle_highlight:#default:*} )
-       (( ${#zle_highlight} )) || unset zle_highlight
+      # Reset some commonly altered bits to the default
+      local hook
+      for hook in chpwd precmd preexec periodic zshaddhistory zshexit \
+          zsh_directory_name; do
+        add-zsh-hook -D "$hook" "prompt_*_$hook"
+      done
+      for hook in isearch-exit isearch-update line-pre-redraw line-init \
+         line-finish history-line-set keymap-select; do
+       add-zle-hook-widget -D "$hook" "prompt_*_$hook"
+      done
+      typeset -ga zle_highlight=( ${zle_highlight:#default:*} )
+      (( ${#zle_highlight} )) || unset zle_highlight
 
-       zstyle -t :prompt-theme cleanup
-       prompt_$1_setup "$@[2,-1]" && prompt_theme=( "$@" )
-       ;;
+      zstyle -t :prompt-theme cleanup
+      prompt_$1_setup "$@[2,-1]" && prompt_theme=( "$@" )
+      ;;
   esac
 }
 
@@ -269,11 +279,11 @@ prompt_preview_theme () {
   (( ${#prompt_opts} )) &&
       setopt noprompt{bang,cr,percent,sp,subst} "prompt${^prompt_opts[@]}"
   [[ -n ${precmd_functions[(r)prompt_${1}_precmd]} ]] &&
-    prompt_${1}_precmd
+      prompt_${1}_precmd
   [[ -o promptcr ]] && print -n $'\r'; :
   print -P "${PS1}command arg1 arg2 ... argn"
   [[ -n ${preexec_functions[(r)prompt_${1}_preexec]} ]] &&
-    prompt_${1}_preexec
+      prompt_${1}_preexec
 }
 
 [[ -o kshautoload ]] || promptinit "$@"
-- 
2.31.0



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