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