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