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