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