more prompt fun
[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 technic 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 openbracket, closebracket, pipe, space, flexline
57
58 Most of those should be self-explanatory, some may need more:
59 line - Draws a single line character
60 XYcorner - Draws a corner. The chars to replace XY are
61 X=u for upper, l for lower
62 Y=l for left, r for right
63 flexline - Same as line, but flexible length to fill remaining space
64 Only works in a two-line prompt in the upper line, that
65 is, a newline MUST appear in the setup!
66
67 The actual configuration is done via zsh's \`zstyle' mechanism. The
68 context, that is used while looking up styles is:
69
70 ':prompt:ganneff:<left-or-right>:<full-or-small>:<subcontext>'
71
72 Here <left-or-right> is either \`left' or \`right', signifying whether the
73 style should affect the left or the right prompt. <full-or-small> is
74 either \`full' or \`small' and only valid in the item selection,
75 signifying wether the item list should affect the full length or
76 the "small terminal" prompt. As "small terminal" prompt does not
77 display the right side prompt, <full-or-small> has no effect on the
78 right side prompt.
79 <subcontext> is either \`setup' or 'items:<item>', where \`<item>'
80 is one of the available items.
81
82 The styles available under ':prompt:ganneff:':
83
84 - vcs_info (boolean): If \`true' (the default), use \`vcs_info'.
85
86 - set_vcs_info_defaults (boolean): If \`true' (the default),
87 various vcs_info settings will be done. If unset or \`false'
88 it is assumed that the user has already done this.
89
90 The default setup is:
91 zstyle ':vcs_info:*' max-exports 1
92 zstyle ':vcs_info:*' use-prompt-escapes
93 zstyle ':vcs_info:*' use_simple
94 zstyle ':vcs_info:*' stagedstr "!"
95 zstyle ':vcs_info:*' unstagedstr "?"
96 zstyle ':vcs_info:*' check-for-changes true
97 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat \
98 "\${PR_YELLOW}%b%{\${PR_RED}%}:\${PR_YELLOW}%r\${PR_NO_COLOR}"
99 zstyle ':vcs_info:*' formats \
100 "(\${PR_YELLOW}%s\${PR_NO_COLOR})-[\${PR_GREEN}%b\${PR_NO_COLOR}]%m%u%c "
101 zstyle ':vcs_info:*' actionformats \
102 "(\${PR_YELLOW}%s\${PR_NO_COLOR})-[\${PR_GREEN}%b\${PR_NO_COLOR}-\${PR_RED}(%a)\${PR_NO_COLOR}]%m%u%c "
103
104 - colors (boolean): If \`true' (the default), use colors. b/w
105 otherwise.
106
107 - nicelines (boolean): If \`true' (the default), use special
108 magic to draw nice lines and corners. Might not work on every
109 terminal. If false, draws using plain ascii characters.
110
111 - battery (string): If \`none' then no battery function at all.
112 If either \`ibam' or \`acpi' then use those tools to gather
113 the current battery level.
114
115 - use-rprompt (boolean): If \`true' (the default), print the
116 right side prompt.
117
118 - items (list): The list of items used in the prompt. If \`vcs' is
119 present in the list, the theme's code invokes \`vcs_info'
120 accordingly. Default (left): rc change-root user at host path vcs
121 percent; Default (right): sad-smiley
122
123 Available styles in 'items:<item>' are: pre, post. These are strings that
124 are inserted before (pre) and after (post) the item in question. Thus, the
125 following would cause the user name to be printed in red instead of the
126 default blue:
127
128 zstyle ':prompt:ganneff:*:items:user' pre '\${PR_RED}'
129
130 Note, that the \`post' style may remain at its default value, because its
131 default value is '\${PR_NO_COLOR}', which turns the foreground text
132 attribute off (which is exactly, what is still required with the new
133 \`pre' value).
134
135 Possible values for the colors: \${PR_XXX} and \${PR_BOLD_XXX} with
136 XXX replaced with one of: RED GREEN YELLOW BLUE MAGENTA CYAN WHITE
137 \${PR_NO_COLOR} resets color.
138 Using the \${PR_XXX} values instead of zsh's internal \%F{xxx} allows
139 the style to turn off colors to work.
140 __EOF0__
141 }
142
143 prompt_ganneff_setup () {
144 emulate -L zsh
145 setopt nolocaltraps
146
147 # See if we can and should use extended characters to look nicer.
148 if zstyle -t ':prompt:ganneff' nicelines && [[ "$TERM" != dumb ]]; then
149 typeset -A altchar
150 set -A altchar ${(s..)terminfo[acsc]}
151 # Some stuff to help us draw nice lines
152 PR_SET_CHARSET="%{$terminfo[enacs]%}"
153 PR_SHIFT_IN="%{$terminfo[smacs]%}"
154 PR_SHIFT_OUT="%{$terminfo[rmacs]%}"
155 PR_HBAR=${altchar[q]:--}
156 PR_ULCORNER=${altchar[l]:--}
157 PR_LLCORNER=${altchar[m]:--}
158 PR_LRCORNER=${altchar[j]:--}
159 PR_URCORNER=${altchar[k]:--}
160 else
161 PR_SET_CHARSET=""
162 PR_SHIFT_IN=""
163 PR_SHIFT_OUT=""
164 PR_HBAR="-"
165 PR_ULCORNER=""
166 PR_LLCORNER=""
167 PR_LRCORNER=""
168 PR_URCORNER=""
169 fi
170
171 if zstyle -t ':prompt:ganneff' colors && [[ "$TERM" != dumb ]]; then
172 if [[ -n "${BLUE}" ]] && [[ -n "${YELLOW}" ]]; then
173 # Two defined, so we assume someone already defined themself
174 # the colors. We just use them and not setup our own.
175 for color in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE; do
176 eval PR_$color="%{${(P)color}%}"
177 eval PR_BOLD_$color="%{$terminfo[bold]${(LP)color}%}"
178 done
179 PR_NO_COLOR="%{${reset_color}%}"
180 else
181 # Seems like colors are not defined, so set them up
182 docolors
183 fi
184 else
185 PR_BLUE=''
186 PR_RED=''
187 PR_GREEN=''
188 PR_CYAN=''
189 PR_WHITE=''
190 PR_MAGENTA=''
191 PR_YELLOW=''
192 PR_NO_COLOR="%{${reset_color}%}"
193 fi
194
195 # Easy things first.
196 # The secondary prompt, printed when the shell needs more
197 # information to complete a command. %_ displays any shell constructs
198 # or quotation marks which are currently being processed.
199 if zstyle -t ':prompt:ganneff' colors && [[ "$TERM" != dumb ]]; then
200 PS2='${PR_CYAN}${PR_SHIFT_IN}${PR_HBAR}${PR_BLUE}${PR_HBAR}${PR_SHIFT_OUT}\
201 (${PR_GREEN}%_${PR_BLUE})\
202 ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
203 else
204 PS2='-(%_)- '
205 fi
206 # selection prompt used within a select loop.
207 PS3='?# '
208 # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
209 PS4='+%N:%i:%_> '
210
211 if zstyle -t ':prompt:ganneff' vcs_info && \
212 is439 && autoload -Uz vcs_info && vcs_info; then
213 if zstyle -t ':prompt:ganneff' set_vcs_info_defaults; then
214 # gather version control information for inclusion in a prompt
215 # we will only be using one variable, so let the code know now.
216 zstyle ':vcs_info:*' max-exports 1
217 zstyle ':vcs_info:*' use-prompt-escapes
218 zstyle ':vcs_info:*' use_simple
219 zstyle ':vcs_info:*' stagedstr "!"
220 zstyle ':vcs_info:*' unstagedstr "?"
221 zstyle ':vcs_info:*' check-for-changes true
222
223 # change vcs_info formats for the prompt
224 zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "${PR_YELLOW}%b%{${PR_RED}%}:${PR_YELLOW}%r${PR_NO_COLOR}"
225 zstyle ':vcs_info:*' formats "(${PR_YELLOW}%s${PR_NO_COLOR})-[${PR_GREEN}%b${PR_NO_COLOR}]%m%u%c "
226 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 "
227 fi
228 fi
229
230 # These maps define default tokens and pre-/post-decoration for items to be
231 # used within the themes. All defaults may be customised in a context sensitive
232 # matter by using zsh's `zstyle' mechanism.
233 typeset -gA ganneff_prompt_pre_default \
234 ganneff_prompt_post_default \
235 ganneff_prompt_token_default
236
237 ganneff_prompt_pre_default=(
238 at ''
239 battery ' '
240 change-root ''
241 date '${PR_BLUE}'
242 history '${PR_GREEN}'
243 host '${PR_RED}'
244 jobs '${PR_CYAN}'
245 newline ''
246 path '${PR_MAGENTA}'
247 percent ''
248 rc '${PR_RED}'
249 rc-always ''
250 shell-level '${PR_RED}'
251 time '${PR_BLUE}'
252 user '${PR_BLUE}'
253 vcs ''
254 ulcorner '${PR_SHIFT_IN}'
255 llcorner '${PR_SHIFT_IN}'
256 urcorner '${PR_SHIFT_IN}'
257 lrcorner '${PR_SHIFT_IN}'
258 line '${PR_SHIFT_IN}'
259 pts ''
260 openbracket ''
261 closebracket ''
262 pipe ''
263 space ''
264 flexline '${PR_SHIFT_IN}'
265 )
266
267 ganneff_prompt_post_default=(
268 at ''
269 battery ''
270 change-root ''
271 date '${PR_NO_COLOR}'
272 history '${PR_NO_COLOR}'
273 host '${PR_NO_COLOR}'
274 jobs '${PR_NO_COLOR}'
275 newline ''
276 path '${PR_NO_COLOR}'
277 percent ''
278 rc '${PR_NO_COLOR}'
279 rc-always ''
280 shell-level '${PR_NO_COLOR}'
281 time '${PR_NO_COLOR}'
282 user '${PR_NO_COLOR}'
283 vcs ''
284 ulcorner '${PR_SHIFT_OUT}'
285 llcorner '${PR_SHIFT_OUT}'
286 urcorner '${PR_SHIFT_OUT}'
287 lrcorner '${PR_SHIFT_OUT}'
288 line '${PR_SHIFT_OUT}'
289 pts ''
290 openbracket ''
291 closebracket ''
292 pipe ''
293 space ''
294 flexline '${PR_SHIFT_OUT}'
295 )
296
297 ganneff_prompt_token_default=(
298 at '@'
299 battery 'PERCENT'
300 change-root 'debian_chroot'
301 date '%D{%Y-%m-%d}'
302 history '{#%!}'
303 host '%m'
304 jobs '[%j running job(s)] '
305 newline $'\n'
306 path '%40<..<%~%<<'
307 percent '% # '
308 rc '%(?..%? )'
309 rc-always '%?'
310 shell-level '%(3L.+ .)'
311 time '%D{%H:%M:%S}'
312 user '%n'
313 vcs '0'
314 ulcorner '${PR_ULCORNER}'
315 llcorner '${PR_LLCORNER}'
316 urcorner '${PR_URCORNER}'
317 lrcorner '${PR_LRCORNER}'
318 line '${PR_HBAR}'
319 pts ':%y'
320 openbracket '('
321 closebracket ')'
322 pipe '|'
323 space ' '
324 flexline 'PR_FLEXLINE'
325 )
326
327 PR_FLEXLINE=""
328 add-zsh-hook precmd prompt_ganneff_precmd
329 # Call the winch function once to ensure the length gets calculated
330 # correctly
331 prompt_ganneff_winch
332 local pr_battery
333 zstyle -s ':prompt:ganneff' battery pr_battery
334 if [[ $pr_battery != "none" ]]; then
335 add-zsh-hook precmd prompt_ganneff_battery
336 prompt_ganneff_battery
337 fi
338
339 functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}
340 prompt_ganneff_winch"
341 }
342
343 prompt_ganneff_precmd () {
344 emulate -L zsh
345 setopt nolocaltraps
346
347 zstyle -t ':prompt:ganneff' vcs_info && vcs_info
348 local -a left_items right_items
349 left_items=(ulcorner line openbracket user at host pts closebracket line history flexline
350 openbracket path closebracket line urcorner newline
351 llcorner line rc openbracket time closebracket line vcs line change-root pipe space)
352 PR_PS1=""; nomore=0
353 ganneff_prompt_addto PS1 full "${left_items[@]}"
354 if zstyle -T ":prompt:ganneff:right:setup" use-rprompt; then
355 right_items=(space pipe line openbracket date closebracket line lrcorner)
356 ganneff_prompt_addto RPS1 full "${right_items[@]}"
357 fi
358
359 # Now a kind-of-hack to reduce the prompt when we run out of space.
360 promptsize=${#PR_PS1}
361 if [[ ${promptsize} -lt ${TERMWIDTH} ]]; then
362 # the q here should be ${PR_HBAR}, but for some reason zsh didn't like me,
363 # so meh
364 if zstyle -t ':prompt:ganneff' nicelines && [[ "$TERM" != dumb ]]; then
365 PR_FLEXLINE="${(l.(($TERMWIDTH - $promptsize ))..q.)}"
366 else
367 PR_FLEXLINE="${(l.(($TERMWIDTH - $promptsize ))..-.)}"
368 fi
369 else
370 # Small size prompt is needed
371 left_items=(ulcorner line openbracket user at host closebracket line openbracket path closebracket newline
372 llcorner line rc openbracket time closebracket line vcs line pipe space)
373 ganneff_prompt_addto PS1 small "${left_items[@]}"
374 # And with a small prompt, we don't show the right size at all.
375 RPS1=""
376 fi
377 }
378
379 prompt_ganneff_length () {
380 (( TERMWIDTH = ${COLUMNS} - 1 ))
381 }
382
383 prompt_ganneff_winch () {
384 emulate -L zsh
385 setopt nolocaltraps noksharrays unset
386
387 # Delete ourself from TRAPWINCH if not using our precmd insert.
388 [[ $precmd_functions = *prompt_ganneff_precmd* ]] && prompt_ganneff_length ||
389 functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}"
390 }
391
392 ganneff_typeset_and_wrap () {
393 emulate -L zsh
394 local target="$1"
395 local new="$2"
396 local left="$3"
397 local right="$4"
398
399 if (( ${+parameters[$new]} )); then
400 typeset -g "${target}=${(P)target}${left}${(P)new}${right}"
401 fi
402 }
403
404 ganneff_prompt_addto () {
405 emulate -L zsh
406 local target="$1"
407 local size="$2"
408 local lr it apre apost new v
409 local -a items
410 shift
411 shift
412
413 [[ $target == PS1 ]] && lr=left || lr=right
414 zstyle -a ":prompt:ganneff:${lr}:${size}:setup" items items || items=( "$@" )
415 typeset -g "${target}="
416 for it in "${items[@]}"; do
417 zstyle -s ":prompt:ganneff:${lr}:items:$it" pre apre \
418 || apre=${ganneff_prompt_pre_default[$it]}
419 zstyle -s ":prompt:ganneff:${lr}:items:$it" post apost \
420 || apost=${ganneff_prompt_post_default[$it]}
421 zstyle -s ":prompt:ganneff:${lr}:items:$it" token new \
422 || new=${ganneff_prompt_token_default[$it]}
423 typeset -g "${target}=${(P)target}${apre}"
424 # Store the expanded value in PR_PS1, as we use that for length calculations
425 [[ $it == "newline" ]] && nomore=1
426 if [[ $nomore -eq 0 ]] && [[ $it != "flexline" ]] && PR_PS1+=${(e%)new}
427 case $it in
428 battery)
429 ganneff_typeset_and_wrap $target $new '' ''
430 ;;
431 change-root)
432 ganneff_typeset_and_wrap $target $new '(' ')'
433 ;;
434 flexline)
435 typeset -g "${target}=${(P)target}\${${new}}"
436 ;;
437 ganneff-chroot)
438 if [[ -n ${(P)new} ]]; then
439 typeset -g "${target}=${(P)target}(CHROOT)"
440 fi
441 ;;
442 vcs)
443 v="vcs_info_msg_${new}_"
444 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
445 typeset -g "${target}=${(P)target}${(P)v}"
446 fi
447 ;;
448 *) typeset -g "${target}=${(P)target}${new}" ;;
449 esac
450 typeset -g "${target}=${(P)target}${apost}"
451 done
452 }
453
454 prompt_ganneff_battery() {
455 zstyle -s ':prompt:ganneff' battery pr_battery
456 case $pr_battery in
457 ibam)
458 local ACPIDATA=$(ibam --percentbattery 2>/dev/null || echo "")
459 PERCENT=${${ACPIDATA[(f)1]}[(w)-2]}
460 ;;
461 acpi)
462 PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
463 ;;
464 *)
465 PERCENT=""
466 ;;
467 esac
468
469 if [[ -z "$PERCENT" ]] ; then
470 PERCENT="No battery or $pr_battery not present "
471 else
472 if [[ "$PERCENT" -lt 20 ]] ; then
473 PERCENT="warning: ${PERCENT}%%"
474 else
475 PERCENT="${PERCENT}%%"
476 fi
477 fi
478 }
479
480 prompt_ganneff_setup "$@"