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

PATCH: My contribution to themed prompts



If I'm going to use a fancy prompt, I tend to want one that's information-
dense rather than filled with a lot of decorative graphics, but the zefram
theme eats too much horizontal space.  So here's my cut at it.

This theme tries to be minimally intrusive and maximally informative.  It
puts all its new stuff on the first line of a two-line prompt, and you can
turn that upper line on and off.  It borrows the last line of the existing
prompt for its own second line (which required some unfortunate hacking in
the case of the oliver theme), so if you already have a one-line prompt
you like, this one just pastes on some more stuff.

Read the help.

Below it is a patch to promptinit to make "prompt -h ..." load the theme
so that the _help function becomes available, like "prompt -p ..." does
for the _preview function.  Oh, and it doesn't set the prompt_theme array
when the _setup function returns nonzero, and it tests kshautoload.

Index: Functions/Prompts/prompt_bart_setup
--- /dev/null	Tue May  5 13:32:27 1998
+++ Functions/Prompts/prompt_bart_setup	Mon Mar 20 01:14:44 2000
@@ -0,0 +1,153 @@
+zmodload -i zsh/parameter || return 1
+
+prompt_bart_help () {
+    setopt localoptions nocshnullcmd noshnullcmd
+    [[ $ZSH_VERSION < 3.1.6-dev-20 ]] &&
+	print 'Requires 3.1.6-dev-19 plus zsh-workers/10168.'$'\n'
+    <<-\EOF
+	This prompt gives the effect of left and right prompts on the upper
+	line of a two-line prompt.  It also illustrates including history
+	text in the prompt.  The lower line is initialized from the last
+	(or only) line of whatever prompt was previously in effect.
+
+	    prompt bart [on|off] [color...]
+
+	You may provide up to five colors, though only three colors (red,
+	blue, and the default foreground) are used if no arguments are
+	given.  The defaults look best on a light background.
+
+	The "off" token temporarily disables the theme; "on" restores it.
+	EOF
+    [[ $(read -Ek 1 "?${(%):-%S[press return]%s}") == [Qq] ]] &&
+	print -nP $'\r'%E && return
+    <<-\EOF
+
+	The "upper left prompt" looks like:
+	    machine [last command] /current/working/dir
+	The first three color arguments apply to these components.  The
+	last command is shown in standout mode if the exit status was
+	nonzero, or underlined if the job was stopped.
+
+	The "upper right prompt" looks like:
+	    date time
+	The fourth color is used for the date, and the first again for the
+	time.  As with RPS1, first the date and then the time disappear as
+	the upper left prompt grows too wide.  The clock is not live; it
+	changes only after each command, as does the rest of the prompt.
+	EOF
+    [[ $(read -Ek 1 "?${(%):-%S[press return]%s}") == [Qq] ]] &&
+	print -nP $'\r'%E && return
+    <<-\EOF
+
+	When RPS1 (RPROMPT) is set before this prompt is selected and a
+	fifth color is specified, that color is turned on before RPS1 is
+	displayed and reset after it.  Other color changes within RPS1, if
+	any, remain in effect.
+
+	This prompt hijacks psvar[8] and psvar[9] to avoid having to reset
+	the entire PS1 string on every command.  It uses TRAPWINCH to set
+	the position of the upper right prompt on a window resize, so the
+	prompt may not match the window width until the next command.  No
+	background colors or hardwired cursor motion escapes are used, and
+	it is not necessary to setopt promptsubst.
+	EOF
+}
+
+prompt_bart_precmd () {
+    setopt localoptions noxtrace extendedglob noksharrays
+
+    # Using psvar here protects against unwanted promptsubst expansions.
+    psvar[8]="$history[$#history]"	# Use history text, not just number
+    psvar[9]=''				# Padding before upper right prompt
+
+    if [[ -o promptsubst ]]
+    then
+	# This is a bug workaround; ${(%)...} mishandles promptsubst
+	repeat $[COLUMNS-${#${(%f)${${(e)PS1}//[%]\{[^%]#%\}/}}[1]}-1]
+	do
+	    psvar[9]="$psvar[9] "
+	done
+    else
+	repeat $[COLUMNS-${#${(%f)${PS1//[%]\{[^%]#%\}/}}[1]}-1]
+	do
+	    psvar[9]="$psvar[9] "
+	done
+    fi
+}
+
+prompt_bart_ps1 () {
+    local -ah ps1
+    local -h host hist dir space date time rs="%{$reset_color%}"
+    local -h eon="%(?.[.%20(?.[%U.%S[))" eoff="%(?.].%20(?.%u].]%s))"
+
+    # Set up the components of the upper line
+    host="%{$fg[%m]%}%m$rs"
+    hist="%{$fg[%h]%}$eon%8v$eoff$rs"
+    dir="%{$fg[%~]%}%~$rs"
+    space=%9v
+    date="%{$fg[%D]%}%D$rs"	# Prefer "%{$fg[%D]%}%W$rs" in the USA?
+    time="%{$fg[%@]%}%@$rs"
+
+    # This is just a tad silly ...
+    [[ $prompt_theme[1] = oliver ]] && PS1='[%h%0(?..:%?)]%# ' ||
+	PS1=${PS1//$prompt_newline/$'\n'}
+
+    # Assemble the new prompt
+    ps1=( ${(f)PS1} )		# Split the existing prompt at newlines
+    ps1=( "%$[COLUMNS-3]>..>"	# Begin truncation (upper left prompt)
+	"$host"
+	" $hist "		# I prefer spaces around this; do you?
+	"$dir"
+	"%<<"			# End truncation (end upper left prompt)
+	"$space"		# Pad line to upper right position
+	"%$[COLUMNS-16](l.  . $date)"
+	"%$[COLUMNS-6](l.. $time)"
+	$'\n'
+	$ps1[-1] )		# Keep last line of the existing prompt
+    PS1="${(j::)ps1}"
+}
+
+prompt_bart_winch () {
+    # Delete ourself from TRAPWINCH if not using our precmd insert.
+    [[ $functions[precmd] = *prompt_bart_precmd* ]] && prompt_bart_ps1 ||
+	functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch}"
+}
+
+prompt_bart_setup () {
+    # A few extra niceties ...
+    repeat 1 case "$1:l" in
+      (off|disable)
+	functions[precmd]="${functions[precmd]//prompt_bart_precmd}"
+	functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch}"
+	[[ $prompt_theme[1] = bart ]] && PS1=${${(f)PS1}[-1]}
+	return 1
+	;;
+      (on|enable)
+	shift
+	[[ $prompt_theme[1] = bart ]] && break
+	;&
+      (*)
+	# Abuse the fg assoc to hold our selected colors ...
+	fg[%m]=$fg[${1:-red}]
+	fg[%h]=$fg[${2:-blue}]
+	fg[%~]=$fg[${3:-none}]
+	fg[%D]=$fg[${4:-none}]
+	fg[%@]=$fg[${1:-red}]
+	;;
+    esac
+
+    prompt_bart_ps1
+
+    # No RPS1 by default because prompt_off_setup doesn't fix it.
+    (($#RPS1 && $# > 4)) && RPS1="%{$fg[$5]%}$RPS1%{$reset_color%}"
+
+    # Paste our special commands into precmd and TRAPWINCH
+    functions[precmd]="${functions[precmd]//prompt_*_precmd}
+	prompt_bart_precmd"
+    functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_bart_winch}
+	prompt_bart_winch"
+
+    return 0
+}
+
+[[ -o kshautoload ]] || prompt_bart_setup "$@"

Index: Functions/Prompts/promptinit
===================================================================
@@ -55,6 +55,18 @@
 
   getopts "chlps" opt
   case "$opt" in
+    (h|p)
+      setopt localtraps
+      if [[ -z "$prompt_theme[1]" ]]; then
+        # Not using a prompt theme; save settings
+	local +h PS1=$PS1 PS2=$PS2 PS3=$PS3 PS4=$PS4 RPS1=$RPS1
+	trap "${$(functions precmd):-:} ; ${$(functions preexec):-:}" 0
+      else
+        trap 'prompt_${prompt_theme[1]}_setup "${(@)prompt_theme[2,-1]}"' 0
+      fi
+      ;;
+  esac
+  case "$opt" in
     c) if (( $+prompt_theme )); then
          print -n "Current prompt theme"
          (( $#prompt_theme > 1 )) && print -n " with parameters"
@@ -65,6 +77,12 @@
        return
        ;;
     h) if [[ -n "$2" && -n $prompt_themes[(r)$2] ]]; then
+         if functions prompt_$2_setup >/dev/null; then
+	   # 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
@@ -81,13 +99,7 @@
        print $prompt_themes
        return
        ;;
-    p) if [[ -z "$prompt_theme[1]" ]]; then
-         # Not using a prompt theme; save settings
-         prompt_non_theme=( "$PS1" "$PS2" "$PS3" "$PS4" "$RPS1" )
-         prompt_old_precmd="$(functions precmd)"
-         prompt_old_preexec="$(functions preexec)"
-       fi
-       preview=( $prompt_themes )
+    p) preview=( $prompt_themes )
        (( $#* > 1 )) && preview=( "$@[2,-1]" )
        for theme in $preview; do
          theme_args=( "$=theme" )
@@ -110,25 +122,6 @@
          fi
        done
        print
-       if [[ -z "$prompt_theme[1]" ]]; then
-         PS1="$prompt_non_theme[1]"
-         PS2="$prompt_non_theme[2]"
-         PS3="$prompt_non_theme[3]"
-         PS4="$prompt_non_theme[4]"
-         RPS1="$prompt_non_theme[5]"
-         if [[ -z "$prompt_old_precmd" ]]; then
-           precmd () { }
-         else
-           eval "$prompt_old_precmd"
-         fi
-         if [[ -z "$prompt_old_preexec" ]]; then
-           preexec () { }
-         else
-           eval "$prompt_old_preexec"
-         fi
-       else
-         prompt_${prompt_theme[1]}_setup "${(@)prompt_theme[2,-1]}"
-       fi
        ;;
     s) print "Set and save not yet implemented.  Please ensure your ~/.zshrc"
        print "contains something similar to the following:\n"
@@ -150,8 +143,7 @@
          print "$usage"
          return
        fi
-       prompt_$1_setup "$@[2,-1]"
-       prompt_theme=( "$@" )
+       prompt_$1_setup "$@[2,-1]" && prompt_theme=( "$@" )
 
        # Avoid screwing up the environment listing
        PSZZZZ=$reset_color
@@ -185,4 +177,4 @@
   print "command arg1 arg2 ... argn"
 }
 
-promptinit "$@"
+[[ -o kshautoload ]] || promptinit "$@"

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com



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