3 # This prompt is based on work of other people.
5 # The prompt itself is based on various others:
6 # - The "design" is taken from Phil!'s ZSH prompt, as found on
7 # http://aperiodic.net/phil/prompt/
9 # - The tech using zstyle is inspired by the prompt as used by
10 # the grml-live system <http://grml.org>, see
11 # http://git.grml.org/?p=grml-etc-core.git;a=summary for details
13 # A good number of their support functions are also taken, though
14 # they got renamed from grml_* to ganneff_* to have a single namespace
17 # - The winch function as seen in the prompt theme "bart", delivered
20 prompt_ganneff_help () {
24 This is the prompt as used by (who would have guessed) Ganneff. By
25 default it is a two-line prompt. You can find its latest version at
26 http://git.ganneff.de/cgi-bin/gitweb.cgi?p=zsh.git;a=summary
28 The prompt itself is based on various others:
29 - The "design" is taken from Phil!'s ZSH prompt, as found on
30 http://aperiodic.net/phil/prompt/
32 - The technic using zstyle is inspired by the prompt as used by
33 the grml-live system <http://grml.org>, see
34 http://git.grml.org/?p=grml-etc-core.git;a=summary for details
37 The prompt integrates with zsh's prompt themes system and uses the
38 zstyle system for its configuration. It is configurable as much as
39 seems to make sense. In particular, these aspects are customisable:
41 - The items used in the prompt and their order (e.g. you can
42 remove \`user' from the list of activated items, which will
43 cause the user name to be omitted from the prompt string).
45 - The attributes used with the items are customisable via strings
46 used before and after the actual item.
48 - An itemset for "small terminals" can be provided. That is, if the
49 length of the upper line exceeds the terminal width, various
50 items get removed from the prompt to (hopefully) make it still
51 look good. Obviously this only works down to a limit.
53 The available items are: at, battery, change-root, date, history,
54 host, jobs, newline, path, percent, rc, rc-always, shell-level,
55 time, user, vcs, ulcorner, llcorner, urcorner, lrcorner, line, pts,
56 privileges, openparentheses, closeparentheses, openbracket,
57 closebracket, openbraces, closebraces, openanglebracket,
58 closeanglebracket, colon, pipe, space, flexline
60 Most of those should be self-explanatory, some may need more:
61 line - Draws a single line character
62 XYcorner - Draws a corner. The chars to replace XY are
63 X=u for upper, l for lower
64 Y=l for left, r for right
65 flexline - Same as line, but flexible length to fill remaining space
66 Only works in a two-line prompt in the upper line, that
67 is, a newline MUST appear in the setup!
69 Should they not fit your need, there is an easy way to have the
70 prompt include basically anything you want. Just define your own
71 items. For that you simply define them inside the
72 ':prompt:ganneff:extra:' namespace.
74 Example: To have the prompt include the value of the variable
75 \$FOOBAR, in red and have the variable updated by the function
76 jj_foobar, use the following:
78 zstyle ':prompt:ganneff:extra:foobar' pre '${PR_RED}'
79 zstyle ':prompt:ganneff:extra:foobar' post '${PR_NO_COLOR}'
80 zstyle ':prompt:ganneff:extra:foobar' token '$FOOBAR'
81 zstyle ':prompt:ganneff:extra:foobar' precmd jj_foobar
83 Now you can add the token \`foobar' to the list of items and voila,
84 your own stuff appears.
86 Note that the function part only works in zsh 4.3.5 or later (I've
87 been to lazy to replace add-zsh-hook with something for the older
91 The configuration of the predefined items can also be changed using
92 zsh's \`zstyle' mechanism. The context, that is used while looking
95 ':prompt:ganneff:<left-or-right>:<full-or-small>:<subcontext>'
97 Here <left-or-right> is either \`left' or \`right', signifying
98 whether the style should affect the left or the right prompt.
100 <full-or-small> is either \`full' or \`small' and only valid in the
101 item selection, signifying wether the item list should affect the
102 full length or the "small terminal" prompt. As "small terminal"
103 prompt does not display the right side prompt, <full-or-small> has
104 no effect on the right side prompt.
106 <subcontext> is either \`setup' or 'items:<item>', where \`<item>'
107 is one of the available items.
109 The styles/settings available under ':prompt:ganneff:':
111 - vcs_info (boolean): If \`true' (the default), use \`vcs_info'.
113 - set_vcs_info_defaults (boolean): If \`true' (the default),
114 various vcs_info settings will be done. If unset or \`false'
115 it is assumed that the user has already done this.
117 The default setup is:
118 zstyle ':vcs_info:*' max-exports 1
119 zstyle ':vcs_info:*' use-prompt-escapes
120 zstyle ':vcs_info:*' use_simple
121 zstyle ':vcs_info:*' stagedstr "!"
122 zstyle ':vcs_info:*' unstagedstr "?"
123 zstyle ':vcs_info:*' check-for-changes true
124 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat \
125 "\${PR_YELLOW}%b%{\${PR_RED}%}:\${PR_YELLOW}%r\${PR_NO_COLOR}"
126 zstyle ':vcs_info:*' formats \
127 "(\${PR_YELLOW}%s\${PR_NO_COLOR})-[\${PR_GREEN}%b\${PR_NO_COLOR}]%m%u%c "
128 zstyle ':vcs_info:*' actionformats \
129 "(\${PR_YELLOW}%s\${PR_NO_COLOR})-[\${PR_GREEN}%b\${PR_NO_COLOR}-\${PR_RED}(%a)\${PR_NO_COLOR}]%m%u%c "
131 - colors (boolean): If \`true' (the default), use colors. b/w
134 - nicelines (boolean): If \`true' (the default), use special
135 magic to draw nice lines and corners. Might not work on every
136 terminal. If false, draws using plain ascii characters.
137 Linux console also seems to identify itself as if it could,
138 but then doesn't do drawing right (not in our way at least).
140 - battery (string): If \`none' then no battery function at all.
141 If either \`ibam' or \`acpi' then use those tools to gather
142 the current battery level.
144 - use-rprompt (boolean): If \`true' (the default), print the
147 - items (list): The list of items used in the prompt. If \`vcs' is
148 present in the list, the theme's code invokes \`vcs_info'
149 accordingly. Default (left): rc change-root user at host path vcs
150 percent; Default (right): sad-smiley
152 Note that both, nicelines and colors are forced to false in case the
153 TERM variable is set to dumb.
155 Available styles in 'items:<item>' are: pre, post, token and precmd.
156 Pre and Post are strings that are inserted before (pre) and after
157 (post) the item in question. Token is the token itself that gets
158 inserted into PS1. Thus, the following would cause the
159 user name to be printed in red instead of the default blue:
161 zstyle ':prompt:ganneff:*:items:user' pre '\${PR_RED}'
165 zstyle ':prompt:ganneff:*:items:date' token '%D{%Y-%m-%d [d:%j/w:%V]}'
167 will output a very different date token compared with the default
168 definition of '%D{%Y-%m-%d}'.
170 Note, that in the above example the \`post' style may remain at its
171 default value, because its default value is '\${PR_NO_COLOR}', which
172 turns the foreground text attribute off (which is exactly, what is
173 still required with the new \`pre' value).
175 Possible values for the colors: \${PR_XXX} and \${PR_BOLD_XXX} with
176 XXX replaced with one of: RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK.
177 \${PR_NO_COLOR} resets color.
178 Using the \${PR_XXX} values instead of zsh's internal \%F{xxx} allows
179 the usage of the colors style to turn of prompt colors easily.
181 Last note: You really want to have "setopt promptsubst", otherwise you
182 won't like this prompt.
186 prompt_ganneff_setup () {
190 # We forcefully overwrite colors and nicelines setting for a dumb
192 if [[ "$TERM" == "dumb" ]]; then
193 zstyle ':prompt:ganneff' colors false
194 zstyle ':prompt:ganneff' nicelines false
197 # See if we can and should use extended characters to look nicer.
198 if zstyle -t ':prompt:ganneff' nicelines; then
199 if [[ $(locale charmap) == "UTF-8" ]]; then
210 set -A altchar ${(s..)terminfo[acsc]}
211 # Some stuff to help us draw nice lines
212 PR_SET_CHARSET="%{$terminfo[enacs]%}"
213 PR_SHIFT_IN="%{$terminfo[smacs]%}"
214 PR_SHIFT_OUT="%{$terminfo[rmacs]%}"
215 PR_HBAR=${altchar[q]:--}
216 PR_ULCORNER=${altchar[l]:--}
217 PR_LLCORNER=${altchar[m]:--}
218 PR_LRCORNER=${altchar[j]:--}
219 PR_URCORNER=${altchar[k]:--}
232 if zstyle -t ':prompt:ganneff' colors; then
233 if [[ -n "${BLUE}" ]] && [[ -n "${YELLOW}" ]]; then
234 # Two defined, so we assume someone already defined themself
235 # the colors. We just use them and not setup our own.
236 for color in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK GREY; do
237 eval PR_$color='%{${(P)color}%}'
238 eval PR_BOLD_$color='%{$terminfo[bold]${(LP)color}%}'
240 PR_NO_COLOR="%{${reset_color}%}"
242 # Seems like colors are not defined, so set them up
243 # This duplicates docolors from 01_Terminfo.zsh, but is here to have
244 # prompt_ganneff_setup not require anything else from my dotfiles
245 if autoload -Uz colors && colors 2>/dev/null ; then
246 for COLOR in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK GREY; do
247 eval PR_$COLOR='%{$fg_no_bold[${(L)COLOR}]%}'
248 eval PR_BOLD_$COLOR='%{$fg_bold[${(L)COLOR}]%}'
250 eval PR_NO_COLOR='%{$reset_color%}'
252 PR_BLUE=$'%{\e[1;34m%}'
253 PR_RED=$'%{\e[1;31m%}'
254 PR_GREEN=$'%{\e[1;32m%}'
255 PR_CYAN=$'%{\e[1;36m%}'
256 PR_WHITE=$'%{\e[1;37m%}'
257 PR_MAGENTA=$'%{\e[1;35m%}'
258 PR_YELLOW=$'%{\e[1;33m%}'
259 PR_NO_COLOR=$'%{\e[0m%}'
270 PR_NO_COLOR="%{${reset_color}%}"
274 # The secondary prompt, printed when the shell needs more
275 # information to complete a command. %_ displays any shell constructs
276 # or quotation marks which are currently being processed.
277 if zstyle -t ':prompt:ganneff' nicelines; then
278 PS2='${PR_CYAN}${PR_SHIFT_IN}${PR_HBAR}${PR_BLUE}${PR_HBAR}${PR_SHIFT_OUT}\
279 (${PR_GREEN}%_${PR_BLUE})\
280 ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
284 # selection prompt used within a select loop.
286 # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
287 # Not changed if the option xtrace is on, assuming that a trace prompt is then
289 if [[ ${options[xtrace]} == off ]]; then
293 if zstyle -t ':prompt:ganneff' vcs_info && \
294 is439 && autoload -Uz vcs_info && vcs_info; then
295 if zstyle -t ':prompt:ganneff' set_vcs_info_defaults; then
296 # gather version control information for inclusion in a prompt
297 # we will only be using one variable, so let the code know now.
298 zstyle ':vcs_info:*' max-exports 1
299 zstyle ':vcs_info:*' use-prompt-escapes
300 zstyle ':vcs_info:*' use_simple
301 zstyle ':vcs_info:*' stagedstr "!"
302 zstyle ':vcs_info:*' unstagedstr "?"
303 zstyle ':vcs_info:*' check-for-changes true
305 # change vcs_info formats for the prompt
306 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "${PR_YELLOW}%b%{${PR_RED}%}:${PR_YELLOW}%r${PR_NO_COLOR}"
307 zstyle ':vcs_info:*' formats "(${PR_YELLOW}%s${PR_NO_COLOR})-[${PR_GREEN}%b${PR_NO_COLOR}]%m%u%c "
308 zstyle ':vcs_info:*' actionformats "(${PR_YELLOW}%s${PR_NO_COLOR})-[${PR_GREEN}%b${PR_NO_COLOR}-${PR_RED}(%a)${PR_NO_COLOR}]%m%u%c "
312 # These maps define default tokens and pre-/post-decoration for items to be
313 # used within the themes. All defaults may be customised in a context sensitive
314 # matter by using zsh's `zstyle' mechanism.
315 typeset -gA ganneff_prompt_pre_default \
316 ganneff_prompt_post_default \
317 ganneff_prompt_token_default
319 ganneff_prompt_pre_default=(
324 history '${PR_GREEN}'
332 shell-level '${PR_RED}'
336 ulcorner '${PR_SHIFT_IN}'
337 llcorner '${PR_SHIFT_IN}'
338 urcorner '${PR_SHIFT_IN}'
339 lrcorner '${PR_SHIFT_IN}'
340 line '${PR_SHIFT_IN}'
354 flexline '${PR_SHIFT_IN}'
358 ganneff_prompt_post_default=(
362 date '${PR_NO_COLOR}'
363 history '${PR_NO_COLOR}'
364 host '${PR_NO_COLOR}'
365 jobs '${PR_NO_COLOR}'
367 path '${PR_NO_COLOR}'
371 shell-level '${PR_NO_COLOR}'
372 time '${PR_NO_COLOR}'
373 user '${PR_NO_COLOR}'
375 ulcorner '${PR_SHIFT_OUT}'
376 llcorner '${PR_SHIFT_OUT}'
377 urcorner '${PR_SHIFT_OUT}'
378 lrcorner '${PR_SHIFT_OUT}'
379 line '${PR_SHIFT_OUT}'
393 flexline '${PR_SHIFT_OUT}'
396 ganneff_prompt_token_default=(
399 change-root 'debian_chroot'
403 jobs '[%j running job(s)] '
409 shell-level '%(2L.%L.)'
413 ulcorner '${PR_ULCORNER}'
414 llcorner '${PR_LLCORNER}'
415 urcorner '${PR_URCORNER}'
416 lrcorner '${PR_LRCORNER}'
427 closeanglebracket '>'
431 flexline 'PR_FLEXLINE'
435 add-zsh-hook precmd prompt_ganneff_precmd
436 # Call the winch function once to ensure the length gets calculated
440 zstyle -s ':prompt:ganneff' battery pr_battery
441 if [[ $pr_battery != "none" ]]; then
442 add-zsh-hook precmd prompt_ganneff_battery
443 prompt_ganneff_battery
446 functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}
447 prompt_ganneff_winch"
449 # Should we "ring the bell" when a command finishes?
450 zstyle -s ':prompt:ganneff' longbell _prompt_ganneff_belltime || \
451 _prompt_ganneff_belltime=600
452 if [[ ${_prompt_ganneff_belltime} -gt 0 ]]; then
453 # New shell, initialize the timestamp once
454 _prompt_ganneff_timestamp=${EPOCHSECONDS}
455 typeset -ga _prompt_ganneff_ignore
456 zstyle -a ':prompt:ganneff' bell_ignore _prompt_ganneff_ignore || \
457 _prompt_ganneff_ignore=( '$EDITOR' '$PAGER' sleep man ssh )
458 # In case the commands to ignore include variables (say $EDITOR), we want to
459 # store them once as variable - and once the variable expanded.
460 for (( i = 1; i <= ${#_prompt_ganneff_ignore}; i++ )) do
461 if (( ${${_prompt_ganneff_ignore[$i]}[(i)$]} <= ${#_prompt_ganneff_ignore[$i]} )); then
462 _prompt_ganneff_ignore+=(${(e)${_prompt_ganneff_ignore[$i]}})
465 add-zsh-hook preexec prompt_ganneff_preexec
469 # right before we begin to execute something, store the time it started at
470 prompt_ganneff_preexec() {
471 _prompt_ganneff_timestamp=${EPOCHSECONDS}
472 _prompt_ganneff_lastcmd=${2}
475 prompt_ganneff_precmd () {
479 zstyle -t ':prompt:ganneff' vcs_info && vcs_info
480 local -a left_items right_items drop_words
482 left_items=(ulcorner line openparantheses user at host colon pts closeparantheses line history
483 line shell-level line flexline openparentheses path closeparentheses line urcorner newline
484 llcorner line rc openparentheses time closeparentheses line vcs line change-root pipe space)
486 ganneff_prompt_addto PS1 full "${left_items[@]}"
487 if zstyle -T ":prompt:ganneff:right:setup" use-rprompt; then
488 right_items=(pipe line openparentheses date closeparentheses line lrcorner)
489 ganneff_prompt_addto RPS1 full "${right_items[@]}"
492 # Now a kind-of-hack to reduce the prompt when we run out of space.
493 promptsize=${#PR_PS1}
494 if [[ ${promptsize} -lt ${TERMWIDTH} ]]; then
495 PR_FLEXLINE=${${(el.(($TERMWIDTH - $promptsize ))..X.)}//X/$PR_HBAR}
497 # Small size prompt is needed
498 left_items=(ulcorner line openparentheses user at host closeparentheses line openparentheses
499 path closeparentheses newline
500 llcorner line rc openparentheses time closeparentheses line vcs line pipe space)
501 ganneff_prompt_addto PS1 small "${left_items[@]}"
502 # And with a small prompt, we don't show the right size at all.
506 # Should we "ring the bell" when a command finishes?
507 if (( _prompt_ganneff_timestamp )); then
508 ran_long=$(( ${EPOCHSECONDS} - ${_prompt_ganneff_timestamp} >= ${_prompt_ganneff_belltime} ))
509 if (( ran_long )); then
511 drop_words=(builtin command nocorrect noglob)
512 for cmd in ${(s:;:)_prompt_ganneff_lastcmd//|/;}; do
515 if (( ${drop_words[(i)$util]} <= ${#drop_words} )); then
518 if (( ${_prompt_ganneff_ignore[(i)$util]} <= ${#_prompt_ganneff_ignore} )); then
523 if (( ! ${has_ignored_cmd} )); then
530 prompt_ganneff_length () {
531 (( TERMWIDTH = ${COLUMNS} - 1 ))
534 prompt_ganneff_winch () {
536 setopt nolocaltraps noksharrays unset
538 # Delete ourself from TRAPWINCH if not using our precmd insert.
539 [[ $precmd_functions = *prompt_ganneff_precmd* ]] && prompt_ganneff_length ||
540 functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}"
543 ganneff_typeset_and_wrap () {
550 if (( ${+parameters[$new]} )); then
551 typeset -g "${target}=${(P)target}${left}${(P)new}${right}"
555 ganneff_prompt_addto () {
559 local lr it apre apost new v prefunc
564 [[ $target == PS1 ]] && lr=left || lr=right
565 zstyle -a ":prompt:ganneff:${lr}:${size}:setup" items items || items=( "$@" )
566 typeset -g "${target}="
567 for it in "${items[@]}"; do
568 zstyle -s ":prompt:ganneff:${lr}:items:$it" pre apre \
569 || zstyle -s ":prompt:ganneff:extra:$it" pre apre \
570 || apre=${ganneff_prompt_pre_default[$it]}
571 zstyle -s ":prompt:ganneff:${lr}:items:$it" post apost \
572 || zstyle -s ":prompt:ganneff:extra:$it" post apost \
573 || apost=${ganneff_prompt_post_default[$it]}
574 zstyle -s ":prompt:ganneff:${lr}:items:$it" token new \
575 || zstyle -s ":prompt:ganneff:extra:$it" token new \
576 || new=${ganneff_prompt_token_default[$it]}
578 # Now check if there is the wish for a precmd function and if so,
580 zstyle -s ":prompt:ganneff:extra:$it" precmd prefunc
581 if [[ -n "${prefunc}" ]]; then
585 typeset -g "${target}=${(P)target}${apre}"
586 # Store the expanded value in PR_PS1, as we use that for length calculations
587 [[ $it == "newline" ]] && nomore=1
588 if [[ $nomore -eq 0 ]] && [[ $it != "flexline" ]] && PR_PS1+=${(e%)new}
591 ganneff_typeset_and_wrap $target $new '' ''
594 ganneff_typeset_and_wrap $target $new '(' ')'
597 typeset -g "${target}=${(P)target}\${${new}}"
600 if [[ -n ${(P)new} ]]; then
601 typeset -g "${target}=${(P)target}(CHROOT)"
605 v="vcs_info_msg_${new}_"
606 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
607 typeset -g "${target}=${(P)target}${(P)v}"
610 *) typeset -g "${target}=${(P)target}${new}" ;;
612 typeset -g "${target}=${(P)target}${apost}"
616 prompt_ganneff_battery() {
617 zstyle -s ':prompt:ganneff' battery pr_battery
620 local ACPIDATA=$(ibam --percentbattery 2>/dev/null || echo "")
621 PERCENT=${${ACPIDATA[(f)1]}[(w)-2]}
624 PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
631 if [[ -z "$PERCENT" ]] ; then
632 PERCENT="No battery or $pr_battery not present "
634 if [[ "$PERCENT" -lt 20 ]] ; then
635 PERCENT="warning: ${PERCENT}%%"
637 PERCENT="${PERCENT}%%"
643 [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
644 || $ZSH_VERSION == <5->* ]] && return 0
648 prompt_ganneff_setup "$@"