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