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