zshrc: ...updated the code, but not its users... fix.
[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 [[ -n $ZSH_PROFILE_RC ]] ; 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/[^_]*[^~] ; 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  zprof
809         ap  mapfile
810     )
811
812     while (( ${#tmpargs} > 0 )) ; do
813         zmodload -${tmpargs[1]} zsh/${tmpargs[2]} ${tmpargs[2]}
814         shift 2 tmpargs
815     done
816     unset tmpargs
817 fi
818
819 if is4 && zrcautoload insert-files && zle -N insert-files ; then
820     #k# Insert files
821     bindkey "^Xf" insert-files # C-x-f
822 fi
823
824 bindkey ' '   magic-space    # also do history expansion on space
825 #k# Trigger menu-complete
826 bindkey '\ei' menu-complete  # menu completion via esc-i
827
828 # press esc-e for editing command line in $EDITOR or $VISUAL
829 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
830     #k# Edit the current line in \kbd{\$EDITOR}
831     bindkey '\ee' edit-command-line
832 fi
833
834 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
835     #k# menu selection: pick item but stay in the menu
836     bindkey -M menuselect '\e^M' accept-and-menu-complete
837
838     # use the vi navigation keys (hjkl) besides cursor keys in menu completion
839     #bindkey -M menuselect 'h' vi-backward-char        # left
840     #bindkey -M menuselect 'k' vi-up-line-or-history   # up
841     #bindkey -M menuselect 'l' vi-forward-char         # right
842     #bindkey -M menuselect 'j' vi-down-line-or-history # bottom
843
844     # accept a completion and try to complete again by using menu
845     # completion; very useful with completing directories
846     # by using 'undo' one's got a simple file browser
847     bindkey -M menuselect '^o' accept-and-infer-next-history
848 fi
849
850 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
851 _bkdate() { BUFFER="$BUFFER$(date '+%F')"; CURSOR=$#BUFFER; }
852 zle -N _bkdate
853
854 #k# Insert a timestamp on the command line (yyyy-mm-dd)
855 bindkey '^Ed' _bkdate
856
857 # press esc-m for inserting last typed word again (thanks to caphuso!)
858 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
859 zle -N insert-last-typed-word;
860
861 #k# Insert last typed word
862 bindkey "\em" insert-last-typed-word
863
864 # set command prediction from history, see 'man 1 zshcontrib'
865 #  is4 && zrcautoload predict-on && \
866 #  zle -N predict-on         && \
867 #  zle -N predict-off        && \
868 #  bindkey "^X^Z" predict-on && \
869 #  bindkey "^Z" predict-off
870
871 #k# Shortcut for \kbd{fg<enter>}
872 bindkey -s '^z' "fg\n"
873
874 # press ctrl-q to quote line:
875 #  mquote () {
876 #        zle beginning-of-line
877 #        zle forward-word
878 #        # RBUFFER="'$RBUFFER'"
879 #        RBUFFER=${(q)RBUFFER}
880 #        zle end-of-line
881 #  }
882 #  zle -N mquote && bindkey '^q' mquote
883
884 # run command line as user root via sudo:
885 sudo-command-line() {
886     [[ -z $BUFFER ]] && zle up-history
887     [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
888 }
889 zle -N sudo-command-line
890
891 #k# Put the current command line into a \kbd{sudo} call
892 bindkey "^Os" sudo-command-line
893
894 ### jump behind the first word on the cmdline.
895 ### useful to add options.
896 function jump_after_first_word() {
897     local words
898     words=(${(z)BUFFER})
899
900     if (( ${#words} <= 1 )) ; then
901         CURSOR=${#BUFFER}
902     else
903         CURSOR=${#${words[1]}}
904     fi
905 }
906 zle -N jump_after_first_word
907
908 bindkey '^x1' jump_after_first_word
909
910 # }}}
911
912 # {{{ set some important options
913 # Please update these tags, if you change the umask settings below.
914 #o# r_umask     002
915 #o# r_umaskstr  rwxrwxr-x
916 #o# umask       022
917 #o# umaskstr    rwxr-xr-x
918 (( EUID != 0 )) && umask 002 || umask 022
919
920 # history:
921 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
922 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
923 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
924 is4 && setopt histignorealldups # If  a  new  command  line being added to the history
925                             # list duplicates an older one, the older command is removed from the list
926 setopt histignorespace      # remove command lines from the history list when
927                             # the first character on the line is a space
928 #  setopt histallowclobber    # add `|' to output redirections in the history
929 #  setopt NO_clobber          # warning if file exists ('cat /dev/null > ~/.zshrc')
930 setopt auto_cd              # if a command is issued that can't be executed as a normal command,
931                             # and the command is the name of a directory, perform the cd command to that directory
932 setopt extended_glob        # in order to use #, ~ and ^ for filename generation
933                             # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
934                             # -> searches for word not in compressed files
935                             # don't forget to quote '^', '~' and '#'!
936 setopt longlistjobs         # display PID when suspending processes as well
937 setopt notify               # report the status of backgrounds jobs immediately
938 setopt hash_list_all        # Whenever a command completion is attempted, make sure \
939                             # the entire command path is hashed first.
940 setopt completeinword       # not just at the end
941 # setopt nocheckjobs          # don't warn me about bg processes when exiting
942 setopt nohup                # and don't kill them, either
943 # setopt printexitvalue       # alert me if something failed
944 # setopt dvorak               # with spelling correction, assume dvorak kb
945 setopt auto_pushd           # make cd push the old directory onto the directory stack.
946 setopt nonomatch            # try to avoid the 'zsh: no matches found...'
947 setopt nobeep               # avoid "beep"ing
948 setopt pushd_ignore_dups    # don't push the same dir twice.
949
950 MAILCHECK=30       # mailchecks
951 REPORTTIME=5       # report about cpu-/system-/user-time of command if running longer than 5 seconds
952 watch=(notme root) # watch for everyone but me and root
953
954 # define word separators (for stuff like backward-word, forward-word, backward-kill-word,..)
955 #  WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' # the default
956 #  WORDCHARS=.
957 #  WORDCHARS='*?_[]~=&;!#$%^(){}'
958 #  WORDCHARS='${WORDCHARS:s@/@}'
959
960 # only slash should be considered as a word separator:
961 slash-backward-kill-word() {
962     local WORDCHARS="${WORDCHARS:s@/@}"
963     # zle backward-word
964     zle backward-kill-word
965 }
966 zle -N slash-backward-kill-word
967
968 #k# Kill everything in a word up to its last \kbd{/}
969 bindkey '\ev' slash-backward-kill-word
970
971 # }}}
972
973 # {{{ history
974
975 ZSHDIR=$HOME/.zsh
976
977 #v#
978 HISTFILE=$HOME/.zsh_history
979 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
980 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
981
982 # }}}
983
984 # dirstack handling {{{
985
986 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
987 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
988
989 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
990     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
991     # "cd -" won't work after login by just setting $OLDPWD, so
992     [[ -d $dirstack[0] ]] && cd $dirstack[0] && cd $OLDPWD
993 fi
994
995 chpwd() {
996     if is42 ; then
997         builtin print -l ${(u)dirstack} >! ${DIRSTACKFILE}
998     else
999         uprint dirstack >! ${DIRSTACKFILE}
1000     fi
1001 }
1002
1003 # }}}
1004
1005 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
1006 if [[ -n "$BATTERY" ]] ; then
1007     if check_com -c acpi ; then
1008         PERCENT="${(C)${(s| |)$(acpi 2>/dev/null)}[4]}"
1009         [[ -z "$PERCENT" ]] && PERCENT='acpi not present'
1010
1011         if [[ "${PERCENT%%%}" -lt 20 ]] ; then
1012             PERCENT="warning: ${PERCENT}%"
1013         fi
1014     fi
1015 fi
1016 # }}}
1017
1018 # set colors for use in prompts {{{
1019 if zrcautoload colors && colors 2>/dev/null ; then
1020     BLUE="%{${fg[blue]}%}"
1021     RED="%{${fg_bold[red]}%}"
1022     GREEN="%{${fg[green]}%}"
1023     CYAN="%{${fg[cyan]}%}"
1024     MAGENTA="%{${fg[magenta]}%}"
1025     YELLOW="%{${fg[yellow]}%}"
1026     WHITE="%{${fg[white]}%}"
1027     NO_COLOUR="%{${reset_color}%}"
1028 else
1029     BLUE=$'%{\e[1;34m%}'
1030     RED=$'%{\e[1;31m%}'
1031     GREEN=$'%{\e[1;32m%}'
1032     CYAN=$'%{\e[1;36m%}'
1033     WHITE=$'%{\e[1;37m%}'
1034     MAGENTA=$'%{\e[1;35m%}'
1035     YELLOW=$'%{\e[1;33m%}'
1036     NO_COLOUR=$'%{\e[0m%}'
1037 fi
1038
1039 # }}}
1040
1041 # gather version control information for inclusion in a prompt {{{
1042
1043 if ! is41 ; then
1044     # Be quiet about version problems in grml's zshrc as the user cannot disable
1045     # loading vcs_info() as it is *in* the zshrc - as you can see. :-)
1046     # Just unset most probable variables and disable vcs_info altogether.
1047     local -i i
1048     for i in {0..9} ; do
1049         unset VCS_INFO_message_${i}_
1050     done
1051     zstyle ':vcs_info:*' enable false
1052 fi
1053
1054 # The following code is imported from the file 'zsh/functions/vcs_info'
1055 # from <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>,
1056 # which distributed under the same terms as zsh itself.
1057
1058 # we will only be using one variable, so let the code know now.
1059 zstyle ':vcs_info:*' max-exports 1
1060
1061 # vcs_info() documentation:
1062 #{{{
1063 # REQUIREMENTS:
1064 #{{{
1065 #     This functionality requires zsh version >= 4.1.*.
1066 #}}}
1067 #
1068 # LOADING:
1069 #{{{
1070 # To load vcs_info(), copy this file to your $fpath[] and do:
1071 #   % autoload -Uz vcs_info && vcs_info
1072 #
1073 # To work, vcs_info() needs 'setopt prompt_subst' in your setup.
1074 #}}}
1075 #
1076 # QUICKSTART:
1077 #{{{
1078 # To get vcs_info() working quickly (including colors), you can do the
1079 # following (assuming, you loaded vcs_info() properly - see above):
1080 #
1081 # % RED=$'%{\e[31m%}'
1082 # % GR=$'%{\e[32m%}'
1083 # % MA=$'%{\e[35m%}'
1084 # % YE=$'%{\e[33m%}'
1085 # % NC=$'%{\e[0m%}'
1086 #
1087 # % zstyle ':vcs_info:*' actionformats \
1088 #       "${MA}(${NC}%s${MA})${YE}-${MA}[${GR}%b${YE}|${RED}%a${MA}]${NC} "
1089 #
1090 # % zstyle ':vcs_info:*' formats       \
1091 #       "${MA}(${NC}%s${MA})${Y}-${MA}[${GR}%b${MA}]${NC}%} "
1092 #
1093 # % zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YE}%r"
1094 #
1095 # % precmd () { vcs_info }
1096 # % PS1='${MA}[${GR}%n${MA}] ${MA}(${RED}%!${MA}) ${YE}%3~ ${VCS_INFO_message_0_}${NC}%# '
1097 #
1098 # Obviously, the las two lines are there for demonstration: You need to
1099 # call vcs_info() from your precmd() function (see 'SPECIAL FUNCTIONS' in
1100 # 'man zshmisc'). Once that is done you need a *single* quoted
1101 # '${VCS_INFO_message_0_}' in your prompt.
1102 #
1103 # Now call the 'vcs_info_printsys' utility from the command line:
1104 #
1105 # % vcs_info_printsys
1106 # # list of supported version control backends:
1107 # # disabled systems are prefixed by a hash sign (#)
1108 # git
1109 # hg
1110 # bzr
1111 # darcs
1112 # svk
1113 # mtn
1114 # svn
1115 # cvs
1116 # cdv
1117 # tla
1118 # # flavours (cannot be used in the disable style; they
1119 # # are disabled with their master [git-svn -> git]):
1120 # git-p4
1121 # git-svn
1122 #
1123 # Ten version control backends as you can see. You may not want all
1124 # of these. Because there is no point in running the code to detect
1125 # systems you do not use. ever. So, there is a way to disable some
1126 # backends altogether:
1127 #
1128 # % zstyle ':vcs_info:*' disable bzr cdv darcs mtn svk tla
1129 #
1130 # If you rerun 'vcs_info_printsys' now, you will see the backends listed
1131 # in the 'disable' style marked as diabled by a hash sign. That means the
1132 # detection of these systems is skipped *completely*. No wasted time there.
1133 #
1134 # For more control, read the reference below.
1135 #}}}
1136 #
1137 # CONFIGURATION:
1138 #{{{
1139 # The vcs_info() feature can be configured via zstyle.
1140 #
1141 # First, the context in which we are working:
1142 #       :vcs_info:<vcs-string>:<user-context>
1143 #
1144 # ...where <vcs-string> is one of:
1145 #   - git, git-svn, git-p4, hg, darcs, bzr, cdv, mtn, svn, cvs, svk or tla.
1146 #
1147 # ...and <user-context> is a freely configurable string, assignable by the
1148 # user as the first argument to vcs_info() (see its description below).
1149 #
1150 # There is are three special values for <vcs-string>: The first is named
1151 # 'init', that is in effect as long as there was no decision what vcs
1152 # backend to use. The second is 'preinit; it is used *before* vcs_info()
1153 # is run, when initializing the data exporting variables. The third
1154 # special value is 'formats' and is used by the 'vcs_info_lastmsg' for
1155 # looking up its styles.
1156 #
1157 # There are two pre-defined values for <user-context>:
1158 #   default  - the one used if none is specified
1159 #   command  - used by vcs_info_lastmsg to lookup its styles.
1160 #
1161 # You may *not* use 'print_systems_' as a user-context string, because it
1162 # is used internally.
1163 #
1164 # You can of course use ':vcs_info:*' to match all VCSs in all
1165 # user-contexts at once.
1166 #
1167 # Another special context is 'formats', which is used by the
1168 # vcs_info_lastmsg() utility function (see below).
1169 #
1170 #
1171 # This is a description of all styles, that are looked up:
1172 #   formats             - A list of formats, used when actionformats is not
1173 #                         used (which is most of the time).
1174 #   actionformats       - A list of formats, used if a there is a special
1175 #                         action going on in your current repository;
1176 #                         (like an interactive rebase or a merge conflict)
1177 #   branchformat        - Some backends replace %b in the formats and
1178 #                         actionformats styles above, not only by a branch
1179 #                         name but also by a revision number. This style
1180 #                         let's you modify how that string should look like.
1181 #   nvcsformats         - These "formats" are exported, when we didn't detect
1182 #                         a version control system for the current directory.
1183 #                         This is useful, if you want vcs_info() to completely
1184 #                         take over the generation of your prompt.
1185 #                         You would do something like
1186 #                           PS1='${VCS_INFO_message_0_}'
1187 #                         to accomplish that.
1188 #   max-exports         - Defines the maximum number if VCS_INFO_message_*_
1189 #                         variables vcs_info() will export.
1190 #   enable              - Checked in the 'init' context. If set to false,
1191 #                         vcs_info() will do nothing.
1192 #   disable             - Provide a list of systems, you don't want
1193 #                         the vcs_info() to check for repositories
1194 #                         (checked in the 'init' context, too).
1195 #   use-simple          - If there are two different ways of gathering
1196 #                         information, you can select the simpler one
1197 #                         by setting this style to true; the default
1198 #                         is to use the not-that-simple code, which is
1199 #                         potentially a lot slower but might be more
1200 #                         accurate in all possible cases.
1201 #   use-prompt-escapes  - determines if we assume that the assembled
1202 #                         string from vcs_info() includes prompt escapes.
1203 #                         (Used by vcs_info_lastmsg().
1204 #
1205 # The use-simple style is only available for the bzr backend.
1206 #
1207 # The default values for these in all contexts are:
1208 #   formats             " (%s)-[%b|%a]-"
1209 #   actionformats       " (%s)-[%b]-"
1210 #   branchformat        "%b:%r" (for bzr, svn and svk)
1211 #   nvcsformats         ""
1212 #   max-exports         2
1213 #   enable              true
1214 #   disable             (empty list)
1215 #   use-simple          false
1216 #   use-prompt-escapes  true
1217 #
1218 #
1219 # In normal formats and actionformats, the following replacements
1220 # are done:
1221 #   %s  - The vcs in use (git, hg, svn etc.)
1222 #   %b  - Information about the current branch.
1223 #   %a  - An identifier, that describes the action.
1224 #         Only makes sense in actionformats.
1225 #   %R  - base directory of the repository.
1226 #   %r  - repository name
1227 #         If %R is '/foo/bar/repoXY', %r is 'repoXY'.
1228 #   %S  - subdirectory within a repository. if $PWD is
1229 #         '/foo/bar/reposXY/beer/tasty', %S is 'beer/tasty'.
1230 #
1231 #
1232 # In branchformat these replacements are done:
1233 #   %b  - the branch name
1234 #   %r  - the current revision number
1235 #
1236 # Not all vcs backends have to support all replacements.
1237 # nvcsformat does not perform *any* replacements. It is just a string.
1238 #}}}
1239 #
1240 # ODDITIES:
1241 #{{{
1242 # If you want to use the %b (bold off) prompt expansion in 'formats', which
1243 # expands %b itself, use %%b. That will cause the vcs_info() expansion to
1244 # replace %%b with %b. So zsh's prompt expansion mechanism can handle it.
1245 # Similarly, to hand down %b from branchformat, use %%%%b. Sorry for this
1246 # inconvenience, but it cannot be easily avoided. Luckily we do not clash
1247 # with a lot of prompt expansions and this only needs to be done for those.
1248 # See 'man zshmisc' for details about EXPANSION OF PROMPT SEQUENCES.
1249 #}}}
1250 #
1251 # FUNCTION DESCRIPTIONS (public API):
1252 #{{{
1253 #   vcs_info()
1254 #       The main function, that runs all backends and assembles
1255 #       all data into ${VCS_INFO_message_*_}. This is the function
1256 #       you want to call from precmd() if you want to include
1257 #       up-to-date information in your prompt (see VARIABLE
1258 #       DESCRIPTION below).
1259 #
1260 #   vcs_info_printsys()
1261 #       Prints a list of all supported version control systems.
1262 #       Useful to find out possible contexts (and which of them are enabled)
1263 #       or values for the 'disable' style.
1264 #
1265 #   vcs_info_lastmsg()
1266 #       Outputs the last ${VCS_INFO_message_*_} value. Takes into account
1267 #       the value of the use-prompt-escapes style in ':vcs_info:formats'.
1268 #       It also only prints max-exports values.
1269 #
1270 # All functions named VCS_INFO_* are for internal use only.
1271 #}}}
1272 #
1273 # VARIABLE DESCRIPTION:
1274 #{{{
1275 #   ${VCS_INFO_message_N_}    (Note the trailing underscore)
1276 #       Where 'N' is an integer, eg: VCS_INFO_message_0_
1277 #       These variables are the storage for the informational message the
1278 #       last vcs_info() call has assembled. These are strongly connected
1279 #       to the formats, actionformats and nvcsformats styles described
1280 #       above. Those styles are lists. the first member of that list gets
1281 #       expanded into ${VCS_INFO_message_0_}, the second into
1282 #       ${VCS_INFO_message_1_} and the Nth into ${VCS_INFO_message_N-1_}.
1283 #       These parameters are exported into the environment.
1284 #       (See the max-exports style above.)
1285 #}}}
1286 #
1287 # EXAMPLES:
1288 #{{{
1289 #   Don't use vcs_info at all (even though it's in your prompt):
1290 #   % zstyle ':vcs_info:*' enable false
1291 #
1292 #   Disable the backends for bzr and svk:
1293 #   % zstyle ':vcs_info:*' disable bzr svk
1294 #
1295 #   Provide a special formats for git:
1296 #   % zstyle ':vcs_info:git:*' formats       ' GIT, BABY! [%b]'
1297 #   % zstyle ':vcs_info:git:*' actionformats ' GIT ACTION! [%b|%a]'
1298 #
1299 #   Use the quicker bzr backend (if you do, please report if it does
1300 #   the-right-thing[tm] - thanks):
1301 #   % zstyle ':vcs_info:bzr:*' use-simple true
1302 #
1303 #   Display the revision number in yellow for bzr and svn:
1304 #   % zstyle ':vcs_info:(svn|bzr):*' branchformat '%b%{'${fg[yellow]}'%}:%r'
1305 #
1306 # If you want colors, make sure you enclose the color codes in %{...%},
1307 # if you want to use the string provided by vcs_info() in prompts.
1308 #
1309 # Here is how to print the vcs infomation as a command:
1310 #   % alias vcsi='vcs_info command; vcs_info_lastmsg'
1311 #
1312 #   This way, you can even define different formats for output via
1313 #   vcs_info_lastmsg() in the ':vcs_info:command:*' namespace.
1314 #}}}
1315 #}}}
1316 # utilities
1317 VCS_INFO_adjust () { #{{{
1318     [[ -n ${vcs_comm[overwrite_name]} ]] && vcs=${vcs_comm[overwrite_name]}
1319     return 0
1320 }
1321 # }}}
1322 VCS_INFO_check_com () { #{{{
1323     (( ${+commands[$1]} )) && [[ -x ${commands[$1]} ]] && return 0
1324     return 1
1325 }
1326 # }}}
1327 VCS_INFO_formats () { # {{{
1328     setopt localoptions noksharrays
1329     local action=$1 branch=$2 base=$3
1330     local msg
1331     local -i i
1332
1333     if [[ -n ${action} ]] ; then
1334         zstyle -a ":vcs_info:${vcs}:${usercontext}" actionformats msgs
1335         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b|%a]-'
1336     else
1337         zstyle -a ":vcs_info:${vcs}:${usercontext}" formats msgs
1338         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b]-'
1339     fi
1340
1341     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1342     for i in {1..${#msgs}} ; do
1343         zformat -f msg ${msgs[$i]} a:${action} b:${branch} s:${vcs} r:${base:t} R:${base} S:"$(VCS_INFO_reposub ${base})"
1344         msgs[$i]=${msg}
1345     done
1346     return 0
1347 }
1348 # }}}
1349 VCS_INFO_maxexports () { #{{{
1350     local -ix maxexports
1351
1352     zstyle -s ":vcs_info:${vcs}:${usercontext}" "max-exports" maxexports || maxexports=2
1353     if [[ ${maxexports} != <-> ]] || (( maxexports < 1 )); then
1354         printf 'vcs_info(): expecting numeric arg >= 1 for max-exports (got %s).\n' ${maxexports}
1355         printf 'Defaulting to 2.\n'
1356         maxexports=2
1357     fi
1358 }
1359 # }}}
1360 VCS_INFO_nvcsformats () { #{{{
1361     setopt localoptions noksharrays
1362     local c v
1363
1364     if [[ $1 == 'preinit' ]] ; then
1365         c=default
1366         v=preinit
1367     fi
1368     zstyle -a ":vcs_info:${v:-$vcs}:${c:-$usercontext}" nvcsformats msgs
1369     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1370 }
1371 # }}}
1372 VCS_INFO_realpath () { #{{{
1373     # a portable 'readlink -f'
1374     # forcing a subshell, to ensure chpwd() is not removed
1375     # from the calling shell (if VCS_INFO_realpath() is called
1376     # manually).
1377     (
1378         (( ${+functions[chpwd]} )) && unfunction chpwd
1379         setopt chaselinks
1380         cd $1 2>/dev/null && pwd
1381     )
1382 }
1383 # }}}
1384 VCS_INFO_reposub () { #{{{
1385     setopt localoptions extendedglob
1386     local base=${1%%/##}
1387
1388     [[ ${PWD} == ${base}/* ]] || {
1389         printf '.'
1390         return 1
1391     }
1392     printf '%s' ${PWD#$base/}
1393     return 0
1394 }
1395 # }}}
1396 VCS_INFO_set () { #{{{
1397     setopt localoptions noksharrays
1398     local -i i j
1399
1400     if [[ $1 == '--clear' ]] ; then
1401         for i in {0..9} ; do
1402             unset VCS_INFO_message_${i}_
1403         done
1404     fi
1405     if [[ $1 == '--nvcs' ]] ; then
1406         [[ $2 == 'preinit' ]] && (( maxexports == 0 )) && (( maxexports = 1 ))
1407         for i in {0..$((maxexports - 1))} ; do
1408             typeset -gx VCS_INFO_message_${i}_=
1409         done
1410         VCS_INFO_nvcsformats $2
1411     fi
1412
1413     (( ${#msgs} - 1 < 0 )) && return 0
1414     for i in {0..$(( ${#msgs} - 1 ))} ; do
1415         (( j = i + 1 ))
1416         typeset -gx VCS_INFO_message_${i}_=${msgs[$j]}
1417     done
1418     return 0
1419 }
1420 # }}}
1421 # information gathering
1422 VCS_INFO_bzr_get_data () { # {{{
1423     setopt localoptions noksharrays
1424     local bzrbase bzrbr
1425     local -a bzrinfo
1426
1427     if zstyle -t ":vcs_info:${vcs}:${usercontext}" "use-simple" ; then
1428         bzrbase=${vcs_comm[basedir]}
1429         bzrinfo[2]=${bzrbase:t}
1430         if [[ -f ${bzrbase}/.bzr/branch/last-revision ]] ; then
1431             bzrinfo[1]=$(< ${bzrbase}/.bzr/branch/last-revision)
1432             bzrinfo[1]=${${bzrinfo[1]}%% *}
1433         fi
1434     else
1435         bzrbase=${${(M)${(f)"$( bzr info )"}:# ##branch\ root:*}/*: ##/}
1436         bzrinfo=( ${${${(M)${(f)"$( bzr version-info )"}:#(#s)(revno|branch-nick)*}/*: /}/*\//} )
1437         bzrbase="$(VCS_INFO_realpath ${bzrbase})"
1438     fi
1439
1440     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat bzrbr || bzrbr="%b:%r"
1441     zformat -f bzrbr "${bzrbr}" "b:${bzrinfo[2]}" "r:${bzrinfo[1]}"
1442     VCS_INFO_formats '' "${bzrbr}" "${bzrbase}"
1443     return 0
1444 }
1445 # }}}
1446 VCS_INFO_cdv_get_data () { # {{{
1447     local cdvbase
1448
1449     cdvbase=${vcs_comm[basedir]}
1450     VCS_INFO_formats '' "${cdvbase:t}" "${cdvbase}"
1451     return 0
1452 }
1453 # }}}
1454 VCS_INFO_cvs_get_data () { # {{{
1455     local cvsbranch cvsbase basename
1456
1457     cvsbase="."
1458     while [[ -d "${cvsbase}/../CVS" ]]; do
1459         cvsbase="${cvsbase}/.."
1460     done
1461     cvsbase="$(VCS_INFO_realpath ${cvsbase})"
1462     cvsbranch=$(< ./CVS/Repository)
1463     basename=${cvsbase:t}
1464     cvsbranch=${cvsbranch##${basename}/}
1465     [[ -z ${cvsbranch} ]] && cvsbranch=${basename}
1466     VCS_INFO_formats '' "${cvsbranch}" "${cvsbase}"
1467     return 0
1468 }
1469 # }}}
1470 VCS_INFO_darcs_get_data () { # {{{
1471     local darcsbase
1472
1473     darcsbase=${vcs_comm[basedir]}
1474     VCS_INFO_formats '' "${darcsbase:t}" "${darcsbase}"
1475     return 0
1476 }
1477 # }}}
1478 VCS_INFO_git_getaction () { #{{{
1479     local gitaction='' gitdir=$1
1480     local tmp
1481
1482     for tmp in "${gitdir}/rebase-apply" \
1483                "${gitdir}/rebase"       \
1484                "${gitdir}/../.dotest" ; do
1485         if [[ -d ${tmp} ]] ; then
1486             if   [[ -f "${tmp}/rebasing" ]] ; then
1487                 gitaction="rebase"
1488             elif [[ -f "${tmp}/applying" ]] ; then
1489                 gitaction="am"
1490             else
1491                 gitaction="am/rebase"
1492             fi
1493             printf '%s' ${gitaction}
1494             return 0
1495         fi
1496     done
1497
1498     for tmp in "${gitdir}/rebase-merge/interactive" \
1499                "${gitdir}/.dotest-merge/interactive" ; do
1500         if [[ -f "${tmp}" ]] ; then
1501             printf '%s' "rebase-i"
1502             return 0
1503         fi
1504     done
1505
1506     for tmp in "${gitdir}/rebase-merge" \
1507                "${gitdir}/.dotest-merge" ; do
1508         if [[ -d "${tmp}" ]] ; then
1509             printf '%s' "rebase-m"
1510             return 0
1511         fi
1512     done
1513
1514     if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1515         printf '%s' "merge"
1516         return 0
1517     fi
1518
1519     if [[ -f "${gitdir}/BISECT_LOG" ]] ; then
1520         printf '%s' "bisect"
1521         return 0
1522     fi
1523     return 1
1524 }
1525 # }}}
1526 VCS_INFO_git_getbranch () { #{{{
1527     local gitbranch gitdir=$1
1528     local gitsymref='git symbolic-ref HEAD'
1529
1530     if    [[ -d "${gitdir}/rebase-apply" ]] \
1531        || [[ -d "${gitdir}/rebase" ]]       \
1532        || [[ -d "${gitdir}/../.dotest" ]]   \
1533        || [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1534         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1535         [[ -z ${gitbranch} ]] && [[ -r ${gitdir}/rebase-apply/head-name ]] \
1536             && gitbranch="$(< ${gitdir}/rebase-apply/head-name)"
1537
1538     elif   [[ -f "${gitdir}/rebase-merge/interactive" ]] \
1539         || [[ -d "${gitdir}/rebase-merge" ]] ; then
1540         gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
1541
1542     elif   [[ -f "${gitdir}/.dotest-merge/interactive" ]] \
1543         || [[ -d "${gitdir}/.dotest-merge" ]] ; then
1544         gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
1545
1546     else
1547         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1548
1549         if [[ $? -ne 0 ]] ; then
1550             gitbranch="$(git describe --exact-match HEAD 2>/dev/null)"
1551
1552             if [[ $? -ne 0 ]] ; then
1553                 gitbranch="${${"$(< $gitdir/HEAD)"}[1,7]}..."
1554             fi
1555         fi
1556     fi
1557
1558     printf '%s' "${gitbranch##refs/heads/}"
1559     return 0
1560 }
1561 # }}}
1562 VCS_INFO_git_get_data () { # {{{
1563     setopt localoptions extendedglob
1564     local gitdir gitbase gitbranch gitaction
1565
1566     gitdir=${vcs_comm[gitdir]}
1567     gitbranch="$(VCS_INFO_git_getbranch ${gitdir})"
1568
1569     if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then
1570         return 1
1571     fi
1572
1573     VCS_INFO_adjust
1574     gitaction="$(VCS_INFO_git_getaction ${gitdir})"
1575     gitbase=${PWD%/${$( git rev-parse --show-prefix )%/##}}
1576     VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}"
1577     return 0
1578 }
1579 # }}}
1580 VCS_INFO_hg_get_data () { # {{{
1581     local hgbranch hgbase
1582
1583     hgbase=${vcs_comm[basedir]}
1584     hgbranch=$(< ${hgbase}/.hg/branch)
1585     VCS_INFO_formats '' "${hgbranch}" "${hgbase}"
1586     return 0
1587 }
1588 # }}}
1589 VCS_INFO_mtn_get_data () { # {{{
1590     local mtnbranch mtnbase
1591
1592     mtnbase=${vcs_comm[basedir]}
1593     mtnbranch=${${(M)${(f)"$( mtn status )"}:#(#s)Current branch:*}/*: /}
1594     VCS_INFO_formats '' "${mtnbranch}" "${mtnbase}"
1595     return 0
1596 }
1597 # }}}
1598 VCS_INFO_svk_get_data () { # {{{
1599     local svkbranch svkbase
1600
1601     svkbase=${vcs_comm[basedir]}
1602     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svkbranch || svkbranch="%b:%r"
1603     zformat -f svkbranch "${svkbranch}" "b:${vcs_comm[branch]}" "r:${vcs_comm[revision]}"
1604     VCS_INFO_formats '' "${svkbranch}" "${svkbase}"
1605     return 0
1606 }
1607 # }}}
1608 VCS_INFO_svn_get_data () { # {{{
1609     setopt localoptions noksharrays
1610     local svnbase svnbranch
1611     local -a svninfo
1612
1613     svnbase="."
1614     while [[ -d "${svnbase}/../.svn" ]]; do
1615         svnbase="${svnbase}/.."
1616     done
1617     svnbase="$(VCS_INFO_realpath ${svnbase})"
1618     svninfo=( ${${${(M)${(f)"$( svn info )"}:#(#s)(URL|Revision)*}/*: /}/*\//} )
1619
1620     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svnbranch || svnbranch="%b:%r"
1621     zformat -f svnbranch "${svnbranch}" "b:${svninfo[1]}" "r:${svninfo[2]}"
1622     VCS_INFO_formats '' "${svnbranch}" "${svnbase}"
1623     return 0
1624 }
1625 # }}}
1626 VCS_INFO_tla_get_data () { # {{{
1627     local tlabase tlabranch
1628
1629     tlabase="$(VCS_INFO_realpath ${vcs_comm[basedir]})"
1630     # tree-id gives us something like 'foo@example.com/demo--1.0--patch-4', so:
1631     tlabranch=${${"$( tla tree-id )"}/*\//}
1632     VCS_INFO_formats '' "${tlabranch}" "${tlabase}"
1633     return 0
1634 }
1635 # }}}
1636 # detection
1637 VCS_INFO_detect_by_dir() { #{{{
1638     local dirname=$1
1639     local basedir="." realbasedir
1640
1641     realbasedir="$(VCS_INFO_realpath ${basedir})"
1642     while [[ ${realbasedir} != '/' ]]; do
1643         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
1644             [[ -d ${basedir}/${dirname} ]] && \
1645             [[ -f ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
1646                 break
1647         else
1648             [[ -d ${basedir}/${dirname} ]] && break
1649         fi
1650
1651         basedir=${basedir}/..
1652         realbasedir="$(VCS_INFO_realpath ${basedir})"
1653     done
1654
1655     [[ ${realbasedir} == "/" ]] && return 1
1656     vcs_comm[basedir]=${realbasedir}
1657     return 0
1658 }
1659 # }}}
1660 VCS_INFO_bzr_detect() { #{{{
1661     VCS_INFO_check_com bzr || return 1
1662     vcs_comm[detect_need_file]=branch/format
1663     VCS_INFO_detect_by_dir '.bzr'
1664     return $?
1665 }
1666 # }}}
1667 VCS_INFO_cdv_detect() { #{{{
1668     VCS_INFO_check_com cdv || return 1
1669     vcs_comm[detect_need_file]=format
1670     VCS_INFO_detect_by_dir '.cdv'
1671     return $?
1672 }
1673 # }}}
1674 VCS_INFO_cvs_detect() { #{{{
1675     VCS_INFO_check_com svn || return 1
1676     [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
1677     return 1
1678 }
1679 # }}}
1680 VCS_INFO_darcs_detect() { #{{{
1681     VCS_INFO_check_com darcs || return 1
1682     vcs_comm[detect_need_file]=format
1683     VCS_INFO_detect_by_dir '_darcs'
1684     return $?
1685 }
1686 # }}}
1687 VCS_INFO_git_detect() { #{{{
1688     if VCS_INFO_check_com git && git rev-parse --is-inside-work-tree &> /dev/null ; then
1689         vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
1690         if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
1691         elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
1692         return 0
1693     fi
1694     return 1
1695 }
1696 # }}}
1697 VCS_INFO_hg_detect() { #{{{
1698     VCS_INFO_check_com hg || return 1
1699     vcs_comm[detect_need_file]=branch
1700     VCS_INFO_detect_by_dir '.hg'
1701     return $?
1702 }
1703 # }}}
1704 VCS_INFO_mtn_detect() { #{{{
1705     VCS_INFO_check_com mtn || return 1
1706     vcs_comm[detect_need_file]=revision
1707     VCS_INFO_detect_by_dir '_MTN'
1708     return $?
1709 }
1710 # }}}
1711 VCS_INFO_svk_detect() { #{{{
1712     setopt localoptions noksharrays extendedglob
1713     local -a info
1714     local -i fhash
1715     fhash=0
1716
1717     VCS_INFO_check_com svk || return 1
1718     [[ -f ~/.svk/config ]] || return 1
1719
1720     # This detection function is a bit different from the others.
1721     # We need to read svk's config file to detect a svk repository
1722     # in the first place. Therefore, we'll just proceed and read
1723     # the other information, too. This is more then any of the
1724     # other detections do but this takes only one file open for
1725     # svk at most. VCS_INFO_svk_get_data() get simpler, too. :-)
1726     while IFS= read -r line ; do
1727         if [[ -n ${vcs_comm[basedir]} ]] ; then
1728             line=${line## ##}
1729             [[ ${line} == depotpath:* ]] && vcs_comm[branch]=${line##*/}
1730             [[ ${line} == revision:* ]] && vcs_comm[revision]=${line##*[[:space:]]##}
1731             [[ -n ${vcs_comm[branch]} ]] && [[ -n ${vcs_comm[revision]} ]] && break
1732             continue
1733         fi
1734         (( fhash > 0 )) && [[ ${line} == '  '[^[:space:]]*:* ]] && break
1735         [[ ${line} == '  hash:'* ]] && fhash=1 && continue
1736         (( fhash == 0 )) && continue
1737         [[ ${PWD}/ == ${${line## ##}%:*}/* ]] && vcs_comm[basedir]=${${line## ##}%:*}
1738     done < ~/.svk/config
1739
1740     [[ -n ${vcs_comm[basedir]} ]]  && \
1741     [[ -n ${vcs_comm[branch]} ]]   && \
1742     [[ -n ${vcs_comm[revision]} ]] && return 0
1743     return 1
1744 }
1745 # }}}
1746 VCS_INFO_svn_detect() { #{{{
1747     VCS_INFO_check_com svn || return 1
1748     [[ -d ".svn" ]] && return 0
1749     return 1
1750 }
1751 # }}}
1752 VCS_INFO_tla_detect() { #{{{
1753     VCS_INFO_check_com tla || return 1
1754     vcs_comm[basedir]="$(tla tree-root 2> /dev/null)" && return 0
1755     return 1
1756 }
1757 # }}}
1758 # public API
1759 vcs_info_printsys () { # {{{
1760     vcs_info print_systems_
1761 }
1762 # }}}
1763 vcs_info_lastmsg () { # {{{
1764     local -i i
1765
1766     VCS_INFO_maxexports
1767     for i in {0..$((maxexports - 1))} ; do
1768         printf '$VCS_INFO_message_%d_: "' $i
1769         if zstyle -T ':vcs_info:formats:command' use-prompt-escapes ; then
1770             print -nP ${(P)${:-VCS_INFO_message_${i}_}}
1771         else
1772             print -n ${(P)${:-VCS_INFO_message_${i}_}}
1773         fi
1774         printf '"\n'
1775     done
1776 }
1777 # }}}
1778 vcs_info () { # {{{
1779     local -i found
1780     local -a VCSs disabled
1781     local -x vcs usercontext
1782     local -ax msgs
1783     local -Ax vcs_comm
1784
1785     vcs="init"
1786     VCSs=(git hg bzr darcs svk mtn svn cvs cdv tla)
1787     case $1 in
1788         (print_systems_)
1789             zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1790             print -l '# list of supported version control backends:' \
1791                      '# disabled systems are prefixed by a hash sign (#)'
1792             for vcs in ${VCSs} ; do
1793                 [[ -n ${(M)disabled:#${vcs}} ]] && printf '#'
1794                 printf '%s\n' ${vcs}
1795             done
1796             print -l '# flavours (cannot be used in the disable style; they' \
1797                      '# are disabled with their master [git-svn -> git]):'   \
1798                      git-{p4,svn}
1799             return 0
1800             ;;
1801         ('')
1802             [[ -z ${usercontext} ]] && usercontext=default
1803             ;;
1804         (*) [[ -z ${usercontext} ]] && usercontext=$1
1805             ;;
1806     esac
1807
1808     zstyle -T ":vcs_info:${vcs}:${usercontext}" "enable" || {
1809         [[ -n ${VCS_INFO_message_0_} ]] && VCS_INFO_set --clear
1810         return 0
1811     }
1812     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1813     VCS_INFO_maxexports
1814
1815     (( found = 0 ))
1816     for vcs in ${VCSs} ; do
1817         [[ -n ${(M)disabled:#${vcs}} ]] && continue
1818         vcs_comm=()
1819         VCS_INFO_${vcs}_detect && (( found = 1 )) && break
1820     done
1821
1822     (( found == 0 )) && {
1823         VCS_INFO_set --nvcs
1824         return 0
1825     }
1826
1827     VCS_INFO_${vcs}_get_data || {
1828         VCS_INFO_set --nvcs
1829         return 1
1830     }
1831
1832     VCS_INFO_set
1833     return 0
1834 }
1835
1836 VCS_INFO_set --nvcs preinit
1837 # }}}
1838
1839 # change vcs_info formats for the grml prompt
1840 if [[ "$TERM" == dumb ]] ; then
1841     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] "
1842     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "
1843 else
1844     # these are the same, just with a lot of colours:
1845     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} "
1846     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} "
1847     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1848 fi
1849
1850 # }}}
1851
1852 # {{{ set prompt
1853 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1854     promptinit # people should be able to use their favourite prompt
1855 else
1856     print 'Notice: no promptinit available :('
1857 fi
1858
1859 setopt prompt_subst
1860
1861 # make sure to use right prompt only when not running a command
1862 is41 && setopt transient_rprompt
1863
1864 is4 && [[ -z $NOPRECMD ]] && precmd () {
1865     [[ -n $NOPRECMD ]] && return 0
1866     # update VCS information
1867     vcs_info
1868
1869     # allow manual overwriting of RPROMPT
1870     if [[ -n $RPROMPT ]] ; then
1871         [[ $TERM == screen* ]] && print -nP "\ekzsh\e\\"
1872         # return 0
1873     fi
1874     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1875     if [[ -z $DONTSETRPROMPT ]] ; then
1876         if [[ -n $BATTERY ]] ; then
1877             RPROMPT="%(?..:()% ${PERCENT}${SCREENTITLE}"
1878             # RPROMPT="${PERCENT}${SCREENTITLE}"
1879         else
1880             RPROMPT="%(?..:()% ${SCREENTITLE}"
1881             # RPROMPT="${SCREENTITLE}"
1882         fi
1883     fi
1884     # adjust title of xterm
1885     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1886     case $TERM in
1887         (xterm*|rxvt)
1888             print -Pn "\e]0;%n@%m: %~\a"
1889             ;;
1890     esac
1891 }
1892
1893 # preexec() => a function running before every command
1894 is4 && [[ -z $NOPRECMD ]] && \
1895 preexec () {
1896     [[ -n $NOPRECMD ]] && return 0
1897 # set hostname if not running on host with name 'grml'
1898     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1899        NAME="@$HOSTNAME"
1900     fi
1901 # get the name of the program currently running and hostname of local machine
1902 # set screen window title if running in a screen
1903     if [[ "$TERM" == screen* ]] ; then
1904         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1905         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1906         echo -ne "\ek$CMD\e\\"
1907     fi
1908 # set the screen title to "zsh" when sitting at the command prompt:
1909     if [[ "$TERM" == screen* ]] ; then
1910         SCREENTITLE=$'%{\ekzsh\e\\%}'
1911     else
1912         SCREENTITLE=''
1913     fi
1914 # adjust title of xterm
1915     case $TERM in
1916         (xterm*|rxvt)
1917             print -Pn "\e]0;%n@%m: $1\a"
1918             ;;
1919     esac
1920 }
1921
1922 EXITCODE="%(?..%?%1v )"
1923 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
1924 PS3='?# '         # selection prompt used within a select loop.
1925 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1926
1927 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1928 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1929     debian_chroot=$(cat /etc/debian_chroot)
1930 fi
1931
1932 # don't use colors on dumb terminals (like emacs):
1933 if [[ "$TERM" == dumb ]] ; then
1934     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1935 else
1936     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
1937     # set variable identifying the chroot you work in (used in the prompt below)
1938     if [[ -n $GRMLPROMPT ]] ; then
1939         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1940 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< %# "
1941     else
1942         # This assembles the primary prompt string
1943         if (( EUID != 0 )); then
1944             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1945         else
1946             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1947         fi
1948     fi
1949 fi
1950
1951 # if we are inside a grml-chroot set a specific prompt theme
1952 if [[ -n "$GRML_CHROOT" ]] ; then
1953     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1954 fi
1955 # }}}
1956
1957 # {{{ 'hash' some often used directories
1958 #d# start
1959 hash -d deb=/var/cache/apt/archives
1960 hash -d doc=/usr/share/doc
1961 hash -d linux=/lib/modules/$(command uname -r)/build/
1962 hash -d log=/var/log
1963 hash -d slog=/var/log/syslog
1964 hash -d src=/usr/src
1965 hash -d templ=/usr/share/doc/grml-templates
1966 hash -d tt=/usr/share/doc/texttools-doc
1967 hash -d www=/var/www
1968 #d# end
1969 # }}}
1970
1971 # {{{ some aliases
1972 if [[ $UID -eq 0 ]] ; then
1973     [[ -r /etc/grml/screenrc ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc'
1974 elif [[ -r $HOME/.screenrc ]] ; then
1975     alias screen="/usr/bin/screen -c $HOME/.screenrc"
1976 else
1977     [[ -r /etc/grml/screenrc_grml ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc_grml'
1978 fi
1979
1980 # do we have GNU ls with color-support?
1981 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
1982     #a1# execute \kbd{@a@}:\quad ls with colors
1983     alias ls='ls -b -CF --color=auto'
1984     #a1# execute \kbd{@a@}:\quad list all files, with colors
1985     alias la='ls -la --color=auto'
1986     #a1# long colored list, without dotfiles (@a@)
1987     alias ll='ls -l --color=auto'
1988     #a1# long colored list, human readable sizes (@a@)
1989     alias lh='ls -hAl --color=auto'
1990     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
1991     alias l='ls -lF --color=auto'
1992 else
1993     alias ls='ls -b -CF'
1994     alias la='ls -la'
1995     alias ll='ls -l'
1996     alias lh='ls -hAl'
1997     alias l='ls -lF'
1998 fi
1999
2000 alias mdstat='cat /proc/mdstat'
2001 alias ...='cd ../../'
2002
2003 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2004 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2005     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2006 fi
2007
2008 alias cp='nocorrect cp'         # no spelling correction on cp
2009 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
2010 alias mv='nocorrect mv'         # no spelling correction on mv
2011 alias rm='nocorrect rm'         # no spelling correction on rm
2012
2013 #a1# Execute \kbd{rmdir}
2014 alias rd='rmdir'
2015 #a1# Execute \kbd{rmdir}
2016 alias md='mkdir'
2017
2018 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2019 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2020 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2021
2022 # make sure it is not assigned yet
2023 [[ $(whence -w utf2iso &>/dev/null) == 'utf2iso: alias' ]] && unalias utf2iso
2024
2025 utf2iso() {
2026     if isutfenv ; then
2027         for ENV in $(env | command grep -i '.utf') ; do
2028             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2029         done
2030     fi
2031 }
2032
2033 # make sure it is not assigned yet
2034 [[ $(whence -w iso2utf &>/dev/null) == 'iso2utf: alias' ]] && unalias iso2utf
2035 iso2utf() {
2036     if ! isutfenv ; then
2037         for ENV in $(env | command grep -i '\.iso') ; do
2038             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2039         done
2040     fi
2041 }
2042
2043 # set up software synthesizer via speakup
2044 swspeak() {
2045     aumix -w 90 -v 90 -p 90 -m 90
2046     if ! [[ -r /dev/softsynth ]] ; then
2047         flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
2048         return 1
2049     else
2050         setopt singlelinezle
2051         unsetopt prompt_cr
2052         export PS1="%m%# "
2053         nice -n -20 speechd-up
2054         sleep 2
2055         flite -o play -t "Finished setting up software synthesizer"
2056     fi
2057 }
2058
2059 # I like clean prompt, so provide simple way to get that
2060 check_com 0 || alias 0='return 0'
2061
2062 # for really lazy people like mika:
2063 check_com S &>/dev/null || alias S='screen'
2064 check_com s &>/dev/null || alias s='ssh'
2065
2066 # get top 10 shell commands:
2067 alias top10='print -l ? ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
2068
2069 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
2070 if check_com -c truecrypt ; then
2071     if isutfenv ; then
2072         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
2073     else
2074         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
2075     fi
2076 fi
2077
2078 #f1# Hints for the use of zsh on grml
2079 zsh-help() {
2080     print "$bg[white]$fg[black]
2081 zsh-help - hints for use of zsh on grml
2082 =======================================$reset_color"
2083
2084     print '
2085 Main configuration of zsh happens in /etc/zsh/zshrc (global)
2086 and /etc/skel/.zshrc which is copied to $HOME/.zshrc once.
2087 The files are part of the package grml-etc-core, if you want to
2088 use them on a non-grml-system just get the tar.gz from
2089 http://deb.grml.org/ or get the files from the mercurial
2090 repository:
2091
2092   http://hg.grml.org/grml-etc-core/raw-file/tip/etc/skel/.zshrc
2093   http://hg.grml.org/grml-etc-core/raw-file/tip/etc/zsh/zshrc
2094
2095 If you want to stay in sync with zsh configuration of grml
2096 run '\''ln -sf /etc/skel/.zshrc $HOME/.zshrc'\'' and configure
2097 your own stuff in $HOME/.zshrc.local. System wide configuration
2098 without touching configuration files of grml can take place
2099 in /etc/zsh/zshrc.local.
2100
2101 If you want to use the configuration of user grml also when
2102 running as user root just run '\''zshskel'\'' which will source
2103 the file /etc/skel/.zshrc.
2104
2105 For information regarding zsh start at http://grml.org/zsh/
2106
2107 Take a look at grml'\''s zsh refcard:
2108 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2109
2110 Check out the main zsh refcard:
2111 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2112
2113 And of course visit the zsh-lovers:
2114 % man zsh-lovers
2115
2116 You can adjust some options through environment variables when
2117 invoking zsh without having to edit configuration files.
2118 Basically meant for bash users who are not used to the power of
2119 the zsh yet. :)
2120
2121   "NOCOR=1    zsh" => deactivate automatic correction
2122   "NOMENU=1   zsh" => do not use menu completion (note: use strg-d for completion instead!)
2123   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2124   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt'
2125
2126     print "
2127 $bg[white]$fg[black]
2128 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2129 Enjoy your grml system with the zsh!$reset_color"
2130 }
2131
2132 # debian stuff
2133 if [[ -r /etc/debian_version ]] ; then
2134     #a3# Execute \kbd{apt-cache search}
2135     alias acs='apt-cache search'
2136     #a3# Execute \kbd{apt-cache show}
2137     alias acsh='apt-cache show'
2138     #a3# Execute \kbd{apt-cache policy}
2139     alias acp='apt-cache policy'
2140     #a3# Execute \kbd{apt-get dist-upgrade}
2141     salias adg="apt-get dist-upgrade"
2142     #a3# Execute \kbd{apt-get install}
2143     salias agi="apt-get install"
2144     #a3# Execute \kbd{aptitude install}
2145     salias ati="aptitude install"
2146     #a3# Execute \kbd{apt-get upgrade}
2147     salias ag="apt-get upgrade"
2148     #a3# Execute \kbd{apt-get update}
2149     salias au="apt-get update"
2150     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2151     salias -a up="aptitude update ; aptitude safe-upgrade"
2152     #a3# Execute \kbd{dpkg-buildpackage}
2153     alias dbp='dpkg-buildpackage'
2154     #a3# Execute \kbd{grep-excuses}
2155     alias ge='grep-excuses'
2156
2157     # debian upgrade
2158     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
2159     upgrade() {
2160         if [[ -z "$1" ]] ; then
2161             $SUDO apt-get update
2162             $SUDO apt-get -u upgrade
2163         else
2164             ssh $1 $SUDO apt-get update
2165             # ask before the upgrade
2166             local dummy
2167             ssh $1 $SUDO apt-get --no-act upgrade
2168             echo -n 'Process the upgrade?'
2169             read -q dummy
2170             if [[ $dummy == "y" ]] ; then
2171                 ssh $1 $SUDO apt-get -u upgrade --yes
2172             fi
2173         fi
2174     }
2175
2176     # get a root shell as normal user in live-cd mode:
2177     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2178        alias su="sudo su"
2179      fi
2180
2181     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2182     alias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2183     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2184     alias tlog="tail -f /var/log/syslog"    # follow the syslog
2185     #a1# (Re)-source \kbd{/etc/skel/.zshrc}
2186     alias zshskel="source /etc/skel/.zshrc" # source skeleton zshrc
2187 fi
2188
2189 # sort installed Debian-packages by size
2190 if check_com -c grep-status ; then
2191     #a3# List installed Debian-packages sorted by size
2192     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
2193 fi
2194
2195 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2196 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord ; then
2197     if check_com -c wodim ; then
2198         alias cdrecord="echo 'cdrecord is not provided under its original name by Debian anymore.
2199 See #377109 in the BTS of Debian for more details.
2200
2201 Please use the wodim binary instead' ; return 1"
2202     fi
2203 fi
2204
2205 # get_tw_cli has been renamed into get_3ware
2206 if check_com -c get_3ware ; then
2207     get_tw_cli() {
2208         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
2209         get_3ware
2210     }
2211 fi
2212
2213 # I hate lacking backward compatibility, so provide an alternative therefore
2214 if ! check_com -c apache2-ssl-certificate ; then
2215
2216     apache2-ssl-certificate() {
2217
2218     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
2219     print 'You might want to take a look at Debian the package ssl-cert as well.'
2220     print 'To generate a certificate for use with apache2 follow the instructions:'
2221
2222     echo '
2223
2224 export RANDFILE=/dev/random
2225 mkdir /etc/apache2/ssl/
2226 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
2227 chmod 600 /etc/apache2/ssl/apache.pem
2228
2229 Run "grml-tips ssl-certificate" if you need further instructions.
2230 '
2231     }
2232 fi
2233 # }}}
2234
2235 # {{{ Use hard limits, except for a smaller stack and no core dumps
2236 unlimit
2237 is425 && limit stack 8192
2238 isgrmlcd && limit core 0 # important for a live-cd-system
2239 limit -s
2240 # }}}
2241
2242 # {{{ completion system
2243
2244 # called later (via is4 && grmlcomp)
2245 # notice: use 'zstyle' for getting current settings
2246 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
2247 grmlcomp() {
2248     # TODO: This could use some additional information
2249
2250     # allow one error for every three characters typed in approximate completer
2251     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
2252
2253     # don't complete backup files as executables
2254     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
2255
2256     # start menu completion only if it could find no unambiguous initial string
2257     zstyle ':completion:*:correct:*'       insert-unambiguous true
2258     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
2259     zstyle ':completion:*:correct:*'       original true
2260
2261     # activate color-completion
2262     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
2263
2264     # format on completion
2265     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
2266
2267     # complete 'cd -<tab>' with menu
2268     zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
2269
2270     # insert all expansions for expand completer
2271     zstyle ':completion:*:expand:*'        tag-order all-expansions
2272     zstyle ':completion:*:history-words'   list false
2273
2274     # activate menu
2275     zstyle ':completion:*:history-words'   menu yes
2276
2277     # ignore duplicate entries
2278     zstyle ':completion:*:history-words'   remove-all-dups yes
2279     zstyle ':completion:*:history-words'   stop yes
2280
2281     # match uppercase from lowercase
2282     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
2283
2284     # separate matches into groups
2285     zstyle ':completion:*:matches'         group 'yes'
2286     zstyle ':completion:*'                 group-name ''
2287
2288     if [[ -z "$NOMENU" ]] ; then
2289         # if there are more than 5 options allow selecting from a menu
2290         zstyle ':completion:*'               menu select=5
2291     else
2292         # don't use any menus at all
2293         setopt no_auto_menu
2294     fi
2295
2296     zstyle ':completion:*:messages'        format '%d'
2297     zstyle ':completion:*:options'         auto-description '%d'
2298
2299     # describe options in full
2300     zstyle ':completion:*:options'         description 'yes'
2301
2302     # on processes completion complete all user processes
2303     zstyle ':completion:*:processes'       command 'ps -au$USER'
2304
2305     # offer indexes before parameters in subscripts
2306     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
2307
2308     # provide verbose completion information
2309     zstyle ':completion:*'                 verbose true
2310
2311     # recent (as of Dec 2007) zsh versions are able to provide descriptions
2312     # for commands (read: 1st word in the line) that it will list for the user
2313     # to choose from. The following disables that, because it's not exactly fast.
2314     zstyle ':completion:*:-command-:*:'    verbose false
2315
2316     # set format for warnings
2317     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
2318
2319     # define files to ignore for zcompile
2320     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
2321     zstyle ':completion:correct:'          prompt 'correct to: %e'
2322
2323     # Ignore completion functions for commands you don't have:
2324     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
2325
2326     # Provide more processes in completion of programs like killall:
2327     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
2328
2329     # complete manual by their section
2330     zstyle ':completion:*:manuals'    separate-sections true
2331     zstyle ':completion:*:manuals.*'  insert-sections   true
2332     zstyle ':completion:*:man:*'      menu yes select
2333
2334     # run rehash on completion so new installed program are found automatically:
2335     _force_rehash() {
2336         (( CURRENT == 1 )) && rehash
2337         return 1
2338     }
2339
2340     ## correction
2341     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
2342     if [[ -n "$NOCOR" ]] ; then
2343         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
2344         setopt nocorrect
2345     else
2346         # try to be smart about when to use what completer...
2347         setopt correct
2348         zstyle -e ':completion:*' completer '
2349             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
2350                 _last_try="$HISTNO$BUFFER$CURSOR"
2351                 reply=(_complete _match _ignored _prefix _files)
2352             else
2353                 if [[ $words[1] == (rm|mv) ]] ; then
2354                     reply=(_complete _files)
2355                 else
2356                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
2357                 fi
2358             fi'
2359     fi
2360
2361     # zstyle ':completion:*' completer _complete _correct _approximate
2362     # zstyle ':completion:*' expand prefix suffix
2363
2364     # complete shell aliases
2365     # zstyle ':completion:*' completer _expand_alias _complete _approximate
2366
2367     # command for process lists, the local web server details and host completion
2368     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
2369
2370     # caching
2371     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
2372                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
2373
2374     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
2375     if is42 ; then
2376         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
2377         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
2378     else
2379         _ssh_hosts=()
2380         _etc_hosts=()
2381     fi
2382     hosts=(
2383         $(hostname)
2384         "$_ssh_hosts[@]"
2385         "$_etc_hosts[@]"
2386         grml.org
2387         localhost
2388     )
2389     zstyle ':completion:*:hosts' hosts $hosts
2390     #  zstyle '*' hosts $hosts
2391
2392     # specify your logins:
2393     # my_accounts=(
2394     #  {grml,grml1}@foo.invalid
2395     #  grml-devel@bar.invalid
2396     # )
2397     # other_accounts=(
2398     #  {fred,root}@foo.invalid
2399     #  vera@bar.invalid
2400     # )
2401     # zstyle ':completion:*:my-accounts' users-hosts $my_accounts
2402     # zstyle ':completion:*:other-accounts' users-hosts $other_accounts
2403
2404     # specify specific port/service settings:
2405     #  telnet_users_hosts_ports=(
2406     #    user1@host1:
2407     #    user2@host2:
2408     #    @mail-server:{smtp,pop3}
2409     #    @news-server:nntp
2410     #    @proxy-server:8000
2411     #  )
2412     # zstyle ':completion:*:*:telnet:*' users-hosts-ports $telnet_users_hosts_ports
2413
2414     # use generic completion system for programs not yet defined; (_gnu_generic works
2415     # with commands that provide a --help option with "standard" gnu-like output.)
2416     compdef _gnu_generic tail head feh cp mv df stow uname ipacsum fetchipac
2417
2418     # see upgrade function in this file
2419     compdef _hosts upgrade
2420 }
2421 # }}}
2422
2423 # {{{ grmlstuff
2424 grmlstuff() {
2425 # people should use 'grml-x'!
2426     startx() {
2427         if [[ -e /etc/X11/xorg.conf ]] ; then
2428             [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
2429         else
2430             echo "Please use the script \"grml-x\" for starting the X Window System
2431 because there does not exist /etc/X11/xorg.conf yet.
2432 If you want to use startx anyway please call \"/usr/bin/startx\"."
2433             return -1
2434         fi
2435     }
2436
2437     xinit() {
2438         if [[ -e /etc/X11/xorg.conf ]] ; then
2439             [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
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 xinit anyway please call \"/usr/bin/xinit\"."
2444             return -1
2445         fi
2446     }
2447
2448     if check_com -c 915resolution ; then
2449         alias 855resolution='echo -e "Please use 915resolution as resolution modify tool for Intel graphic chipset."; return -1'
2450     fi
2451
2452     #a1# Output version of running grml
2453     alias grml-version='cat /etc/grml_version'
2454
2455     if check_com -c rebuildfstab ; then
2456         #a1# Rebuild /etc/fstab
2457         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2458     fi
2459
2460     if check_com -c grml-debootstrap ; then
2461         alias debian2hd='print "Installing debian to harddisk is possible via using grml-debootstrap." ; return 1'
2462     fi
2463 }
2464 # }}}
2465
2466 # {{{ now run the functions
2467 isgrml && checkhome
2468 is4    && isgrml    && grmlstuff
2469 is4    && grmlcomp
2470 # }}}
2471
2472 # {{{ keephack
2473 is4 && xsource "/etc/zsh/keephack"
2474 # }}}
2475
2476 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2477 # You use it as follows:
2478 # $ NTREF=/reference/file
2479 # $ ls -l *(e:nt:)
2480 # This lists all the files in the current directory newer than the reference file.
2481 # You can also specify the reference file inline; note quotes:
2482 # $ ls -l *(e:'nt ~/.zshenv':)
2483 is4 && nt() {
2484     if [[ -n $1 ]] ; then
2485         local NTREF=${~1}
2486     fi
2487     [[ $REPLY -nt $NTREF ]]
2488 }
2489 # }}}
2490
2491 # shell functions {{{
2492
2493 #f1# Provide csh compatibility
2494 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2495
2496 #f1# Reload an autoloadable function
2497 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2498
2499 #f1# Reload zsh setup
2500 reload() {
2501     if [[ "$#*" -eq 0 ]] ; then
2502         [[ -r ~/.zshrc ]] && . ~/.zshrc
2503     else
2504         local fn
2505         for fn in "$@"; do
2506             unfunction $fn
2507             autoload -U $fn
2508         done
2509     fi
2510 }
2511 compdef _functions reload freload
2512
2513 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2514 sll() {
2515     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2516     for i in "$@" ; do
2517         file=$i
2518         while [[ -h "$file" ]] ; do
2519             ls -l $file
2520             file=$(readlink "$file")
2521         done
2522     done
2523 }
2524
2525 # fast manual access
2526 if check_com qma ; then
2527     #f1# View the zsh manual
2528     manzsh()  { qma zshall "$1" }
2529     compdef _man qma
2530 else
2531     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2532     # manzsh()  { /usr/bin/man zshall |  most +/"$1" ; }
2533     # [[ -f ~/.terminfo/m/mostlike ]] && MYLESS='LESS=C TERMINFO=~/.terminfo TERM=mostlike less' || MYLESS='less'
2534     # manzsh()  { man zshall | $MYLESS -p $1 ; }
2535 fi
2536
2537 if check_com -c $PAGER ; then
2538     #f1# View Debian's changelog of a given package
2539     dchange() {
2540         if [[ -r /usr/share/doc/${1}/changelog.Debian.gz ]] ; then
2541             $PAGER /usr/share/doc/${1}/changelog.Debian.gz
2542         elif [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2543             $PAGER /usr/share/doc/${1}/changelog.gz
2544         else
2545             if check_com -c aptitude ; then
2546                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2547                 if isgrml ; then
2548                     aptitude -t unstable changelog ${1}
2549                 else
2550                     aptitude changelog ${1}
2551                 fi
2552             else
2553                 echo "No changelog for package $1 found, sorry."
2554                 return 1
2555             fi
2556         fi
2557     }
2558     _dchange() { _files -W /usr/share/doc -/ }
2559     compdef _dchange dchange
2560
2561     #f1# View Debian's NEWS of a given package
2562     dnews() {
2563         if [[ -r /usr/share/doc/${1}/NEWS.Debian.gz ]] ; then
2564             $PAGER /usr/share/doc/${1}/NEWS.Debian.gz
2565         else
2566             if [[ -r /usr/share/doc/${1}/NEWS.gz ]] ; then
2567                 $PAGER /usr/share/doc/${1}/NEWS.gz
2568             else
2569                 echo "No NEWS file for package $1 found, sorry."
2570                 return 1
2571             fi
2572         fi
2573     }
2574     _dnews() { _files -W /usr/share/doc -/ }
2575     compdef _dnews dnews
2576
2577     #f1# View upstream's changelog of a given package
2578     uchange() {
2579         if [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2580             $PAGER /usr/share/doc/${1}/changelog.gz
2581         else
2582             echo "No changelog for package $1 found, sorry."
2583             return 1
2584         fi
2585     }
2586     _uchange() { _files -W /usr/share/doc -/ }
2587     compdef _uchange uchange
2588 fi
2589
2590 # zsh profiling
2591 profile() {
2592     ZSH_PROFILE_RC=1 $SHELL "$@"
2593 }
2594
2595 #f1# Edit an alias via zle
2596 edalias() {
2597     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2598 }
2599 compdef _aliases edalias
2600
2601 #f1# Edit a function via zle
2602 edfunc() {
2603     [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
2604 }
2605 compdef _functions edfunc
2606
2607 # use it e.g. via 'Restart apache2'
2608 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2609 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2610 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2611 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2612 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2613 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2614     __start_stop() {
2615         local action_="${1:l}"  # e.g Start/Stop/Restart
2616         local service_="$2"
2617         local param_="$3"
2618
2619         local service_target_="$(readlink /etc/init.d/$service_)"
2620         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2621             # runit
2622             case "${action_}" in
2623                 start) if [[ ! -e /etc/service/$service_ ]]; then
2624                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2625                        else
2626                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2627                        fi ;;
2628                 # there is no reload in runits sysv emulation
2629                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2630                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2631             esac
2632         else
2633             # sysvinit
2634             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2635         fi
2636     }
2637
2638     for i in Start Restart Stop Force-Reload Reload ; do
2639         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2640     done
2641 fi
2642
2643 #f1# Provides useful information on globbing
2644 H-Glob() {
2645     echo -e "
2646     /      directories
2647     .      plain files
2648     @      symbolic links
2649     =      sockets
2650     p      named pipes (FIFOs)
2651     *      executable plain files (0100)
2652     %      device files (character or block special)
2653     %b     block special files
2654     %c     character special files
2655     r      owner-readable files (0400)
2656     w      owner-writable files (0200)
2657     x      owner-executable files (0100)
2658     A      group-readable files (0040)
2659     I      group-writable files (0020)
2660     E      group-executable files (0010)
2661     R      world-readable files (0004)
2662     W      world-writable files (0002)
2663     X      world-executable files (0001)
2664     s      setuid files (04000)
2665     S      setgid files (02000)
2666     t      files with the sticky bit (01000)
2667
2668   print *(m-1)          # Files modified up to a day ago
2669   print *(a1)           # Files accessed a day ago
2670   print *(@)            # Just symlinks
2671   print *(Lk+50)        # Files bigger than 50 kilobytes
2672   print *(Lk-50)        # Files smaller than 50 kilobytes
2673   print **/*.c          # All *.c files recursively starting in \$PWD
2674   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2675   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2676   print *~*.*           # All Files that do not contain a dot
2677   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2678   print -l *(.c|.h)     # Lists *.c and *.h
2679   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2680   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2681 }
2682 alias help-zshglob=H-Glob
2683
2684 check_com -c qma && alias ?='qma zshall'
2685
2686 # grep for running process, like: 'any vim'
2687 any() {
2688     if [[ -z "$1" ]] ; then
2689         echo "any - grep for process(es) by keyword" >&2
2690         echo "Usage: any <keyword>" >&2 ; return 1
2691     else
2692         local STRING=$1
2693         local LENGTH=$(expr length $STRING)
2694         local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
2695         local REST=$(echo $(expr substr $STRING 2 $LENGTH))
2696         ps xauwww| grep "[$FIRSCHAR]$REST"
2697     fi
2698 }
2699
2700 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2701 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2702 [[ -r /proc/1/maps ]] && \
2703 deswap() {
2704     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2705     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2706     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2707 }
2708
2709 # print hex value of a number
2710 hex() {
2711     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2712 }
2713
2714 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2715 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2716 peval() {
2717     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2718     perl -e "print eval($CALC),\"\n\";"
2719 }
2720 functions peval &>/dev/null && alias calc=peval
2721
2722 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2723 # certain circumstances, so work around it, no matter which environment we have
2724 brltty() {
2725     if [[ -z "$DISPLAY" ]] ; then
2726         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2727         command brltty "$@"
2728     else
2729         command brltty "$@"
2730     fi
2731 }
2732
2733 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2734 aoeu() {
2735     echo -n 'Switching to us keyboard layout: '
2736     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2737     echo 'Done'
2738 }
2739 asdf() {
2740     echo -n 'Switching to dvorak keyboard layout: '
2741     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2742     echo 'Done'
2743 }
2744 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2745 uiae() {
2746     echo -n 'Switching to us keyboard layout: '
2747     setxkbmap us && echo 'Done' || echo 'Failed'
2748 }
2749
2750 # set up an ipv6 tunnel
2751 ipv6-tunnel() {
2752     case $1 in
2753         start)
2754             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2755                 print 'ipv6 tunnel already set up, nothing to be done.'
2756                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2757             else
2758                 [[ -n "$PUBLIC_IP" ]] || \
2759                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2760                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2761
2762                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2763                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2764                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2765                 ifconfig sit0 tunnel ::192.88.99.1 up
2766                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2767             fi
2768             ;;
2769         status)
2770             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2771                 print 'ipv6 tunnel available' ; return 0
2772             else
2773                 print 'ipv6 tunnel not available' ; return 1
2774             fi
2775             ;;
2776         stop)
2777             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2778                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2779                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2780             else
2781                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2782             fi
2783             ;;
2784         *)
2785             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2786             ;;
2787     esac
2788 }
2789
2790 # run dhclient for wireless device
2791 iwclient() {
2792     salias dhclient "$(wavemon -d | awk '/device/{print $2}')"
2793 }
2794
2795 # spawn a minimally set up ksh - useful if you want to umount /usr/.
2796 minimal-shell() {
2797     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
2798 }
2799
2800 # make a backup of a file
2801 bk() {
2802     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2803 }
2804
2805 # Switching shell safely and efficiently? http://www.zsh.org/mla/workers/2001/msg02410.html
2806 # bash() {
2807 #  NO_SWITCH="yes" command bash "$@"
2808 # }
2809 # restart () {
2810 #  exec $SHELL $SHELL_ARGS "$@"
2811 # }
2812
2813 # }}}
2814
2815 # log out? set timeout in seconds {{{
2816 # TMOUT=1800
2817 # do not log out in some specific terminals:
2818 #  if [[ "${TERM}" == ([Exa]term*|rxvt|dtterm|screen*) ]] ; then
2819 #    unset TMOUT
2820 #  fi
2821 # }}}
2822
2823 # {{{ make sure our environment is clean regarding colors
2824 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2825 # }}}
2826
2827 # source another config file if present {{{
2828 xsource "/etc/zsh/zshrc.local"
2829 xsource "${HOME}/.zshenv"
2830 # }}}
2831
2832 # "persistent history" {{{
2833 # just write important commands you always need to ~/.important_commands
2834 if [[ -r ~/.important_commands ]] ; then
2835     fc -R ~/.important_commands
2836 fi
2837 # }}}
2838
2839 ## genrefcard.pl settings {{{
2840 ### example: split functions-search 8,16,24,32
2841 #@# split functions-search 8
2842 ## }}}
2843
2844 # add variable to be able to check whether the file has been read {{{
2845 ZSHRC_GLOBAL_HAS_BEEN_READ=1
2846 # }}}
2847
2848 ## END OF FILE #################################################################
2849 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4