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