zshrc: improvements by Kai Wilke. Thanks!
[grml-etc-core.git] / etc / zsh / zshrc
1 # Filename:      zshrc
2 # Purpose:       config file for zsh (z shell)
3 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
4 # Bug-Reports:   see http://grml.org/bugs/
5 # License:       This file is licensed under the GPL v2.
6 # Latest change: Wed Aug 06 23:50:53 CEST 2008 [mika]
7 ################################################################################
8 # This file is sourced only for interactive shells. It
9 # should contain commands to set up aliases, functions,
10 # options, key bindings, etc.
11 #
12 # Global Order: zshenv, zprofile, zshrc, zlogin
13 ################################################################################
14
15 # zsh-refcard-tag documentation: {{{
16 #   You may notice strange looking comments in the zshrc (and ~/.zshrc as
17 #   well). These are there for a purpose. grml's zsh-refcard can now be
18 #   automatically generated from the contents of the actual configuration
19 #   files. However, we need a little extra information on which comments
20 #   and what lines of code to take into account (and for what purpose).
21 #
22 # Here is what they mean:
23 #
24 # List of tags (comment types) used:
25 #   #a#     Next line contains an important alias, that should
26 #           be included in the grml-zsh-refcard.
27 #           (placement tag: @@INSERT-aliases@@)
28 #   #f#     Next line contains the beginning of an important function.
29 #           (placement tag: @@INSERT-functions@@)
30 #   #v#     Next line contains an important variable.
31 #           (placement tag: @@INSERT-variables@@)
32 #   #k#     Next line contains an important keybinding.
33 #           (placement tag: @@INSERT-keybindings@@)
34 #   #d#     Hashed directories list generation:
35 #               start   denotes the start of a list of 'hash -d'
36 #                       definitions.
37 #               end     denotes its end.
38 #           (placement tag: @@INSERT-hasheddirs@@)
39 #   #A#     Abbreviation expansion list generation:
40 #               start   denotes the beginning of abbreviations.
41 #               end     denotes their end.
42 #           Lines within this section that end in '#d .*' provide
43 #           extra documentation to be included in the refcard.
44 #           (placement tag: @@INSERT-abbrev@@)
45 #   #m#     This tag allows you to manually generate refcard entries
46 #           for code lines that are hard/impossible to parse.
47 #               Example:
48 #                   #m# k ESC-h Call the run-help function
49 #               That would add a refcard entry in the keybindings table
50 #               for 'ESC-h' with the given comment.
51 #           So the syntax is: #m# <section> <argument> <comment>
52 #   #o#     This tag lets you insert entries to the 'other' hash.
53 #           Generally, this should not be used. It is there for
54 #           things that cannot be done easily in another way.
55 #           (placement tag: @@INSERT-other-foobar@@)
56 #
57 #   All of these tags (except for m and o) take two arguments, the first
58 #   within the tag, the other after the tag:
59 #
60 #   #<tag><section># <comment>
61 #
62 #   Where <section> is really just a number, which are defined by the
63 #   @secmap array on top of 'genrefcard.pl'. The reason for numbers
64 #   instead of names is, that for the reader, the tag should not differ
65 #   much from a regular comment. For zsh, it is a regular comment indeed.
66 #   The numbers have got the following meanings:
67 #         0 -> "default"
68 #         1 -> "system"
69 #         2 -> "user"
70 #         3 -> "debian"
71 #         4 -> "search"
72 #         5 -> "shortcuts"
73 #         6 -> "services"
74 #
75 #   So, the following will add an entry to the 'functions' table in the
76 #   'system' section, with a (hopefully) descriptive comment:
77 #       #f1# Edit an alias via zle
78 #       edalias() {
79 #
80 #   It will then show up in the @@INSERT-aliases-system@@ replacement tag
81 #   that can be found in 'grml-zsh-refcard.tex.in'.
82 #   If the section number is omitted, the 'default' section is assumed.
83 #   Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
84 #   exactly the same as @@INSERT-aliases-default@@. If you want a list of
85 #   *all* aliases, for example, use @@INSERT-aliases-all@@.
86 #}}}
87
88 # zsh profiling {{{
89 # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
90 if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
91     zmodload zsh/zprof
92 fi
93 # }}}
94
95 # {{{ check for version/system
96 # check for versions (compatibility reasons)
97 is4(){
98     [[ $ZSH_VERSION == <4->* ]] && return 0
99     return 1
100 }
101
102 is41(){
103     [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
104     return 1
105 }
106
107 is42(){
108     [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
109     return 1
110 }
111
112 is425(){
113     [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
114     return 1
115 }
116
117 is43(){
118     [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
119     return 1
120 }
121
122 #f1# Checks whether or not you're running grml
123 isgrml(){
124     [[ -f /etc/grml_version ]] && return 0
125     return 1
126 }
127
128 #f1# Checks whether or not you're running a grml cd
129 isgrmlcd(){
130     [[ -f /etc/grml_cd ]] && return 0
131     return 1
132 }
133
134 if isgrml ; then
135 #f1# Checks whether or not you're running grml-small
136     isgrmlsmall() {
137         [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]] && return 0 ; return 1
138     }
139 else
140     isgrmlsmall() { return 1 }
141 fi
142
143 #f1# are we running within an utf environment?
144 isutfenv() {
145     case "$LANG $CHARSET $LANGUAGE" in
146         *utf*) return 0 ;;
147         *UTF*) return 0 ;;
148         *)     return 1 ;;
149     esac
150 }
151
152 # check for user, if not running as root set $SUDO to sudo
153 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
154
155 # change directory to home on first invocation of zsh
156 # important for rungetty -> autologin
157 # Thanks go to Bart Schaefer!
158 isgrml && checkhome() {
159     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
160         export ALREADY_DID_CD_HOME=$HOME
161         cd
162     fi
163 }
164
165 # check for zsh v3.1.7+
166
167 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
168      || ${ZSH_VERSION} == 3.<2->.<->*    \
169      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
170
171     printf '-!-\n'
172     printf '-!- In this configuration we try to make use of features, that only\n'
173     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
174     printf '-!- used with a wide range of zsh versions, while using fairly\n'
175     printf '-!- advanced features in all supported versions.\n'
176     printf '-!-\n'
177     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
178     printf '-!-\n'
179     printf '-!- While this *may* work, it might as well fail.\n'
180     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
181     printf '-!-\n'
182     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
183     printf '-!- If it does today, you'\''ve been lucky.\n'
184     printf '-!-\n'
185     printf '-!- Ye been warned!\n'
186     printf '-!-\n'
187
188     function zstyle() { : }
189 fi
190
191 # }}}
192
193 # utility functions {{{
194 # this function checks if a command exists and returns either true
195 # or false. This avoids using 'which' and 'whence', which will
196 # avoid problems with aliases for which on certain weird systems. :-)
197 check_com() {
198     local -i comonly
199
200     if [[ ${1} == '-c' ]] ; then
201         (( comonly = 1 ))
202         shift
203     else
204         (( comonly = 0 ))
205     fi
206
207     if (( ${#argv} != 1 )) ; then
208         printf 'usage: check_com [-c] <command>\n' >&2
209         return 1
210     fi
211
212     if (( comonly > 0 )) ; then
213         [[ -n ${commands[$1]}  ]] && return 0
214         return 1
215     fi
216
217     if   [[ -n ${commands[$1]}    ]] \
218       || [[ -n ${functions[$1]}   ]] \
219       || [[ -n ${aliases[$1]}     ]] \
220       || [[ -n ${reswords[(r)$1]} ]] ; then
221
222         return 0
223     fi
224
225     return 1
226 }
227
228 # creates an alias and precedes the command with
229 # sudo if $EUID is not zero.
230 salias() {
231     local only=0 ; local multi=0
232     while [[ ${1} == -* ]] ; do
233         case ${1} in
234             (-o) only=1 ;;
235             (-a) multi=1 ;;
236             (--) shift ; break ;;
237             (-h)
238                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
239                 printf '  -h      shows this help text.\n'
240                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
241                 printf '          be careful using this option.\n'
242                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
243                 return 0
244                 ;;
245             (*) printf "unkown option: '%s'\n" "${1}" ; return 1 ;;
246         esac
247         shift
248     done
249
250     if (( ${#argv} > 1 )) ; then
251         printf 'Too many arguments %s\n' "${#argv}"
252         return 1
253     fi
254
255     key="${1%%\=*}" ;  val="${1#*\=}"
256     if (( EUID == 0 )) && (( only == 0 )); then
257         alias -- "${key}=${val}"
258     elif (( EUID > 0 )) ; then
259         (( multi > 0 )) && val="${val// ; / ; sudo }"
260         alias -- "${key}=sudo ${val}"
261     fi
262
263     return 0
264 }
265
266 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
267 # usage: uprint foo
268 #   Where foo is the *name* of the parameter you want printed.
269 #   Note that foo is no typo; $foo would be wrong here!
270 if ! is42 ; then
271     uprint () {
272         local -a u
273         local w
274         local parameter=${1}
275
276         if [[ -z ${parameter} ]] ; then
277             printf 'usage: uprint <parameter>\n'
278             return 1
279         fi
280
281         for w in ${(P)parameter} ; do
282             [[ -z ${(M)u:#${w}} ]] && u=( ${u} ${w} )
283         done
284
285         builtin print -l ${u}
286     }
287 fi
288
289 # Check if we can read given files and source those we can.
290 xsource() {
291     if (( ${#argv} < 1 )) ; then
292         printf 'usage: xsource FILE(s)...\n' >&2
293         return 1
294     fi
295
296     while (( ${#argv} > 0 )) ; do
297         [[ -r ${1} ]] && source ${1}
298         shift
299     done
300     return 0
301 }
302
303 # Check if we can read a given file and 'cat(1)' it.
304 xcat() {
305     if (( ${#argv} != 1 )) ; then
306         printf 'usage: xcat FILE\n' >&2
307         return 1
308     fi
309
310     [[ -r ${1} ]] && cat ${1}
311     return 0
312 }
313
314 # Remove these functions again, they are of use only in these
315 # setup files. This should be called at the end of .zshrc.
316 xunfunction() {
317     local -a funcs
318     funcs=(salias xcat xsource xunfunction zrcautoload)
319
320     for func in $funcs ; do
321         [[ -n ${functions[$func]} ]] \
322             && unfunction $func
323     done
324     return 0
325 }
326
327 # autoload wrapper - use this one instead of autoload directly
328 function zrcautoload() {
329     setopt local_options extended_glob
330     local fdir ffile
331     local -i ffound
332
333     ffile=${1}
334     (( found = 0 ))
335     for fdir in ${fpath} ; do
336         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
337     done
338
339     (( ffound == 0 )) && return 1
340     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
341         autoload -U ${ffile} || return 1
342     else
343         autoload ${ffile} || return 1
344     fi
345     return 0
346 }
347
348 #}}}
349
350 # Load is-at-least() for more precise version checks {{{
351
352 # Note that this test will *always* fail, if the is-at-least
353 # function could not be marked for autoloading.
354 zrcautoload is-at-least || is-at-least() { return 1 }
355
356 # }}}
357
358 # locale setup {{{
359 if [[ -z "$LANG" ]] ; then
360    xsource "/etc/default/locale"
361 fi
362
363 export LANG=${LANG:-en_US.iso885915}
364 for var in LC_ALL LC_MESSAGES ; do
365     [[ -n ${(P)var} ]] && export $var
366 done
367
368 xsource "/etc/sysconfig/keyboard"
369
370 TZ=$(xcat /etc/timezone)
371 # }}}
372
373 # check for potentially old files in 'completion.d' {{{
374 setopt extendedglob
375 xof=(/etc/zsh/completion.d/*~/etc/zsh/completion.d/_*(N))
376 if (( ${#xof} > 0 )) ; then
377     printf '\n -!- INFORMATION\n\n'
378     printf ' -!- %s file(s) not starting with an underscore (_) found in\n' ${#xof}
379     printf ' -!- /etc/zsh/completion.d/.\n\n'
380     printf ' -!- While this has been the case in old versions of grml-etc-core,\n'
381     printf ' -!- recent versions of the grml-zsh-setup have all these files rewritten\n'
382     printf ' -!- and renamed. Furthermore, the grml-zsh-setup will *only* add files\n'
383     printf ' -!- named _* to that directory.\n\n'
384     printf ' -!- If you added functions to completion.d yourself, please consider\n'
385     printf ' -!- moving them to /etc/zsh/functions.d/. Files in that directory, not\n'
386     printf ' -!- starting with an underscore are marked for automatic loading\n'
387     printf ' -!- by default (so that is quite convenient).\n\n'
388     printf ' -!- If there are files *not* starting with an underscore from an older\n'
389     printf ' -!- grml-etc-core in completion.d, you may safely remove them.\n\n'
390     printf ' -!- Delete the files for example via running:\n\n'
391     printf "      rm ${xof}\n\n"
392     printf ' -!- Note, that this message will *not* go away, unless you yourself\n'
393     printf ' -!- resolve the situation manually.\n\n'
394     BROKEN_COMPLETION_DIR=1
395 fi
396 unset xof
397 # }}}
398
399 # {{{ set some variables
400 if check_com -c vim ; then
401 #v#
402     export EDITOR=${EDITOR:-vim}
403 else
404     export EDITOR=${EDITOR:-vi}
405 fi
406
407 #v#
408 export PAGER=${PAGER:-less}
409
410 #v#
411 export MAIL=${MAIL:-/var/mail/$USER}
412
413 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
414 export SHELL='/bin/zsh'
415
416 # color setup for ls:
417 check_com -c dircolors && eval $(dircolors -b)
418
419 # set width of man pages to 80 for more convenient reading
420 # export MANWIDTH=${MANWIDTH:-80}
421
422 # Search path for the cd command
423 #  cdpath=(.. ~)
424
425 # completion functions go to /etc/zsh/completion.d
426 # function files may be put into /etc/zsh/functions.d, from where they
427 # will be automatically autoloaded.
428 if [[ -n "$BROKEN_COMPLETION_DIR" ]] ; then
429     print 'Warning: not setting completion directories because broken files have been found.' >&2
430 else
431     [[ -d /etc/zsh/completion.d ]] && fpath=( $fpath /etc/zsh/completion.d )
432     if [[ -d /etc/zsh/functions.d ]] ; then
433         fpath+=( /etc/zsh/functions.d )
434         for func in /etc/zsh/functions.d/[^_]*[^~](N.) ; do
435             zrcautoload -U ${func:t}
436         done
437     fi
438 fi
439
440 # automatically remove duplicates from these arrays
441 typeset -U path cdpath fpath manpath
442 # }}}
443
444 # {{{ keybindings
445 if [[ "$TERM" != emacs ]] ; then
446     [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
447     [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
448     [[ -z "$terminfo[kend]"  ]] || bindkey -M emacs "$terminfo[kend]"  end-of-line
449     [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
450     [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
451     [[ -z "$terminfo[kend]"  ]] || bindkey -M vicmd "$terminfo[kend]"  vi-end-of-line
452     [[ -z "$terminfo[cuu1]"  ]] || bindkey -M viins "$terminfo[cuu1]"  vi-up-line-or-history
453     [[ -z "$terminfo[cuf1]"  ]] || bindkey -M viins "$terminfo[cuf1]"  vi-forward-char
454     [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
455     [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
456     [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
457     [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
458     # ncurses stuff:
459     [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
460     [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
461     [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
462     [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
463     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
464     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}"  end-of-line
465     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
466     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line
467 fi
468
469 ## keybindings (run 'bindkeys' for details, more details via man zshzle)
470 # use emacs style per default:
471 bindkey -e
472 # use vi style:
473 # bindkey -v
474
475 #if [[ "$TERM" == screen ]] ; then
476 bindkey '\e[1~' beginning-of-line       # home
477 bindkey '\e[4~' end-of-line             # end
478 bindkey '\e[A'  up-line-or-search       # cursor up
479 bindkey '\e[B'  down-line-or-search     # <ESC>-
480
481 bindkey '^xp'   history-beginning-search-backward
482 bindkey '^xP'   history-beginning-search-forward
483 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
484 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
485 # if terminal type is set to 'rxvt':
486 bindkey '\e[7~' beginning-of-line       # home
487 bindkey '\e[8~' end-of-line             # end
488 #fi
489
490 # insert unicode character
491 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
492 # See for example http://unicode.org/charts/ for unicode characters code
493 zrcautoload insert-unicode-char
494 zle -N insert-unicode-char
495 #k# Insert Unicode character
496 bindkey '^Xi' insert-unicode-char
497
498 # just type 'cd ...' to get 'cd ../..'
499 #  rationalise-dot() {
500 #  if [[ $LBUFFER == *.. ]] ; then
501 #    LBUFFER+=/..
502 #  else
503 #    LBUFFER+=.
504 #  fi
505 #  }
506 #  zle -N rationalise-dot
507 #  bindkey . rationalise-dot
508
509 #  bindkey '\eq' push-line-or-edit
510
511 ## toggle the ,. abbreviation feature on/off
512 # NOABBREVIATION: default abbreviation-state
513 #                 0 - enabled (default)
514 #                 1 - disabled
515 NOABBREVIATION=${NOABBREVIATION:-0}
516
517 grml_toggle_abbrev() {
518     if (( ${NOABBREVIATION} > 0 )) ; then
519         NOABBREVIATION=0
520     else
521         NOABBREVIATION=1
522     fi
523 }
524
525 zle -N grml_toggle_abbrev
526 bindkey '^xA' grml_toggle_abbrev
527
528 # }}}
529
530 # a generic accept-line wrapper {{{
531
532 # This widget can prevent unwanted autocorrections from command-name
533 # to _command-name, rehash automatically on enter and call any number
534 # of builtin and user-defined widgets in different contexts.
535 #
536 # For a broader description, see:
537 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
538 #
539 # The code is imported from the file 'zsh/functions/accept-line' from
540 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
541 # distributed under the same terms as zsh itself.
542
543 # A newly added command will may not be found or will cause false
544 # correction attempts, if you got auto-correction set. By setting the
545 # following style, we force accept-line() to rehash, if it cannot
546 # find the first word on the command line in the $command[] hash.
547 zstyle ':acceptline:*' rehash true
548
549 function Accept-Line() {
550     setopt localoptions noksharrays
551     local -a subs
552     local -xi aldone
553     local sub
554
555     zstyle -a ":acceptline:${alcontext}" actions subs
556
557     (( ${#subs} < 1 )) && return 0
558
559     (( aldone = 0 ))
560     for sub in ${subs} ; do
561         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
562         zle ${sub}
563
564         (( aldone > 0 )) && break
565     done
566 }
567
568 function Accept-Line-getdefault() {
569     local default_action
570
571     zstyle -s ":acceptline:${alcontext}" default_action default_action
572     case ${default_action} in
573         ((accept-line|))
574             printf ".accept-line"
575             ;;
576         (*)
577             printf ${default_action}
578             ;;
579     esac
580 }
581
582 function accept-line() {
583     setopt localoptions noksharrays
584     local -a cmdline
585     local -x alcontext
586     local buf com fname format msg default_action
587
588     alcontext='default'
589     buf="${BUFFER}"
590     cmdline=(${(z)BUFFER})
591     com="${cmdline[1]}"
592     fname="_${com}"
593
594     zstyle -t ":acceptline:${alcontext}" rehash \
595         && [[ -z ${commands[$com]} ]]           \
596         && rehash
597
598     if    [[ -n ${reswords[(r)$com]} ]] \
599        || [[ -n ${aliases[$com]}     ]] \
600        || [[ -n ${functions[$com]}   ]] \
601        || [[ -n ${builtins[$com]}    ]] \
602        || [[ -n ${commands[$com]}    ]] ; then
603
604         # there is something sensible to execute, just do it.
605         alcontext='normal'
606         zle Accept-Line
607
608         default_action=$(Accept-Line-getdefault)
609         zstyle -T ":acceptline:${alcontext}" call_default \
610             && zle ${default_action}
611         return
612     fi
613
614     if    [[ -o correct              ]] \
615        || [[ -o correctall           ]] \
616        && [[ -n ${functions[$fname]} ]] ; then
617
618         # nothing there to execute but there is a function called
619         # _command_name; a completion widget. Makes no sense to
620         # call it on the commandline, but the correct{,all} options
621         # will ask for it nevertheless, so warn the user.
622         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
623             # Okay, we warned the user before, he called us again,
624             # so have it his way.
625             alcontext='force'
626             zle Accept-Line
627
628             default_action=$(Accept-Line-getdefault)
629             zstyle -T ":acceptline:${alcontext}" call_default \
630                 && zle ${default_action}
631             return
632         fi
633
634         # prepare warning message for the user, configurable via zstyle.
635         zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
636
637         if [[ -z ${msg} ]] ; then
638             msg="%c will not execute and completion %f exists."
639         fi
640
641         zformat -f msg "${msg}" "c:${com}" "f:${fname}"
642
643         zle -M -- "${msg}"
644         return
645     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
646         # If we are here, the commandline contains something that is not
647         # executable, which is neither subject to _command_name correction
648         # and is not empty. might be a variable assignment
649         alcontext='misc'
650         zle Accept-Line
651
652         default_action=$(Accept-Line-getdefault)
653         zstyle -T ":acceptline:${alcontext}" call_default \
654             && zle ${default_action}
655         return
656     fi
657
658     # If we got this far, the commandline only contains whitespace, or is empty.
659     alcontext='empty'
660     zle Accept-Line
661
662     default_action=$(Accept-Line-getdefault)
663     zstyle -T ":acceptline:${alcontext}" call_default \
664         && zle ${default_action}
665 }
666
667 zle -N accept-line
668 zle -N Accept-Line
669
670 # }}}
671
672 # power completion - abbreviation expansion {{{
673 # power completion / abbreviation expansion / buffer expansion
674 # see http://zshwiki.org/home/examples/zleiab for details
675 # less risky than the global aliases but powerful as well
676 # just type the abbreviation key and afterwards ',.' to expand it
677 declare -A abk
678 setopt extendedglob
679 setopt interactivecomments
680 abk=(
681 # key  # value                (#d additional doc string)
682 #A# start
683     '...' '../..'
684     '....' '../../..'
685     'BG' '& exit'
686     'C' '| wc -l'
687     'G' '|& grep --color=auto'
688     'H' '| head'
689     'Hl' ' --help |& less -r'      #d (Display help in pager)
690     'L' '| less'
691     'LL' '|& less -r'
692     'M' '| most'
693     'N' '&>/dev/null'              #d (No Output)
694     'R' '| tr A-z N-za-m'          #d (ROT13)
695     'SL' '| sort | less'
696     'S' '| sort -u'
697     'T' '| tail'
698     'V' '|& vim -'
699 #A# end
700     'hide' "echo -en '\033]50;nil2\007'"
701     'tiny' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
702     'small' 'echo -en "\033]50;6x10\007"'
703     'medium' 'echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
704     'default' 'echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
705     'large' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
706     'huge' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
707     'smartfont' 'echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
708     'semifont' 'echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
709     'da' 'du -sch'
710     'j' 'jobs -l'
711     'u' 'translate -i'
712     'co' "./configure && make && sudo make install"
713     'CH' "./configure --help"
714     'conkeror' 'firefox -chrome chrome://conkeror/content'
715     'dir' 'ls -lSrah'
716     'lad' $'ls -d .*(/)\n# only show dot-directories'
717     'lsa' $'ls -a .*(.)\n# only show dot-files'
718     'lss' $'ls -l *(s,S,t)\n# only files with setgid/setuid/sticky flag'
719     'lsl' $'ls -l *(@[1,10])\n# only symlinks'
720     'lsx' $'ls -l *(*[1,10])\n# only executables'
721     'lsw' $'ls -ld *(R,W,X.^ND/)\n# world-{readable,writable,executable} files'
722     'lsbig' $'ls -flh *(.OL[1,10])\n# display the biggest files'
723     'lsd' $'ls -d *(/)\n# only show directories'
724     'lse' $'ls -d *(/^F)\n# only show empty directories'
725     'lsnew' $'ls -rl *(D.om[1,10])\n# display the newest files'
726     'lsold' $'ls -rtlh *(D.om[-11,-1])\n # display the oldest files'
727     'lssmall' $'ls -Srl *(.oL[1,10])\n# display the smallest files'
728     'rw-' 'chmod 600'
729     '600' 'chmod u+rw-x,g-rwx,o-rwx'
730     'rwx' 'chmod u+rwx'
731     '700' 'chmod u+rwx,g-rwx,o-rwx'
732     'r--' 'chmod u+r-wx,g-rwx,o-rwx'
733     '644' $'chmod u+rw-x,g+r-wx,o+r-wx\n # 4=r,2=w,1=x'
734     '755' 'chmod u+rwx,g+r-w+x,o+r-w+x'
735     'md' 'mkdir -p '
736     'cmplayer' 'mplayer -vo -fs -zoom fbdev'
737     'fbmplayer' 'mplayer -vo -fs -zoom fbdev'
738     'fblinks' 'links2 -driver fb'
739     'insecssh' 'ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
740     'insecscp' 'scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
741     'fori' 'for i ({..}) { }'
742     'cx' 'chmod +x'
743     'e'  'print -l'
744     'se' 'setopt interactivecomments'
745     'va' 'valac --vapidir=../vapi/ --pkg=gtk+-2.0 gtktest.vala'
746     'fb2' '=mplayer -vo fbdev -fs -zoom 1>/dev/null -xy 2'
747     'fb3' '=mplayer -vo fbdev -fs  -zoom 1>/dev/null -xy 3'
748     'ci' 'centericq'
749     'D'  'export DISPLAY=:0.0'
750     'mp' 'mplayer -vo xv -fs -zoom'
751 )
752
753 globalias() {
754     local MATCH
755
756     if (( NOABBREVIATION > 0 )) ; then
757         LBUFFER="${LBUFFER},."
758         return 0
759     fi
760
761     matched_chars='[.-|_a-zA-Z0-9]#'
762     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
763     LBUFFER+=${abk[$MATCH]:-$MATCH}
764 }
765
766 zle -N globalias
767 bindkey ",." globalias
768 # }}}
769
770 # {{{ autoloading
771 zrcautoload zmv    # who needs mmv or rename?
772 zrcautoload history-search-end
773
774 # we don't want to quote/espace URLs on our own...
775 # if autoload -U url-quote-magic ; then
776 #    zle -N self-insert url-quote-magic
777 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
778 # else
779 #    print 'Notice: no url-quote-magic available :('
780 # fi
781 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
782
783 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
784 alias run-help >&/dev/null && unalias run-help
785 zrcautoload run-help # use via 'esc-h'
786
787 # completion system
788 if zrcautoload compinit && compinit 2>/dev/null ; then
789     compinit 2>/dev/null || print 'Notice: no compinit available :('
790 else
791     print 'Notice: no compinit available :('
792     function zstyle { }
793     function compdef { }
794 fi
795
796 is4 && zrcautoload zed # use ZLE editor to edit a file or function
797
798 is4 && \
799 for mod in complist deltochar mathfunc ; do
800     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
801 done
802
803 # autoload zsh modules when they are referenced
804 if is4 ; then
805     tmpargs=(
806         a   stat
807         a   zpty
808         ap  mapfile
809     )
810
811     while (( ${#tmpargs} > 0 )) ; do
812         zmodload -${tmpargs[1]} zsh/${tmpargs[2]} ${tmpargs[2]}
813         shift 2 tmpargs
814     done
815     unset tmpargs
816 fi
817
818 if is4 && zrcautoload insert-files && zle -N insert-files ; then
819     #k# Insert files
820     bindkey "^Xf" insert-files # C-x-f
821 fi
822
823 bindkey ' '   magic-space    # also do history expansion on space
824 #k# Trigger menu-complete
825 bindkey '\ei' menu-complete  # menu completion via esc-i
826
827 # press esc-e for editing command line in $EDITOR or $VISUAL
828 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
829     #k# Edit the current line in \kbd{\$EDITOR}
830     bindkey '\ee' edit-command-line
831 fi
832
833 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
834     #k# menu selection: pick item but stay in the menu
835     bindkey -M menuselect '\e^M' accept-and-menu-complete
836
837     # use the vi navigation keys (hjkl) besides cursor keys in menu completion
838     #bindkey -M menuselect 'h' vi-backward-char        # left
839     #bindkey -M menuselect 'k' vi-up-line-or-history   # up
840     #bindkey -M menuselect 'l' vi-forward-char         # right
841     #bindkey -M menuselect 'j' vi-down-line-or-history # bottom
842
843     # accept a completion and try to complete again by using menu
844     # completion; very useful with completing directories
845     # by using 'undo' one's got a simple file browser
846     bindkey -M menuselect '^o' accept-and-infer-next-history
847 fi
848
849 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
850 _bkdate() { BUFFER="$BUFFER$(date '+%F')"; CURSOR=$#BUFFER; }
851 zle -N _bkdate
852
853 #k# Insert a timestamp on the command line (yyyy-mm-dd)
854 bindkey '^Ed' _bkdate
855
856 # press esc-m for inserting last typed word again (thanks to caphuso!)
857 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
858 zle -N insert-last-typed-word;
859
860 #k# Insert last typed word
861 bindkey "\em" insert-last-typed-word
862
863 # set command prediction from history, see 'man 1 zshcontrib'
864 #  is4 && zrcautoload predict-on && \
865 #  zle -N predict-on         && \
866 #  zle -N predict-off        && \
867 #  bindkey "^X^Z" predict-on && \
868 #  bindkey "^Z" predict-off
869
870 #k# Shortcut for \kbd{fg<enter>}
871 bindkey -s '^z' "fg\n"
872
873 # press ctrl-q to quote line:
874 #  mquote () {
875 #        zle beginning-of-line
876 #        zle forward-word
877 #        # RBUFFER="'$RBUFFER'"
878 #        RBUFFER=${(q)RBUFFER}
879 #        zle end-of-line
880 #  }
881 #  zle -N mquote && bindkey '^q' mquote
882
883 # run command line as user root via sudo:
884 sudo-command-line() {
885     [[ -z $BUFFER ]] && zle up-history
886     [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
887 }
888 zle -N sudo-command-line
889
890 #k# Put the current command line into a \kbd{sudo} call
891 bindkey "^Os" sudo-command-line
892
893 ### jump behind the first word on the cmdline.
894 ### useful to add options.
895 function jump_after_first_word() {
896     local words
897     words=(${(z)BUFFER})
898
899     if (( ${#words} <= 1 )) ; then
900         CURSOR=${#BUFFER}
901     else
902         CURSOR=${#${words[1]}}
903     fi
904 }
905 zle -N jump_after_first_word
906
907 bindkey '^x1' jump_after_first_word
908
909 # }}}
910
911 # {{{ set some important options
912 # Please update these tags, if you change the umask settings below.
913 #o# r_umask     002
914 #o# r_umaskstr  rwxrwxr-x
915 #o# umask       022
916 #o# umaskstr    rwxr-xr-x
917 (( EUID != 0 )) && umask 002 || umask 022
918
919 # history:
920 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
921 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
922 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
923 is4 && setopt histignorealldups # If  a  new  command  line being added to the history
924                             # list duplicates an older one, the older command is removed from the list
925 setopt histignorespace      # remove command lines from the history list when
926                             # the first character on the line is a space
927 #  setopt histallowclobber    # add `|' to output redirections in the history
928 #  setopt NO_clobber          # warning if file exists ('cat /dev/null > ~/.zshrc')
929 setopt auto_cd              # if a command is issued that can't be executed as a normal command,
930                             # and the command is the name of a directory, perform the cd command to that directory
931 setopt extended_glob        # in order to use #, ~ and ^ for filename generation
932                             # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
933                             # -> searches for word not in compressed files
934                             # don't forget to quote '^', '~' and '#'!
935 setopt longlistjobs         # display PID when suspending processes as well
936 setopt notify               # report the status of backgrounds jobs immediately
937 setopt hash_list_all        # Whenever a command completion is attempted, make sure \
938                             # the entire command path is hashed first.
939 setopt completeinword       # not just at the end
940 # setopt nocheckjobs          # don't warn me about bg processes when exiting
941 setopt nohup                # and don't kill them, either
942 # setopt printexitvalue       # alert me if something failed
943 # setopt dvorak               # with spelling correction, assume dvorak kb
944 setopt auto_pushd           # make cd push the old directory onto the directory stack.
945 setopt nonomatch            # try to avoid the 'zsh: no matches found...'
946 setopt nobeep               # avoid "beep"ing
947 setopt pushd_ignore_dups    # don't push the same dir twice.
948
949 MAILCHECK=30       # mailchecks
950 REPORTTIME=5       # report about cpu-/system-/user-time of command if running longer than 5 seconds
951 watch=(notme root) # watch for everyone but me and root
952
953 # define word separators (for stuff like backward-word, forward-word, backward-kill-word,..)
954 #  WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' # the default
955 #  WORDCHARS=.
956 #  WORDCHARS='*?_[]~=&;!#$%^(){}'
957 #  WORDCHARS='${WORDCHARS:s@/@}'
958
959 # only slash should be considered as a word separator:
960 slash-backward-kill-word() {
961     local WORDCHARS="${WORDCHARS:s@/@}"
962     # zle backward-word
963     zle backward-kill-word
964 }
965 zle -N slash-backward-kill-word
966
967 #k# Kill everything in a word up to its last \kbd{/}
968 bindkey '\ev' slash-backward-kill-word
969
970 # }}}
971
972 # {{{ history
973
974 ZSHDIR=$HOME/.zsh
975
976 #v#
977 HISTFILE=$HOME/.zsh_history
978 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
979 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
980
981 # }}}
982
983 # dirstack handling {{{
984
985 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
986 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
987
988 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
989     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
990     # "cd -" won't work after login by just setting $OLDPWD, so
991     [[ -d $dirstack[0] ]] && cd $dirstack[0] && cd $OLDPWD
992 fi
993
994 chpwd() {
995     if is42 ; then
996         builtin print -l ${(u)dirstack} >! ${DIRSTACKFILE}
997     else
998         uprint dirstack >! ${DIRSTACKFILE}
999     fi
1000 }
1001
1002 # }}}
1003
1004 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
1005 if [[ $BATTERY -gt 0 ]] ; then
1006     if ! check_com -c acpi ; then
1007         BATTERY=0
1008     fi
1009 fi
1010
1011 battery() {
1012 if [[ $BATTERY -gt 0 ]] ; then
1013     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]##Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1014     if [[ -z "$PERCENT" ]] ; then
1015         PERCENT='acpi not present'
1016     else
1017         if [[ "$PERCENT" -lt 20 ]] ; then
1018             PERCENT="warning: ${PERCENT}%%"
1019         else
1020             PERCENT="${PERCENT}%%"
1021         fi
1022     fi
1023 fi
1024 }
1025 # }}}
1026
1027 # set colors for use in prompts {{{
1028 if zrcautoload colors && colors 2>/dev/null ; then
1029     BLUE="%{${fg[blue]}%}"
1030     RED="%{${fg_bold[red]}%}"
1031     GREEN="%{${fg[green]}%}"
1032     CYAN="%{${fg[cyan]}%}"
1033     MAGENTA="%{${fg[magenta]}%}"
1034     YELLOW="%{${fg[yellow]}%}"
1035     WHITE="%{${fg[white]}%}"
1036     NO_COLOUR="%{${reset_color}%}"
1037 else
1038     BLUE=$'%{\e[1;34m%}'
1039     RED=$'%{\e[1;31m%}'
1040     GREEN=$'%{\e[1;32m%}'
1041     CYAN=$'%{\e[1;36m%}'
1042     WHITE=$'%{\e[1;37m%}'
1043     MAGENTA=$'%{\e[1;35m%}'
1044     YELLOW=$'%{\e[1;33m%}'
1045     NO_COLOUR=$'%{\e[0m%}'
1046 fi
1047
1048 # }}}
1049
1050 # gather version control information for inclusion in a prompt {{{
1051
1052 if ! is41 ; then
1053     # Be quiet about version problems in grml's zshrc as the user cannot disable
1054     # loading vcs_info() as it is *in* the zshrc - as you can see. :-)
1055     # Just unset most probable variables and disable vcs_info altogether.
1056     local -i i
1057     for i in {0..9} ; do
1058         unset VCS_INFO_message_${i}_
1059     done
1060     zstyle ':vcs_info:*' enable false
1061 fi
1062
1063 # The following code is imported from the file 'zsh/functions/vcs_info'
1064 # from <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>,
1065 # which distributed under the same terms as zsh itself.
1066
1067 # we will only be using one variable, so let the code know now.
1068 zstyle ':vcs_info:*' max-exports 1
1069
1070 # vcs_info() documentation:
1071 #{{{
1072 # REQUIREMENTS:
1073 #{{{
1074 #     This functionality requires zsh version >= 4.1.*.
1075 #}}}
1076 #
1077 # LOADING:
1078 #{{{
1079 # To load vcs_info(), copy this file to your $fpath[] and do:
1080 #   % autoload -Uz vcs_info && vcs_info
1081 #
1082 # To work, vcs_info() needs 'setopt prompt_subst' in your setup.
1083 #}}}
1084 #
1085 # QUICKSTART:
1086 #{{{
1087 # To get vcs_info() working quickly (including colors), you can do the
1088 # following (assuming, you loaded vcs_info() properly - see above):
1089 #
1090 # % RED=$'%{\e[31m%}'
1091 # % GR=$'%{\e[32m%}'
1092 # % MA=$'%{\e[35m%}'
1093 # % YE=$'%{\e[33m%}'
1094 # % NC=$'%{\e[0m%}'
1095 #
1096 # % zstyle ':vcs_info:*' actionformats \
1097 #       "${MA}(${NC}%s${MA})${YE}-${MA}[${GR}%b${YE}|${RED}%a${MA}]${NC} "
1098 #
1099 # % zstyle ':vcs_info:*' formats       \
1100 #       "${MA}(${NC}%s${MA})${Y}-${MA}[${GR}%b${MA}]${NC}%} "
1101 #
1102 # % zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YE}%r"
1103 #
1104 # % precmd () { vcs_info }
1105 # % PS1='${MA}[${GR}%n${MA}] ${MA}(${RED}%!${MA}) ${YE}%3~ ${VCS_INFO_message_0_}${NC}%# '
1106 #
1107 # Obviously, the las two lines are there for demonstration: You need to
1108 # call vcs_info() from your precmd() function (see 'SPECIAL FUNCTIONS' in
1109 # 'man zshmisc'). Once that is done you need a *single* quoted
1110 # '${VCS_INFO_message_0_}' in your prompt.
1111 #
1112 # Now call the 'vcs_info_printsys' utility from the command line:
1113 #
1114 # % vcs_info_printsys
1115 # # list of supported version control backends:
1116 # # disabled systems are prefixed by a hash sign (#)
1117 # git
1118 # hg
1119 # bzr
1120 # darcs
1121 # svk
1122 # mtn
1123 # svn
1124 # cvs
1125 # cdv
1126 # tla
1127 # # flavours (cannot be used in the disable style; they
1128 # # are disabled with their master [git-svn -> git]):
1129 # git-p4
1130 # git-svn
1131 #
1132 # Ten version control backends as you can see. You may not want all
1133 # of these. Because there is no point in running the code to detect
1134 # systems you do not use. ever. So, there is a way to disable some
1135 # backends altogether:
1136 #
1137 # % zstyle ':vcs_info:*' disable bzr cdv darcs mtn svk tla
1138 #
1139 # If you rerun 'vcs_info_printsys' now, you will see the backends listed
1140 # in the 'disable' style marked as diabled by a hash sign. That means the
1141 # detection of these systems is skipped *completely*. No wasted time there.
1142 #
1143 # For more control, read the reference below.
1144 #}}}
1145 #
1146 # CONFIGURATION:
1147 #{{{
1148 # The vcs_info() feature can be configured via zstyle.
1149 #
1150 # First, the context in which we are working:
1151 #       :vcs_info:<vcs-string>:<user-context>
1152 #
1153 # ...where <vcs-string> is one of:
1154 #   - git, git-svn, git-p4, hg, darcs, bzr, cdv, mtn, svn, cvs, svk or tla.
1155 #
1156 # ...and <user-context> is a freely configurable string, assignable by the
1157 # user as the first argument to vcs_info() (see its description below).
1158 #
1159 # There is are three special values for <vcs-string>: The first is named
1160 # 'init', that is in effect as long as there was no decision what vcs
1161 # backend to use. The second is 'preinit; it is used *before* vcs_info()
1162 # is run, when initializing the data exporting variables. The third
1163 # special value is 'formats' and is used by the 'vcs_info_lastmsg' for
1164 # looking up its styles.
1165 #
1166 # There are two pre-defined values for <user-context>:
1167 #   default  - the one used if none is specified
1168 #   command  - used by vcs_info_lastmsg to lookup its styles.
1169 #
1170 # You may *not* use 'print_systems_' as a user-context string, because it
1171 # is used internally.
1172 #
1173 # You can of course use ':vcs_info:*' to match all VCSs in all
1174 # user-contexts at once.
1175 #
1176 # Another special context is 'formats', which is used by the
1177 # vcs_info_lastmsg() utility function (see below).
1178 #
1179 #
1180 # This is a description of all styles, that are looked up:
1181 #   formats             - A list of formats, used when actionformats is not
1182 #                         used (which is most of the time).
1183 #   actionformats       - A list of formats, used if a there is a special
1184 #                         action going on in your current repository;
1185 #                         (like an interactive rebase or a merge conflict)
1186 #   branchformat        - Some backends replace %b in the formats and
1187 #                         actionformats styles above, not only by a branch
1188 #                         name but also by a revision number. This style
1189 #                         let's you modify how that string should look like.
1190 #   nvcsformats         - These "formats" are exported, when we didn't detect
1191 #                         a version control system for the current directory.
1192 #                         This is useful, if you want vcs_info() to completely
1193 #                         take over the generation of your prompt.
1194 #                         You would do something like
1195 #                           PS1='${VCS_INFO_message_0_}'
1196 #                         to accomplish that.
1197 #   max-exports         - Defines the maximum number if VCS_INFO_message_*_
1198 #                         variables vcs_info() will export.
1199 #   enable              - Checked in the 'init' context. If set to false,
1200 #                         vcs_info() will do nothing.
1201 #   disable             - Provide a list of systems, you don't want
1202 #                         the vcs_info() to check for repositories
1203 #                         (checked in the 'init' context, too).
1204 #   use-simple          - If there are two different ways of gathering
1205 #                         information, you can select the simpler one
1206 #                         by setting this style to true; the default
1207 #                         is to use the not-that-simple code, which is
1208 #                         potentially a lot slower but might be more
1209 #                         accurate in all possible cases.
1210 #   use-prompt-escapes  - determines if we assume that the assembled
1211 #                         string from vcs_info() includes prompt escapes.
1212 #                         (Used by vcs_info_lastmsg().
1213 #
1214 # The use-simple style is only available for the bzr backend.
1215 #
1216 # The default values for these in all contexts are:
1217 #   formats             " (%s)-[%b|%a]-"
1218 #   actionformats       " (%s)-[%b]-"
1219 #   branchformat        "%b:%r" (for bzr, svn and svk)
1220 #   nvcsformats         ""
1221 #   max-exports         2
1222 #   enable              true
1223 #   disable             (empty list)
1224 #   use-simple          false
1225 #   use-prompt-escapes  true
1226 #
1227 #
1228 # In normal formats and actionformats, the following replacements
1229 # are done:
1230 #   %s  - The vcs in use (git, hg, svn etc.)
1231 #   %b  - Information about the current branch.
1232 #   %a  - An identifier, that describes the action.
1233 #         Only makes sense in actionformats.
1234 #   %R  - base directory of the repository.
1235 #   %r  - repository name
1236 #         If %R is '/foo/bar/repoXY', %r is 'repoXY'.
1237 #   %S  - subdirectory within a repository. if $PWD is
1238 #         '/foo/bar/reposXY/beer/tasty', %S is 'beer/tasty'.
1239 #
1240 #
1241 # In branchformat these replacements are done:
1242 #   %b  - the branch name
1243 #   %r  - the current revision number
1244 #
1245 # Not all vcs backends have to support all replacements.
1246 # nvcsformat does not perform *any* replacements. It is just a string.
1247 #}}}
1248 #
1249 # ODDITIES:
1250 #{{{
1251 # If you want to use the %b (bold off) prompt expansion in 'formats', which
1252 # expands %b itself, use %%b. That will cause the vcs_info() expansion to
1253 # replace %%b with %b. So zsh's prompt expansion mechanism can handle it.
1254 # Similarly, to hand down %b from branchformat, use %%%%b. Sorry for this
1255 # inconvenience, but it cannot be easily avoided. Luckily we do not clash
1256 # with a lot of prompt expansions and this only needs to be done for those.
1257 # See 'man zshmisc' for details about EXPANSION OF PROMPT SEQUENCES.
1258 #}}}
1259 #
1260 # FUNCTION DESCRIPTIONS (public API):
1261 #{{{
1262 #   vcs_info()
1263 #       The main function, that runs all backends and assembles
1264 #       all data into ${VCS_INFO_message_*_}. This is the function
1265 #       you want to call from precmd() if you want to include
1266 #       up-to-date information in your prompt (see VARIABLE
1267 #       DESCRIPTION below).
1268 #
1269 #   vcs_info_printsys()
1270 #       Prints a list of all supported version control systems.
1271 #       Useful to find out possible contexts (and which of them are enabled)
1272 #       or values for the 'disable' style.
1273 #
1274 #   vcs_info_lastmsg()
1275 #       Outputs the last ${VCS_INFO_message_*_} value. Takes into account
1276 #       the value of the use-prompt-escapes style in ':vcs_info:formats'.
1277 #       It also only prints max-exports values.
1278 #
1279 # All functions named VCS_INFO_* are for internal use only.
1280 #}}}
1281 #
1282 # VARIABLE DESCRIPTION:
1283 #{{{
1284 #   ${VCS_INFO_message_N_}    (Note the trailing underscore)
1285 #       Where 'N' is an integer, eg: VCS_INFO_message_0_
1286 #       These variables are the storage for the informational message the
1287 #       last vcs_info() call has assembled. These are strongly connected
1288 #       to the formats, actionformats and nvcsformats styles described
1289 #       above. Those styles are lists. the first member of that list gets
1290 #       expanded into ${VCS_INFO_message_0_}, the second into
1291 #       ${VCS_INFO_message_1_} and the Nth into ${VCS_INFO_message_N-1_}.
1292 #       These parameters are exported into the environment.
1293 #       (See the max-exports style above.)
1294 #}}}
1295 #
1296 # EXAMPLES:
1297 #{{{
1298 #   Don't use vcs_info at all (even though it's in your prompt):
1299 #   % zstyle ':vcs_info:*' enable false
1300 #
1301 #   Disable the backends for bzr and svk:
1302 #   % zstyle ':vcs_info:*' disable bzr svk
1303 #
1304 #   Provide a special formats for git:
1305 #   % zstyle ':vcs_info:git:*' formats       ' GIT, BABY! [%b]'
1306 #   % zstyle ':vcs_info:git:*' actionformats ' GIT ACTION! [%b|%a]'
1307 #
1308 #   Use the quicker bzr backend (if you do, please report if it does
1309 #   the-right-thing[tm] - thanks):
1310 #   % zstyle ':vcs_info:bzr:*' use-simple true
1311 #
1312 #   Display the revision number in yellow for bzr and svn:
1313 #   % zstyle ':vcs_info:(svn|bzr):*' branchformat '%b%{'${fg[yellow]}'%}:%r'
1314 #
1315 # If you want colors, make sure you enclose the color codes in %{...%},
1316 # if you want to use the string provided by vcs_info() in prompts.
1317 #
1318 # Here is how to print the vcs infomation as a command:
1319 #   % alias vcsi='vcs_info command; vcs_info_lastmsg'
1320 #
1321 #   This way, you can even define different formats for output via
1322 #   vcs_info_lastmsg() in the ':vcs_info:command:*' namespace.
1323 #}}}
1324 #}}}
1325 # utilities
1326 VCS_INFO_adjust () { #{{{
1327     [[ -n ${vcs_comm[overwrite_name]} ]] && vcs=${vcs_comm[overwrite_name]}
1328     return 0
1329 }
1330 # }}}
1331 VCS_INFO_check_com () { #{{{
1332     (( ${+commands[$1]} )) && [[ -x ${commands[$1]} ]] && return 0
1333     return 1
1334 }
1335 # }}}
1336 VCS_INFO_formats () { # {{{
1337     setopt localoptions noksharrays
1338     local action=$1 branch=$2 base=$3
1339     local msg
1340     local -i i
1341
1342     if [[ -n ${action} ]] ; then
1343         zstyle -a ":vcs_info:${vcs}:${usercontext}" actionformats msgs
1344         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b|%a]-'
1345     else
1346         zstyle -a ":vcs_info:${vcs}:${usercontext}" formats msgs
1347         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b]-'
1348     fi
1349
1350     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1351     for i in {1..${#msgs}} ; do
1352         zformat -f msg ${msgs[$i]} a:${action} b:${branch} s:${vcs} r:${base:t} R:${base} S:"$(VCS_INFO_reposub ${base})"
1353         msgs[$i]=${msg}
1354     done
1355     return 0
1356 }
1357 # }}}
1358 VCS_INFO_maxexports () { #{{{
1359     local -ix maxexports
1360
1361     zstyle -s ":vcs_info:${vcs}:${usercontext}" "max-exports" maxexports || maxexports=2
1362     if [[ ${maxexports} != <-> ]] || (( maxexports < 1 )); then
1363         printf 'vcs_info(): expecting numeric arg >= 1 for max-exports (got %s).\n' ${maxexports}
1364         printf 'Defaulting to 2.\n'
1365         maxexports=2
1366     fi
1367 }
1368 # }}}
1369 VCS_INFO_nvcsformats () { #{{{
1370     setopt localoptions noksharrays
1371     local c v
1372
1373     if [[ $1 == 'preinit' ]] ; then
1374         c=default
1375         v=preinit
1376     fi
1377     zstyle -a ":vcs_info:${v:-$vcs}:${c:-$usercontext}" nvcsformats msgs
1378     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1379 }
1380 # }}}
1381 VCS_INFO_realpath () { #{{{
1382     # a portable 'readlink -f'
1383     # forcing a subshell, to ensure chpwd() is not removed
1384     # from the calling shell (if VCS_INFO_realpath() is called
1385     # manually).
1386     (
1387         (( ${+functions[chpwd]} )) && unfunction chpwd
1388         setopt chaselinks
1389         cd $1 2>/dev/null && pwd
1390     )
1391 }
1392 # }}}
1393 VCS_INFO_reposub () { #{{{
1394     setopt localoptions extendedglob
1395     local base=${1%%/##}
1396
1397     [[ ${PWD} == ${base}/* ]] || {
1398         printf '.'
1399         return 1
1400     }
1401     printf '%s' ${PWD#$base/}
1402     return 0
1403 }
1404 # }}}
1405 VCS_INFO_set () { #{{{
1406     setopt localoptions noksharrays
1407     local -i i j
1408
1409     if [[ $1 == '--clear' ]] ; then
1410         for i in {0..9} ; do
1411             unset VCS_INFO_message_${i}_
1412         done
1413     fi
1414     if [[ $1 == '--nvcs' ]] ; then
1415         [[ $2 == 'preinit' ]] && (( maxexports == 0 )) && (( maxexports = 1 ))
1416         for i in {0..$((maxexports - 1))} ; do
1417             typeset -gx VCS_INFO_message_${i}_=
1418         done
1419         VCS_INFO_nvcsformats $2
1420     fi
1421
1422     (( ${#msgs} - 1 < 0 )) && return 0
1423     for i in {0..$(( ${#msgs} - 1 ))} ; do
1424         (( j = i + 1 ))
1425         typeset -gx VCS_INFO_message_${i}_=${msgs[$j]}
1426     done
1427     return 0
1428 }
1429 # }}}
1430 # information gathering
1431 VCS_INFO_bzr_get_data () { # {{{
1432     setopt localoptions noksharrays
1433     local bzrbase bzrbr
1434     local -a bzrinfo
1435
1436     if zstyle -t ":vcs_info:${vcs}:${usercontext}" "use-simple" ; then
1437         bzrbase=${vcs_comm[basedir]}
1438         bzrinfo[2]=${bzrbase:t}
1439         if [[ -f ${bzrbase}/.bzr/branch/last-revision ]] ; then
1440             bzrinfo[1]=$(< ${bzrbase}/.bzr/branch/last-revision)
1441             bzrinfo[1]=${${bzrinfo[1]}%% *}
1442         fi
1443     else
1444         bzrbase=${${(M)${(f)"$( bzr info )"}:# ##branch\ root:*}/*: ##/}
1445         bzrinfo=( ${${${(M)${(f)"$( bzr version-info )"}:#(#s)(revno|branch-nick)*}/*: /}/*\//} )
1446         bzrbase="$(VCS_INFO_realpath ${bzrbase})"
1447     fi
1448
1449     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat bzrbr || bzrbr="%b:%r"
1450     zformat -f bzrbr "${bzrbr}" "b:${bzrinfo[2]}" "r:${bzrinfo[1]}"
1451     VCS_INFO_formats '' "${bzrbr}" "${bzrbase}"
1452     return 0
1453 }
1454 # }}}
1455 VCS_INFO_cdv_get_data () { # {{{
1456     local cdvbase
1457
1458     cdvbase=${vcs_comm[basedir]}
1459     VCS_INFO_formats '' "${cdvbase:t}" "${cdvbase}"
1460     return 0
1461 }
1462 # }}}
1463 VCS_INFO_cvs_get_data () { # {{{
1464     local cvsbranch cvsbase basename
1465
1466     cvsbase="."
1467     while [[ -d "${cvsbase}/../CVS" ]]; do
1468         cvsbase="${cvsbase}/.."
1469     done
1470     cvsbase="$(VCS_INFO_realpath ${cvsbase})"
1471     cvsbranch=$(< ./CVS/Repository)
1472     basename=${cvsbase:t}
1473     cvsbranch=${cvsbranch##${basename}/}
1474     [[ -z ${cvsbranch} ]] && cvsbranch=${basename}
1475     VCS_INFO_formats '' "${cvsbranch}" "${cvsbase}"
1476     return 0
1477 }
1478 # }}}
1479 VCS_INFO_darcs_get_data () { # {{{
1480     local darcsbase
1481
1482     darcsbase=${vcs_comm[basedir]}
1483     VCS_INFO_formats '' "${darcsbase:t}" "${darcsbase}"
1484     return 0
1485 }
1486 # }}}
1487 VCS_INFO_git_getaction () { #{{{
1488     local gitaction='' gitdir=$1
1489     local tmp
1490
1491     for tmp in "${gitdir}/rebase-apply" \
1492                "${gitdir}/rebase"       \
1493                "${gitdir}/../.dotest" ; do
1494         if [[ -d ${tmp} ]] ; then
1495             if   [[ -f "${tmp}/rebasing" ]] ; then
1496                 gitaction="rebase"
1497             elif [[ -f "${tmp}/applying" ]] ; then
1498                 gitaction="am"
1499             else
1500                 gitaction="am/rebase"
1501             fi
1502             printf '%s' ${gitaction}
1503             return 0
1504         fi
1505     done
1506
1507     for tmp in "${gitdir}/rebase-merge/interactive" \
1508                "${gitdir}/.dotest-merge/interactive" ; do
1509         if [[ -f "${tmp}" ]] ; then
1510             printf '%s' "rebase-i"
1511             return 0
1512         fi
1513     done
1514
1515     for tmp in "${gitdir}/rebase-merge" \
1516                "${gitdir}/.dotest-merge" ; do
1517         if [[ -d "${tmp}" ]] ; then
1518             printf '%s' "rebase-m"
1519             return 0
1520         fi
1521     done
1522
1523     if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1524         printf '%s' "merge"
1525         return 0
1526     fi
1527
1528     if [[ -f "${gitdir}/BISECT_LOG" ]] ; then
1529         printf '%s' "bisect"
1530         return 0
1531     fi
1532     return 1
1533 }
1534 # }}}
1535 VCS_INFO_git_getbranch () { #{{{
1536     local gitbranch gitdir=$1
1537     local gitsymref='git symbolic-ref HEAD'
1538
1539     if    [[ -d "${gitdir}/rebase-apply" ]] \
1540        || [[ -d "${gitdir}/rebase" ]]       \
1541        || [[ -d "${gitdir}/../.dotest" ]]   \
1542        || [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1543         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1544         [[ -z ${gitbranch} ]] && [[ -r ${gitdir}/rebase-apply/head-name ]] \
1545             && gitbranch="$(< ${gitdir}/rebase-apply/head-name)"
1546
1547     elif   [[ -f "${gitdir}/rebase-merge/interactive" ]] \
1548         || [[ -d "${gitdir}/rebase-merge" ]] ; then
1549         gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
1550
1551     elif   [[ -f "${gitdir}/.dotest-merge/interactive" ]] \
1552         || [[ -d "${gitdir}/.dotest-merge" ]] ; then
1553         gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
1554
1555     else
1556         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1557
1558         if [[ $? -ne 0 ]] ; then
1559             gitbranch="$(git describe --exact-match HEAD 2>/dev/null)"
1560
1561             if [[ $? -ne 0 ]] ; then
1562                 gitbranch="${${"$(< $gitdir/HEAD)"}[1,7]}..."
1563             fi
1564         fi
1565     fi
1566
1567     printf '%s' "${gitbranch##refs/heads/}"
1568     return 0
1569 }
1570 # }}}
1571 VCS_INFO_git_get_data () { # {{{
1572     setopt localoptions extendedglob
1573     local gitdir gitbase gitbranch gitaction
1574
1575     gitdir=${vcs_comm[gitdir]}
1576     gitbranch="$(VCS_INFO_git_getbranch ${gitdir})"
1577
1578     if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then
1579         return 1
1580     fi
1581
1582     VCS_INFO_adjust
1583     gitaction="$(VCS_INFO_git_getaction ${gitdir})"
1584     gitbase=${PWD%/${$( git rev-parse --show-prefix )%/##}}
1585     VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}"
1586     return 0
1587 }
1588 # }}}
1589 VCS_INFO_hg_get_data () { # {{{
1590     local hgbranch hgbase
1591
1592     hgbase=${vcs_comm[basedir]}
1593     hgbranch=$(< ${hgbase}/.hg/branch)
1594     VCS_INFO_formats '' "${hgbranch}" "${hgbase}"
1595     return 0
1596 }
1597 # }}}
1598 VCS_INFO_mtn_get_data () { # {{{
1599     local mtnbranch mtnbase
1600
1601     mtnbase=${vcs_comm[basedir]}
1602     mtnbranch=${${(M)${(f)"$( mtn status )"}:#(#s)Current branch:*}/*: /}
1603     VCS_INFO_formats '' "${mtnbranch}" "${mtnbase}"
1604     return 0
1605 }
1606 # }}}
1607 VCS_INFO_svk_get_data () { # {{{
1608     local svkbranch svkbase
1609
1610     svkbase=${vcs_comm[basedir]}
1611     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svkbranch || svkbranch="%b:%r"
1612     zformat -f svkbranch "${svkbranch}" "b:${vcs_comm[branch]}" "r:${vcs_comm[revision]}"
1613     VCS_INFO_formats '' "${svkbranch}" "${svkbase}"
1614     return 0
1615 }
1616 # }}}
1617 VCS_INFO_svn_get_data () { # {{{
1618     setopt localoptions noksharrays
1619     local svnbase svnbranch
1620     local -a svninfo
1621
1622     svnbase="."
1623     while [[ -d "${svnbase}/../.svn" ]]; do
1624         svnbase="${svnbase}/.."
1625     done
1626     svnbase="$(VCS_INFO_realpath ${svnbase})"
1627     svninfo=( ${${${(M)${(f)"$( svn info )"}:#(#s)(URL|Revision)*}/*: /}/*\//} )
1628
1629     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svnbranch || svnbranch="%b:%r"
1630     zformat -f svnbranch "${svnbranch}" "b:${svninfo[1]}" "r:${svninfo[2]}"
1631     VCS_INFO_formats '' "${svnbranch}" "${svnbase}"
1632     return 0
1633 }
1634 # }}}
1635 VCS_INFO_tla_get_data () { # {{{
1636     local tlabase tlabranch
1637
1638     tlabase="$(VCS_INFO_realpath ${vcs_comm[basedir]})"
1639     # tree-id gives us something like 'foo@example.com/demo--1.0--patch-4', so:
1640     tlabranch=${${"$( tla tree-id )"}/*\//}
1641     VCS_INFO_formats '' "${tlabranch}" "${tlabase}"
1642     return 0
1643 }
1644 # }}}
1645 # detection
1646 VCS_INFO_detect_by_dir() { #{{{
1647     local dirname=$1
1648     local basedir="." realbasedir
1649
1650     realbasedir="$(VCS_INFO_realpath ${basedir})"
1651     while [[ ${realbasedir} != '/' ]]; do
1652         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
1653             [[ -d ${basedir}/${dirname} ]] && \
1654             [[ -f ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
1655                 break
1656         else
1657             [[ -d ${basedir}/${dirname} ]] && break
1658         fi
1659
1660         basedir=${basedir}/..
1661         realbasedir="$(VCS_INFO_realpath ${basedir})"
1662     done
1663
1664     [[ ${realbasedir} == "/" ]] && return 1
1665     vcs_comm[basedir]=${realbasedir}
1666     return 0
1667 }
1668 # }}}
1669 VCS_INFO_bzr_detect() { #{{{
1670     VCS_INFO_check_com bzr || return 1
1671     vcs_comm[detect_need_file]=branch/format
1672     VCS_INFO_detect_by_dir '.bzr'
1673     return $?
1674 }
1675 # }}}
1676 VCS_INFO_cdv_detect() { #{{{
1677     VCS_INFO_check_com cdv || return 1
1678     vcs_comm[detect_need_file]=format
1679     VCS_INFO_detect_by_dir '.cdv'
1680     return $?
1681 }
1682 # }}}
1683 VCS_INFO_cvs_detect() { #{{{
1684     VCS_INFO_check_com svn || return 1
1685     [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
1686     return 1
1687 }
1688 # }}}
1689 VCS_INFO_darcs_detect() { #{{{
1690     VCS_INFO_check_com darcs || return 1
1691     vcs_comm[detect_need_file]=format
1692     VCS_INFO_detect_by_dir '_darcs'
1693     return $?
1694 }
1695 # }}}
1696 VCS_INFO_git_detect() { #{{{
1697     if VCS_INFO_check_com git && git rev-parse --is-inside-work-tree &> /dev/null ; then
1698         vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
1699         if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
1700         elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
1701         return 0
1702     fi
1703     return 1
1704 }
1705 # }}}
1706 VCS_INFO_hg_detect() { #{{{
1707     VCS_INFO_check_com hg || return 1
1708     vcs_comm[detect_need_file]=branch
1709     VCS_INFO_detect_by_dir '.hg'
1710     return $?
1711 }
1712 # }}}
1713 VCS_INFO_mtn_detect() { #{{{
1714     VCS_INFO_check_com mtn || return 1
1715     vcs_comm[detect_need_file]=revision
1716     VCS_INFO_detect_by_dir '_MTN'
1717     return $?
1718 }
1719 # }}}
1720 VCS_INFO_svk_detect() { #{{{
1721     setopt localoptions noksharrays extendedglob
1722     local -a info
1723     local -i fhash
1724     fhash=0
1725
1726     VCS_INFO_check_com svk || return 1
1727     [[ -f ~/.svk/config ]] || return 1
1728
1729     # This detection function is a bit different from the others.
1730     # We need to read svk's config file to detect a svk repository
1731     # in the first place. Therefore, we'll just proceed and read
1732     # the other information, too. This is more then any of the
1733     # other detections do but this takes only one file open for
1734     # svk at most. VCS_INFO_svk_get_data() get simpler, too. :-)
1735     while IFS= read -r line ; do
1736         if [[ -n ${vcs_comm[basedir]} ]] ; then
1737             line=${line## ##}
1738             [[ ${line} == depotpath:* ]] && vcs_comm[branch]=${line##*/}
1739             [[ ${line} == revision:* ]] && vcs_comm[revision]=${line##*[[:space:]]##}
1740             [[ -n ${vcs_comm[branch]} ]] && [[ -n ${vcs_comm[revision]} ]] && break
1741             continue
1742         fi
1743         (( fhash > 0 )) && [[ ${line} == '  '[^[:space:]]*:* ]] && break
1744         [[ ${line} == '  hash:'* ]] && fhash=1 && continue
1745         (( fhash == 0 )) && continue
1746         [[ ${PWD}/ == ${${line## ##}%:*}/* ]] && vcs_comm[basedir]=${${line## ##}%:*}
1747     done < ~/.svk/config
1748
1749     [[ -n ${vcs_comm[basedir]} ]]  && \
1750     [[ -n ${vcs_comm[branch]} ]]   && \
1751     [[ -n ${vcs_comm[revision]} ]] && return 0
1752     return 1
1753 }
1754 # }}}
1755 VCS_INFO_svn_detect() { #{{{
1756     VCS_INFO_check_com svn || return 1
1757     [[ -d ".svn" ]] && return 0
1758     return 1
1759 }
1760 # }}}
1761 VCS_INFO_tla_detect() { #{{{
1762     VCS_INFO_check_com tla || return 1
1763     vcs_comm[basedir]="$(tla tree-root 2> /dev/null)" && return 0
1764     return 1
1765 }
1766 # }}}
1767 # public API
1768 vcs_info_printsys () { # {{{
1769     vcs_info print_systems_
1770 }
1771 # }}}
1772 vcs_info_lastmsg () { # {{{
1773     local -i i
1774
1775     VCS_INFO_maxexports
1776     for i in {0..$((maxexports - 1))} ; do
1777         printf '$VCS_INFO_message_%d_: "' $i
1778         if zstyle -T ':vcs_info:formats:command' use-prompt-escapes ; then
1779             print -nP ${(P)${:-VCS_INFO_message_${i}_}}
1780         else
1781             print -n ${(P)${:-VCS_INFO_message_${i}_}}
1782         fi
1783         printf '"\n'
1784     done
1785 }
1786 # }}}
1787 vcs_info () { # {{{
1788     local -i found
1789     local -a VCSs disabled
1790     local -x vcs usercontext
1791     local -ax msgs
1792     local -Ax vcs_comm
1793
1794     vcs="init"
1795     VCSs=(git hg bzr darcs svk mtn svn cvs cdv tla)
1796     case $1 in
1797         (print_systems_)
1798             zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1799             print -l '# list of supported version control backends:' \
1800                      '# disabled systems are prefixed by a hash sign (#)'
1801             for vcs in ${VCSs} ; do
1802                 [[ -n ${(M)disabled:#${vcs}} ]] && printf '#'
1803                 printf '%s\n' ${vcs}
1804             done
1805             print -l '# flavours (cannot be used in the disable style; they' \
1806                      '# are disabled with their master [git-svn -> git]):'   \
1807                      git-{p4,svn}
1808             return 0
1809             ;;
1810         ('')
1811             [[ -z ${usercontext} ]] && usercontext=default
1812             ;;
1813         (*) [[ -z ${usercontext} ]] && usercontext=$1
1814             ;;
1815     esac
1816
1817     zstyle -T ":vcs_info:${vcs}:${usercontext}" "enable" || {
1818         [[ -n ${VCS_INFO_message_0_} ]] && VCS_INFO_set --clear
1819         return 0
1820     }
1821     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1822     VCS_INFO_maxexports
1823
1824     (( found = 0 ))
1825     for vcs in ${VCSs} ; do
1826         [[ -n ${(M)disabled:#${vcs}} ]] && continue
1827         vcs_comm=()
1828         VCS_INFO_${vcs}_detect && (( found = 1 )) && break
1829     done
1830
1831     (( found == 0 )) && {
1832         VCS_INFO_set --nvcs
1833         return 0
1834     }
1835
1836     VCS_INFO_${vcs}_get_data || {
1837         VCS_INFO_set --nvcs
1838         return 1
1839     }
1840
1841     VCS_INFO_set
1842     return 0
1843 }
1844
1845 VCS_INFO_set --nvcs preinit
1846 # }}}
1847
1848 # change vcs_info formats for the grml prompt
1849 if [[ "$TERM" == dumb ]] ; then
1850     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] "
1851     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "
1852 else
1853     # these are the same, just with a lot of colours:
1854     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} "
1855     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} "
1856     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1857 fi
1858
1859 # }}}
1860
1861 # {{{ set prompt
1862 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1863     promptinit # people should be able to use their favourite prompt
1864 else
1865     print 'Notice: no promptinit available :('
1866 fi
1867
1868 setopt prompt_subst
1869
1870 # make sure to use right prompt only when not running a command
1871 is41 && setopt transient_rprompt
1872
1873 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1874     [[ $NOPRECMD -gt 0 ]] && return 0
1875     # update VCS information
1876     vcs_info
1877
1878     # allow manual overwriting of RPROMPT
1879     if [[ -n $RPROMPT ]] ; then
1880         [[ $TERM == screen* ]] && print -nP "\ekzsh\e\\"
1881         # return 0
1882     fi
1883     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1884     if [[ $DONTSETRPROMPT -eq 0 ]] ; then
1885         if [[ $BATTERY -gt 0 ]] ; then
1886             # update BATTERY information
1887             battery
1888             RPROMPT="%(?..:()% ${PERCENT}${SCREENTITLE}"
1889             # RPROMPT="${PERCENT}${SCREENTITLE}"
1890         else
1891             RPROMPT="%(?..:()% ${SCREENTITLE}"
1892             # RPROMPT="${SCREENTITLE}"
1893         fi
1894     fi
1895     # adjust title of xterm
1896     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1897     case $TERM in
1898         (xterm*|rxvt)
1899             print -Pn "\e]0;%n@%m: %~\a"
1900             ;;
1901     esac
1902 }
1903
1904 # preexec() => a function running before every command
1905 is4 && [[ $NOPRECMD -eq 0 ]] && \
1906 preexec () {
1907     [[ $NOPRECMD -gt 0 ]] && return 0
1908 # set hostname if not running on host with name 'grml'
1909     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1910        NAME="@$HOSTNAME"
1911     fi
1912 # get the name of the program currently running and hostname of local machine
1913 # set screen window title if running in a screen
1914     if [[ "$TERM" == screen* ]] ; then
1915         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1916         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1917         echo -ne "\ek$CMD\e\\"
1918     fi
1919 # set the screen title to "zsh" when sitting at the command prompt:
1920     if [[ "$TERM" == screen* ]] ; then
1921         SCREENTITLE=$'%{\ekzsh\e\\%}'
1922     else
1923         SCREENTITLE=''
1924     fi
1925 # adjust title of xterm
1926     case $TERM in
1927         (xterm*|rxvt)
1928             print -Pn "\e]0;%n@%m: $1\a"
1929             ;;
1930     esac
1931 }
1932
1933 EXITCODE="%(?..%?%1v )"
1934 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
1935 PS3='?# '         # selection prompt used within a select loop.
1936 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1937
1938 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1939 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1940     debian_chroot=$(cat /etc/debian_chroot)
1941 fi
1942
1943 # don't use colors on dumb terminals (like emacs):
1944 if [[ "$TERM" == dumb ]] ; then
1945     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1946 else
1947     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
1948     # set variable identifying the chroot you work in (used in the prompt below)
1949     if [[ $GRMLPROMPT -gt 0 ]] ; then
1950         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1951 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< %# "
1952     else
1953         # This assembles the primary prompt string
1954         if (( EUID != 0 )); then
1955             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1956         else
1957             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1958         fi
1959     fi
1960 fi
1961
1962 # if we are inside a grml-chroot set a specific prompt theme
1963 if [[ -n "$GRML_CHROOT" ]] ; then
1964     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1965 fi
1966 # }}}
1967
1968 # {{{ 'hash' some often used directories
1969 #d# start
1970 hash -d deb=/var/cache/apt/archives
1971 hash -d doc=/usr/share/doc
1972 hash -d linux=/lib/modules/$(command uname -r)/build/
1973 hash -d log=/var/log
1974 hash -d slog=/var/log/syslog
1975 hash -d src=/usr/src
1976 hash -d templ=/usr/share/doc/grml-templates
1977 hash -d tt=/usr/share/doc/texttools-doc
1978 hash -d www=/var/www
1979 #d# end
1980 # }}}
1981
1982 # {{{ some aliases
1983 if [[ $UID -eq 0 ]] ; then
1984     [[ -r /etc/grml/screenrc ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc'
1985 elif [[ -r $HOME/.screenrc ]] ; then
1986     alias screen="/usr/bin/screen -c $HOME/.screenrc"
1987 else
1988     [[ -r /etc/grml/screenrc_grml ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc_grml'
1989 fi
1990
1991 # do we have GNU ls with color-support?
1992 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
1993     #a1# execute \kbd{@a@}:\quad ls with colors
1994     alias ls='ls -b -CF --color=auto'
1995     #a1# execute \kbd{@a@}:\quad list all files, with colors
1996     alias la='ls -la --color=auto'
1997     #a1# long colored list, without dotfiles (@a@)
1998     alias ll='ls -l --color=auto'
1999     #a1# long colored list, human readable sizes (@a@)
2000     alias lh='ls -hAl --color=auto'
2001     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2002     alias l='ls -lF --color=auto'
2003 else
2004     alias ls='ls -b -CF'
2005     alias la='ls -la'
2006     alias ll='ls -l'
2007     alias lh='ls -hAl'
2008     alias l='ls -lF'
2009 fi
2010
2011 alias mdstat='cat /proc/mdstat'
2012 alias ...='cd ../../'
2013
2014 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2015 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2016     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2017 fi
2018
2019 alias cp='nocorrect cp'         # no spelling correction on cp
2020 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
2021 alias mv='nocorrect mv'         # no spelling correction on mv
2022 alias rm='nocorrect rm'         # no spelling correction on rm
2023
2024 #a1# Execute \kbd{rmdir}
2025 alias rd='rmdir'
2026 #a1# Execute \kbd{rmdir}
2027 alias md='mkdir'
2028
2029 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2030 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2031 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2032
2033 # make sure it is not assigned yet
2034 [[ $(whence -w utf2iso &>/dev/null) == 'utf2iso: alias' ]] && unalias utf2iso
2035
2036 utf2iso() {
2037     if isutfenv ; then
2038         for ENV in $(env | command grep -i '.utf') ; do
2039             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2040         done
2041     fi
2042 }
2043
2044 # make sure it is not assigned yet
2045 [[ $(whence -w iso2utf &>/dev/null) == 'iso2utf: alias' ]] && unalias iso2utf
2046 iso2utf() {
2047     if ! isutfenv ; then
2048         for ENV in $(env | command grep -i '\.iso') ; do
2049             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2050         done
2051     fi
2052 }
2053
2054 # set up software synthesizer via speakup
2055 swspeak() {
2056     aumix -w 90 -v 90 -p 90 -m 90
2057     if ! [[ -r /dev/softsynth ]] ; then
2058         flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
2059         return 1
2060     else
2061         setopt singlelinezle
2062         unsetopt prompt_cr
2063         export PS1="%m%# "
2064         nice -n -20 speechd-up
2065         sleep 2
2066         flite -o play -t "Finished setting up software synthesizer"
2067     fi
2068 }
2069
2070 # I like clean prompt, so provide simple way to get that
2071 check_com 0 || alias 0='return 0'
2072
2073 # for really lazy people like mika:
2074 check_com S &>/dev/null || alias S='screen'
2075 check_com s &>/dev/null || alias s='ssh'
2076
2077 # get top 10 shell commands:
2078 alias top10='print -l ? ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
2079
2080 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
2081 if check_com -c truecrypt ; then
2082     if isutfenv ; then
2083         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
2084     else
2085         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
2086     fi
2087 fi
2088
2089 #f1# Hints for the use of zsh on grml
2090 zsh-help() {
2091     print "$bg[white]$fg[black]
2092 zsh-help - hints for use of zsh on grml
2093 =======================================$reset_color"
2094
2095     print '
2096 Main configuration of zsh happens in /etc/zsh/zshrc (global)
2097 and /etc/skel/.zshrc which is copied to $HOME/.zshrc once.
2098 The files are part of the package grml-etc-core, if you want to
2099 use them on a non-grml-system just get the tar.gz from
2100 http://deb.grml.org/ or get the files from the mercurial
2101 repository:
2102
2103   http://hg.grml.org/grml-etc-core/raw-file/tip/etc/skel/.zshrc
2104   http://hg.grml.org/grml-etc-core/raw-file/tip/etc/zsh/zshrc
2105
2106 If you want to stay in sync with zsh configuration of grml
2107 run '\''ln -sf /etc/skel/.zshrc $HOME/.zshrc'\'' and configure
2108 your own stuff in $HOME/.zshrc.local. System wide configuration
2109 without touching configuration files of grml can take place
2110 in /etc/zsh/zshrc.local.
2111
2112 If you want to use the configuration of user grml also when
2113 running as user root just run '\''zshskel'\'' which will source
2114 the file /etc/skel/.zshrc.
2115
2116 For information regarding zsh start at http://grml.org/zsh/
2117
2118 Take a look at grml'\''s zsh refcard:
2119 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2120
2121 Check out the main zsh refcard:
2122 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2123
2124 And of course visit the zsh-lovers:
2125 % man zsh-lovers
2126
2127 You can adjust some options through environment variables when
2128 invoking zsh without having to edit configuration files.
2129 Basically meant for bash users who are not used to the power of
2130 the zsh yet. :)
2131
2132   "NOCOR=1    zsh" => deactivate automatic correction
2133   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
2134   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2135   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt'
2136
2137     print "
2138 $bg[white]$fg[black]
2139 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2140 Enjoy your grml system with the zsh!$reset_color"
2141 }
2142
2143 # debian stuff
2144 if [[ -r /etc/debian_version ]] ; then
2145     #a3# Execute \kbd{apt-cache search}
2146     alias acs='apt-cache search'
2147     #a3# Execute \kbd{apt-cache show}
2148     alias acsh='apt-cache show'
2149     #a3# Execute \kbd{apt-cache policy}
2150     alias acp='apt-cache policy'
2151     #a3# Execute \kbd{apt-get dist-upgrade}
2152     salias adg="apt-get dist-upgrade"
2153     #a3# Execute \kbd{apt-get install}
2154     salias agi="apt-get install"
2155     #a3# Execute \kbd{aptitude install}
2156     salias ati="aptitude install"
2157     #a3# Execute \kbd{apt-get upgrade}
2158     salias ag="apt-get upgrade"
2159     #a3# Execute \kbd{apt-get update}
2160     salias au="apt-get update"
2161     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2162     salias -a up="aptitude update ; aptitude safe-upgrade"
2163     #a3# Execute \kbd{dpkg-buildpackage}
2164     alias dbp='dpkg-buildpackage'
2165     #a3# Execute \kbd{grep-excuses}
2166     alias ge='grep-excuses'
2167
2168     # debian upgrade
2169     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
2170     upgrade() {
2171         if [[ -z "$1" ]] ; then
2172             $SUDO apt-get update
2173             $SUDO apt-get -u upgrade
2174         else
2175             ssh $1 $SUDO apt-get update
2176             # ask before the upgrade
2177             local dummy
2178             ssh $1 $SUDO apt-get --no-act upgrade
2179             echo -n 'Process the upgrade?'
2180             read -q dummy
2181             if [[ $dummy == "y" ]] ; then
2182                 ssh $1 $SUDO apt-get -u upgrade --yes
2183             fi
2184         fi
2185     }
2186
2187     # get a root shell as normal user in live-cd mode:
2188     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2189        alias su="sudo su"
2190      fi
2191
2192     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2193     alias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2194     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2195     alias tlog="tail -f /var/log/syslog"    # follow the syslog
2196     #a1# (Re)-source \kbd{/etc/skel/.zshrc}
2197     alias zshskel="source /etc/skel/.zshrc" # source skeleton zshrc
2198 fi
2199
2200 # sort installed Debian-packages by size
2201 if check_com -c grep-status ; then
2202     #a3# List installed Debian-packages sorted by size
2203     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
2204 fi
2205
2206 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2207 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord ; then
2208     if check_com -c wodim ; then
2209         alias cdrecord="echo 'cdrecord is not provided under its original name by Debian anymore.
2210 See #377109 in the BTS of Debian for more details.
2211
2212 Please use the wodim binary instead' ; return 1"
2213     fi
2214 fi
2215
2216 # get_tw_cli has been renamed into get_3ware
2217 if check_com -c get_3ware ; then
2218     get_tw_cli() {
2219         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
2220         get_3ware
2221     }
2222 fi
2223
2224 # I hate lacking backward compatibility, so provide an alternative therefore
2225 if ! check_com -c apache2-ssl-certificate ; then
2226
2227     apache2-ssl-certificate() {
2228
2229     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
2230     print 'You might want to take a look at Debian the package ssl-cert as well.'
2231     print 'To generate a certificate for use with apache2 follow the instructions:'
2232
2233     echo '
2234
2235 export RANDFILE=/dev/random
2236 mkdir /etc/apache2/ssl/
2237 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
2238 chmod 600 /etc/apache2/ssl/apache.pem
2239
2240 Run "grml-tips ssl-certificate" if you need further instructions.
2241 '
2242     }
2243 fi
2244 # }}}
2245
2246 # {{{ Use hard limits, except for a smaller stack and no core dumps
2247 unlimit
2248 is425 && limit stack 8192
2249 isgrmlcd && limit core 0 # important for a live-cd-system
2250 limit -s
2251 # }}}
2252
2253 # {{{ completion system
2254
2255 # called later (via is4 && grmlcomp)
2256 # notice: use 'zstyle' for getting current settings
2257 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
2258 grmlcomp() {
2259     # TODO: This could use some additional information
2260
2261     # allow one error for every three characters typed in approximate completer
2262     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
2263
2264     # don't complete backup files as executables
2265     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
2266
2267     # start menu completion only if it could find no unambiguous initial string
2268     zstyle ':completion:*:correct:*'       insert-unambiguous true
2269     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
2270     zstyle ':completion:*:correct:*'       original true
2271
2272     # activate color-completion
2273     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
2274
2275     # format on completion
2276     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
2277
2278     # complete 'cd -<tab>' with menu
2279     zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
2280
2281     # insert all expansions for expand completer
2282     zstyle ':completion:*:expand:*'        tag-order all-expansions
2283     zstyle ':completion:*:history-words'   list false
2284
2285     # activate menu
2286     zstyle ':completion:*:history-words'   menu yes
2287
2288     # ignore duplicate entries
2289     zstyle ':completion:*:history-words'   remove-all-dups yes
2290     zstyle ':completion:*:history-words'   stop yes
2291
2292     # match uppercase from lowercase
2293     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
2294
2295     # separate matches into groups
2296     zstyle ':completion:*:matches'         group 'yes'
2297     zstyle ':completion:*'                 group-name ''
2298
2299     if [[ "$NOMENU" -eq 0 ]] ; then
2300         # if there are more than 5 options allow selecting from a menu
2301         zstyle ':completion:*'               menu select=5
2302     else
2303         # don't use any menus at all
2304         setopt no_auto_menu
2305     fi
2306
2307     zstyle ':completion:*:messages'        format '%d'
2308     zstyle ':completion:*:options'         auto-description '%d'
2309
2310     # describe options in full
2311     zstyle ':completion:*:options'         description 'yes'
2312
2313     # on processes completion complete all user processes
2314     zstyle ':completion:*:processes'       command 'ps -au$USER'
2315
2316     # offer indexes before parameters in subscripts
2317     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
2318
2319     # provide verbose completion information
2320     zstyle ':completion:*'                 verbose true
2321
2322     # recent (as of Dec 2007) zsh versions are able to provide descriptions
2323     # for commands (read: 1st word in the line) that it will list for the user
2324     # to choose from. The following disables that, because it's not exactly fast.
2325     zstyle ':completion:*:-command-:*:'    verbose false
2326
2327     # set format for warnings
2328     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
2329
2330     # define files to ignore for zcompile
2331     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
2332     zstyle ':completion:correct:'          prompt 'correct to: %e'
2333
2334     # Ignore completion functions for commands you don't have:
2335     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
2336
2337     # Provide more processes in completion of programs like killall:
2338     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
2339
2340     # complete manual by their section
2341     zstyle ':completion:*:manuals'    separate-sections true
2342     zstyle ':completion:*:manuals.*'  insert-sections   true
2343     zstyle ':completion:*:man:*'      menu yes select
2344
2345     # run rehash on completion so new installed program are found automatically:
2346     _force_rehash() {
2347         (( CURRENT == 1 )) && rehash
2348         return 1
2349     }
2350
2351     ## correction
2352     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
2353     if [[ "$NOCOR" -gt 0 ]] ; then
2354         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
2355         setopt nocorrect
2356     else
2357         # try to be smart about when to use what completer...
2358         setopt correct
2359         zstyle -e ':completion:*' completer '
2360             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
2361                 _last_try="$HISTNO$BUFFER$CURSOR"
2362                 reply=(_complete _match _ignored _prefix _files)
2363             else
2364                 if [[ $words[1] == (rm|mv) ]] ; then
2365                     reply=(_complete _files)
2366                 else
2367                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
2368                 fi
2369             fi'
2370     fi
2371
2372     # zstyle ':completion:*' completer _complete _correct _approximate
2373     # zstyle ':completion:*' expand prefix suffix
2374
2375     # complete shell aliases
2376     # zstyle ':completion:*' completer _expand_alias _complete _approximate
2377
2378     # command for process lists, the local web server details and host completion
2379     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
2380
2381     # caching
2382     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
2383                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
2384
2385     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
2386     if is42 ; then
2387         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
2388         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
2389     else
2390         _ssh_hosts=()
2391         _etc_hosts=()
2392     fi
2393     hosts=(
2394         $(hostname)
2395         "$_ssh_hosts[@]"
2396         "$_etc_hosts[@]"
2397         grml.org
2398         localhost
2399     )
2400     zstyle ':completion:*:hosts' hosts $hosts
2401     #  zstyle '*' hosts $hosts
2402
2403     # specify your logins:
2404     # my_accounts=(
2405     #  {grml,grml1}@foo.invalid
2406     #  grml-devel@bar.invalid
2407     # )
2408     # other_accounts=(
2409     #  {fred,root}@foo.invalid
2410     #  vera@bar.invalid
2411     # )
2412     # zstyle ':completion:*:my-accounts' users-hosts $my_accounts
2413     # zstyle ':completion:*:other-accounts' users-hosts $other_accounts
2414
2415     # specify specific port/service settings:
2416     #  telnet_users_hosts_ports=(
2417     #    user1@host1:
2418     #    user2@host2:
2419     #    @mail-server:{smtp,pop3}
2420     #    @news-server:nntp
2421     #    @proxy-server:8000
2422     #  )
2423     # zstyle ':completion:*:*:telnet:*' users-hosts-ports $telnet_users_hosts_ports
2424
2425     # use generic completion system for programs not yet defined; (_gnu_generic works
2426     # with commands that provide a --help option with "standard" gnu-like output.)
2427     compdef _gnu_generic tail head feh cp mv df stow uname ipacsum fetchipac
2428
2429     # see upgrade function in this file
2430     compdef _hosts upgrade
2431 }
2432 # }}}
2433
2434 # {{{ grmlstuff
2435 grmlstuff() {
2436 # people should use 'grml-x'!
2437     startx() {
2438         if [[ -e /etc/X11/xorg.conf ]] ; then
2439             [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
2440         else
2441             echo "Please use the script \"grml-x\" for starting the X Window System
2442 because there does not exist /etc/X11/xorg.conf yet.
2443 If you want to use startx anyway please call \"/usr/bin/startx\"."
2444             return -1
2445         fi
2446     }
2447
2448     xinit() {
2449         if [[ -e /etc/X11/xorg.conf ]] ; then
2450             [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
2451         else
2452             echo "Please use the script \"grml-x\" for starting the X Window System.
2453 because there does not exist /etc/X11/xorg.conf yet.
2454 If you want to use xinit anyway please call \"/usr/bin/xinit\"."
2455             return -1
2456         fi
2457     }
2458
2459     if check_com -c 915resolution ; then
2460         alias 855resolution='echo -e "Please use 915resolution as resolution modify tool for Intel graphic chipset."; return -1'
2461     fi
2462
2463     #a1# Output version of running grml
2464     alias grml-version='cat /etc/grml_version'
2465
2466     if check_com -c rebuildfstab ; then
2467         #a1# Rebuild /etc/fstab
2468         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2469     fi
2470
2471     if check_com -c grml-debootstrap ; then
2472         alias debian2hd='print "Installing debian to harddisk is possible via using grml-debootstrap." ; return 1'
2473     fi
2474 }
2475 # }}}
2476
2477 # {{{ now run the functions
2478 isgrml && checkhome
2479 is4    && isgrml    && grmlstuff
2480 is4    && grmlcomp
2481 # }}}
2482
2483 # {{{ keephack
2484 is4 && xsource "/etc/zsh/keephack"
2485 # }}}
2486
2487 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2488 # You use it as follows:
2489 # $ NTREF=/reference/file
2490 # $ ls -l *(e:nt:)
2491 # This lists all the files in the current directory newer than the reference file.
2492 # You can also specify the reference file inline; note quotes:
2493 # $ ls -l *(e:'nt ~/.zshenv':)
2494 is4 && nt() {
2495     if [[ -n $1 ]] ; then
2496         local NTREF=${~1}
2497     fi
2498     [[ $REPLY -nt $NTREF ]]
2499 }
2500 # }}}
2501
2502 # shell functions {{{
2503
2504 #f1# Provide csh compatibility
2505 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2506
2507 #f1# Reload an autoloadable function
2508 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2509
2510 #f1# Reload zsh setup
2511 reload() {
2512     if [[ "$#*" -eq 0 ]] ; then
2513         [[ -r ~/.zshrc ]] && . ~/.zshrc
2514     else
2515         local fn
2516         for fn in "$@"; do
2517             unfunction $fn
2518             autoload -U $fn
2519         done
2520     fi
2521 }
2522 compdef _functions reload freload
2523
2524 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2525 sll() {
2526     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2527     for i in "$@" ; do
2528         file=$i
2529         while [[ -h "$file" ]] ; do
2530             ls -l $file
2531             file=$(readlink "$file")
2532         done
2533     done
2534 }
2535
2536 # fast manual access
2537 if check_com qma ; then
2538     #f1# View the zsh manual
2539     manzsh()  { qma zshall "$1" }
2540     compdef _man qma
2541 else
2542     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2543     # manzsh()  { /usr/bin/man zshall |  most +/"$1" ; }
2544     # [[ -f ~/.terminfo/m/mostlike ]] && MYLESS='LESS=C TERMINFO=~/.terminfo TERM=mostlike less' || MYLESS='less'
2545     # manzsh()  { man zshall | $MYLESS -p $1 ; }
2546 fi
2547
2548 if check_com -c $PAGER ; then
2549     #f1# View Debian's changelog of a given package
2550     dchange() {
2551         if [[ -r /usr/share/doc/${1}/changelog.Debian.gz ]] ; then
2552             $PAGER /usr/share/doc/${1}/changelog.Debian.gz
2553         elif [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2554             $PAGER /usr/share/doc/${1}/changelog.gz
2555         else
2556             if check_com -c aptitude ; then
2557                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2558                 if isgrml ; then
2559                     aptitude -t unstable changelog ${1}
2560                 else
2561                     aptitude changelog ${1}
2562                 fi
2563             else
2564                 echo "No changelog for package $1 found, sorry."
2565                 return 1
2566             fi
2567         fi
2568     }
2569     _dchange() { _files -W /usr/share/doc -/ }
2570     compdef _dchange dchange
2571
2572     #f1# View Debian's NEWS of a given package
2573     dnews() {
2574         if [[ -r /usr/share/doc/${1}/NEWS.Debian.gz ]] ; then
2575             $PAGER /usr/share/doc/${1}/NEWS.Debian.gz
2576         else
2577             if [[ -r /usr/share/doc/${1}/NEWS.gz ]] ; then
2578                 $PAGER /usr/share/doc/${1}/NEWS.gz
2579             else
2580                 echo "No NEWS file for package $1 found, sorry."
2581                 return 1
2582             fi
2583         fi
2584     }
2585     _dnews() { _files -W /usr/share/doc -/ }
2586     compdef _dnews dnews
2587
2588     #f1# View upstream's changelog of a given package
2589     uchange() {
2590         if [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2591             $PAGER /usr/share/doc/${1}/changelog.gz
2592         else
2593             echo "No changelog for package $1 found, sorry."
2594             return 1
2595         fi
2596     }
2597     _uchange() { _files -W /usr/share/doc -/ }
2598     compdef _uchange uchange
2599 fi
2600
2601 # zsh profiling
2602 profile() {
2603     ZSH_PROFILE_RC=1 $SHELL "$@"
2604 }
2605
2606 #f1# Edit an alias via zle
2607 edalias() {
2608     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2609 }
2610 compdef _aliases edalias
2611
2612 #f1# Edit a function via zle
2613 edfunc() {
2614     [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
2615 }
2616 compdef _functions edfunc
2617
2618 # use it e.g. via 'Restart apache2'
2619 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2620 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2621 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2622 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2623 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2624 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2625     __start_stop() {
2626         local action_="${1:l}"  # e.g Start/Stop/Restart
2627         local service_="$2"
2628         local param_="$3"
2629
2630         local service_target_="$(readlink /etc/init.d/$service_)"
2631         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2632             # runit
2633             case "${action_}" in
2634                 start) if [[ ! -e /etc/service/$service_ ]]; then
2635                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2636                        else
2637                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2638                        fi ;;
2639                 # there is no reload in runits sysv emulation
2640                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2641                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2642             esac
2643         else
2644             # sysvinit
2645             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2646         fi
2647     }
2648
2649     for i in Start Restart Stop Force-Reload Reload ; do
2650         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2651     done
2652 fi
2653
2654 #f1# Provides useful information on globbing
2655 H-Glob() {
2656     echo -e "
2657     /      directories
2658     .      plain files
2659     @      symbolic links
2660     =      sockets
2661     p      named pipes (FIFOs)
2662     *      executable plain files (0100)
2663     %      device files (character or block special)
2664     %b     block special files
2665     %c     character special files
2666     r      owner-readable files (0400)
2667     w      owner-writable files (0200)
2668     x      owner-executable files (0100)
2669     A      group-readable files (0040)
2670     I      group-writable files (0020)
2671     E      group-executable files (0010)
2672     R      world-readable files (0004)
2673     W      world-writable files (0002)
2674     X      world-executable files (0001)
2675     s      setuid files (04000)
2676     S      setgid files (02000)
2677     t      files with the sticky bit (01000)
2678
2679   print *(m-1)          # Files modified up to a day ago
2680   print *(a1)           # Files accessed a day ago
2681   print *(@)            # Just symlinks
2682   print *(Lk+50)        # Files bigger than 50 kilobytes
2683   print *(Lk-50)        # Files smaller than 50 kilobytes
2684   print **/*.c          # All *.c files recursively starting in \$PWD
2685   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2686   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2687   print *~*.*           # All Files that do not contain a dot
2688   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2689   print -l *(.c|.h)     # Lists *.c and *.h
2690   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2691   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2692 }
2693 alias help-zshglob=H-Glob
2694
2695 check_com -c qma && alias ?='qma zshall'
2696
2697 # grep for running process, like: 'any vim'
2698 any() {
2699     if [[ -z "$1" ]] ; then
2700         echo "any - grep for process(es) by keyword" >&2
2701         echo "Usage: any <keyword>" >&2 ; return 1
2702     else
2703         local STRING=$1
2704         local LENGTH=$(expr length $STRING)
2705         local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
2706         local REST=$(echo $(expr substr $STRING 2 $LENGTH))
2707         ps xauwww| grep "[$FIRSCHAR]$REST"
2708     fi
2709 }
2710
2711 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2712 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2713 [[ -r /proc/1/maps ]] && \
2714 deswap() {
2715     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2716     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2717     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2718 }
2719
2720 # print hex value of a number
2721 hex() {
2722     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2723 }
2724
2725 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2726 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2727 peval() {
2728     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2729     perl -e "print eval($CALC),\"\n\";"
2730 }
2731 functions peval &>/dev/null && alias calc=peval
2732
2733 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2734 # certain circumstances, so work around it, no matter which environment we have
2735 brltty() {
2736     if [[ -z "$DISPLAY" ]] ; then
2737         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2738         command brltty "$@"
2739     else
2740         command brltty "$@"
2741     fi
2742 }
2743
2744 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2745 aoeu() {
2746     echo -n 'Switching to us keyboard layout: '
2747     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2748     echo 'Done'
2749 }
2750 asdf() {
2751     echo -n 'Switching to dvorak keyboard layout: '
2752     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2753     echo 'Done'
2754 }
2755 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2756 uiae() {
2757     echo -n 'Switching to us keyboard layout: '
2758     setxkbmap us && echo 'Done' || echo 'Failed'
2759 }
2760
2761 # set up an ipv6 tunnel
2762 ipv6-tunnel() {
2763     case $1 in
2764         start)
2765             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2766                 print 'ipv6 tunnel already set up, nothing to be done.'
2767                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2768             else
2769                 [[ -n "$PUBLIC_IP" ]] || \
2770                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2771                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2772
2773                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2774                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2775                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2776                 ifconfig sit0 tunnel ::192.88.99.1 up
2777                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2778             fi
2779             ;;
2780         status)
2781             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2782                 print 'ipv6 tunnel available' ; return 0
2783             else
2784                 print 'ipv6 tunnel not available' ; return 1
2785             fi
2786             ;;
2787         stop)
2788             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2789                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2790                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2791             else
2792                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2793             fi
2794             ;;
2795         *)
2796             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2797             ;;
2798     esac
2799 }
2800
2801 # run dhclient for wireless device
2802 iwclient() {
2803     salias dhclient "$(wavemon -d | awk '/device/{print $2}')"
2804 }
2805
2806 # spawn a minimally set up ksh - useful if you want to umount /usr/.
2807 minimal-shell() {
2808     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
2809 }
2810
2811 # make a backup of a file
2812 bk() {
2813     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2814 }
2815
2816 # Switching shell safely and efficiently? http://www.zsh.org/mla/workers/2001/msg02410.html
2817 # bash() {
2818 #  NO_SWITCH="yes" command bash "$@"
2819 # }
2820 # restart () {
2821 #  exec $SHELL $SHELL_ARGS "$@"
2822 # }
2823
2824 # }}}
2825
2826 # log out? set timeout in seconds {{{
2827 # TMOUT=1800
2828 # do not log out in some specific terminals:
2829 #  if [[ "${TERM}" == ([Exa]term*|rxvt|dtterm|screen*) ]] ; then
2830 #    unset TMOUT
2831 #  fi
2832 # }}}
2833
2834 # {{{ make sure our environment is clean regarding colors
2835 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2836 # }}}
2837
2838 # source another config file if present {{{
2839 xsource "/etc/zsh/zshrc.local"
2840 xsource "${HOME}/.zshenv"
2841 # }}}
2842
2843 # "persistent history" {{{
2844 # just write important commands you always need to ~/.important_commands
2845 if [[ -r ~/.important_commands ]] ; then
2846     fc -R ~/.important_commands
2847 fi
2848 # }}}
2849
2850 ## genrefcard.pl settings {{{
2851 ### example: split functions-search 8,16,24,32
2852 #@# split functions-search 8
2853 ## }}}
2854
2855 # add variable to be able to check whether the file has been read {{{
2856 ZSHRC_GLOBAL_HAS_BEEN_READ=1
2857 # }}}
2858
2859 ## END OF FILE #################################################################
2860 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4