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