Actual working fix guarding against malicious branch names
[zsh.git] / .zsh / functions / prompt_ganneff_setup
1 # -*- mode:sh -*-
2
3 # This prompt is based on work of other people.
4 #
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/
8 #
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
12 #     on theirs.
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
15 #     here.
16 #
17 #   - The winch function as seen in the prompt theme "bart", delivered
18 #     with zsh
19
20 prompt_ganneff_help () {
21     cat <<__EOF0__
22   prompt ganneff
23
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
27
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/
31
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
35         on theirs.
36
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:
40
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).
44
45         - The attributes used with the items are customisable via strings
46           used before and after the actual item.
47
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.
52
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
59
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!
68
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.
73
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:
77
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
82
83     Now you can add the token \`foobar' to the list of items and voila,
84     your own stuff appears.
85
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
88     versions).
89
90
91     The configuration of the predefined items can also be changed using
92     zsh's \`zstyle' mechanism. The context, that is used while looking
93     up styles is:
94
95         ':prompt:ganneff:<left-or-right>:<full-or-small>:<subcontext>'
96
97     Here <left-or-right> is either \`left' or \`right', signifying
98     whether the style should affect the left or the right prompt.
99
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.
105
106     <subcontext> is either \`setup' or 'items:<item>', where \`<item>'
107     is one of the available items.
108
109     The styles/settings available under ':prompt:ganneff:':
110
111         - vcs_info (boolean): If \`true' (the default), use \`vcs_info'.
112
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.
116
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 "
130
131         - colors (boolean): If \`true' (the default), use colors. b/w
132           otherwise.
133
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).
139
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.
143
144         - use-rprompt (boolean): If \`true' (the default), print the
145           right side prompt.
146
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
151
152     Note that both, nicelines and colors are forced to false in case the
153     TERM variable is set to dumb.
154
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:
160
161         zstyle ':prompt:ganneff:*:items:user' pre '\${PR_RED}'
162
163     and
164
165         zstyle ':prompt:ganneff:*:items:date' token '%D{%Y-%m-%d [d:%j/w:%V]}'
166
167     will output a very different date token compared with the default
168     definition of '%D{%Y-%m-%d}'.
169
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).
174
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.
180
181     Last note: You really want to have "setopt promptsubst", otherwise you
182     won't like this prompt.
183 __EOF0__
184 }
185
186 prompt_ganneff_setup () {
187     emulate -L zsh
188     setopt nolocaltraps
189
190     # We forcefully overwrite colors and nicelines setting for a dumb
191     # terminal.
192     if [[ "$TERM" == "dumb" ]]; then
193         zstyle ':prompt:ganneff' colors false
194         zstyle ':prompt:ganneff' nicelines false
195     fi
196
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
200             PR_SET_CHARSET=""
201             PR_SHIFT_IN=""
202             PR_SHIFT_OUT=""
203             PR_HBAR="─"
204             PR_ULCORNER="┌"
205             PR_LLCORNER="└"
206             PR_LRCORNER="┘"
207             PR_URCORNER="┐"
208         else
209             typeset -A altchar
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]:--}
220         fi
221     else
222         PR_SET_CHARSET=""
223         PR_SHIFT_IN=""
224         PR_SHIFT_OUT=""
225         PR_HBAR="-"
226         PR_ULCORNER=""
227         PR_LLCORNER=""
228         PR_LRCORNER=""
229         PR_URCORNER=""
230     fi
231
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}%}'
239             done
240             PR_NO_COLOR="%{${reset_color}%}"
241         else
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}]%}'
249                 done
250                 eval PR_NO_COLOR='%{$reset_color%}'
251             else
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%}'
260             fi
261         fi
262     else
263         PR_BLUE=''
264         PR_RED=''
265         PR_GREEN=''
266         PR_CYAN=''
267         PR_WHITE=''
268         PR_MAGENTA=''
269         PR_YELLOW=''
270         PR_NO_COLOR="%{${reset_color}%}"
271     fi
272
273     # Easy things first.
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} '
281     else
282         PS2='-(%_)- '
283     fi
284     # selection prompt used within a select loop.
285     PS3='?# '
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
288     # already defined.
289     if [[ ${options[xtrace]} == off ]]; then
290         PS4='+%N:%i:%_> '
291     fi
292
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 2
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
304
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" "%R"
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 "
309         fi
310     fi
311
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
318
319     ganneff_prompt_pre_default=(
320         at                 ''
321         battery            ' '
322         change-root        ''
323         date               '${PR_BLUE}'
324         history            '${PR_GREEN}'
325         host               '${PR_RED}'
326         jobs               '${PR_CYAN}'
327         newline            ''
328         path               '${PR_MAGENTA}'
329         percent            ''
330         rc                 '${PR_RED}'
331         rc-always          ''
332         shell-level        '${PR_RED}'
333         time               '${PR_BLUE}'
334         user               '${PR_BLUE}'
335         vcs                ''
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}'
341         pts                ''
342         privileges         ''
343         openparentheses    ''
344         closeparentheses   ''
345         openbracket        ''
346         closebracket       ''
347         openbraces         ''
348         closebraces        ''
349         openanglebracket   ''
350         closeanglebracket  ''
351         pipe               ''
352         space              ''
353         colon              ''
354         flexline           '${PR_SHIFT_IN}'
355     )
356
357
358     ganneff_prompt_post_default=(
359         at                ''
360         battery           ''
361         change-root       ''
362         date              '${PR_NO_COLOR}'
363         history           '${PR_NO_COLOR}'
364         host              '${PR_NO_COLOR}'
365         jobs              '${PR_NO_COLOR}'
366         newline           ''
367         path              '${PR_NO_COLOR}'
368         percent           ''
369         rc                '${PR_NO_COLOR}'
370         rc-always         ''
371         shell-level       '${PR_NO_COLOR}'
372         time              '${PR_NO_COLOR}'
373         user              '${PR_NO_COLOR}'
374         vcs               ''
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}'
380         pts               ''
381         privileges        ''
382         openparentheses   ''
383         closeparentheses  ''
384         openbracket       ''
385         closebracket      ''
386         openbraces        ''
387         closebraces       ''
388         openanglebracket  ''
389         closeanglebracket ''
390         pipe              ''
391         space             ''
392         colon             ''
393         flexline          '${PR_SHIFT_OUT}'
394     )
395
396     ganneff_prompt_token_default=(
397         at                '@'
398         battery           'PERCENT'
399         change-root       'debian_chroot'
400         date              '%D{%Y-%m-%d}'
401         history           '{#%!}'
402         host              '%m'
403         jobs              '[%j running job(s)] '
404         newline           $'\n'
405         path              '%40<..<%~%<<'
406         percent           '%# '
407         rc                '%(?..%? )'
408         rc-always         '%?'
409         shell-level       '%(2L.%L.)'
410         time              '%D{%H:%M:%S}'
411         user              '%n'
412         vcs               '0'
413         ulcorner          '${PR_ULCORNER}'
414         llcorner          '${PR_LLCORNER}'
415         urcorner          '${PR_URCORNER}'
416         lrcorner          '${PR_LRCORNER}'
417         line              '${PR_HBAR}'
418         pts               '%y'
419         privileges        '%#'
420         openparentheses   '('
421         closeparentheses  ')'
422         openbracket       '['
423         closebracket      ']'
424         openbraces        '{'
425         closebraces       '}'
426         openanglebracket  '<'
427         closeanglebracket '>'
428         pipe              '|'
429         space             ' '
430         colon             ':'
431         flexline          'PR_FLEXLINE'
432     )
433
434     PR_FLEXLINE=""
435     is435 && add-zsh-hook precmd prompt_ganneff_precmd
436     # Call the winch function once to ensure the length gets calculated
437     # correctly
438     prompt_ganneff_winch
439     local pr_battery
440     zstyle -s ':prompt:ganneff' battery pr_battery || pr_battery="none"
441     if [[ $pr_battery != "none" ]]; then
442         is435 && add-zsh-hook precmd prompt_ganneff_battery
443         prompt_ganneff_battery
444     fi
445
446     functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}
447         prompt_ganneff_winch"
448
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 zsh watch less )
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]}})
463             fi
464         done
465         is435 && add-zsh-hook preexec prompt_ganneff_preexec
466     fi
467 }
468
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}
473 }
474
475 prompt_ganneff_precmd () {
476     emulate -L zsh
477     setopt nolocaltraps
478
479     zstyle -T ':prompt:ganneff' vcs_info && vcs_info
480     local -a left_items right_items drop_words
481
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)
485     PR_PS1=""; nomore=0
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[@]}"
490     fi
491
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}
496     else
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.
503         RPS1=""
504     fi
505
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
510             has_ignored_cmd=0
511             drop_words=(builtin command nocorrect noglob nohup LANG=C)
512             for cmd in ${(s:;:)_prompt_ganneff_lastcmd//|/;}; do
513                 for key in ${drop_words}; do
514                     cmd=${cmd/${key}/}
515                 done
516                 words=(${(z)cmd})
517                 util=${words[1]}
518                 if (( ${drop_words[(i)$util]} <= ${#drop_words} )); then
519                     util=${words[2]}
520                 fi
521                 if (( ${_prompt_ganneff_ignore[(i)$util]} <= ${#_prompt_ganneff_ignore} )); then
522                     has_ignored_cmd=1
523                     break
524                 fi
525             done
526             if (( ! ${has_ignored_cmd} )); then
527                 print -n "\a"
528             fi
529         fi
530     fi
531     # And a variant that can be used in plain cd commands - directory alias
532     hash -d gtd="${vcs_info_msg_1_}"
533 }
534
535 prompt_ganneff_length () {
536     (( TERMWIDTH = ${COLUMNS} - 1 ))
537 }
538
539 prompt_ganneff_winch () {
540     emulate -L zsh
541     setopt nolocaltraps noksharrays unset
542
543     # Delete ourself from TRAPWINCH if not using our precmd insert.
544     [[ $precmd_functions = *prompt_ganneff_precmd* ]] && prompt_ganneff_length ||
545         functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}"
546 }
547
548 ganneff_typeset_and_wrap () {
549     emulate -L zsh
550     local target="$1"
551     local new="$2"
552     local left="$3"
553     local right="$4"
554
555     if (( ${+parameters[$new]} )); then
556         typeset -g "${target}=${(P)target}${left}${(P)new}${right}"
557     fi
558 }
559
560 ganneff_prompt_addto () {
561     emulate -L zsh
562     local target="$1"
563     local size="$2"
564     local lr it apre apost new v prefunc
565     local -a items
566     shift
567     shift
568
569     [[ $target == PS1 ]] && lr=left || lr=right
570     zstyle -a ":prompt:ganneff:${lr}:${size}:setup" items items || items=( "$@" )
571     typeset -g "${target}="
572     for it in "${items[@]}"; do
573         zstyle -s ":prompt:ganneff:${lr}:items:$it" pre apre \
574             || zstyle -s ":prompt:ganneff:extra:$it" pre apre \
575             || apre=${ganneff_prompt_pre_default[$it]}
576         zstyle -s ":prompt:ganneff:${lr}:items:$it" post apost \
577             || zstyle -s ":prompt:ganneff:extra:$it" post apost \
578             || apost=${ganneff_prompt_post_default[$it]}
579         zstyle -s ":prompt:ganneff:${lr}:items:$it" token new \
580             || zstyle -s ":prompt:ganneff:extra:$it" token new \
581             || new=${ganneff_prompt_token_default[$it]}
582
583         # Now check if there is the wish for a precmd function and if so,
584         # run it
585         zstyle -s ":prompt:ganneff:extra:$it" precmd prefunc
586         if [[ -n "${prefunc}" ]]; then
587             ${prefunc} || true
588         fi
589
590         typeset -g "${target}=${(P)target}${apre}"
591         # Store the expanded value in PR_PS1, as we use that for length calculations
592         [[ $it == "newline" ]] && nomore=1
593         if [[ $nomore -eq 0 ]] && [[ $it != "flexline" ]] &&  PR_PS1+=${(e%)new}
594         case $it in
595             battery)
596                 ganneff_typeset_and_wrap $target $new '' ''
597                 ;;
598             change-root)
599                 ganneff_typeset_and_wrap $target $new '(' ')'
600                 ;;
601             flexline)
602                 typeset -g "${target}=${(P)target}\${${new}}"
603                 ;;
604             ganneff-chroot)
605                 if [[ -n ${(P)new} ]]; then
606                     typeset -g "${target}=${(P)target}(CHROOT)"
607                 fi
608                 ;;
609             vcs)
610                 v="vcs_info_msg_${new}_"
611                 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
612                     typeset -g "${target}=${(P)target}${(P)v//[$\`]/}"
613                 fi
614                 ;;
615             *) typeset -g "${target}=${(P)target}${new}" ;;
616         esac
617         typeset -g "${target}=${(P)target}${apost}"
618     done
619 }
620
621 prompt_ganneff_battery() {
622     zstyle -s ':prompt:ganneff' battery pr_battery
623     case $pr_battery in
624         ibam)
625             local ACPIDATA=$(ibam --percentbattery 2>/dev/null || echo "")
626             PERCENT=${${ACPIDATA[(f)1]}[(w)-2]}
627             ;;
628         acpi)
629             PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
630             ;;
631         *)
632             PERCENT=""
633             ;;
634     esac
635
636     if [[ -z "$PERCENT" ]] ; then
637         PERCENT="No battery or $pr_battery not present "
638     else
639         if [[ "$PERCENT" -lt 20 ]] ; then
640             PERCENT="warning: ${PERCENT}%%"
641         else
642             PERCENT="${PERCENT}%%"
643         fi
644     fi
645 }
646
647 is435(){
648     [[ $ZSH_VERSION == 4.3.<5->* || $ZSH_VERSION == 4.<4->* \
649                                  || $ZSH_VERSION == <5->* ]] && return 0
650     return 1
651 }
652
653 is439(){
654     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
655                                  || $ZSH_VERSION == <5->* ]] && return 0
656     return 1
657 }
658
659 # Ensure the add-zsh-hook function is available
660 is435 && autoload -Uz add-zsh-hook
661 prompt_ganneff_setup "$@"