zshrc: Unification cleanup - Episode II
[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 ################################################################################
7 # This file is sourced only for interactive shells. It
8 # should contain commands to set up aliases, functions,
9 # options, key bindings, etc.
10 #
11 # Global Order: zshenv, zprofile, zshrc, zlogin
12 ################################################################################
13
14 # zsh-refcard-tag documentation: {{{
15 #   You may notice strange looking comments in this file.
16 #   These are there for a purpose. grml's zsh-refcard can now be
17 #   automatically generated from the contents of the actual configuration
18 #   file. However, we need a little extra information on which comments
19 #   and what lines of code to take into account (and for what purpose).
20 #
21 # Here is what they mean:
22 #
23 # List of tags (comment types) used:
24 #   #a#     Next line contains an important alias, that should
25 #           be included in the grml-zsh-refcard.
26 #           (placement tag: @@INSERT-aliases@@)
27 #   #f#     Next line contains the beginning of an important function.
28 #           (placement tag: @@INSERT-functions@@)
29 #   #v#     Next line contains an important variable.
30 #           (placement tag: @@INSERT-variables@@)
31 #   #k#     Next line contains an important keybinding.
32 #           (placement tag: @@INSERT-keybindings@@)
33 #   #d#     Hashed directories list generation:
34 #               start   denotes the start of a list of 'hash -d'
35 #                       definitions.
36 #               end     denotes its end.
37 #           (placement tag: @@INSERT-hasheddirs@@)
38 #   #A#     Abbreviation expansion list generation:
39 #               start   denotes the beginning of abbreviations.
40 #               end     denotes their end.
41 #           Lines within this section that end in '#d .*' provide
42 #           extra documentation to be included in the refcard.
43 #           (placement tag: @@INSERT-abbrev@@)
44 #   #m#     This tag allows you to manually generate refcard entries
45 #           for code lines that are hard/impossible to parse.
46 #               Example:
47 #                   #m# k ESC-h Call the run-help function
48 #               That would add a refcard entry in the keybindings table
49 #               for 'ESC-h' with the given comment.
50 #           So the syntax is: #m# <section> <argument> <comment>
51 #   #o#     This tag lets you insert entries to the 'other' hash.
52 #           Generally, this should not be used. It is there for
53 #           things that cannot be done easily in another way.
54 #           (placement tag: @@INSERT-other-foobar@@)
55 #
56 #   All of these tags (except for m and o) take two arguments, the first
57 #   within the tag, the other after the tag:
58 #
59 #   #<tag><section># <comment>
60 #
61 #   Where <section> is really just a number, which are defined by the
62 #   @secmap array on top of 'genrefcard.pl'. The reason for numbers
63 #   instead of names is, that for the reader, the tag should not differ
64 #   much from a regular comment. For zsh, it is a regular comment indeed.
65 #   The numbers have got the following meanings:
66 #         0 -> "default"
67 #         1 -> "system"
68 #         2 -> "user"
69 #         3 -> "debian"
70 #         4 -> "search"
71 #         5 -> "shortcuts"
72 #         6 -> "services"
73 #
74 #   So, the following will add an entry to the 'functions' table in the
75 #   'system' section, with a (hopefully) descriptive comment:
76 #       #f1# Edit an alias via zle
77 #       edalias() {
78 #
79 #   It will then show up in the @@INSERT-aliases-system@@ replacement tag
80 #   that can be found in 'grml-zsh-refcard.tex.in'.
81 #   If the section number is omitted, the 'default' section is assumed.
82 #   Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
83 #   exactly the same as @@INSERT-aliases-default@@. If you want a list of
84 #   *all* aliases, for example, use @@INSERT-aliases-all@@.
85 #}}}
86
87 # zsh profiling {{{
88 # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
89 if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
90     zmodload zsh/zprof
91 fi
92 # }}}
93
94 # setting some default values {{{
95
96 # load .zshrc.pre to give the user the chance to overwrite the defaults
97 [[ -r ${HOME}/.zshrc.pre ]] && source ${HOME}/.zshrc.pre
98
99 NOCOR=${NOCOR:-0}
100 NOMENU=${NOMENU:-0}
101 NOPRECMD=${NOPRECMD:-0}
102 BATTERY=${BATTERY:-0}
103 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
104 GRML_ALWAYS_LOAD_ALL=${GRML_ALWAYS_LOAD_ALL:-0}
105 # }}}
106
107 # {{{ check for version/system
108 # check for versions (compatibility reasons)
109 is4(){
110     [[ $ZSH_VERSION == <4->* ]] && return 0
111     return 1
112 }
113
114 is41(){
115     [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
116     return 1
117 }
118
119 is42(){
120     [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
121     return 1
122 }
123
124 is425(){
125     [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
126     return 1
127 }
128
129 is43(){
130     [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
131     return 1
132 }
133
134 #f1# Checks whether or not you're running grml
135 isgrml(){
136     [[ -f /etc/grml_version ]] && return 0
137     return 1
138 }
139
140 #f1# Checks whether or not you're running a grml cd
141 isgrmlcd(){
142     [[ -f /etc/grml_cd ]] && return 0
143     return 1
144 }
145
146 if isgrml ; then
147 #f1# Checks whether or not you're running grml-small
148     isgrmlsmall() {
149         [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]] && return 0 ; return 1
150     }
151 else
152     isgrmlsmall() { return 1 }
153 fi
154
155 #f1# are we running within an utf environment?
156 isutfenv() {
157     case "$LANG $CHARSET $LANGUAGE" in
158         *utf*) return 0 ;;
159         *UTF*) return 0 ;;
160         *)     return 1 ;;
161     esac
162 }
163
164 # check for user, if not running as root set $SUDO to sudo
165 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
166
167 # change directory to home on first invocation of zsh
168 # important for rungetty -> autologin
169 # Thanks go to Bart Schaefer!
170 isgrml && checkhome() {
171     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
172         export ALREADY_DID_CD_HOME=$HOME
173         cd
174     fi
175 }
176
177 # check for zsh v3.1.7+
178
179 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
180      || ${ZSH_VERSION} == 3.<2->.<->*    \
181      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
182
183     printf '-!-\n'
184     printf '-!- In this configuration we try to make use of features, that only\n'
185     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
186     printf '-!- used with a wide range of zsh versions, while using fairly\n'
187     printf '-!- advanced features in all supported versions.\n'
188     printf '-!-\n'
189     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
190     printf '-!-\n'
191     printf '-!- While this *may* work, it might as well fail.\n'
192     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
193     printf '-!-\n'
194     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
195     printf '-!- If it does today, you'\''ve been lucky.\n'
196     printf '-!-\n'
197     printf '-!- Ye been warned!\n'
198     printf '-!-\n'
199
200     function zstyle() { : }
201 fi
202
203 # }}}
204
205 # utility functions {{{
206 # this function checks if a command exists and returns either true
207 # or false. This avoids using 'which' and 'whence', which will
208 # avoid problems with aliases for which on certain weird systems. :-)
209 check_com() {
210     local -i comonly
211
212     if [[ ${1} == '-c' ]] ; then
213         (( comonly = 1 ))
214         shift
215     else
216         (( comonly = 0 ))
217     fi
218
219     if (( ${#argv} != 1 )) ; then
220         printf 'usage: check_com [-c] <command>\n' >&2
221         return 1
222     fi
223
224     if (( comonly > 0 )) ; then
225         [[ -n ${commands[$1]}  ]] && return 0
226         return 1
227     fi
228
229     if   [[ -n ${commands[$1]}    ]] \
230       || [[ -n ${functions[$1]}   ]] \
231       || [[ -n ${aliases[$1]}     ]] \
232       || [[ -n ${reswords[(r)$1]} ]] ; then
233
234         return 0
235     fi
236
237     return 1
238 }
239
240 # creates an alias and precedes the command with
241 # sudo if $EUID is not zero.
242 salias() {
243     local only=0 ; local multi=0
244     while [[ ${1} == -* ]] ; do
245         case ${1} in
246             (-o) only=1 ;;
247             (-a) multi=1 ;;
248             (--) shift ; break ;;
249             (-h)
250                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
251                 printf '  -h      shows this help text.\n'
252                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
253                 printf '          be careful using this option.\n'
254                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
255                 return 0
256                 ;;
257             (*) printf "unkown option: '%s'\n" "${1}" ; return 1 ;;
258         esac
259         shift
260     done
261
262     if (( ${#argv} > 1 )) ; then
263         printf 'Too many arguments %s\n' "${#argv}"
264         return 1
265     fi
266
267     key="${1%%\=*}" ;  val="${1#*\=}"
268     if (( EUID == 0 )) && (( only == 0 )); then
269         alias -- "${key}=${val}"
270     elif (( EUID > 0 )) ; then
271         (( multi > 0 )) && val="${val// ; / ; sudo }"
272         alias -- "${key}=sudo ${val}"
273     fi
274
275     return 0
276 }
277
278 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
279 # usage: uprint foo
280 #   Where foo is the *name* of the parameter you want printed.
281 #   Note that foo is no typo; $foo would be wrong here!
282 if ! is42 ; then
283     uprint () {
284         local -a u
285         local w
286         local parameter=${1}
287
288         if [[ -z ${parameter} ]] ; then
289             printf 'usage: uprint <parameter>\n'
290             return 1
291         fi
292
293         for w in ${(P)parameter} ; do
294             [[ -z ${(M)u:#${w}} ]] && u=( ${u} ${w} )
295         done
296
297         builtin print -l ${u}
298     }
299 fi
300
301 # Check if we can read given files and source those we can.
302 xsource() {
303     if (( ${#argv} < 1 )) ; then
304         printf 'usage: xsource FILE(s)...\n' >&2
305         return 1
306     fi
307
308     while (( ${#argv} > 0 )) ; do
309         [[ -r ${1} ]] && source ${1}
310         shift
311     done
312     return 0
313 }
314
315 # Check if we can read a given file and 'cat(1)' it.
316 xcat() {
317     if (( ${#argv} != 1 )) ; then
318         printf 'usage: xcat FILE\n' >&2
319         return 1
320     fi
321
322     [[ -r ${1} ]] && cat ${1}
323     return 0
324 }
325
326 # Remove these functions again, they are of use only in these
327 # setup files. This should be called at the end of .zshrc.
328 xunfunction() {
329     local -a funcs
330     funcs=(salias xcat xsource xunfunction zrcautoload)
331
332     for func in $funcs ; do
333         [[ -n ${functions[$func]} ]] \
334             && unfunction $func
335     done
336     return 0
337 }
338
339 # autoload wrapper - use this one instead of autoload directly
340 function zrcautoload() {
341     setopt local_options extended_glob
342     local fdir ffile
343     local -i ffound
344
345     ffile=${1}
346     (( found = 0 ))
347     for fdir in ${fpath} ; do
348         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
349     done
350
351     (( ffound == 0 )) && return 1
352     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
353         autoload -U ${ffile} || return 1
354     else
355         autoload ${ffile} || return 1
356     fi
357     return 0
358 }
359
360 #}}}
361
362 # Load is-at-least() for more precise version checks {{{
363
364 # Note that this test will *always* fail, if the is-at-least
365 # function could not be marked for autoloading.
366 zrcautoload is-at-least || is-at-least() { return 1 }
367
368 # }}}
369
370 # locale setup {{{
371 if [[ -z "$LANG" ]] ; then
372    xsource "/etc/default/locale"
373 fi
374
375 export LANG=${LANG:-en_US.iso885915}
376 for var in LC_ALL LC_MESSAGES ; do
377     [[ -n ${(P)var} ]] && export $var
378 done
379
380 xsource "/etc/sysconfig/keyboard"
381
382 TZ=$(xcat /etc/timezone)
383 # }}}
384
385 # check for potentially old files in 'completion.d' {{{
386 setopt extendedglob
387 xof=(/etc/zsh/completion.d/*~/etc/zsh/completion.d/_*(N))
388 if (( ${#xof} > 0 )) ; then
389     printf '\n -!- INFORMATION\n\n'
390     printf ' -!- %s file(s) not starting with an underscore (_) found in\n' ${#xof}
391     printf ' -!- /etc/zsh/completion.d/.\n\n'
392     printf ' -!- While this has been the case in old versions of grml-etc-core,\n'
393     printf ' -!- recent versions of the grml-zsh-setup have all these files rewritten\n'
394     printf ' -!- and renamed. Furthermore, the grml-zsh-setup will *only* add files\n'
395     printf ' -!- named _* to that directory.\n\n'
396     printf ' -!- If you added functions to completion.d yourself, please consider\n'
397     printf ' -!- moving them to /etc/zsh/functions.d/. Files in that directory, not\n'
398     printf ' -!- starting with an underscore are marked for automatic loading\n'
399     printf ' -!- by default (so that is quite convenient).\n\n'
400     printf ' -!- If there are files *not* starting with an underscore from an older\n'
401     printf ' -!- grml-etc-core in completion.d, you may safely remove them.\n\n'
402     printf ' -!- Delete the files for example via running:\n\n'
403     printf "      rm ${xof}\n\n"
404     printf ' -!- Note, that this message will *not* go away, unless you yourself\n'
405     printf ' -!- resolve the situation manually.\n\n'
406     BROKEN_COMPLETION_DIR=1
407 fi
408 unset xof
409 # }}}
410
411 # {{{ set some variables
412 if check_com -c vim ; then
413 #v#
414     export EDITOR=${EDITOR:-vim}
415 else
416     export EDITOR=${EDITOR:-vi}
417 fi
418
419 #v#
420 export PAGER=${PAGER:-less}
421
422 #v#
423 export MAIL=${MAIL:-/var/mail/$USER}
424
425 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
426 export SHELL='/bin/zsh'
427
428 # color setup for ls:
429 check_com -c dircolors && eval $(dircolors -b)
430
431 # set width of man pages to 80 for more convenient reading
432 # export MANWIDTH=${MANWIDTH:-80}
433
434 # Search path for the cd command
435 #  cdpath=(.. ~)
436
437 # completion functions go to /etc/zsh/completion.d
438 # function files may be put into /etc/zsh/functions.d, from where they
439 # will be automatically autoloaded.
440 if [[ -n "$BROKEN_COMPLETION_DIR" ]] ; then
441     print 'Warning: not setting completion directories because broken files have been found.' >&2
442 else
443     [[ -d /etc/zsh/completion.d ]] && fpath=( $fpath /etc/zsh/completion.d )
444     if [[ -d /etc/zsh/functions.d ]] ; then
445         fpath+=( /etc/zsh/functions.d )
446         for func in /etc/zsh/functions.d/[^_]*[^~](N.) ; do
447             zrcautoload -U ${func:t}
448         done
449     fi
450 fi
451
452 # automatically remove duplicates from these arrays
453 typeset -U path cdpath fpath manpath
454 # }}}
455
456 # {{{ keybindings
457 if [[ "$TERM" != emacs ]] ; then
458     [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
459     [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
460     [[ -z "$terminfo[kend]"  ]] || bindkey -M emacs "$terminfo[kend]"  end-of-line
461     [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
462     [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
463     [[ -z "$terminfo[kend]"  ]] || bindkey -M vicmd "$terminfo[kend]"  vi-end-of-line
464     [[ -z "$terminfo[cuu1]"  ]] || bindkey -M viins "$terminfo[cuu1]"  vi-up-line-or-history
465     [[ -z "$terminfo[cuf1]"  ]] || bindkey -M viins "$terminfo[cuf1]"  vi-forward-char
466     [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
467     [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
468     [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
469     [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
470     # ncurses stuff:
471     [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
472     [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
473     [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
474     [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
475     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
476     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}"  end-of-line
477     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
478     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line
479 fi
480
481 ## keybindings (run 'bindkeys' for details, more details via man zshzle)
482 # use emacs style per default:
483 bindkey -e
484 # use vi style:
485 # bindkey -v
486
487 #if [[ "$TERM" == screen ]] ; then
488 bindkey '\e[1~' beginning-of-line       # home
489 bindkey '\e[4~' end-of-line             # end
490 bindkey '\e[A'  up-line-or-search       # cursor up
491 bindkey '\e[B'  down-line-or-search     # <ESC>-
492
493 bindkey '^xp'   history-beginning-search-backward
494 bindkey '^xP'   history-beginning-search-forward
495 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
496 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
497 # if terminal type is set to 'rxvt':
498 bindkey '\e[7~' beginning-of-line       # home
499 bindkey '\e[8~' end-of-line             # end
500 #fi
501
502 # insert unicode character
503 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
504 # See for example http://unicode.org/charts/ for unicode characters code
505 zrcautoload insert-unicode-char
506 zle -N insert-unicode-char
507 #k# Insert Unicode character
508 bindkey '^Xi' insert-unicode-char
509
510 # just type 'cd ...' to get 'cd ../..'
511 #  rationalise-dot() {
512 #  if [[ $LBUFFER == *.. ]] ; then
513 #    LBUFFER+=/..
514 #  else
515 #    LBUFFER+=.
516 #  fi
517 #  }
518 #  zle -N rationalise-dot
519 #  bindkey . rationalise-dot
520
521 #  bindkey '\eq' push-line-or-edit
522
523 ## toggle the ,. abbreviation feature on/off
524 # NOABBREVIATION: default abbreviation-state
525 #                 0 - enabled (default)
526 #                 1 - disabled
527 NOABBREVIATION=${NOABBREVIATION:-0}
528
529 grml_toggle_abbrev() {
530     if (( ${NOABBREVIATION} > 0 )) ; then
531         NOABBREVIATION=0
532     else
533         NOABBREVIATION=1
534     fi
535 }
536
537 zle -N grml_toggle_abbrev
538 bindkey '^xA' grml_toggle_abbrev
539
540 # }}}
541
542 # a generic accept-line wrapper {{{
543
544 # This widget can prevent unwanted autocorrections from command-name
545 # to _command-name, rehash automatically on enter and call any number
546 # of builtin and user-defined widgets in different contexts.
547 #
548 # For a broader description, see:
549 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
550 #
551 # The code is imported from the file 'zsh/functions/accept-line' from
552 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
553 # distributed under the same terms as zsh itself.
554
555 # A newly added command will may not be found or will cause false
556 # correction attempts, if you got auto-correction set. By setting the
557 # following style, we force accept-line() to rehash, if it cannot
558 # find the first word on the command line in the $command[] hash.
559 zstyle ':acceptline:*' rehash true
560
561 function Accept-Line() {
562     setopt localoptions noksharrays
563     local -a subs
564     local -xi aldone
565     local sub
566
567     zstyle -a ":acceptline:${alcontext}" actions subs
568
569     (( ${#subs} < 1 )) && return 0
570
571     (( aldone = 0 ))
572     for sub in ${subs} ; do
573         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
574         zle ${sub}
575
576         (( aldone > 0 )) && break
577     done
578 }
579
580 function Accept-Line-getdefault() {
581     local default_action
582
583     zstyle -s ":acceptline:${alcontext}" default_action default_action
584     case ${default_action} in
585         ((accept-line|))
586             printf ".accept-line"
587             ;;
588         (*)
589             printf ${default_action}
590             ;;
591     esac
592 }
593
594 function accept-line() {
595     setopt localoptions noksharrays
596     local -a cmdline
597     local -x alcontext
598     local buf com fname format msg default_action
599
600     alcontext='default'
601     buf="${BUFFER}"
602     cmdline=(${(z)BUFFER})
603     com="${cmdline[1]}"
604     fname="_${com}"
605
606     zstyle -t ":acceptline:${alcontext}" rehash \
607         && [[ -z ${commands[$com]} ]]           \
608         && rehash
609
610     if    [[ -n ${reswords[(r)$com]} ]] \
611        || [[ -n ${aliases[$com]}     ]] \
612        || [[ -n ${functions[$com]}   ]] \
613        || [[ -n ${builtins[$com]}    ]] \
614        || [[ -n ${commands[$com]}    ]] ; then
615
616         # there is something sensible to execute, just do it.
617         alcontext='normal'
618         zle Accept-Line
619
620         default_action=$(Accept-Line-getdefault)
621         zstyle -T ":acceptline:${alcontext}" call_default \
622             && zle ${default_action}
623         return
624     fi
625
626     if    [[ -o correct              ]] \
627        || [[ -o correctall           ]] \
628        && [[ -n ${functions[$fname]} ]] ; then
629
630         # nothing there to execute but there is a function called
631         # _command_name; a completion widget. Makes no sense to
632         # call it on the commandline, but the correct{,all} options
633         # will ask for it nevertheless, so warn the user.
634         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
635             # Okay, we warned the user before, he called us again,
636             # so have it his way.
637             alcontext='force'
638             zle Accept-Line
639
640             default_action=$(Accept-Line-getdefault)
641             zstyle -T ":acceptline:${alcontext}" call_default \
642                 && zle ${default_action}
643             return
644         fi
645
646         # prepare warning message for the user, configurable via zstyle.
647         zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
648
649         if [[ -z ${msg} ]] ; then
650             msg="%c will not execute and completion %f exists."
651         fi
652
653         zformat -f msg "${msg}" "c:${com}" "f:${fname}"
654
655         zle -M -- "${msg}"
656         return
657     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
658         # If we are here, the commandline contains something that is not
659         # executable, which is neither subject to _command_name correction
660         # and is not empty. might be a variable assignment
661         alcontext='misc'
662         zle Accept-Line
663
664         default_action=$(Accept-Line-getdefault)
665         zstyle -T ":acceptline:${alcontext}" call_default \
666             && zle ${default_action}
667         return
668     fi
669
670     # If we got this far, the commandline only contains whitespace, or is empty.
671     alcontext='empty'
672     zle Accept-Line
673
674     default_action=$(Accept-Line-getdefault)
675     zstyle -T ":acceptline:${alcontext}" call_default \
676         && zle ${default_action}
677 }
678
679 zle -N accept-line
680 zle -N Accept-Line
681
682 # }}}
683
684 # power completion - abbreviation expansion {{{
685 # power completion / abbreviation expansion / buffer expansion
686 # see http://zshwiki.org/home/examples/zleiab for details
687 # less risky than the global aliases but powerful as well
688 # just type the abbreviation key and afterwards ',.' to expand it
689 declare -A abk
690 setopt extendedglob
691 setopt interactivecomments
692 abk=(
693 # key  # value                (#d additional doc string)
694 #A# start
695     '...' '../..'
696     '....' '../../..'
697     'BG' '& exit'
698     'C' '| wc -l'
699     'G' '|& grep --color=auto'
700     'H' '| head'
701     'Hl' ' --help |& less -r'      #d (Display help in pager)
702     'L' '| less'
703     'LL' '|& less -r'
704     'M' '| most'
705     'N' '&>/dev/null'              #d (No Output)
706     'R' '| tr A-z N-za-m'          #d (ROT13)
707     'SL' '| sort | less'
708     'S' '| sort -u'
709     'T' '| tail'
710     'V' '|& vim -'
711 #A# end
712     'hide' "echo -en '\033]50;nil2\007'"
713     'tiny' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
714     'small' 'echo -en "\033]50;6x10\007"'
715     'medium' 'echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
716     'default' 'echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
717     'large' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
718     'huge' 'echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
719     'smartfont' 'echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
720     'semifont' 'echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
721     'da' 'du -sch'
722     'j' 'jobs -l'
723     'u' 'translate -i'
724     'co' "./configure && make && sudo make install"
725     'CH' "./configure --help"
726     'conkeror' 'firefox -chrome chrome://conkeror/content'
727     'dir' 'ls -lSrah'
728     'lad' $'ls -d .*(/)\n# only show dot-directories'
729     'lsa' $'ls -a .*(.)\n# only show dot-files'
730     'lss' $'ls -l *(s,S,t)\n# only files with setgid/setuid/sticky flag'
731     'lsl' $'ls -l *(@[1,10])\n# only symlinks'
732     'lsx' $'ls -l *(*[1,10])\n# only executables'
733     'lsw' $'ls -ld *(R,W,X.^ND/)\n# world-{readable,writable,executable} files'
734     'lsbig' $'ls -flh *(.OL[1,10])\n# display the biggest files'
735     'lsd' $'ls -d *(/)\n# only show directories'
736     'lse' $'ls -d *(/^F)\n# only show empty directories'
737     'lsnew' $'ls -rl *(D.om[1,10])\n# display the newest files'
738     'lsold' $'ls -rtlh *(D.om[-11,-1])\n # display the oldest files'
739     'lssmall' $'ls -Srl *(.oL[1,10])\n# display the smallest files'
740     'rw-' 'chmod 600'
741     '600' 'chmod u+rw-x,g-rwx,o-rwx'
742     'rwx' 'chmod u+rwx'
743     '700' 'chmod u+rwx,g-rwx,o-rwx'
744     'r--' 'chmod u+r-wx,g-rwx,o-rwx'
745     '644' $'chmod u+rw-x,g+r-wx,o+r-wx\n # 4=r,2=w,1=x'
746     '755' 'chmod u+rwx,g+r-w+x,o+r-w+x'
747     'md' 'mkdir -p '
748     'cmplayer' 'mplayer -vo -fs -zoom fbdev'
749     'fbmplayer' 'mplayer -vo -fs -zoom fbdev'
750     'fblinks' 'links2 -driver fb'
751     'insecssh' 'ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
752     'insecscp' 'scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
753     'fori' 'for i ({..}) { }'
754     'cx' 'chmod +x'
755     'e'  'print -l'
756     'se' 'setopt interactivecomments'
757     'va' 'valac --vapidir=../vapi/ --pkg=gtk+-2.0 gtktest.vala'
758     'fb2' '=mplayer -vo fbdev -fs -zoom 1>/dev/null -xy 2'
759     'fb3' '=mplayer -vo fbdev -fs  -zoom 1>/dev/null -xy 3'
760     'ci' 'centericq'
761     'D'  'export DISPLAY=:0.0'
762     'mp' 'mplayer -vo xv -fs -zoom'
763 )
764
765 globalias() {
766     local MATCH
767
768     if (( NOABBREVIATION > 0 )) ; then
769         LBUFFER="${LBUFFER},."
770         return 0
771     fi
772
773     matched_chars='[.-|_a-zA-Z0-9]#'
774     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
775     LBUFFER+=${abk[$MATCH]:-$MATCH}
776 }
777
778 zle -N globalias
779 bindkey ",." globalias
780 # }}}
781
782 # {{{ autoloading
783 zrcautoload zmv    # who needs mmv or rename?
784 zrcautoload history-search-end
785
786 # we don't want to quote/espace URLs on our own...
787 # if autoload -U url-quote-magic ; then
788 #    zle -N self-insert url-quote-magic
789 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
790 # else
791 #    print 'Notice: no url-quote-magic available :('
792 # fi
793 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
794
795 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
796 alias run-help >&/dev/null && unalias run-help
797 zrcautoload run-help # use via 'esc-h'
798
799 # completion system
800 if zrcautoload compinit && compinit 2>/dev/null ; then
801     compinit 2>/dev/null || print 'Notice: no compinit available :('
802 else
803     print 'Notice: no compinit available :('
804     function zstyle { }
805     function compdef { }
806 fi
807
808 is4 && zrcautoload zed # use ZLE editor to edit a file or function
809
810 is4 && \
811 for mod in complist deltochar mathfunc ; do
812     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
813 done
814
815 # autoload zsh modules when they are referenced
816 if is4 ; then
817     tmpargs=(
818         a   stat
819         a   zpty
820         ap  mapfile
821     )
822
823     while (( ${#tmpargs} > 0 )) ; do
824         zmodload -${tmpargs[1]} zsh/${tmpargs[2]} ${tmpargs[2]}
825         shift 2 tmpargs
826     done
827     unset tmpargs
828 fi
829
830 if is4 && zrcautoload insert-files && zle -N insert-files ; then
831     #k# Insert files
832     bindkey "^Xf" insert-files # C-x-f
833 fi
834
835 bindkey ' '   magic-space    # also do history expansion on space
836 #k# Trigger menu-complete
837 bindkey '\ei' menu-complete  # menu completion via esc-i
838
839 # press esc-e for editing command line in $EDITOR or $VISUAL
840 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
841     #k# Edit the current line in \kbd{\$EDITOR}
842     bindkey '\ee' edit-command-line
843 fi
844
845 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
846     #k# menu selection: pick item but stay in the menu
847     bindkey -M menuselect '\e^M' accept-and-menu-complete
848
849     # use the vi navigation keys (hjkl) besides cursor keys in menu completion
850     #bindkey -M menuselect 'h' vi-backward-char        # left
851     #bindkey -M menuselect 'k' vi-up-line-or-history   # up
852     #bindkey -M menuselect 'l' vi-forward-char         # right
853     #bindkey -M menuselect 'j' vi-down-line-or-history # bottom
854
855     # accept a completion and try to complete again by using menu
856     # completion; very useful with completing directories
857     # by using 'undo' one's got a simple file browser
858     bindkey -M menuselect '^o' accept-and-infer-next-history
859 fi
860
861 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
862 _bkdate() { BUFFER="$BUFFER$(date '+%F')"; CURSOR=$#BUFFER; }
863 zle -N _bkdate
864
865 #k# Insert a timestamp on the command line (yyyy-mm-dd)
866 bindkey '^Ed' _bkdate
867
868 # press esc-m for inserting last typed word again (thanks to caphuso!)
869 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
870 zle -N insert-last-typed-word;
871
872 #k# Insert last typed word
873 bindkey "\em" insert-last-typed-word
874
875 # set command prediction from history, see 'man 1 zshcontrib'
876 #  is4 && zrcautoload predict-on && \
877 #  zle -N predict-on         && \
878 #  zle -N predict-off        && \
879 #  bindkey "^X^Z" predict-on && \
880 #  bindkey "^Z" predict-off
881
882 #k# Shortcut for \kbd{fg<enter>}
883 bindkey -s '^z' "fg\n"
884
885 # press ctrl-q to quote line:
886 #  mquote () {
887 #        zle beginning-of-line
888 #        zle forward-word
889 #        # RBUFFER="'$RBUFFER'"
890 #        RBUFFER=${(q)RBUFFER}
891 #        zle end-of-line
892 #  }
893 #  zle -N mquote && bindkey '^q' mquote
894
895 # run command line as user root via sudo:
896 sudo-command-line() {
897     [[ -z $BUFFER ]] && zle up-history
898     [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
899 }
900 zle -N sudo-command-line
901
902 #k# Put the current command line into a \kbd{sudo} call
903 bindkey "^Os" sudo-command-line
904
905 ### jump behind the first word on the cmdline.
906 ### useful to add options.
907 function jump_after_first_word() {
908     local words
909     words=(${(z)BUFFER})
910
911     if (( ${#words} <= 1 )) ; then
912         CURSOR=${#BUFFER}
913     else
914         CURSOR=${#${words[1]}}
915     fi
916 }
917 zle -N jump_after_first_word
918
919 bindkey '^x1' jump_after_first_word
920
921 # }}}
922
923 # {{{ set some important options
924 # Please update these tags, if you change the umask settings below.
925 #o# r_umask     002
926 #o# r_umaskstr  rwxrwxr-x
927 #o# umask       022
928 #o# umaskstr    rwxr-xr-x
929 (( EUID != 0 )) && umask 002 || umask 022
930
931 # history:
932 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
933 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
934 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
935 is4 && setopt histignorealldups # If  a  new  command  line being added to the history
936                             # list duplicates an older one, the older command is removed from the list
937 setopt histignorespace      # remove command lines from the history list when
938                             # the first character on the line is a space
939 #  setopt histallowclobber    # add `|' to output redirections in the history
940 #  setopt NO_clobber          # warning if file exists ('cat /dev/null > ~/.zshrc')
941 setopt auto_cd              # if a command is issued that can't be executed as a normal command,
942                             # and the command is the name of a directory, perform the cd command to that directory
943 setopt extended_glob        # in order to use #, ~ and ^ for filename generation
944                             # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
945                             # -> searches for word not in compressed files
946                             # don't forget to quote '^', '~' and '#'!
947 setopt longlistjobs         # display PID when suspending processes as well
948 setopt notify               # report the status of backgrounds jobs immediately
949 setopt hash_list_all        # Whenever a command completion is attempted, make sure \
950                             # the entire command path is hashed first.
951 setopt completeinword       # not just at the end
952 # setopt nocheckjobs          # don't warn me about bg processes when exiting
953 setopt nohup                # and don't kill them, either
954 # setopt printexitvalue       # alert me if something failed
955 # setopt dvorak               # with spelling correction, assume dvorak kb
956 setopt auto_pushd           # make cd push the old directory onto the directory stack.
957 setopt nonomatch            # try to avoid the 'zsh: no matches found...'
958 setopt nobeep               # avoid "beep"ing
959 setopt pushd_ignore_dups    # don't push the same dir twice.
960
961 MAILCHECK=30       # mailchecks
962 REPORTTIME=5       # report about cpu-/system-/user-time of command if running longer than 5 seconds
963 watch=(notme root) # watch for everyone but me and root
964
965 # define word separators (for stuff like backward-word, forward-word, backward-kill-word,..)
966 #  WORDCHARS='*?_-.[]~=/&;!#$%^(){}<>' # the default
967 #  WORDCHARS=.
968 #  WORDCHARS='*?_[]~=&;!#$%^(){}'
969 #  WORDCHARS='${WORDCHARS:s@/@}'
970
971 # only slash should be considered as a word separator:
972 slash-backward-kill-word() {
973     local WORDCHARS="${WORDCHARS:s@/@}"
974     # zle backward-word
975     zle backward-kill-word
976 }
977 zle -N slash-backward-kill-word
978
979 #k# Kill everything in a word up to its last \kbd{/}
980 bindkey '\ev' slash-backward-kill-word
981
982 # }}}
983
984 # {{{ history
985
986 ZSHDIR=$HOME/.zsh
987
988 #v#
989 HISTFILE=$HOME/.zsh_history
990 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
991 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
992
993 # }}}
994
995 # dirstack handling {{{
996
997 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
998 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
999
1000 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1001     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1002     # "cd -" won't work after login by just setting $OLDPWD, so
1003     [[ -d $dirstack[0] ]] && cd $dirstack[0] && cd $OLDPWD
1004 fi
1005
1006 chpwd() {
1007     if is42 ; then
1008         builtin print -l ${(u)dirstack} >! ${DIRSTACKFILE}
1009     else
1010         uprint dirstack >! ${DIRSTACKFILE}
1011     fi
1012 }
1013
1014 # }}}
1015
1016 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
1017 if [[ $BATTERY -gt 0 ]] ; then
1018     if ! check_com -c acpi ; then
1019         BATTERY=0
1020     fi
1021 fi
1022
1023 battery() {
1024 if [[ $BATTERY -gt 0 ]] ; then
1025     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]##Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1026     if [[ -z "$PERCENT" ]] ; then
1027         PERCENT='acpi not present'
1028     else
1029         if [[ "$PERCENT" -lt 20 ]] ; then
1030             PERCENT="warning: ${PERCENT}%%"
1031         else
1032             PERCENT="${PERCENT}%%"
1033         fi
1034     fi
1035 fi
1036 }
1037 # }}}
1038
1039 # set colors for use in prompts {{{
1040 if zrcautoload colors && colors 2>/dev/null ; then
1041     BLUE="%{${fg[blue]}%}"
1042     RED="%{${fg_bold[red]}%}"
1043     GREEN="%{${fg[green]}%}"
1044     CYAN="%{${fg[cyan]}%}"
1045     MAGENTA="%{${fg[magenta]}%}"
1046     YELLOW="%{${fg[yellow]}%}"
1047     WHITE="%{${fg[white]}%}"
1048     NO_COLOUR="%{${reset_color}%}"
1049 else
1050     BLUE=$'%{\e[1;34m%}'
1051     RED=$'%{\e[1;31m%}'
1052     GREEN=$'%{\e[1;32m%}'
1053     CYAN=$'%{\e[1;36m%}'
1054     WHITE=$'%{\e[1;37m%}'
1055     MAGENTA=$'%{\e[1;35m%}'
1056     YELLOW=$'%{\e[1;33m%}'
1057     NO_COLOUR=$'%{\e[0m%}'
1058 fi
1059
1060 # }}}
1061
1062 # gather version control information for inclusion in a prompt {{{
1063
1064 if ! is41 ; then
1065     # Be quiet about version problems in grml's zshrc as the user cannot disable
1066     # loading vcs_info() as it is *in* the zshrc - as you can see. :-)
1067     # Just unset most probable variables and disable vcs_info altogether.
1068     local -i i
1069     for i in {0..9} ; do
1070         unset VCS_INFO_message_${i}_
1071     done
1072     zstyle ':vcs_info:*' enable false
1073 fi
1074
1075 # The following code is imported from the file 'zsh/functions/vcs_info'
1076 # from <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>,
1077 # which distributed under the same terms as zsh itself.
1078
1079 # we will only be using one variable, so let the code know now.
1080 zstyle ':vcs_info:*' max-exports 1
1081
1082 # vcs_info() documentation:
1083 #{{{
1084 # REQUIREMENTS:
1085 #{{{
1086 #     This functionality requires zsh version >= 4.1.*.
1087 #}}}
1088 #
1089 # LOADING:
1090 #{{{
1091 # To load vcs_info(), copy this file to your $fpath[] and do:
1092 #   % autoload -Uz vcs_info && vcs_info
1093 #
1094 # To work, vcs_info() needs 'setopt prompt_subst' in your setup.
1095 #}}}
1096 #
1097 # QUICKSTART:
1098 #{{{
1099 # To get vcs_info() working quickly (including colors), you can do the
1100 # following (assuming, you loaded vcs_info() properly - see above):
1101 #
1102 # % RED=$'%{\e[31m%}'
1103 # % GR=$'%{\e[32m%}'
1104 # % MA=$'%{\e[35m%}'
1105 # % YE=$'%{\e[33m%}'
1106 # % NC=$'%{\e[0m%}'
1107 #
1108 # % zstyle ':vcs_info:*' actionformats \
1109 #       "${MA}(${NC}%s${MA})${YE}-${MA}[${GR}%b${YE}|${RED}%a${MA}]${NC} "
1110 #
1111 # % zstyle ':vcs_info:*' formats       \
1112 #       "${MA}(${NC}%s${MA})${Y}-${MA}[${GR}%b${MA}]${NC}%} "
1113 #
1114 # % zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YE}%r"
1115 #
1116 # % precmd () { vcs_info }
1117 # % PS1='${MA}[${GR}%n${MA}] ${MA}(${RED}%!${MA}) ${YE}%3~ ${VCS_INFO_message_0_}${NC}%# '
1118 #
1119 # Obviously, the las two lines are there for demonstration: You need to
1120 # call vcs_info() from your precmd() function (see 'SPECIAL FUNCTIONS' in
1121 # 'man zshmisc'). Once that is done you need a *single* quoted
1122 # '${VCS_INFO_message_0_}' in your prompt.
1123 #
1124 # Now call the 'vcs_info_printsys' utility from the command line:
1125 #
1126 # % vcs_info_printsys
1127 # # list of supported version control backends:
1128 # # disabled systems are prefixed by a hash sign (#)
1129 # git
1130 # hg
1131 # bzr
1132 # darcs
1133 # svk
1134 # mtn
1135 # svn
1136 # cvs
1137 # cdv
1138 # tla
1139 # # flavours (cannot be used in the disable style; they
1140 # # are disabled with their master [git-svn -> git]):
1141 # git-p4
1142 # git-svn
1143 #
1144 # Ten version control backends as you can see. You may not want all
1145 # of these. Because there is no point in running the code to detect
1146 # systems you do not use. ever. So, there is a way to disable some
1147 # backends altogether:
1148 #
1149 # % zstyle ':vcs_info:*' disable bzr cdv darcs mtn svk tla
1150 #
1151 # If you rerun 'vcs_info_printsys' now, you will see the backends listed
1152 # in the 'disable' style marked as diabled by a hash sign. That means the
1153 # detection of these systems is skipped *completely*. No wasted time there.
1154 #
1155 # For more control, read the reference below.
1156 #}}}
1157 #
1158 # CONFIGURATION:
1159 #{{{
1160 # The vcs_info() feature can be configured via zstyle.
1161 #
1162 # First, the context in which we are working:
1163 #       :vcs_info:<vcs-string>:<user-context>
1164 #
1165 # ...where <vcs-string> is one of:
1166 #   - git, git-svn, git-p4, hg, darcs, bzr, cdv, mtn, svn, cvs, svk or tla.
1167 #
1168 # ...and <user-context> is a freely configurable string, assignable by the
1169 # user as the first argument to vcs_info() (see its description below).
1170 #
1171 # There is are three special values for <vcs-string>: The first is named
1172 # 'init', that is in effect as long as there was no decision what vcs
1173 # backend to use. The second is 'preinit; it is used *before* vcs_info()
1174 # is run, when initializing the data exporting variables. The third
1175 # special value is 'formats' and is used by the 'vcs_info_lastmsg' for
1176 # looking up its styles.
1177 #
1178 # There are two pre-defined values for <user-context>:
1179 #   default  - the one used if none is specified
1180 #   command  - used by vcs_info_lastmsg to lookup its styles.
1181 #
1182 # You may *not* use 'print_systems_' as a user-context string, because it
1183 # is used internally.
1184 #
1185 # You can of course use ':vcs_info:*' to match all VCSs in all
1186 # user-contexts at once.
1187 #
1188 # Another special context is 'formats', which is used by the
1189 # vcs_info_lastmsg() utility function (see below).
1190 #
1191 #
1192 # This is a description of all styles, that are looked up:
1193 #   formats             - A list of formats, used when actionformats is not
1194 #                         used (which is most of the time).
1195 #   actionformats       - A list of formats, used if a there is a special
1196 #                         action going on in your current repository;
1197 #                         (like an interactive rebase or a merge conflict)
1198 #   branchformat        - Some backends replace %b in the formats and
1199 #                         actionformats styles above, not only by a branch
1200 #                         name but also by a revision number. This style
1201 #                         let's you modify how that string should look like.
1202 #   nvcsformats         - These "formats" are exported, when we didn't detect
1203 #                         a version control system for the current directory.
1204 #                         This is useful, if you want vcs_info() to completely
1205 #                         take over the generation of your prompt.
1206 #                         You would do something like
1207 #                           PS1='${VCS_INFO_message_0_}'
1208 #                         to accomplish that.
1209 #   max-exports         - Defines the maximum number if VCS_INFO_message_*_
1210 #                         variables vcs_info() will export.
1211 #   enable              - Checked in the 'init' context. If set to false,
1212 #                         vcs_info() will do nothing.
1213 #   disable             - Provide a list of systems, you don't want
1214 #                         the vcs_info() to check for repositories
1215 #                         (checked in the 'init' context, too).
1216 #   use-simple          - If there are two different ways of gathering
1217 #                         information, you can select the simpler one
1218 #                         by setting this style to true; the default
1219 #                         is to use the not-that-simple code, which is
1220 #                         potentially a lot slower but might be more
1221 #                         accurate in all possible cases.
1222 #   use-prompt-escapes  - determines if we assume that the assembled
1223 #                         string from vcs_info() includes prompt escapes.
1224 #                         (Used by vcs_info_lastmsg().
1225 #
1226 # The use-simple style is only available for the bzr backend.
1227 #
1228 # The default values for these in all contexts are:
1229 #   formats             " (%s)-[%b|%a]-"
1230 #   actionformats       " (%s)-[%b]-"
1231 #   branchformat        "%b:%r" (for bzr, svn and svk)
1232 #   nvcsformats         ""
1233 #   max-exports         2
1234 #   enable              true
1235 #   disable             (empty list)
1236 #   use-simple          false
1237 #   use-prompt-escapes  true
1238 #
1239 #
1240 # In normal formats and actionformats, the following replacements
1241 # are done:
1242 #   %s  - The vcs in use (git, hg, svn etc.)
1243 #   %b  - Information about the current branch.
1244 #   %a  - An identifier, that describes the action.
1245 #         Only makes sense in actionformats.
1246 #   %R  - base directory of the repository.
1247 #   %r  - repository name
1248 #         If %R is '/foo/bar/repoXY', %r is 'repoXY'.
1249 #   %S  - subdirectory within a repository. if $PWD is
1250 #         '/foo/bar/reposXY/beer/tasty', %S is 'beer/tasty'.
1251 #
1252 #
1253 # In branchformat these replacements are done:
1254 #   %b  - the branch name
1255 #   %r  - the current revision number
1256 #
1257 # Not all vcs backends have to support all replacements.
1258 # nvcsformat does not perform *any* replacements. It is just a string.
1259 #}}}
1260 #
1261 # ODDITIES:
1262 #{{{
1263 # If you want to use the %b (bold off) prompt expansion in 'formats', which
1264 # expands %b itself, use %%b. That will cause the vcs_info() expansion to
1265 # replace %%b with %b. So zsh's prompt expansion mechanism can handle it.
1266 # Similarly, to hand down %b from branchformat, use %%%%b. Sorry for this
1267 # inconvenience, but it cannot be easily avoided. Luckily we do not clash
1268 # with a lot of prompt expansions and this only needs to be done for those.
1269 # See 'man zshmisc' for details about EXPANSION OF PROMPT SEQUENCES.
1270 #}}}
1271 #
1272 # FUNCTION DESCRIPTIONS (public API):
1273 #{{{
1274 #   vcs_info()
1275 #       The main function, that runs all backends and assembles
1276 #       all data into ${VCS_INFO_message_*_}. This is the function
1277 #       you want to call from precmd() if you want to include
1278 #       up-to-date information in your prompt (see VARIABLE
1279 #       DESCRIPTION below).
1280 #
1281 #   vcs_info_printsys()
1282 #       Prints a list of all supported version control systems.
1283 #       Useful to find out possible contexts (and which of them are enabled)
1284 #       or values for the 'disable' style.
1285 #
1286 #   vcs_info_lastmsg()
1287 #       Outputs the last ${VCS_INFO_message_*_} value. Takes into account
1288 #       the value of the use-prompt-escapes style in ':vcs_info:formats'.
1289 #       It also only prints max-exports values.
1290 #
1291 # All functions named VCS_INFO_* are for internal use only.
1292 #}}}
1293 #
1294 # VARIABLE DESCRIPTION:
1295 #{{{
1296 #   ${VCS_INFO_message_N_}    (Note the trailing underscore)
1297 #       Where 'N' is an integer, eg: VCS_INFO_message_0_
1298 #       These variables are the storage for the informational message the
1299 #       last vcs_info() call has assembled. These are strongly connected
1300 #       to the formats, actionformats and nvcsformats styles described
1301 #       above. Those styles are lists. the first member of that list gets
1302 #       expanded into ${VCS_INFO_message_0_}, the second into
1303 #       ${VCS_INFO_message_1_} and the Nth into ${VCS_INFO_message_N-1_}.
1304 #       These parameters are exported into the environment.
1305 #       (See the max-exports style above.)
1306 #}}}
1307 #
1308 # EXAMPLES:
1309 #{{{
1310 #   Don't use vcs_info at all (even though it's in your prompt):
1311 #   % zstyle ':vcs_info:*' enable false
1312 #
1313 #   Disable the backends for bzr and svk:
1314 #   % zstyle ':vcs_info:*' disable bzr svk
1315 #
1316 #   Provide a special formats for git:
1317 #   % zstyle ':vcs_info:git:*' formats       ' GIT, BABY! [%b]'
1318 #   % zstyle ':vcs_info:git:*' actionformats ' GIT ACTION! [%b|%a]'
1319 #
1320 #   Use the quicker bzr backend (if you do, please report if it does
1321 #   the-right-thing[tm] - thanks):
1322 #   % zstyle ':vcs_info:bzr:*' use-simple true
1323 #
1324 #   Display the revision number in yellow for bzr and svn:
1325 #   % zstyle ':vcs_info:(svn|bzr):*' branchformat '%b%{'${fg[yellow]}'%}:%r'
1326 #
1327 # If you want colors, make sure you enclose the color codes in %{...%},
1328 # if you want to use the string provided by vcs_info() in prompts.
1329 #
1330 # Here is how to print the vcs infomation as a command:
1331 #   % alias vcsi='vcs_info command; vcs_info_lastmsg'
1332 #
1333 #   This way, you can even define different formats for output via
1334 #   vcs_info_lastmsg() in the ':vcs_info:command:*' namespace.
1335 #}}}
1336 #}}}
1337 # utilities
1338 VCS_INFO_adjust () { #{{{
1339     [[ -n ${vcs_comm[overwrite_name]} ]] && vcs=${vcs_comm[overwrite_name]}
1340     return 0
1341 }
1342 # }}}
1343 VCS_INFO_check_com () { #{{{
1344     (( ${+commands[$1]} )) && [[ -x ${commands[$1]} ]] && return 0
1345     return 1
1346 }
1347 # }}}
1348 VCS_INFO_formats () { # {{{
1349     setopt localoptions noksharrays
1350     local action=$1 branch=$2 base=$3
1351     local msg
1352     local -i i
1353
1354     if [[ -n ${action} ]] ; then
1355         zstyle -a ":vcs_info:${vcs}:${usercontext}" actionformats msgs
1356         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b|%a]-'
1357     else
1358         zstyle -a ":vcs_info:${vcs}:${usercontext}" formats msgs
1359         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b]-'
1360     fi
1361
1362     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1363     for i in {1..${#msgs}} ; do
1364         zformat -f msg ${msgs[$i]} a:${action} b:${branch} s:${vcs} r:${base:t} R:${base} S:"$(VCS_INFO_reposub ${base})"
1365         msgs[$i]=${msg}
1366     done
1367     return 0
1368 }
1369 # }}}
1370 VCS_INFO_maxexports () { #{{{
1371     local -ix maxexports
1372
1373     zstyle -s ":vcs_info:${vcs}:${usercontext}" "max-exports" maxexports || maxexports=2
1374     if [[ ${maxexports} != <-> ]] || (( maxexports < 1 )); then
1375         printf 'vcs_info(): expecting numeric arg >= 1 for max-exports (got %s).\n' ${maxexports}
1376         printf 'Defaulting to 2.\n'
1377         maxexports=2
1378     fi
1379 }
1380 # }}}
1381 VCS_INFO_nvcsformats () { #{{{
1382     setopt localoptions noksharrays
1383     local c v
1384
1385     if [[ $1 == 'preinit' ]] ; then
1386         c=default
1387         v=preinit
1388     fi
1389     zstyle -a ":vcs_info:${v:-$vcs}:${c:-$usercontext}" nvcsformats msgs
1390     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1391 }
1392 # }}}
1393 VCS_INFO_realpath () { #{{{
1394     # a portable 'readlink -f'
1395     # forcing a subshell, to ensure chpwd() is not removed
1396     # from the calling shell (if VCS_INFO_realpath() is called
1397     # manually).
1398     (
1399         (( ${+functions[chpwd]} )) && unfunction chpwd
1400         setopt chaselinks
1401         cd $1 2>/dev/null && pwd
1402     )
1403 }
1404 # }}}
1405 VCS_INFO_reposub () { #{{{
1406     setopt localoptions extendedglob
1407     local base=${1%%/##}
1408
1409     [[ ${PWD} == ${base}/* ]] || {
1410         printf '.'
1411         return 1
1412     }
1413     printf '%s' ${PWD#$base/}
1414     return 0
1415 }
1416 # }}}
1417 VCS_INFO_set () { #{{{
1418     setopt localoptions noksharrays
1419     local -i i j
1420
1421     if [[ $1 == '--clear' ]] ; then
1422         for i in {0..9} ; do
1423             unset VCS_INFO_message_${i}_
1424         done
1425     fi
1426     if [[ $1 == '--nvcs' ]] ; then
1427         [[ $2 == 'preinit' ]] && (( maxexports == 0 )) && (( maxexports = 1 ))
1428         for i in {0..$((maxexports - 1))} ; do
1429             typeset -gx VCS_INFO_message_${i}_=
1430         done
1431         VCS_INFO_nvcsformats $2
1432     fi
1433
1434     (( ${#msgs} - 1 < 0 )) && return 0
1435     for i in {0..$(( ${#msgs} - 1 ))} ; do
1436         (( j = i + 1 ))
1437         typeset -gx VCS_INFO_message_${i}_=${msgs[$j]}
1438     done
1439     return 0
1440 }
1441 # }}}
1442 # information gathering
1443 VCS_INFO_bzr_get_data () { # {{{
1444     setopt localoptions noksharrays
1445     local bzrbase bzrbr
1446     local -a bzrinfo
1447
1448     if zstyle -t ":vcs_info:${vcs}:${usercontext}" "use-simple" ; then
1449         bzrbase=${vcs_comm[basedir]}
1450         bzrinfo[2]=${bzrbase:t}
1451         if [[ -f ${bzrbase}/.bzr/branch/last-revision ]] ; then
1452             bzrinfo[1]=$(< ${bzrbase}/.bzr/branch/last-revision)
1453             bzrinfo[1]=${${bzrinfo[1]}%% *}
1454         fi
1455     else
1456         bzrbase=${${(M)${(f)"$( bzr info )"}:# ##branch\ root:*}/*: ##/}
1457         bzrinfo=( ${${${(M)${(f)"$( bzr version-info )"}:#(#s)(revno|branch-nick)*}/*: /}/*\//} )
1458         bzrbase="$(VCS_INFO_realpath ${bzrbase})"
1459     fi
1460
1461     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat bzrbr || bzrbr="%b:%r"
1462     zformat -f bzrbr "${bzrbr}" "b:${bzrinfo[2]}" "r:${bzrinfo[1]}"
1463     VCS_INFO_formats '' "${bzrbr}" "${bzrbase}"
1464     return 0
1465 }
1466 # }}}
1467 VCS_INFO_cdv_get_data () { # {{{
1468     local cdvbase
1469
1470     cdvbase=${vcs_comm[basedir]}
1471     VCS_INFO_formats '' "${cdvbase:t}" "${cdvbase}"
1472     return 0
1473 }
1474 # }}}
1475 VCS_INFO_cvs_get_data () { # {{{
1476     local cvsbranch cvsbase basename
1477
1478     cvsbase="."
1479     while [[ -d "${cvsbase}/../CVS" ]]; do
1480         cvsbase="${cvsbase}/.."
1481     done
1482     cvsbase="$(VCS_INFO_realpath ${cvsbase})"
1483     cvsbranch=$(< ./CVS/Repository)
1484     basename=${cvsbase:t}
1485     cvsbranch=${cvsbranch##${basename}/}
1486     [[ -z ${cvsbranch} ]] && cvsbranch=${basename}
1487     VCS_INFO_formats '' "${cvsbranch}" "${cvsbase}"
1488     return 0
1489 }
1490 # }}}
1491 VCS_INFO_darcs_get_data () { # {{{
1492     local darcsbase
1493
1494     darcsbase=${vcs_comm[basedir]}
1495     VCS_INFO_formats '' "${darcsbase:t}" "${darcsbase}"
1496     return 0
1497 }
1498 # }}}
1499 VCS_INFO_git_getaction () { #{{{
1500     local gitaction='' gitdir=$1
1501     local tmp
1502
1503     for tmp in "${gitdir}/rebase-apply" \
1504                "${gitdir}/rebase"       \
1505                "${gitdir}/../.dotest" ; do
1506         if [[ -d ${tmp} ]] ; then
1507             if   [[ -f "${tmp}/rebasing" ]] ; then
1508                 gitaction="rebase"
1509             elif [[ -f "${tmp}/applying" ]] ; then
1510                 gitaction="am"
1511             else
1512                 gitaction="am/rebase"
1513             fi
1514             printf '%s' ${gitaction}
1515             return 0
1516         fi
1517     done
1518
1519     for tmp in "${gitdir}/rebase-merge/interactive" \
1520                "${gitdir}/.dotest-merge/interactive" ; do
1521         if [[ -f "${tmp}" ]] ; then
1522             printf '%s' "rebase-i"
1523             return 0
1524         fi
1525     done
1526
1527     for tmp in "${gitdir}/rebase-merge" \
1528                "${gitdir}/.dotest-merge" ; do
1529         if [[ -d "${tmp}" ]] ; then
1530             printf '%s' "rebase-m"
1531             return 0
1532         fi
1533     done
1534
1535     if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1536         printf '%s' "merge"
1537         return 0
1538     fi
1539
1540     if [[ -f "${gitdir}/BISECT_LOG" ]] ; then
1541         printf '%s' "bisect"
1542         return 0
1543     fi
1544     return 1
1545 }
1546 # }}}
1547 VCS_INFO_git_getbranch () { #{{{
1548     local gitbranch gitdir=$1
1549     local gitsymref='git symbolic-ref HEAD'
1550
1551     if    [[ -d "${gitdir}/rebase-apply" ]] \
1552        || [[ -d "${gitdir}/rebase" ]]       \
1553        || [[ -d "${gitdir}/../.dotest" ]]   \
1554        || [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1555         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1556         [[ -z ${gitbranch} ]] && [[ -r ${gitdir}/rebase-apply/head-name ]] \
1557             && gitbranch="$(< ${gitdir}/rebase-apply/head-name)"
1558
1559     elif   [[ -f "${gitdir}/rebase-merge/interactive" ]] \
1560         || [[ -d "${gitdir}/rebase-merge" ]] ; then
1561         gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
1562
1563     elif   [[ -f "${gitdir}/.dotest-merge/interactive" ]] \
1564         || [[ -d "${gitdir}/.dotest-merge" ]] ; then
1565         gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
1566
1567     else
1568         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1569
1570         if [[ $? -ne 0 ]] ; then
1571             gitbranch="$(git describe --exact-match HEAD 2>/dev/null)"
1572
1573             if [[ $? -ne 0 ]] ; then
1574                 gitbranch="${${"$(< $gitdir/HEAD)"}[1,7]}..."
1575             fi
1576         fi
1577     fi
1578
1579     printf '%s' "${gitbranch##refs/heads/}"
1580     return 0
1581 }
1582 # }}}
1583 VCS_INFO_git_get_data () { # {{{
1584     setopt localoptions extendedglob
1585     local gitdir gitbase gitbranch gitaction
1586
1587     gitdir=${vcs_comm[gitdir]}
1588     gitbranch="$(VCS_INFO_git_getbranch ${gitdir})"
1589
1590     if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then
1591         return 1
1592     fi
1593
1594     VCS_INFO_adjust
1595     gitaction="$(VCS_INFO_git_getaction ${gitdir})"
1596     gitbase=${PWD%/${$( git rev-parse --show-prefix )%/##}}
1597     VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}"
1598     return 0
1599 }
1600 # }}}
1601 VCS_INFO_hg_get_data () { # {{{
1602     local hgbranch hgbase
1603
1604     hgbase=${vcs_comm[basedir]}
1605     hgbranch=$(< ${hgbase}/.hg/branch)
1606     VCS_INFO_formats '' "${hgbranch}" "${hgbase}"
1607     return 0
1608 }
1609 # }}}
1610 VCS_INFO_mtn_get_data () { # {{{
1611     local mtnbranch mtnbase
1612
1613     mtnbase=${vcs_comm[basedir]}
1614     mtnbranch=${${(M)${(f)"$( mtn status )"}:#(#s)Current branch:*}/*: /}
1615     VCS_INFO_formats '' "${mtnbranch}" "${mtnbase}"
1616     return 0
1617 }
1618 # }}}
1619 VCS_INFO_svk_get_data () { # {{{
1620     local svkbranch svkbase
1621
1622     svkbase=${vcs_comm[basedir]}
1623     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svkbranch || svkbranch="%b:%r"
1624     zformat -f svkbranch "${svkbranch}" "b:${vcs_comm[branch]}" "r:${vcs_comm[revision]}"
1625     VCS_INFO_formats '' "${svkbranch}" "${svkbase}"
1626     return 0
1627 }
1628 # }}}
1629 VCS_INFO_svn_get_data () { # {{{
1630     setopt localoptions noksharrays
1631     local svnbase svnbranch
1632     local -a svninfo
1633
1634     svnbase="."
1635     while [[ -d "${svnbase}/../.svn" ]]; do
1636         svnbase="${svnbase}/.."
1637     done
1638     svnbase="$(VCS_INFO_realpath ${svnbase})"
1639     svninfo=( ${${${(M)${(f)"$( svn info )"}:#(#s)(URL|Revision)*}/*: /}/*\//} )
1640
1641     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svnbranch || svnbranch="%b:%r"
1642     zformat -f svnbranch "${svnbranch}" "b:${svninfo[1]}" "r:${svninfo[2]}"
1643     VCS_INFO_formats '' "${svnbranch}" "${svnbase}"
1644     return 0
1645 }
1646 # }}}
1647 VCS_INFO_tla_get_data () { # {{{
1648     local tlabase tlabranch
1649
1650     tlabase="$(VCS_INFO_realpath ${vcs_comm[basedir]})"
1651     # tree-id gives us something like 'foo@example.com/demo--1.0--patch-4', so:
1652     tlabranch=${${"$( tla tree-id )"}/*\//}
1653     VCS_INFO_formats '' "${tlabranch}" "${tlabase}"
1654     return 0
1655 }
1656 # }}}
1657 # detection
1658 VCS_INFO_detect_by_dir() { #{{{
1659     local dirname=$1
1660     local basedir="." realbasedir
1661
1662     realbasedir="$(VCS_INFO_realpath ${basedir})"
1663     while [[ ${realbasedir} != '/' ]]; do
1664         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
1665             [[ -d ${basedir}/${dirname} ]] && \
1666             [[ -f ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
1667                 break
1668         else
1669             [[ -d ${basedir}/${dirname} ]] && break
1670         fi
1671
1672         basedir=${basedir}/..
1673         realbasedir="$(VCS_INFO_realpath ${basedir})"
1674     done
1675
1676     [[ ${realbasedir} == "/" ]] && return 1
1677     vcs_comm[basedir]=${realbasedir}
1678     return 0
1679 }
1680 # }}}
1681 VCS_INFO_bzr_detect() { #{{{
1682     VCS_INFO_check_com bzr || return 1
1683     vcs_comm[detect_need_file]=branch/format
1684     VCS_INFO_detect_by_dir '.bzr'
1685     return $?
1686 }
1687 # }}}
1688 VCS_INFO_cdv_detect() { #{{{
1689     VCS_INFO_check_com cdv || return 1
1690     vcs_comm[detect_need_file]=format
1691     VCS_INFO_detect_by_dir '.cdv'
1692     return $?
1693 }
1694 # }}}
1695 VCS_INFO_cvs_detect() { #{{{
1696     VCS_INFO_check_com svn || return 1
1697     [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
1698     return 1
1699 }
1700 # }}}
1701 VCS_INFO_darcs_detect() { #{{{
1702     VCS_INFO_check_com darcs || return 1
1703     vcs_comm[detect_need_file]=format
1704     VCS_INFO_detect_by_dir '_darcs'
1705     return $?
1706 }
1707 # }}}
1708 VCS_INFO_git_detect() { #{{{
1709     if VCS_INFO_check_com git && git rev-parse --is-inside-work-tree &> /dev/null ; then
1710         vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
1711         if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
1712         elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
1713         return 0
1714     fi
1715     return 1
1716 }
1717 # }}}
1718 VCS_INFO_hg_detect() { #{{{
1719     VCS_INFO_check_com hg || return 1
1720     vcs_comm[detect_need_file]=branch
1721     VCS_INFO_detect_by_dir '.hg'
1722     return $?
1723 }
1724 # }}}
1725 VCS_INFO_mtn_detect() { #{{{
1726     VCS_INFO_check_com mtn || return 1
1727     vcs_comm[detect_need_file]=revision
1728     VCS_INFO_detect_by_dir '_MTN'
1729     return $?
1730 }
1731 # }}}
1732 VCS_INFO_svk_detect() { #{{{
1733     setopt localoptions noksharrays extendedglob
1734     local -a info
1735     local -i fhash
1736     fhash=0
1737
1738     VCS_INFO_check_com svk || return 1
1739     [[ -f ~/.svk/config ]] || return 1
1740
1741     # This detection function is a bit different from the others.
1742     # We need to read svk's config file to detect a svk repository
1743     # in the first place. Therefore, we'll just proceed and read
1744     # the other information, too. This is more then any of the
1745     # other detections do but this takes only one file open for
1746     # svk at most. VCS_INFO_svk_get_data() get simpler, too. :-)
1747     while IFS= read -r line ; do
1748         if [[ -n ${vcs_comm[basedir]} ]] ; then
1749             line=${line## ##}
1750             [[ ${line} == depotpath:* ]] && vcs_comm[branch]=${line##*/}
1751             [[ ${line} == revision:* ]] && vcs_comm[revision]=${line##*[[:space:]]##}
1752             [[ -n ${vcs_comm[branch]} ]] && [[ -n ${vcs_comm[revision]} ]] && break
1753             continue
1754         fi
1755         (( fhash > 0 )) && [[ ${line} == '  '[^[:space:]]*:* ]] && break
1756         [[ ${line} == '  hash:'* ]] && fhash=1 && continue
1757         (( fhash == 0 )) && continue
1758         [[ ${PWD}/ == ${${line## ##}%:*}/* ]] && vcs_comm[basedir]=${${line## ##}%:*}
1759     done < ~/.svk/config
1760
1761     [[ -n ${vcs_comm[basedir]} ]]  && \
1762     [[ -n ${vcs_comm[branch]} ]]   && \
1763     [[ -n ${vcs_comm[revision]} ]] && return 0
1764     return 1
1765 }
1766 # }}}
1767 VCS_INFO_svn_detect() { #{{{
1768     VCS_INFO_check_com svn || return 1
1769     [[ -d ".svn" ]] && return 0
1770     return 1
1771 }
1772 # }}}
1773 VCS_INFO_tla_detect() { #{{{
1774     VCS_INFO_check_com tla || return 1
1775     vcs_comm[basedir]="$(tla tree-root 2> /dev/null)" && return 0
1776     return 1
1777 }
1778 # }}}
1779 # public API
1780 vcs_info_printsys () { # {{{
1781     vcs_info print_systems_
1782 }
1783 # }}}
1784 vcs_info_lastmsg () { # {{{
1785     local -i i
1786
1787     VCS_INFO_maxexports
1788     for i in {0..$((maxexports - 1))} ; do
1789         printf '$VCS_INFO_message_%d_: "' $i
1790         if zstyle -T ':vcs_info:formats:command' use-prompt-escapes ; then
1791             print -nP ${(P)${:-VCS_INFO_message_${i}_}}
1792         else
1793             print -n ${(P)${:-VCS_INFO_message_${i}_}}
1794         fi
1795         printf '"\n'
1796     done
1797 }
1798 # }}}
1799 vcs_info () { # {{{
1800     local -i found
1801     local -a VCSs disabled
1802     local -x vcs usercontext
1803     local -ax msgs
1804     local -Ax vcs_comm
1805
1806     vcs="init"
1807     VCSs=(git hg bzr darcs svk mtn svn cvs cdv tla)
1808     case $1 in
1809         (print_systems_)
1810             zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1811             print -l '# list of supported version control backends:' \
1812                      '# disabled systems are prefixed by a hash sign (#)'
1813             for vcs in ${VCSs} ; do
1814                 [[ -n ${(M)disabled:#${vcs}} ]] && printf '#'
1815                 printf '%s\n' ${vcs}
1816             done
1817             print -l '# flavours (cannot be used in the disable style; they' \
1818                      '# are disabled with their master [git-svn -> git]):'   \
1819                      git-{p4,svn}
1820             return 0
1821             ;;
1822         ('')
1823             [[ -z ${usercontext} ]] && usercontext=default
1824             ;;
1825         (*) [[ -z ${usercontext} ]] && usercontext=$1
1826             ;;
1827     esac
1828
1829     zstyle -T ":vcs_info:${vcs}:${usercontext}" "enable" || {
1830         [[ -n ${VCS_INFO_message_0_} ]] && VCS_INFO_set --clear
1831         return 0
1832     }
1833     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1834     VCS_INFO_maxexports
1835
1836     (( found = 0 ))
1837     for vcs in ${VCSs} ; do
1838         [[ -n ${(M)disabled:#${vcs}} ]] && continue
1839         vcs_comm=()
1840         VCS_INFO_${vcs}_detect && (( found = 1 )) && break
1841     done
1842
1843     (( found == 0 )) && {
1844         VCS_INFO_set --nvcs
1845         return 0
1846     }
1847
1848     VCS_INFO_${vcs}_get_data || {
1849         VCS_INFO_set --nvcs
1850         return 1
1851     }
1852
1853     VCS_INFO_set
1854     return 0
1855 }
1856
1857 VCS_INFO_set --nvcs preinit
1858 # }}}
1859
1860 # change vcs_info formats for the grml prompt
1861 if [[ "$TERM" == dumb ]] ; then
1862     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] "
1863     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "
1864 else
1865     # these are the same, just with a lot of colours:
1866     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} "
1867     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} "
1868     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1869 fi
1870
1871 # }}}
1872
1873 # {{{ set prompt
1874 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1875     promptinit # people should be able to use their favourite prompt
1876 else
1877     print 'Notice: no promptinit available :('
1878 fi
1879
1880 setopt prompt_subst
1881
1882 # make sure to use right prompt only when not running a command
1883 is41 && setopt transient_rprompt
1884
1885 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1886     [[ $NOPRECMD -gt 0 ]] && return 0
1887     # update VCS information
1888     vcs_info
1889
1890     # allow manual overwriting of RPROMPT
1891     if [[ -n $RPROMPT ]] ; then
1892         [[ $TERM == screen* ]] && print -nP "\ekzsh\e\\"
1893         # return 0
1894     fi
1895     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1896     if [[ $DONTSETRPROMPT -eq 0 ]] ; then
1897         if [[ $BATTERY -gt 0 ]] ; then
1898             # update BATTERY information
1899             battery
1900             RPROMPT="%(?..:()% ${PERCENT}${SCREENTITLE}"
1901             # RPROMPT="${PERCENT}${SCREENTITLE}"
1902         else
1903             RPROMPT="%(?..:()% ${SCREENTITLE}"
1904             # RPROMPT="${SCREENTITLE}"
1905         fi
1906     fi
1907     # adjust title of xterm
1908     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1909     case $TERM in
1910         (xterm*|rxvt)
1911             print -Pn "\e]0;%n@%m: %~\a"
1912             ;;
1913     esac
1914 }
1915
1916 # preexec() => a function running before every command
1917 is4 && [[ $NOPRECMD -eq 0 ]] && \
1918 preexec () {
1919     [[ $NOPRECMD -gt 0 ]] && return 0
1920 # set hostname if not running on host with name 'grml'
1921     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1922        NAME="@$HOSTNAME"
1923     fi
1924 # get the name of the program currently running and hostname of local machine
1925 # set screen window title if running in a screen
1926     if [[ "$TERM" == screen* ]] ; then
1927         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1928         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1929         echo -ne "\ek$CMD\e\\"
1930     fi
1931 # set the screen title to "zsh" when sitting at the command prompt:
1932     if [[ "$TERM" == screen* ]] ; then
1933         SCREENTITLE=$'%{\ekzsh\e\\%}'
1934     else
1935         SCREENTITLE=''
1936     fi
1937 # adjust title of xterm
1938     case $TERM in
1939         (xterm*|rxvt)
1940             print -Pn "\e]0;%n@%m: $1\a"
1941             ;;
1942     esac
1943 }
1944
1945 EXITCODE="%(?..%?%1v )"
1946 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
1947 PS3='?# '         # selection prompt used within a select loop.
1948 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1949
1950 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1951 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1952     debian_chroot=$(cat /etc/debian_chroot)
1953 fi
1954
1955 # don't use colors on dumb terminals (like emacs):
1956 if [[ "$TERM" == dumb ]] ; then
1957     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1958 else
1959     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
1960     # set variable identifying the chroot you work in (used in the prompt below)
1961     if [[ $GRMLPROMPT -gt 0 ]] ; then
1962         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1963 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< %# "
1964     else
1965         # This assembles the primary prompt string
1966         if (( EUID != 0 )); then
1967             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1968         else
1969             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
1970         fi
1971     fi
1972 fi
1973
1974 # if we are inside a grml-chroot set a specific prompt theme
1975 if [[ -n "$GRML_CHROOT" ]] ; then
1976     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1977 fi
1978 # }}}
1979
1980 # {{{ 'hash' some often used directories
1981 #d# start
1982 hash -d deb=/var/cache/apt/archives
1983 hash -d doc=/usr/share/doc
1984 hash -d linux=/lib/modules/$(command uname -r)/build/
1985 hash -d log=/var/log
1986 hash -d slog=/var/log/syslog
1987 hash -d src=/usr/src
1988 hash -d templ=/usr/share/doc/grml-templates
1989 hash -d tt=/usr/share/doc/texttools-doc
1990 hash -d www=/var/www
1991 #d# end
1992 # }}}
1993
1994 # {{{ some aliases
1995 if [[ $UID -eq 0 ]] ; then
1996     [[ -r /etc/grml/screenrc ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc'
1997 elif [[ -r $HOME/.screenrc ]] ; then
1998     alias screen="/usr/bin/screen -c $HOME/.screenrc"
1999 else
2000     [[ -r /etc/grml/screenrc_grml ]] && alias screen='/usr/bin/screen -c /etc/grml/screenrc_grml'
2001 fi
2002
2003 # do we have GNU ls with color-support?
2004 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
2005     #a1# execute \kbd{@a@}:\quad ls with colors
2006     alias ls='ls -b -CF --color=auto'
2007     #a1# execute \kbd{@a@}:\quad list all files, with colors
2008     alias la='ls -la --color=auto'
2009     #a1# long colored list, without dotfiles (@a@)
2010     alias ll='ls -l --color=auto'
2011     #a1# long colored list, human readable sizes (@a@)
2012     alias lh='ls -hAl --color=auto'
2013     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2014     alias l='ls -lF --color=auto'
2015 else
2016     alias ls='ls -b -CF'
2017     alias la='ls -la'
2018     alias ll='ls -l'
2019     alias lh='ls -hAl'
2020     alias l='ls -lF'
2021 fi
2022
2023 alias mdstat='cat /proc/mdstat'
2024 alias ...='cd ../../'
2025
2026 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2027 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2028     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2029 fi
2030
2031 alias cp='nocorrect cp'         # no spelling correction on cp
2032 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
2033 alias mv='nocorrect mv'         # no spelling correction on mv
2034 alias rm='nocorrect rm'         # no spelling correction on rm
2035
2036 #a1# Execute \kbd{rmdir}
2037 alias rd='rmdir'
2038 #a1# Execute \kbd{rmdir}
2039 alias md='mkdir'
2040
2041 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2042 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2043 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2044
2045 # make sure it is not assigned yet
2046 [[ $(whence -w utf2iso &>/dev/null) == 'utf2iso: alias' ]] && unalias utf2iso
2047
2048 utf2iso() {
2049     if isutfenv ; then
2050         for ENV in $(env | command grep -i '.utf') ; do
2051             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2052         done
2053     fi
2054 }
2055
2056 # make sure it is not assigned yet
2057 [[ $(whence -w iso2utf &>/dev/null) == 'iso2utf: alias' ]] && unalias iso2utf
2058 iso2utf() {
2059     if ! isutfenv ; then
2060         for ENV in $(env | command grep -i '\.iso') ; do
2061             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2062         done
2063     fi
2064 }
2065
2066 # set up software synthesizer via speakup
2067 swspeak() {
2068     if [ -x /usr/sbin/swspeak-setup ] ; then
2069        setopt singlelinezle
2070        unsetopt prompt_cr
2071        export PS1="%m%# "
2072        /usr/sbin/swspeak-setup $@
2073      else # old version:
2074         aumix -w 90 -v 90 -p 90 -m 90
2075         if ! [[ -r /dev/softsynth ]] ; then
2076             flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
2077             return 1
2078         else
2079            setopt singlelinezle
2080            unsetopt prompt_cr
2081            export PS1="%m%# "
2082             nice -n -20 speechd-up
2083             sleep 2
2084             flite -o play -t "Finished setting up software synthesizer"
2085         fi
2086      fi
2087 }
2088
2089 # I like clean prompt, so provide simple way to get that
2090 check_com 0 || alias 0='return 0'
2091
2092 # for really lazy people like mika:
2093 check_com S &>/dev/null || alias S='screen'
2094 check_com s &>/dev/null || alias s='ssh'
2095
2096 # get top 10 shell commands:
2097 alias top10='print -l ? ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
2098
2099 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
2100 if check_com -c truecrypt ; then
2101     if isutfenv ; then
2102         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
2103     else
2104         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
2105     fi
2106 fi
2107
2108 #f1# Hints for the use of zsh on grml
2109 zsh-help() {
2110     print "$bg[white]$fg[black]
2111 zsh-help - hints for use of zsh on grml
2112 =======================================$reset_color"
2113
2114     print '
2115 Main configuration of zsh happens in /etc/zsh/zshrc.
2116 That file is part of the package grml-etc-core, if you want to
2117 use them on a non-grml-system just get the tar.gz from
2118 http://deb.grml.org/ or (preferably) get it from the git repository:
2119
2120   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2121
2122 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2123 The file is still there, but it is empty for backwards compatibility.
2124
2125 For your own changes use these two files:
2126     $HOME/.zshrc.pre
2127     $HOME/.zshrc.local
2128
2129 The former is sourced very early in our zshrc, the latter is sourced
2130 very lately.
2131
2132 System wide configuration without touching configuration files of grml
2133 can take place in /etc/zsh/zshrc.local.
2134
2135 Normally, the root user (EUID == 0) does not get the whole grml setup.
2136 If you want to force the whole setup for that user, too, set
2137 GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
2138
2139 For information regarding zsh start at http://grml.org/zsh/
2140
2141 Take a look at grml'\''s zsh refcard:
2142 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2143
2144 Check out the main zsh refcard:
2145 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2146
2147 And of course visit the zsh-lovers:
2148 % man zsh-lovers
2149
2150 You can adjust some options through environment variables when
2151 invoking zsh without having to edit configuration files.
2152 Basically meant for bash users who are not used to the power of
2153 the zsh yet. :)
2154
2155   "NOCOR=1    zsh" => deactivate automatic correction
2156   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
2157   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2158   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
2159
2160 A value greater than 0 is enables a feature; a value equal to zero
2161 disables it. If you like one or the other of these settings, you can
2162 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2163 zshrc.'
2164
2165     print "
2166 $bg[white]$fg[black]
2167 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2168 Enjoy your grml system with the zsh!$reset_color"
2169 }
2170
2171 # debian stuff
2172 if [[ -r /etc/debian_version ]] ; then
2173     #a3# Execute \kbd{apt-cache search}
2174     alias acs='apt-cache search'
2175     #a3# Execute \kbd{apt-cache show}
2176     alias acsh='apt-cache show'
2177     #a3# Execute \kbd{apt-cache policy}
2178     alias acp='apt-cache policy'
2179     #a3# Execute \kbd{apt-get dist-upgrade}
2180     salias adg="apt-get dist-upgrade"
2181     #a3# Execute \kbd{apt-get install}
2182     salias agi="apt-get install"
2183     #a3# Execute \kbd{aptitude install}
2184     salias ati="aptitude install"
2185     #a3# Execute \kbd{apt-get upgrade}
2186     salias ag="apt-get upgrade"
2187     #a3# Execute \kbd{apt-get update}
2188     salias au="apt-get update"
2189     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2190     salias -a up="aptitude update ; aptitude safe-upgrade"
2191     #a3# Execute \kbd{dpkg-buildpackage}
2192     alias dbp='dpkg-buildpackage'
2193     #a3# Execute \kbd{grep-excuses}
2194     alias ge='grep-excuses'
2195
2196     # debian upgrade
2197     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
2198     upgrade() {
2199         if [[ -z "$1" ]] ; then
2200             $SUDO apt-get update
2201             $SUDO apt-get -u upgrade
2202         else
2203             ssh $1 $SUDO apt-get update
2204             # ask before the upgrade
2205             local dummy
2206             ssh $1 $SUDO apt-get --no-act upgrade
2207             echo -n 'Process the upgrade?'
2208             read -q dummy
2209             if [[ $dummy == "y" ]] ; then
2210                 ssh $1 $SUDO apt-get -u upgrade --yes
2211             fi
2212         fi
2213     }
2214
2215     # get a root shell as normal user in live-cd mode:
2216     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2217        alias su="sudo su"
2218      fi
2219
2220     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2221     alias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2222     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2223     alias tlog="tail -f /var/log/syslog"    # follow the syslog
2224     #a1# (Re)-source \kbd{/etc/skel/.zshrc}
2225     alias zshskel="source /etc/skel/.zshrc" # source skeleton zshrc
2226 fi
2227
2228 # sort installed Debian-packages by size
2229 if check_com -c grep-status ; then
2230     #a3# List installed Debian-packages sorted by size
2231     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
2232 fi
2233
2234 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2235 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord ; then
2236     if check_com -c wodim ; then
2237         alias cdrecord="echo 'cdrecord is not provided under its original name by Debian anymore.
2238 See #377109 in the BTS of Debian for more details.
2239
2240 Please use the wodim binary instead' ; return 1"
2241     fi
2242 fi
2243
2244 # get_tw_cli has been renamed into get_3ware
2245 if check_com -c get_3ware ; then
2246     get_tw_cli() {
2247         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
2248         get_3ware
2249     }
2250 fi
2251
2252 # I hate lacking backward compatibility, so provide an alternative therefore
2253 if ! check_com -c apache2-ssl-certificate ; then
2254
2255     apache2-ssl-certificate() {
2256
2257     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
2258     print 'You might want to take a look at Debian the package ssl-cert as well.'
2259     print 'To generate a certificate for use with apache2 follow the instructions:'
2260
2261     echo '
2262
2263 export RANDFILE=/dev/random
2264 mkdir /etc/apache2/ssl/
2265 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
2266 chmod 600 /etc/apache2/ssl/apache.pem
2267
2268 Run "grml-tips ssl-certificate" if you need further instructions.
2269 '
2270     }
2271 fi
2272 # }}}
2273
2274 # {{{ Use hard limits, except for a smaller stack and no core dumps
2275 unlimit
2276 is425 && limit stack 8192
2277 isgrmlcd && limit core 0 # important for a live-cd-system
2278 limit -s
2279 # }}}
2280
2281 # {{{ completion system
2282
2283 # called later (via is4 && grmlcomp)
2284 # notice: use 'zstyle' for getting current settings
2285 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
2286 grmlcomp() {
2287     # TODO: This could use some additional information
2288
2289     # allow one error for every three characters typed in approximate completer
2290     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
2291
2292     # don't complete backup files as executables
2293     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
2294
2295     # start menu completion only if it could find no unambiguous initial string
2296     zstyle ':completion:*:correct:*'       insert-unambiguous true
2297     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
2298     zstyle ':completion:*:correct:*'       original true
2299
2300     # activate color-completion
2301     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
2302
2303     # format on completion
2304     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
2305
2306     # complete 'cd -<tab>' with menu
2307     zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
2308
2309     # insert all expansions for expand completer
2310     zstyle ':completion:*:expand:*'        tag-order all-expansions
2311     zstyle ':completion:*:history-words'   list false
2312
2313     # activate menu
2314     zstyle ':completion:*:history-words'   menu yes
2315
2316     # ignore duplicate entries
2317     zstyle ':completion:*:history-words'   remove-all-dups yes
2318     zstyle ':completion:*:history-words'   stop yes
2319
2320     # match uppercase from lowercase
2321     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
2322
2323     # separate matches into groups
2324     zstyle ':completion:*:matches'         group 'yes'
2325     zstyle ':completion:*'                 group-name ''
2326
2327     if [[ "$NOMENU" -eq 0 ]] ; then
2328         # if there are more than 5 options allow selecting from a menu
2329         zstyle ':completion:*'               menu select=5
2330     else
2331         # don't use any menus at all
2332         setopt no_auto_menu
2333     fi
2334
2335     zstyle ':completion:*:messages'        format '%d'
2336     zstyle ':completion:*:options'         auto-description '%d'
2337
2338     # describe options in full
2339     zstyle ':completion:*:options'         description 'yes'
2340
2341     # on processes completion complete all user processes
2342     zstyle ':completion:*:processes'       command 'ps -au$USER'
2343
2344     # offer indexes before parameters in subscripts
2345     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
2346
2347     # provide verbose completion information
2348     zstyle ':completion:*'                 verbose true
2349
2350     # recent (as of Dec 2007) zsh versions are able to provide descriptions
2351     # for commands (read: 1st word in the line) that it will list for the user
2352     # to choose from. The following disables that, because it's not exactly fast.
2353     zstyle ':completion:*:-command-:*:'    verbose false
2354
2355     # set format for warnings
2356     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
2357
2358     # define files to ignore for zcompile
2359     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
2360     zstyle ':completion:correct:'          prompt 'correct to: %e'
2361
2362     # Ignore completion functions for commands you don't have:
2363     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
2364
2365     # Provide more processes in completion of programs like killall:
2366     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
2367
2368     # complete manual by their section
2369     zstyle ':completion:*:manuals'    separate-sections true
2370     zstyle ':completion:*:manuals.*'  insert-sections   true
2371     zstyle ':completion:*:man:*'      menu yes select
2372
2373     # run rehash on completion so new installed program are found automatically:
2374     _force_rehash() {
2375         (( CURRENT == 1 )) && rehash
2376         return 1
2377     }
2378
2379     ## correction
2380     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
2381     if [[ "$NOCOR" -gt 0 ]] ; then
2382         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
2383         setopt nocorrect
2384     else
2385         # try to be smart about when to use what completer...
2386         setopt correct
2387         zstyle -e ':completion:*' completer '
2388             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
2389                 _last_try="$HISTNO$BUFFER$CURSOR"
2390                 reply=(_complete _match _ignored _prefix _files)
2391             else
2392                 if [[ $words[1] == (rm|mv) ]] ; then
2393                     reply=(_complete _files)
2394                 else
2395                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
2396                 fi
2397             fi'
2398     fi
2399
2400     # zstyle ':completion:*' completer _complete _correct _approximate
2401     # zstyle ':completion:*' expand prefix suffix
2402
2403     # complete shell aliases
2404     # zstyle ':completion:*' completer _expand_alias _complete _approximate
2405
2406     # command for process lists, the local web server details and host completion
2407     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
2408
2409     # caching
2410     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
2411                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
2412
2413     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
2414     if is42 ; then
2415         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
2416         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
2417     else
2418         _ssh_hosts=()
2419         _etc_hosts=()
2420     fi
2421     hosts=(
2422         $(hostname)
2423         "$_ssh_hosts[@]"
2424         "$_etc_hosts[@]"
2425         grml.org
2426         localhost
2427     )
2428     zstyle ':completion:*:hosts' hosts $hosts
2429     #  zstyle '*' hosts $hosts
2430
2431     # specify your logins:
2432     # my_accounts=(
2433     #  {grml,grml1}@foo.invalid
2434     #  grml-devel@bar.invalid
2435     # )
2436     # other_accounts=(
2437     #  {fred,root}@foo.invalid
2438     #  vera@bar.invalid
2439     # )
2440     # zstyle ':completion:*:my-accounts' users-hosts $my_accounts
2441     # zstyle ':completion:*:other-accounts' users-hosts $other_accounts
2442
2443     # specify specific port/service settings:
2444     #  telnet_users_hosts_ports=(
2445     #    user1@host1:
2446     #    user2@host2:
2447     #    @mail-server:{smtp,pop3}
2448     #    @news-server:nntp
2449     #    @proxy-server:8000
2450     #  )
2451     # zstyle ':completion:*:*:telnet:*' users-hosts-ports $telnet_users_hosts_ports
2452
2453     # use generic completion system for programs not yet defined; (_gnu_generic works
2454     # with commands that provide a --help option with "standard" gnu-like output.)
2455     compdef _gnu_generic tail head feh cp mv df stow uname ipacsum fetchipac
2456
2457     # see upgrade function in this file
2458     compdef _hosts upgrade
2459 }
2460 # }}}
2461
2462 # {{{ grmlstuff
2463 grmlstuff() {
2464 # people should use 'grml-x'!
2465     startx() {
2466         if [[ -e /etc/X11/xorg.conf ]] ; then
2467             [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
2468         else
2469             echo "Please use the script \"grml-x\" for starting the X Window System
2470 because there does not exist /etc/X11/xorg.conf yet.
2471 If you want to use startx anyway please call \"/usr/bin/startx\"."
2472             return -1
2473         fi
2474     }
2475
2476     xinit() {
2477         if [[ -e /etc/X11/xorg.conf ]] ; then
2478             [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
2479         else
2480             echo "Please use the script \"grml-x\" for starting the X Window System.
2481 because there does not exist /etc/X11/xorg.conf yet.
2482 If you want to use xinit anyway please call \"/usr/bin/xinit\"."
2483             return -1
2484         fi
2485     }
2486
2487     if check_com -c 915resolution ; then
2488         alias 855resolution='echo -e "Please use 915resolution as resolution modify tool for Intel graphic chipset."; return -1'
2489     fi
2490
2491     #a1# Output version of running grml
2492     alias grml-version='cat /etc/grml_version'
2493
2494     if check_com -c rebuildfstab ; then
2495         #a1# Rebuild /etc/fstab
2496         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2497     fi
2498
2499     if check_com -c grml-debootstrap ; then
2500         alias debian2hd='print "Installing debian to harddisk is possible via using grml-debootstrap." ; return 1'
2501     fi
2502 }
2503 # }}}
2504
2505 # {{{ now run the functions
2506 isgrml && checkhome
2507 is4    && isgrml    && grmlstuff
2508 is4    && grmlcomp
2509 # }}}
2510
2511 # {{{ keephack
2512 is4 && xsource "/etc/zsh/keephack"
2513 # }}}
2514
2515 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2516 # You use it as follows:
2517 # $ NTREF=/reference/file
2518 # $ ls -l *(e:nt:)
2519 # This lists all the files in the current directory newer than the reference file.
2520 # You can also specify the reference file inline; note quotes:
2521 # $ ls -l *(e:'nt ~/.zshenv':)
2522 is4 && nt() {
2523     if [[ -n $1 ]] ; then
2524         local NTREF=${~1}
2525     fi
2526     [[ $REPLY -nt $NTREF ]]
2527 }
2528 # }}}
2529
2530 # shell functions {{{
2531
2532 #f1# Provide csh compatibility
2533 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2534
2535 #f1# Reload an autoloadable function
2536 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2537
2538 #f1# Reload zsh setup
2539 reload() {
2540     if [[ "$#*" -eq 0 ]] ; then
2541         [[ -r ~/.zshrc ]] && . ~/.zshrc
2542     else
2543         local fn
2544         for fn in "$@"; do
2545             unfunction $fn
2546             autoload -U $fn
2547         done
2548     fi
2549 }
2550 compdef _functions reload freload
2551
2552 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2553 sll() {
2554     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2555     for i in "$@" ; do
2556         file=$i
2557         while [[ -h "$file" ]] ; do
2558             ls -l $file
2559             file=$(readlink "$file")
2560         done
2561     done
2562 }
2563
2564 # fast manual access
2565 if check_com qma ; then
2566     #f1# View the zsh manual
2567     manzsh()  { qma zshall "$1" }
2568     compdef _man qma
2569 else
2570     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2571     # manzsh()  { /usr/bin/man zshall |  most +/"$1" ; }
2572     # [[ -f ~/.terminfo/m/mostlike ]] && MYLESS='LESS=C TERMINFO=~/.terminfo TERM=mostlike less' || MYLESS='less'
2573     # manzsh()  { man zshall | $MYLESS -p $1 ; }
2574 fi
2575
2576 if check_com -c $PAGER ; then
2577     #f1# View Debian's changelog of a given package
2578     dchange() {
2579         if [[ -r /usr/share/doc/${1}/changelog.Debian.gz ]] ; then
2580             $PAGER /usr/share/doc/${1}/changelog.Debian.gz
2581         elif [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2582             $PAGER /usr/share/doc/${1}/changelog.gz
2583         else
2584             if check_com -c aptitude ; then
2585                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2586                 if isgrml ; then
2587                     aptitude -t unstable changelog ${1}
2588                 else
2589                     aptitude changelog ${1}
2590                 fi
2591             else
2592                 echo "No changelog for package $1 found, sorry."
2593                 return 1
2594             fi
2595         fi
2596     }
2597     _dchange() { _files -W /usr/share/doc -/ }
2598     compdef _dchange dchange
2599
2600     #f1# View Debian's NEWS of a given package
2601     dnews() {
2602         if [[ -r /usr/share/doc/${1}/NEWS.Debian.gz ]] ; then
2603             $PAGER /usr/share/doc/${1}/NEWS.Debian.gz
2604         else
2605             if [[ -r /usr/share/doc/${1}/NEWS.gz ]] ; then
2606                 $PAGER /usr/share/doc/${1}/NEWS.gz
2607             else
2608                 echo "No NEWS file for package $1 found, sorry."
2609                 return 1
2610             fi
2611         fi
2612     }
2613     _dnews() { _files -W /usr/share/doc -/ }
2614     compdef _dnews dnews
2615
2616     #f1# View upstream's changelog of a given package
2617     uchange() {
2618         if [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2619             $PAGER /usr/share/doc/${1}/changelog.gz
2620         else
2621             echo "No changelog for package $1 found, sorry."
2622             return 1
2623         fi
2624     }
2625     _uchange() { _files -W /usr/share/doc -/ }
2626     compdef _uchange uchange
2627 fi
2628
2629 # zsh profiling
2630 profile() {
2631     ZSH_PROFILE_RC=1 $SHELL "$@"
2632 }
2633
2634 #f1# Edit an alias via zle
2635 edalias() {
2636     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2637 }
2638 compdef _aliases edalias
2639
2640 #f1# Edit a function via zle
2641 edfunc() {
2642     [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
2643 }
2644 compdef _functions edfunc
2645
2646 # use it e.g. via 'Restart apache2'
2647 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2648 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2649 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2650 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2651 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2652 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2653     __start_stop() {
2654         local action_="${1:l}"  # e.g Start/Stop/Restart
2655         local service_="$2"
2656         local param_="$3"
2657
2658         local service_target_="$(readlink /etc/init.d/$service_)"
2659         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2660             # runit
2661             case "${action_}" in
2662                 start) if [[ ! -e /etc/service/$service_ ]]; then
2663                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2664                        else
2665                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2666                        fi ;;
2667                 # there is no reload in runits sysv emulation
2668                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2669                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2670             esac
2671         else
2672             # sysvinit
2673             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2674         fi
2675     }
2676
2677     for i in Start Restart Stop Force-Reload Reload ; do
2678         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2679     done
2680 fi
2681
2682 #f1# Provides useful information on globbing
2683 H-Glob() {
2684     echo -e "
2685     /      directories
2686     .      plain files
2687     @      symbolic links
2688     =      sockets
2689     p      named pipes (FIFOs)
2690     *      executable plain files (0100)
2691     %      device files (character or block special)
2692     %b     block special files
2693     %c     character special files
2694     r      owner-readable files (0400)
2695     w      owner-writable files (0200)
2696     x      owner-executable files (0100)
2697     A      group-readable files (0040)
2698     I      group-writable files (0020)
2699     E      group-executable files (0010)
2700     R      world-readable files (0004)
2701     W      world-writable files (0002)
2702     X      world-executable files (0001)
2703     s      setuid files (04000)
2704     S      setgid files (02000)
2705     t      files with the sticky bit (01000)
2706
2707   print *(m-1)          # Files modified up to a day ago
2708   print *(a1)           # Files accessed a day ago
2709   print *(@)            # Just symlinks
2710   print *(Lk+50)        # Files bigger than 50 kilobytes
2711   print *(Lk-50)        # Files smaller than 50 kilobytes
2712   print **/*.c          # All *.c files recursively starting in \$PWD
2713   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2714   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2715   print *~*.*           # All Files that do not contain a dot
2716   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2717   print -l *(.c|.h)     # Lists *.c and *.h
2718   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2719   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2720 }
2721 alias help-zshglob=H-Glob
2722
2723 check_com -c qma && alias ?='qma zshall'
2724
2725 # grep for running process, like: 'any vim'
2726 any() {
2727     if [[ -z "$1" ]] ; then
2728         echo "any - grep for process(es) by keyword" >&2
2729         echo "Usage: any <keyword>" >&2 ; return 1
2730     else
2731         local STRING=$1
2732         local LENGTH=$(expr length $STRING)
2733         local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
2734         local REST=$(echo $(expr substr $STRING 2 $LENGTH))
2735         ps xauwww| grep "[$FIRSCHAR]$REST"
2736     fi
2737 }
2738
2739 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2740 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2741 [[ -r /proc/1/maps ]] && \
2742 deswap() {
2743     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2744     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2745     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2746 }
2747
2748 # print hex value of a number
2749 hex() {
2750     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2751 }
2752
2753 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2754 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2755 peval() {
2756     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2757     perl -e "print eval($CALC),\"\n\";"
2758 }
2759 functions peval &>/dev/null && alias calc=peval
2760
2761 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2762 # certain circumstances, so work around it, no matter which environment we have
2763 brltty() {
2764     if [[ -z "$DISPLAY" ]] ; then
2765         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2766         command brltty "$@"
2767     else
2768         command brltty "$@"
2769     fi
2770 }
2771
2772 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2773 aoeu() {
2774     echo -n 'Switching to us keyboard layout: '
2775     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2776     echo 'Done'
2777 }
2778 asdf() {
2779     echo -n 'Switching to dvorak keyboard layout: '
2780     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2781     echo 'Done'
2782 }
2783 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2784 uiae() {
2785     echo -n 'Switching to us keyboard layout: '
2786     setxkbmap us && echo 'Done' || echo 'Failed'
2787 }
2788
2789 # set up an ipv6 tunnel
2790 ipv6-tunnel() {
2791     case $1 in
2792         start)
2793             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2794                 print 'ipv6 tunnel already set up, nothing to be done.'
2795                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2796             else
2797                 [[ -n "$PUBLIC_IP" ]] || \
2798                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2799                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2800
2801                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2802                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2803                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2804                 ifconfig sit0 tunnel ::192.88.99.1 up
2805                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2806             fi
2807             ;;
2808         status)
2809             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2810                 print 'ipv6 tunnel available' ; return 0
2811             else
2812                 print 'ipv6 tunnel not available' ; return 1
2813             fi
2814             ;;
2815         stop)
2816             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2817                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2818                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2819             else
2820                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2821             fi
2822             ;;
2823         *)
2824             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2825             ;;
2826     esac
2827 }
2828
2829 # run dhclient for wireless device
2830 iwclient() {
2831     salias dhclient "$(wavemon -d | awk '/device/{print $2}')"
2832 }
2833
2834 # spawn a minimally set up ksh - useful if you want to umount /usr/.
2835 minimal-shell() {
2836     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
2837 }
2838
2839 # make a backup of a file
2840 bk() {
2841     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2842 }
2843
2844 # Switching shell safely and efficiently? http://www.zsh.org/mla/workers/2001/msg02410.html
2845 # bash() {
2846 #  NO_SWITCH="yes" command bash "$@"
2847 # }
2848 # restart () {
2849 #  exec $SHELL $SHELL_ARGS "$@"
2850 # }
2851
2852 #f1# grep for patterns in grml's zsh setup
2853 zg() {
2854 #{{{
2855     LANG=C perl -e '
2856
2857 sub usage {
2858     print "usage: zg -[anr] <pattern>\n";
2859     print " Search for patterns in grml'\''s zshrc.\n";
2860     print " zg takes no or exactly one option plus a non empty pattern.\n\n";
2861     print "   options:\n";
2862     print "     --  no options (use if your pattern starts in with a dash.\n";
2863     print "     -a  search for the pattern in all code regions\n";
2864     print "     -n  search for the pattern in non-root code only\n";
2865     print "     -r  search in code for everyone (also root) only\n\n";
2866     print "   The default is -a for non-root users and -r for root.\n\n";
2867     print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
2868     print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
2869     print " ...in case you copied the file to that location.\n\n";
2870     exit 1;
2871 }
2872
2873 if ($ENV{GRML_ZSHRC} ne "") {
2874     $RC = $ENV{GRML_ZSHRC};
2875 } else {
2876     $RC = "/etc/zsh/zshrc";
2877 }
2878
2879 usage if ($#ARGV < 0 || $#ARGV > 1);
2880 if ($> == 0) { $mode = "allonly"; }
2881 else { $mode = "all"; }
2882
2883 $opt = $ARGV[0];
2884 if ($opt eq "--")     { shift; }
2885 elsif ($opt eq "-a")  { $mode = "all"; shift; }
2886 elsif ($opt eq "-n")  { $mode = "nonroot"; shift; }
2887 elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
2888 elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
2889
2890 $pattern = $ARGV[0];
2891 usage() if ($pattern eq "");
2892
2893 open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
2894 while ($line = <FH>) {
2895     chomp $line;
2896     if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
2897     next if ($mode eq "nonroot" && markerfound == 0);
2898     break if ($mode eq "allonly" && markerfound == 1);
2899     print $line, "\n" if ($line =~ /$pattern/);
2900 }
2901 close FH;
2902 exit 0;
2903
2904     ' -- "$@"
2905 #}}}
2906     return $?
2907 }
2908
2909 # }}}
2910
2911 # log out? set timeout in seconds {{{
2912 # TMOUT=1800
2913 # do not log out in some specific terminals:
2914 #  if [[ "${TERM}" == ([Exa]term*|rxvt|dtterm|screen*) ]] ; then
2915 #    unset TMOUT
2916 #  fi
2917 # }}}
2918
2919 # {{{ make sure our environment is clean regarding colors
2920 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2921 # }}}
2922
2923 # source another config file if present {{{
2924 xsource "/etc/zsh/zshrc.local"
2925 xsource "${HOME}/.zshenv"
2926 # }}}
2927
2928 # "persistent history" {{{
2929 # just write important commands you always need to ~/.important_commands
2930 if [[ -r ~/.important_commands ]] ; then
2931     fc -R ~/.important_commands
2932 fi
2933 # }}}
2934
2935 ## genrefcard.pl settings {{{
2936 ### example: split functions-search 8,16,24,32
2937 #@# split functions-search 8
2938 ## }}}
2939
2940 #:grep:marker:for:mika: :-)
2941 ### non-root (EUID != 0) code below
2942 ###
2943
2944 (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) && return 0
2945
2946 # autoloading stuff {{{
2947 # associate types and extensions (be aware with perl scripts and anwanted behaviour!)
2948 #  check_com zsh-mime-setup || { autoload zsh-mime-setup && zsh-mime-setup }
2949 #  alias -s pl='perl -S'
2950 # }}}
2951
2952 # variables {{{
2953
2954 # set terminal property (used e.g. by msgid-chooser)
2955 export COLORTERM="yes"
2956
2957 # set default browser
2958 if [[ -z "$BROWSER" ]] ; then
2959     if [[ -n "$DISPLAY" ]] ; then
2960         #v# If X11 is running
2961         check_com -c firefox && export BROWSER=firefox
2962     else
2963         #v# If no X11 is running
2964         check_com -c w3m && export BROWSER=w3m
2965     fi
2966 fi
2967
2968 #m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
2969 [[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
2970 [[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
2971
2972 # support running 'jikes *.java && jamvm HelloWorld' OOTB:
2973 #v# [for non-root only]
2974 [[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
2975 # }}}
2976
2977 # set options {{{
2978
2979 # Allow comments even in interactive shells i. e.
2980 # $ uname # This command prints system informations
2981 # zsh: bad pattern: #
2982 # $ setopt interactivecomments
2983 # $ uname # This command prints system informations
2984 # Linux
2985 #  setopt interactivecomments
2986
2987 # ctrl-s will no longer freeze the terminal.
2988 #  stty erase "^?"
2989
2990 # }}}
2991
2992 # {{{ global aliases
2993 # These do not have to be at the beginning of the command line.
2994 # Avoid typing cd ../../ for going two dirs down and so on
2995 # Usage, e.g.: "$ cd ...' or just '$ ...' with 'setopt auto_cd'
2996 # Notice: deactivated by 061112 by default, we use another approach
2997 # known as "power completion / abbreviation expansion"
2998 #  alias -g '...'='../..'
2999 #  alias -g '....'='../../..'
3000 #  alias -g BG='& exit'
3001 #  alias -g C='|wc -l'
3002 #  alias -g G='|grep'
3003 #  alias -g H='|head'
3004 #  alias -g Hl=' --help |& less -r'
3005 #  alias -g K='|keep'
3006 #  alias -g L='|less'
3007 #  alias -g LL='|& less -r'
3008 #  alias -g M='|most'
3009 #  alias -g N='&>/dev/null'
3010 #  alias -g R='| tr A-z N-za-m'
3011 #  alias -g SL='| sort | less'
3012 #  alias -g S='| sort'
3013 #  alias -g T='|tail'
3014 #  alias -g V='| vim -'
3015 # }}}
3016
3017 # aliases {{{
3018
3019 # Xterm resizing-fu.
3020 # Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
3021 alias hide='echo -en "\033]50;nil2\007"'
3022 alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
3023 alias small='echo -en "\033]50;6x10\007"'
3024 alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
3025 alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
3026 alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
3027 alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
3028 alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
3029 alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
3030 #  if [[ "$TERM" == "xterm" ]] && [[ "$LINES" -ge 50 ]] && [[ "$COLUMNS" -ge 100 ]] && [[ -z "$SSH_CONNECTION" ]] ; then
3031 #          large
3032 #  fi
3033
3034 # general
3035 #a2# Execute \kbd{du -sch}
3036 alias da='du -sch'
3037 #a2# Execute \kbd{jobs -l}
3038 alias j='jobs -l'
3039 #  alias u='translate -i'          # translate
3040
3041 # compile stuff
3042 #a2# Execute \kbd{./configure}
3043 alias CO="./configure"
3044 #a2# Execute \kbd{./configure --help}
3045 alias CH="./configure --help"
3046
3047 # http://conkeror.mozdev.org/
3048 #a2# Run a keyboard driven firefox
3049 alias conkeror='firefox -chrome chrome://conkeror/content'
3050
3051 # arch/tla stuff
3052 if check_com -c tla ; then
3053     #a2# Execute \kbd{tla what-changed --diffs | less}
3054     alias tdi='tla what-changed --diffs | less'
3055     #a2# Execute \kbd{tla-buildpackage}
3056     alias tbp='tla-buildpackage'
3057     #a2# Execute \kbd{tla archive-mirror}
3058     alias tmi='tla archive-mirror'
3059     #a2# Execute \kbd{tla commit}
3060     alias tco='tla commit'
3061     #a2# Execute \kbd{tla star-merge}
3062     alias tme='tla star-merge'
3063 fi
3064
3065 # listing stuff
3066 #a2# Execute \kbd{ls -lSrah}
3067 alias dir="ls -lSrah"
3068 #a2# Only show dot-directories
3069 alias lad='ls -d .*(/)'                # only show dot-directories
3070 #a2# Only show dot-files
3071 alias lsa='ls -a .*(.)'                # only show dot-files
3072 #a2# Only files with setgid/setuid/sticky flag
3073 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
3074 #a2# Only show 1st ten symlinks
3075 alias lsl='ls -l *(@[1,10])'           # only symlinks
3076 #a2# Display only executables
3077 alias lsx='ls -l *(*[1,10])'           # only executables
3078 #a2# Display world-{readable,writable,executable} files
3079 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
3080 #a2# Display the ten biggest files
3081 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
3082 #a2# Only show directories
3083 alias lsd='ls -d *(/)'                 # only show directories
3084 #a2# Only show empty directories
3085 alias lse='ls -d *(/^F)'               # only show empty directories
3086 #a2# Display the ten newest files
3087 alias lsnew="ls -rl *(D.om[1,10])"     # display the newest files
3088 #a2# Display the ten oldest files
3089 alias lsold="ls -rtlh *(D.om[1,10])"   # display the oldest files
3090 #a2# Display the ten smallest files
3091 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
3092
3093 # chmod
3094 #a2# Execute \kbd{chmod 600}
3095 alias rw-='chmod 600'
3096 #a2# Execute \kbd{chmod 700}
3097 alias rwx='chmod 700'
3098 #m# a2 r-{}- Execute \kbd{chmod 644}
3099 alias r--='chmod 644'
3100 #a2# Execute \kbd{chmod 755}
3101 alias r-x='chmod 755'
3102
3103 # some useful aliases
3104 #a2# Execute \kbd{mkdir -o}
3105 alias md='mkdir -p'
3106
3107 check_com -c ipython && alias ips='ipython -p sh'
3108
3109 # console stuff
3110 #a2# Execute \kbd{mplayer -vo fbdev}
3111 alias cmplayer='mplayer -vo fbdev'
3112 #a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
3113 alias fbmplayer='mplayer -vo fbdev -fs -zoom'
3114 #a2# Execute \kbd{links2 -driver fb}
3115 alias fblinks='links2 -driver fb'
3116
3117 # ignore ~/.ssh/known_hosts entries
3118 #  alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null" -o "PreferredAuthentications=keyboard-interactive"'
3119 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3120 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3121 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3122
3123 # simple webserver
3124 check_com -c python && alias http="python -m SimpleHTTPServer"
3125
3126 # Use 'g' instead of 'git':
3127 check_com g || alias g='git'
3128
3129 # use colors when browsing man pages, but only if not using LESS_TERMCAP_* from /etc/zsh/zshenv:
3130 if [[ -z "$LESS_TERMCAP_md" ]] ; then
3131     [[ -d ~/.terminfo/ ]] && alias man='TERMINFO=~/.terminfo/ LESS=C TERM=mostlike PAGER=less man'
3132 fi
3133
3134 # check whether Debian's package management (dpkg) is running
3135 if check_com salias ; then
3136     #a2# Check whether a dpkg instance is currently running
3137     salias check_dpkg_running="dpkg_running"
3138 fi
3139
3140 # work around non utf8 capable software in utf environment via $LANG and luit
3141 if check_com isutfenv && check_com luit ; then
3142     if check_com -c mrxvt ; then
3143         isutfenv && [[ -n "$LANG" ]] && \
3144             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3145     fi
3146
3147     if check_com -c aterm ; then
3148         isutfenv && [[ -n "$LANG" ]] && \
3149             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3150     fi
3151
3152     if check_com -c centericq ; then
3153         isutfenv && [[ -n "$LANG" ]] && \
3154             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3155     fi
3156 fi
3157 # }}}
3158
3159 # useful functions {{{
3160
3161 # searching
3162 #f4# Search for newspostings from authors
3163 agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
3164 #f4# Search Debian Bug Tracking System
3165 debbug()  {
3166     setopt localoptions extendedglob
3167     if [[ $# -eq 1 ]]; then
3168         case "$1" in
3169             ([0-9]##)
3170             ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
3171             ;;
3172             (*@*)
3173             ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
3174             ;;
3175             (*)
3176             ${=BROWSER} "http://bugs.debian.org/$*"
3177             ;;
3178         esac
3179     else
3180         print "$0 needs one argument"
3181         return 1
3182     fi
3183 }
3184 #f4# Search Debian Bug Tracking System in mbox format
3185 debbugm() { bts show --mbox $1 } # provide bugnummer as "$1"
3186 #f4# Search DMOZ
3187 dmoz()    { ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_} }
3188 #f4# Search German   Wiktionary
3189 dwicti()  { ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_} }
3190 #f4# Search English  Wiktionary
3191 ewicti()  { ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_} }
3192 #f4# Search Google Groups
3193 ggogle()  { ${=BROWSER} "http://groups.google.com/groups?q=$*" }
3194 #f4# Search Google
3195 google()  { ${=BROWSER} "http://www.google.com/search?&num=100&q=$*" }
3196 #f4# Search Google Groups for MsgID
3197 mggogle() { ${=BROWSER} "http://groups.google.com/groups?selm=$*" }
3198 #f4# Search Netcraft
3199 netcraft(){ ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1" }
3200 #f4# Use German Wikipedia's full text search
3201 swiki()   { ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1} }
3202 #f4# search \kbd{dict.leo.org}
3203 oleo()    { ${=BROWSER} "http://dict.leo.org/?search=$*" }
3204 #f4# Search German   Wikipedia
3205 wikide()  { ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}" }
3206 #f4# Search English  Wikipedia
3207 wikien()  { ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}" }
3208 #f4# Search official debs
3209 wodeb()   { ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all" }
3210
3211 #m# f4 gex() Exact search via Google
3212 check_com google && gex () { google "\"[ $1]\" $*" } # exact search at google
3213
3214 # misc
3215 #f5# Backup \kbd{file {\rm to} file\_timestamp}
3216 bk()      { cp -b ${1} ${1}_`date --iso-8601=m` }
3217 #f5# Copied diff
3218 cdiff()   { diff -crd "$*" | egrep -v "^Only in |^Binary files " }
3219 #f5# cd to directoy and list files
3220 cl()      { cd $1 && ls -a }        # cd && ls
3221 #f5# Cvs add
3222 cvsa()    { cvs add $* && cvs com -m 'initial checkin' $* }
3223 #f5# Cvs diff
3224 cvsd()    { cvs diff -N $* |& $PAGER }
3225 #f5# Cvs log
3226 cvsl()    { cvs log $* |& $PAGER }
3227 #f5# Cvs update
3228 cvsq()    { cvs -nq update }
3229 #f5# Rcs2log
3230 cvsr()    { rcs2log $* | $PAGER }
3231 #f5# Cvs status
3232 cvss()    { cvs status -v $* }
3233 #f5# Disassemble source files using gcc and as
3234 disassemble(){ gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null }
3235 #f5# Firefox remote control - open given URL
3236 fir()     { firefox -a firefox -remote "openURL($1)" }
3237 #f5# Create Directoy and \kbd{cd} to it
3238 mcd()     { mkdir -p "$@"; cd "$@" } # mkdir && cd
3239 #f5# Unified diff to timestamped outputfile
3240 mdiff()   { diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1" }
3241 #f5# Memory overview
3242 memusage(){ ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc }
3243 #f5# Show contents of tar file
3244 shtar()   { gunzip -c $1 | tar -tf - -- | $PAGER }
3245 #f5# Show contents of tgz file
3246 shtgz()   { tar -ztf $1 | $PAGER }
3247 #f5# Show contents of zip file
3248 shzip()   { unzip -l $1 | $PAGER }
3249 #f5# Greps signature from file
3250 sig()     { agrep -d '^-- $' "$*" ~/.Signature }
3251 #f5# Unified diff
3252 udiff()   { diff -urd $* | egrep -v "^Only in |^Binary files " }
3253 #f5# (Mis)use \kbd{vim} as \kbd{less}
3254 viless()  { vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}" }
3255
3256 # download video from youtube
3257 ytdl() {
3258     if ! [[ -n "$2" ]] ; then
3259         print "Usage: ydtl http://youtube.com/watch?v=.... outputfile.flv">&2
3260         return 1
3261     else
3262         wget -O${2} "http://youtube.com/get_video?"${${${"$(wget -o/dev/null -O- "${1}" | grep -e watch_fullscreen)"}##*watch_fullscreen\?}%%\&fs=*}
3263     fi
3264 }
3265
3266 # Function Usage: uopen $URL/$file
3267 #f5# Download a file and display it locally
3268 uopen() {
3269     if ! [[ -n "$1" ]] ; then
3270         print "Usage: uopen \$URL/\$file">&2
3271         return 1
3272     else
3273         FILE=$1
3274         MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
3275         MIME=${MIME%$'\r'}
3276         curl $FILE | see ${MIME}:-
3277     fi
3278 }
3279
3280 # Function Usage: doc packagename
3281 #f5# \kbd{cd} to /usr/share/doc/\textit{package}
3282 doc() { cd /usr/share/doc/$1 && ls }
3283 _doc() { _files -W /usr/share/doc -/ }
3284 check_com compdef && compdef _doc doc
3285
3286 #f5# Make screenshot
3287 sshot() {
3288     [[ ! -d ~/shots  ]] && mkdir ~/shots
3289     #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
3290     cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
3291 }
3292
3293 # list images only
3294 limg() {
3295     local -a images
3296     images=( *.{jpg,gif,png}(.N) )
3297
3298     if [[ $#images -eq 0 ]] ; then
3299         print "No image files found"
3300     else
3301         ls "$@" "$images[@]"
3302     fi
3303 }
3304
3305 #f5# Create PDF file from source code
3306 makereadable() {
3307     output=$1
3308     shift
3309     a2ps --medium A4dj -E -o $output $*
3310     ps2pdf $output
3311 }
3312
3313 # zsh with perl-regex - use it e.g. via:
3314 # regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
3315 #f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
3316 regcheck() {
3317     zmodload -i zsh/pcre
3318     pcre_compile $1 && \
3319     pcre_match $2 && echo "regex matches" || echo "regex does not match"
3320 }
3321
3322 #f5# List files which have been modified within the last {\it n} days
3323 new() { print -l *(m-$1) }
3324
3325 #f5# Grep in history
3326 greph() { history 0 | grep $1 }
3327 # use colors when GNU grep with color-support
3328 #a2# Execute \kbd{grep -{}-color=auto}
3329 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
3330 #a2# Execute \kbd{grep -i -{}-color=auto}
3331 alias GREP='grep -i --color=auto'
3332
3333 # one blank line between each line
3334 if [[ -r ~/.terminfo/m/mostlike ]] ; then
3335 #   alias man2='MANPAGER="sed -e G |less" TERMINFO=~/.terminfo TERM=mostlike /usr/bin/man'
3336     #f5# Watch manpages in a stretched style
3337     man2() { PAGER='dash -c "sed G | /usr/bin/less"' TERM=mostlike /usr/bin/man "$@" ; }
3338 fi
3339
3340 # d():Copyright 2005 Nikolai Weibull <nikolai@bitwi.se>
3341 # notice: option AUTO_PUSHD has to be set
3342 #f5# Jump between directories
3343 d() {
3344     emulate -L zsh
3345     autoload -U colors
3346     local color=$fg_bold[blue]
3347     integer i=0
3348     dirs -p | while read dir; do
3349         local num="${$(printf "%-4d " $i)/ /.}"
3350         printf " %s  $color%s$reset_color\n" $num $dir
3351         (( i++ ))
3352     done
3353     integer dir=-1
3354     read -r 'dir?Jump to directory: ' || return
3355     (( dir == -1 )) && return
3356     if (( dir < 0 || dir >= i )); then
3357         echo d: no such directory stack entry: $dir
3358         return 1
3359     fi
3360     cd ~$dir
3361 }
3362
3363 # usage example: 'lcheck strcpy'
3364 #f5# Find out which libs define a symbol
3365 lcheck() {
3366     if [[ -n "$1" ]] ; then
3367         nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
3368     else
3369         echo "Usage: lcheck <function>" >&2
3370     fi
3371 }
3372
3373 #f5# Clean up directory - remove well known tempfiles
3374 purge() {
3375     FILES=(*~(N) .*~(N) \#*\#(N) *.o(N) a.out(N) *.core(N) *.cmo(N) *.cmi(N) .*.swp(N))
3376     NBFILES=${#FILES}
3377     if [[ $NBFILES > 0 ]] ; then
3378         print $FILES
3379         local ans
3380         echo -n "Remove these files? [y/n] "
3381         read -q ans
3382         if [[ $ans == "y" ]] ; then
3383             rm ${FILES}
3384             echo ">> $PWD purged, $NBFILES files removed"
3385         else
3386             echo "Ok. .. than not.."
3387         fi
3388     fi
3389 }
3390
3391 # Translate DE<=>EN
3392 # 'translate' looks up fot a word in a file with language-to-language
3393 # translations (field separator should be " : "). A typical wordlist looks
3394 # like at follows:
3395 #  | english-word : german-transmission
3396 # It's also only possible to translate english to german but not reciprocal.
3397 # Use the following oneliner to turn back the sort order:
3398 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3399 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3400 #f5# Translates a word
3401 trans() {
3402     case "$1" in
3403         -[dD]*)
3404             translate -l de-en $2
3405             ;;
3406         -[eE]*)
3407             translate -l en-de $2
3408             ;;
3409         *)
3410             echo "Usage: $0 { -D | -E }"
3411             echo "         -D == German to English"
3412             echo "         -E == English to German"
3413     esac
3414 }
3415
3416 # Some quick Perl-hacks aka /useful/ oneliner
3417 #  bew() { perl -le 'print unpack "B*","'$1'"' }
3418 #  web() { perl -le 'print pack "B*","'$1'"' }
3419 #  hew() { perl -le 'print unpack "H*","'$1'"' }
3420 #  weh() { perl -le 'print pack "H*","'$1'"' }
3421 #  pversion()    { perl -M$1 -le "print $1->VERSION" } # i. e."pversion LWP -> 5.79"
3422 #  getlinks ()   { perl -ne 'while ( m/"((www|ftp|http):\/\/.*?)"/gc ) { print $1, "\n"; }' $* }
3423 #  gethrefs ()   { perl -ne 'while ( m/href="([^"]*)"/gc ) { print $1, "\n"; }' $* }
3424 #  getanames ()  { perl -ne 'while ( m/a name="([^"]*)"/gc ) { print $1, "\n"; }' $* }
3425 #  getforms ()   { perl -ne 'while ( m:(\</?(input|form|select|option).*?\>):gic ) { print $1, "\n"; }' $* }
3426 #  getstrings () { perl -ne 'while ( m/"(.*?)"/gc ) { print $1, "\n"; }' $*}
3427 #  getanchors () { perl -ne 'while ( m/«([^«»\n]+)»/gc ) { print $1, "\n"; }' $* }
3428 #  showINC ()    { perl -e 'for (@INC) { printf "%d %s\n", $i++, $_ }' }
3429 #  vimpm ()      { vim `perldoc -l $1 | sed -e 's/pod$/pm/'` }
3430 #  vimhelp ()    { vim -c "help $1" -c on -c "au! VimEnter *" }
3431
3432 #f5# List all occurrences of programm in current PATH
3433 plap() {
3434     if [[ $# = 0 ]] ; then
3435         echo "Usage:    $0 program"
3436         echo "Example:  $0 zsh"
3437         echo "Lists all occurrences of program in the current PATH."
3438     else
3439         ls -l ${^path}/*$1*(*N)
3440     fi
3441 }
3442
3443 # Found in the mailinglistarchive from Zsh (IIRC ~1996)
3444 #f5# Select items for specific command(s) from history
3445 selhist() {
3446     emulate -L zsh
3447     local TAB=$'\t';
3448     (( $# < 1 )) && {
3449         echo "Usage: $0 command"
3450         return 1
3451     };
3452     cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
3453     print -l $cmd | less -F
3454     echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
3455     local answer
3456     read answer
3457     print -z "${cmd[$answer]#*$TAB}"
3458 }
3459
3460 # Use vim to convert plaintext to HTML
3461 #f5# Transform files to html with highlighting
3462 2html() { vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null }
3463
3464 # Usage: simple-extract <file>
3465 #f5# Smart archive extractor
3466 simple-extract () {
3467     if [[ -f $1 ]] ; then
3468         case $1 in
3469             *.tar.bz2)  bzip2 -v -d $1      ;;
3470             *.tar.gz)   tar -xvzf $1        ;;
3471             *.rar)      unrar $1            ;;
3472             *.deb)      ar -x $1            ;;
3473             *.bz2)      bzip2 -d $1         ;;
3474             *.lzh)      lha x $1            ;;
3475             *.gz)       gunzip -d $1        ;;
3476             *.tar)      tar -xvf $1         ;;
3477             *.tgz)      gunzip -d $1        ;;
3478             *.tbz2)     tar -jxvf $1        ;;
3479             *.zip)      unzip $1            ;;
3480             *.Z)        uncompress $1       ;;
3481             *)          echo "'$1' Error. Please go away" ;;
3482         esac
3483     else
3484         echo "'$1' is not a valid file"
3485     fi
3486 }
3487
3488 # Usage: smartcompress <file> (<type>)
3489 #f5# Smart archive creator
3490 smartcompress() {
3491     if [[ -n $2 ]] ; then
3492         case $2 in
3493             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
3494             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
3495             tar.Z)          tar -Zcvf$1.$2 $1 ;;
3496             tar)            tar -cvf$1.$2  $1 ;;
3497             gz | gzip)      gzip           $1 ;;
3498             bz2 | bzip2)    bzip2          $1 ;;
3499             *)
3500                 echo "Error: $2 is not a valid compression type"
3501                 ;;
3502         esac
3503     else
3504         smartcompress $1 tar.gz
3505     fi
3506 }
3507
3508 # Usage: show-archive <archive>
3509 #f5# List an archive's content
3510 show-archive() {
3511     if [[ -f $1 ]] ; then
3512         case $1 in
3513             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
3514             *.tar)         tar -tf $1 ;;
3515             *.tgz)         tar -ztf $1 ;;
3516             *.zip)         unzip -l $1 ;;
3517             *.bz2)         bzless $1 ;;
3518             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
3519             *)             echo "'$1' Error. Please go away" ;;
3520         esac
3521     else
3522         echo "'$1' is not a valid archive"
3523     fi
3524 }
3525
3526 # It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
3527 #f5# Use \kbd{vim} as your manpage reader
3528 vman() { man $* | col -b | view -c 'set ft=man nomod nolist' - }
3529
3530 # function readme() { $PAGER -- (#ia3)readme* }
3531 #f5# View all README-like files in current directory in pager
3532 readme() {
3533     local files
3534     files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
3535     if (($#files)) ; then
3536         $PAGER $files
3537     else
3538         print 'No README files.'
3539     fi
3540 }
3541
3542 # function ansi-colors()
3543 #f5# Display ANSI colors
3544 ansi-colors() {
3545     typeset esc="\033[" line1 line2
3546     echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
3547     for fore in 30 31 32 33 34 35 36 37; do
3548         line1="$fore "
3549         line2="   "
3550         for back in 40 41 42 43 44 45 46 47 49; do
3551             line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
3552             line2="${line2}${esc}${back};${fore};1m Bold   ${esc}0m"
3553         done
3554         echo -e "$line1\n$line2"
3555     done
3556 }
3557
3558 # suidfind() { ls -latg $path | grep '^...s' }
3559 #f5# Find all files in \$PATH with setuid bit set
3560 suidfind() { ls -latg $path/*(sN) }
3561
3562 # See above but this is /better/ ... anywise ..
3563 findsuid() {
3564     print 'Output will be written to ~/suid_* ...'
3565     $SUDO find / -type f \( -perm -4000 -o -perm -2000 \) -ls > ~/suid_suidfiles.`date "+%Y-%m-%d"`.out 2>&1
3566     $SUDO find / -type d \( -perm -4000 -o -perm -2000 \) -ls > ~/suid_suiddirs.`date "+%Y-%m-%d"`.out 2>&1
3567     $SUDO find / -type f \( -perm -2 -o -perm -20 \) -ls > ~/suid_writefiles.`date "+%Y-%m-%d"`.out 2>&1
3568     $SUDO find / -type d \( -perm -2 -o -perm -20 \) -ls > ~/suid_writedirs.`date "+%Y-%m-%d"`.out 2>&1
3569     print 'Finished'
3570 }
3571
3572 #f5# Reload given functions
3573 refunc() {
3574     for func in $argv ; do
3575         unfunction $func
3576         autoload $func
3577     done
3578 }
3579
3580 # a small check to see which DIR is located on which server/partition.
3581 # stolen and modified from Sven's zshrc.forall
3582 #f5# Report diskusage of a directory
3583 dirspace() {
3584     if [[ -n "$1" ]] ; then
3585         for dir in $* ; do
3586             if [[ -d "$dir" ]] ; then
3587                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3588             else
3589                 echo "warning: $dir does not exist" >&2
3590             fi
3591         done
3592     else
3593         for dir in $path; do
3594             if [[ -d "$dir" ]] ; then
3595                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3596             else
3597                 echo "warning: $dir does not exist" >&2
3598             fi
3599         done
3600     fi
3601 }
3602
3603 # % slow_print `cat /etc/passwd`
3604 #f5# Slowly print out parameters
3605 slow_print() {
3606     for argument in "${@}" ; do
3607         for ((i = 1; i <= ${#1} ;i++)) ; do
3608             print -n "${argument[i]}"
3609             sleep 0.08
3610         done
3611         print -n " "
3612     done
3613     print ""
3614 }
3615
3616 #f5# Show some status info
3617 status() {
3618     print ""
3619     print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")""
3620     print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
3621     print "Term..: $TTY ($TERM), $BAUD bauds, $COLUMNS x $LINES cars"
3622     print "Login.: $LOGNAME (UID = $EUID) on $HOST"
3623     print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
3624     print "Uptime:$(uptime)"
3625     print ""
3626 }
3627
3628 # Rip an audio CD
3629 #f5# Rip an audio CD
3630 audiorip() {
3631     mkdir -p ~/ripps
3632     cd ~/ripps
3633     cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
3634     cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
3635     echo " * Would you like to burn the cd now? (yes/no)"
3636     read input
3637     if [[ "$input" = "yes" ]] ; then
3638         echo " ! Burning Audio CD"
3639         audioburn
3640         echo " * done."
3641     else
3642         echo " ! Invalid response."
3643     fi
3644 }
3645
3646 # and burn it
3647 #f5# Burn an audio CD (in combination with audiorip)
3648 audioburn() {
3649     cd ~/ripps
3650     cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
3651     echo " * Should I remove the temporary files? (yes/no)"
3652     read input
3653     if [[ "$input" = "yes" ]] ; then
3654         echo " ! Removing Temporary Files."
3655         cd ~
3656         rm -rf ~/ripps
3657         echo " * done."
3658     else
3659         echo " ! Invalid response."
3660     fi
3661 }
3662
3663 #f5# Make an audio CD from all mp3 files
3664 mkaudiocd() {
3665     # TODO: do the renaming more zshish, possibly with zmv()
3666     cd ~/ripps
3667     for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
3668     for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
3669     for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
3670     normalize -m *.wav
3671     for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
3672 }
3673
3674 #f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
3675 mkiso() {
3676     echo " * Volume name "
3677     read volume
3678     echo " * ISO Name (ie. tmp.iso)"
3679     read iso
3680     echo " * Directory or File"
3681     read files
3682     mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
3683 }
3684
3685 #f5# Simple thumbnails generator
3686 genthumbs() {
3687     rm -rf thumb-* index.html
3688     echo "
3689 <html>
3690   <head>
3691     <title>Images</title>
3692   </head>
3693   <body>" > index.html
3694     for f in *.(gif|jpeg|jpg|png) ; do
3695         convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
3696         echo "    <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
3697     done
3698     echo "
3699   </body>
3700 </html>" >> index.html
3701 }
3702
3703 #f5# Set all ulimit parameters to \kbd{unlimited}
3704 allulimit() {
3705     ulimit -c unlimited
3706     ulimit -d unlimited
3707     ulimit -f unlimited
3708     ulimit -l unlimited
3709     ulimit -n unlimited
3710     ulimit -s unlimited
3711     ulimit -t unlimited
3712 }
3713
3714 # ogg2mp3 with bitrate of 192
3715 ogg2mp3_192() {
3716     oggdec -o - ${1} | lame -b 192 - ${1:r}.mp3
3717 }
3718
3719 #f5# RFC 2396 URL encoding in Z-Shell
3720 urlencode() {
3721     setopt localoptions extendedglob
3722     input=( ${(s::)1} )
3723     print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
3724 }
3725
3726 #f5# Install x-lite (VoIP software)
3727 getxlite() {
3728     setopt local_options
3729     setopt errreturn
3730     [[ -d ~/tmp ]] || mkdir ~/tmp
3731     cd ~/tmp
3732
3733     echo "Downloading http://www.counterpath.com/download/X-Lite_Install.tar.gz and storing it in ~/tmp:"
3734     if wget http://www.counterpath.com/download/X-Lite_Install.tar.gz ; then
3735         unp X-Lite_Install.tar.gz && echo done || echo failed
3736     else
3737         echo "Error while downloading." ; return 1
3738     fi
3739
3740     if [[ -x xten-xlite/xtensoftphone ]] ; then
3741         echo "Execute xten-xlite/xtensoftphone to start xlite."
3742     fi
3743 }
3744
3745 #f5# Install skype
3746 getskype() {
3747     setopt local_options
3748     setopt errreturn
3749     echo "Downloading debian package of skype."
3750     echo "Notice: If you want to use a more recent skype version run 'getskypebeta'."
3751     wget http://www.skype.com/go/getskype-linux-deb
3752     $SUDO dpkg -i skype*.deb && echo "skype installed."
3753 }
3754
3755 #f5# Install beta-version of skype
3756 getskypebeta() {
3757     setopt local_options
3758     setopt errreturn
3759     echo "Downloading debian package of skype (beta version)."
3760     wget http://www.skype.com/go/getskype-linux-beta-deb
3761     $SUDO dpkg -i skype-beta*.deb && echo "skype installed."
3762 }
3763
3764 #f5# Install gizmo (VoIP software)
3765 getgizmo() {
3766     setopt local_options
3767     setopt errreturn
3768     echo "libgtk2.0-0, gconf2, libstdc++6, libasound2 and zlib1g have to be available. Installing."
3769     $SUDO apt-get update
3770     $SUDO apt-get install libgtk2.0-0 gconf2 libstdc++6 libasound2 zlib1g
3771     wget "$(lynx --dump http://gizmo5.com/pc/download/linux/ | awk '/libstdc\+\+6.*\.deb/ {print $2}')"
3772     $SUDO dpkg -i gizmo-project*.deb && echo "gizmo installed."
3773 }
3774
3775 #f5# Get and run AIR (Automated Image and Restore)
3776 getair() {
3777     setopt local_options
3778     setopt errreturn
3779     [[ -w . ]] || { echo 'Error: you do not have write permissions in this directory. Exiting.' ; return 1 }
3780     local VER='1.2.8'
3781     wget http://puzzle.dl.sourceforge.net/sourceforge/air-imager/air-$VER.tar.gz
3782     tar zxf air-$VER.tar.gz
3783     cd air-$VER
3784     INTERACTIVE=no $SUDO ./install-air-1.2.8
3785     [[ -x /usr/local/bin/air ]] && [[ -n "$DISPLAY" ]] && $SUDO air
3786 }
3787
3788 #f5# Get specific git commitdiff
3789 git-get-diff() {
3790     if [[ -z $GITTREE ]] ; then
3791         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3792     fi
3793     if ! [[ -z $1 ]] ; then
3794         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commitdiff;h=$1"
3795     else
3796         echo "Usage: git-get-diff <commit>"
3797     fi
3798 }
3799
3800 #f5# Get specific git commit
3801 git-get-commit() {
3802     if [[ -z $GITTREE ]] ; then
3803         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3804     fi
3805     if ! [[ -z $1 ]] ; then
3806         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commit;h=$1"
3807     else
3808         echo "Usage: git-get-commit <commit>"
3809     fi
3810 }
3811
3812 #f5# Get specific git diff
3813 git-get-plaindiff () {
3814     if [[ -z $GITTREE ]] ; then
3815        GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3816     fi
3817     if [[ -z $1 ]] ; then
3818        echo 'Usage: git-get-plaindiff '
3819     else
3820        echo -n "Downloading $1.diff ... "
3821        # avoid "generating ..." stuff from kernel.org server:
3822        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O /dev/null
3823        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O $1.diff \
3824             && echo done || echo failed
3825     fi
3826 }
3827
3828
3829 # http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
3830 #f5# Log 'make install' output
3831 mmake() {
3832     [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
3833     make -n install > ~/.errorlogs/${PWD##*/}-makelog
3834 }
3835
3836 #f5# Indent source code
3837 smart-indent() {
3838     indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs $*
3839 }
3840
3841 # highlight important stuff in diff output, usage example: hg diff | hidiff
3842 #m# a2 hidiff \kbd{histring} oneliner for diffs
3843 check_com -c histring && \
3844     alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
3845
3846 # rename pictures based on information found in exif headers
3847 #f5# Rename pictures based on information found in exif headers
3848 exirename() {
3849     if [[ $# -lt 1 ]] ; then
3850         echo 'Usage: jpgrename $FILES' >& 2
3851         return 1
3852     else
3853         echo -n 'Checking for jhead with version newer than 1.9: '
3854         jhead_version=`jhead -h | grep 'used by most Digital Cameras.  v.*' | awk '{print $6}' | tr -d v`
3855         if [[ $jhead_version > '1.9' ]]; then
3856             echo 'success - now running jhead.'
3857             jhead -n%Y-%m-%d_%Hh%M_%f $*
3858         else
3859             echo 'failed - exiting.'
3860         fi
3861     fi
3862 }
3863
3864 # open file in vim and jump to line
3865 # http://www.downgra.de/archives/2007/05/08/T19_21_11/
3866 j2v() {
3867     local -a params
3868     params=(${*//(#m):[0-9]*:/\\n+${MATCH//:/}}) # replace ':23:' to '\n+23'
3869     params=(${(s|\n|)${(j|\n|)params}}) # join array using '\n', then split on all '\n'
3870     vim ${params}
3871 }
3872
3873 # get_ic() - queries imap servers for capabilities; real simple. no imaps
3874 ic_get() {
3875     local port
3876     if [[ ! -z $1 ]] ; then
3877         port=${2:-143}
3878         print "querying imap server on $1:${port}...\n";
3879         print "a1 capability\na2 logout\n" | nc $1 ${port}
3880     else
3881         print "usage:\n  $0 <imap-server> [port]"
3882     fi
3883 }
3884
3885 # creates a Maildir/ with its {new,cur,tmp} subdirs
3886 mkmaildir() {
3887     local root subdir
3888     root=${MAILDIR_ROOT:-${HOME}/Mail}
3889     if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
3890     subdir=${1}
3891     mkdir -p ${root}/${subdir}/{cur,new,tmp}
3892 }
3893
3894 # xtrename() rename xterm from within GNU-screen
3895 xtrename() {
3896     if [[ -z ${DISPLAY} ]] ; then
3897         printf 'xtrename only makes sense in X11.\n'
3898         return 1
3899     fi
3900     if [[ -z ${1} ]] ; then
3901         printf 'usage: xtrename() "title for xterm"\n'
3902         printf '  renames the title of xterm from _within_ screen.\n'
3903         printf '  Also works without screen.\n'
3904         return 0
3905     fi
3906     print -n "\eP\e]0;${1}\C-G\e\\"
3907     return 0
3908 }
3909
3910 # hl() highlighted less
3911 # http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
3912 if check_com -c highlight ; then
3913     function hl() {
3914         local theme lang
3915         theme=${HL_THEME:-""}
3916         case ${1} in
3917             (-l|--list)
3918                 ( printf 'available languages (syntax parameter):\n\n' ;
3919                     highlight --list-langs ; ) | less -SMr
3920                 ;;
3921             (-t|--themes)
3922                 ( printf 'available themes (style parameter):\n\n' ;
3923                     highlight --list-themes ; ) | less -SMr
3924                 ;;
3925             (-h|--help)
3926                 printf 'usage: hl <syntax[:theme]> <file>\n'
3927                 printf '    available options: --list (-l), --themes (-t), --help (-h)\n\n'
3928                 printf '  Example: hl c main.c\n'
3929                 ;;
3930             (*)
3931                 if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
3932                     printf 'usage: hl <syntax[:theme]> <file>\n'
3933                     printf '    available options: --list (-l), --themes (-t), --help (-h)\n'
3934                     (( ${#argv} > 2 )) && printf '  Too many arguments.\n'
3935                     return 1
3936                 fi
3937                 lang=${1%:*}
3938                 [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
3939                 if [[ -n ${theme} ]] ; then
3940                     highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
3941                 else
3942                     highlight --ansi --syntax ${lang} ${2} | less -SMr
3943                 fi
3944                 ;;
3945         esac
3946         return 0
3947     }
3948     # ... and a proper completion for hl()
3949     # needs 'highlight' as well, so it fits fine in here.
3950     function _hl_genarg()  {
3951         local expl
3952         if [[ -prefix 1 *: ]] ; then
3953             local themes
3954             themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
3955             compset -P 1 '*:'
3956             _wanted -C list themes expl theme compadd ${themes}
3957         else
3958             local langs
3959             langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
3960             _wanted -C list languages expl languages compadd -S ':' -q ${langs}
3961         fi
3962     }
3963     function _hl_complete() {
3964         _arguments -s '1: :_hl_genarg' '2:files:_path_files'
3965     }
3966     compdef _hl_complete hl
3967 fi
3968
3969 # create small urls via tinyurl.com using wget, grep and sed
3970 zurl() {
3971     [[ -z ${1} ]] && print "please give an url to shrink." && return 1
3972     local url=${1}
3973     local tiny="http://tinyurl.com/create.php?url="
3974     #print "${tiny}${url}" ; return
3975     wget  -O-             \
3976           -o/dev/null     \
3977           "${tiny}${url}" \
3978         | grep -Eio 'value="(http://tinyurl.com/.*)"' \
3979         | sed 's/value=//;s/"//g'
3980 }
3981
3982 #f2# Print a specific line of file(s).
3983 linenr () {
3984 # {{{
3985     if [ $# -lt 2 ] ; then
3986        print "Usage: linenr <number>[,<number>] <file>" ; return 1
3987     elif [ $# -eq 2 ] ; then
3988          local number=$1
3989          local file=$2
3990          command ed -s $file <<< "${number}n"
3991     else
3992          local number=$1
3993          shift
3994          for file in "$@" ; do
3995              if [ ! -d $file ] ; then
3996                 echo "${file}:"
3997                 command ed -s $file <<< "${number}n" 2> /dev/null
3998              else
3999                 continue
4000              fi
4001          done | less
4002     fi
4003 # }}}
4004 }
4005
4006 #f2# Find history events by search pattern and list them by date.
4007 whatwhen()  {
4008 # {{{
4009     local usage help ident format_l format_s first_char remain first last
4010     usage='USAGE: whatwhen [options] <searchstring> <search range>'
4011     help='Use' \`'whatwhen -h'\'' for further explanations.'
4012     ident=${(l,${#${:-Usage: }},, ,)}
4013     format_l="${ident}%s\t\t\t%s\n"
4014     format_s="${format_l//(\\t)##/\\t}"
4015     # Make the first char of the word to search for case
4016     # insensitive; e.g. [aA]
4017     first_char=[${(L)1[1]}${(U)1[1]}]
4018     remain=${1[2,-1]}
4019     # Default search range is `-100'.
4020     first=${2:-\-100}
4021     # Optional, just used for `<first> <last>' given.
4022     last=$3
4023     case $1 in
4024         ("")
4025             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
4026             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4027         ;;
4028         (-h)
4029             printf '%s\n\n' ${usage}
4030             print 'OPTIONS:'
4031             printf $format_l '-h' 'show help text'
4032             print '\f'
4033             print 'SEARCH RANGE:'
4034             printf $format_l "'0'" 'the whole history,'
4035             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
4036             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
4037             printf '\n%s\n' 'EXAMPLES:'
4038             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
4039             printf $format_l 'whatwhen zsh -250'
4040             printf $format_l 'whatwhen foo 1 99'
4041         ;;
4042         (\?)
4043             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4044         ;;
4045         (*)
4046             # -l list results on stout rather than invoking $EDITOR.
4047             # -i Print dates as in YYYY-MM-DD.
4048             # -m Search for a - quoted - pattern within the history.
4049             fc -li -m "*${first_char}${remain}*" $first $last
4050         ;;
4051     esac
4052 # }}}
4053 }
4054
4055 # change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
4056 fluxkey-change() {
4057     [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
4058     if ! [[ -r "$FLUXKEYS" ]] ; then
4059         echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
4060         return 1
4061     else
4062         if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
4063             echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
4064             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
4065         elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
4066             echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
4067             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
4068         else
4069             echo 'Sorry, do not know what to do.'
4070             return 1
4071         fi
4072     fi
4073 }
4074
4075 # retrieve weather information on the console
4076 # Usage example: 'weather LOWG'
4077 weather() {
4078     [[ -n "$1" ]] || {
4079         print 'Usage: weather <station_id>' >&2
4080         print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
4081         return 1
4082     }
4083
4084     local PLACE="${1:u}"
4085     local FILE="$HOME/.weather/$PLACE"
4086     local LOG="$HOME/.weather/log"
4087
4088     [[ -d $HOME/.weather ]] || {
4089         print -n "Creating $HOME/.weather: "
4090         mkdir $HOME/.weather
4091         print 'done'
4092     }
4093
4094     print "Retrieving information for ${PLACE}:"
4095     print
4096     wget -T 10 --no-verbose --output-file=$LOG --output-document=$FILE --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
4097
4098     if [[ $? -eq 0 ]] ; then
4099         if [[ -n "$VERBOSE" ]] ; then
4100             cat $FILE
4101         else
4102             DATE=$(grep 'UTC' $FILE | sed 's#.* /##')
4103             TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' $FILE| tr -d '(')
4104             echo "date: $DATE"
4105             echo "temp:  $TEMPERATURE"
4106         fi
4107     else
4108         print "There was an error retrieving the weather information for $PLACE" >&2
4109         cat $LOG
4110         return 1
4111     fi
4112 }
4113 # }}}
4114
4115 # mercurial related stuff {{{
4116 if check_com -c hg ; then
4117     # gnu like diff for mercurial
4118     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
4119     #f5# GNU like diff for mercurial
4120     hgdi() {
4121         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
4122     }
4123
4124     # build debian package
4125     #a2# Alias for \kbd{hg-buildpackage}
4126     alias hbp='hg-buildpackage'
4127
4128     # execute commands on the versioned patch-queue from the current repos
4129     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
4130
4131     # diffstat for specific version of a mercurial repository
4132     #   hgstat      => display diffstat between last revision and tip
4133     #   hgstat 1234 => display diffstat between revision 1234 and tip
4134     #f5# Diffstat for specific version of a mercurial repos
4135     hgstat() {
4136         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
4137     }
4138
4139     #f5# Get current mercurial tip via hg itself
4140     gethgclone() {
4141         setopt local_options
4142         setopt errreturn
4143         if [[ -f mercurial-tree/.hg ]] ; then
4144             cd mercurial-tree
4145             echo "Running hg pull for retreiving latest version..."
4146             hg pull
4147             echo "Finished update. Building mercurial"
4148             make local
4149             echo "Setting \$PATH to $PWD:\$PATH..."
4150             export PATH="$PWD:$PATH"
4151         else
4152             echo "Downloading mercurial via hg"
4153             hg clone http://selenic.com/repo/hg mercurial-tree
4154             cd mercurial-tree
4155             echo "Building mercurial"
4156             make local
4157             echo "Setting \$PATH to $PWD:\$PATH..."
4158             export PATH="$PWD:$PATH"
4159             echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4160             # echo "Setting \$PYTHONPATH to PYTHONPATH=\${HOME}/lib/python,"
4161             # export PYTHONPATH=${HOME}/lib/python
4162         fi
4163     }
4164
4165 fi # end of check whether we have the 'hg'-executable
4166
4167 # get current mercurial snapshot
4168 #f5# Get current mercurial snapshot
4169 gethgsnap() {
4170     setopt local_options
4171     setopt errreturn
4172     if [[ -f mercurial-snapshot.tar.gz ]] ; then
4173          echo "mercurial-snapshot.tar.gz exists already, skipping download."
4174     else
4175         echo "Downloading mercurial snapshot"
4176         wget http://www.selenic.com/mercurial/mercurial-snapshot.tar.gz
4177     fi
4178     echo "Unpacking mercurial-snapshot.tar.gz"
4179     tar zxf mercurial-snapshot.tar.gz
4180     cd mercurial-snapshot/
4181     echo "Installing required build-dependencies"
4182     $SUDO apt-get update
4183     $SUDO apt-get install python2.4-dev
4184     echo "Building mercurial"
4185     make local
4186     echo "Setting \$PATH to $PWD:\$PATH..."
4187     export PATH="$PWD:$PATH"
4188     echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4189 }
4190 # }}}
4191
4192 # some useful commands often hard to remember - let's grep for them {{{
4193
4194 # Work around ion/xterm resize bug.
4195 #if [[ "$SHLVL" -eq 1 ]]; then
4196 #       if check_com -c resize ; then
4197 #               eval `resize </dev/null`
4198 #       fi
4199 #fi
4200
4201 # enable jackd:
4202 #  /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
4203 # now play audio file:
4204 #  alsaplayer -o jack foobar.mp3
4205
4206 # send files via netcat
4207 # on sending side:
4208 #  send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
4209 #  send dir* $HOST
4210 #  alias receive='nc -vlp 51330 | tar xzvp'
4211
4212 # debian stuff:
4213 # dh_make -e foo@localhost -f $1
4214 # dpkg-buildpackage -rfakeroot
4215 # lintian *.deb
4216 # dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
4217 # dpkg-scansources . | gzip > Sources.gz
4218 # grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
4219
4220 # other stuff:
4221 # convert -geometry 200x200 -interlace LINE -verbose
4222 # ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
4223 # ps -ao user,pcpu,start,command
4224 # gpg --keyserver blackhole.pca.dfn.de --recv-keys
4225 # xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
4226 # nc -vz $1 1-1024   # portscan via netcat
4227 # wget --mirror --no-parent --convert-links
4228 # pal -d `date +%d`
4229 # autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
4230 #
4231 # modify console cursor
4232 # see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
4233 # print $'\e[?96;0;64c'
4234 # }}}
4235
4236 # grml-small cleanups {{{
4237
4238 # The following is used to remove zsh-config-items that do not work
4239 # in grml-small by default.
4240 # If you do not want these adjustments (for whatever reason), set
4241 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
4242 # sources if it is there).
4243
4244 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
4245
4246     unset abk[V]
4247     unalias    'V'      &> /dev/null
4248     unfunction vman     &> /dev/null
4249     unfunction vimpm    &> /dev/null
4250     unfunction vimhelp  &> /dev/null
4251     unfunction viless   &> /dev/null
4252     unfunction 2html    &> /dev/null
4253
4254     # manpages are not in grmlsmall
4255     unfunction manzsh   &> /dev/null
4256     unalias    man2     &> /dev/null
4257     unalias    man      &> /dev/null
4258     unfunction man2     &> /dev/null
4259
4260 fi
4261
4262 #}}}
4263
4264 # finally source a local zshrc {{{
4265
4266 # this allows us to stay in sync with grml's zshrc and put own
4267 # modifications in ~/.zshrc.local
4268
4269 xsource "${HOME}/.zshrc.local"
4270
4271 # }}}
4272
4273 ### doc strings for external functions from files {{{
4274 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
4275 #}}}
4276
4277 ## END OF FILE #################################################################
4278 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4