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