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