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