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