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