zshrc: Removing mostlike references competely
[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 tail head feh cp mv df stow uname ipacsum fetchipac; do
2617         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
2618     done; unset compcom
2619
2620     # see upgrade function in this file
2621     compdef _hosts upgrade
2622 }
2623 # }}}
2624
2625 # {{{ grmlstuff
2626 grmlstuff() {
2627 # people should use 'grml-x'!
2628     startx() {
2629         if [[ -e /etc/X11/xorg.conf ]] ; then
2630             [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
2631         else
2632             echo "Please use the script \"grml-x\" for starting the X Window System
2633 because there does not exist /etc/X11/xorg.conf yet.
2634 If you want to use startx anyway please call \"/usr/bin/startx\"."
2635             return -1
2636         fi
2637     }
2638
2639     xinit() {
2640         if [[ -e /etc/X11/xorg.conf ]] ; then
2641             [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
2642         else
2643             echo "Please use the script \"grml-x\" for starting the X Window System.
2644 because there does not exist /etc/X11/xorg.conf yet.
2645 If you want to use xinit anyway please call \"/usr/bin/xinit\"."
2646             return -1
2647         fi
2648     }
2649
2650     if check_com -c 915resolution ; then
2651         alias 855resolution='echo -e "Please use 915resolution as resolution modify tool for Intel graphic chipset."; return -1'
2652     fi
2653
2654     #a1# Output version of running grml
2655     alias grml-version='cat /etc/grml_version'
2656
2657     if check_com -c rebuildfstab ; then
2658         #a1# Rebuild /etc/fstab
2659         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2660     fi
2661
2662     if check_com -c grml-debootstrap ; then
2663         alias debian2hd='print "Installing debian to harddisk is possible via using grml-debootstrap." ; return 1'
2664     fi
2665 }
2666 # }}}
2667
2668 # {{{ now run the functions
2669 isgrml && checkhome
2670 is4    && isgrml    && grmlstuff
2671 is4    && grmlcomp
2672 # }}}
2673
2674 # {{{ keephack
2675 is4 && xsource "/etc/zsh/keephack"
2676 # }}}
2677
2678 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2679 # You use it as follows:
2680 # $ NTREF=/reference/file
2681 # $ ls -l *(e:nt:)
2682 # This lists all the files in the current directory newer than the reference file.
2683 # You can also specify the reference file inline; note quotes:
2684 # $ ls -l *(e:'nt ~/.zshenv':)
2685 is4 && nt() {
2686     if [[ -n $1 ]] ; then
2687         local NTREF=${~1}
2688     fi
2689     [[ $REPLY -nt $NTREF ]]
2690 }
2691 # }}}
2692
2693 # shell functions {{{
2694
2695 #f1# Provide csh compatibility
2696 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2697
2698 #f1# Reload an autoloadable function
2699 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2700
2701 #f1# Reload zsh setup
2702 reload() {
2703     if [[ "$#*" -eq 0 ]] ; then
2704         [[ -r ~/.zshrc ]] && . ~/.zshrc
2705     else
2706         local fn
2707         for fn in "$@"; do
2708             unfunction $fn
2709             autoload -U $fn
2710         done
2711     fi
2712 }
2713 compdef _functions reload freload
2714
2715 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2716 sll() {
2717     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2718     for i in "$@" ; do
2719         file=$i
2720         while [[ -h "$file" ]] ; do
2721             ls -l $file
2722             file=$(readlink "$file")
2723         done
2724     done
2725 }
2726
2727 # fast manual access
2728 if check_com qma ; then
2729     #f1# View the zsh manual
2730     manzsh()  { qma zshall "$1" }
2731     compdef _man qma
2732 else
2733     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2734 fi
2735
2736 if check_com -c $PAGER ; then
2737     #f1# View Debian's changelog of a given package
2738     dchange() {
2739         if [[ -r /usr/share/doc/${1}/changelog.Debian.gz ]] ; then
2740             $PAGER /usr/share/doc/${1}/changelog.Debian.gz
2741         elif [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2742             $PAGER /usr/share/doc/${1}/changelog.gz
2743         else
2744             if check_com -c aptitude ; then
2745                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2746                 if isgrml ; then
2747                     aptitude -t unstable changelog ${1}
2748                 else
2749                     aptitude changelog ${1}
2750                 fi
2751             else
2752                 echo "No changelog for package $1 found, sorry."
2753                 return 1
2754             fi
2755         fi
2756     }
2757     _dchange() { _files -W /usr/share/doc -/ }
2758     compdef _dchange dchange
2759
2760     #f1# View Debian's NEWS of a given package
2761     dnews() {
2762         if [[ -r /usr/share/doc/${1}/NEWS.Debian.gz ]] ; then
2763             $PAGER /usr/share/doc/${1}/NEWS.Debian.gz
2764         else
2765             if [[ -r /usr/share/doc/${1}/NEWS.gz ]] ; then
2766                 $PAGER /usr/share/doc/${1}/NEWS.gz
2767             else
2768                 echo "No NEWS file for package $1 found, sorry."
2769                 return 1
2770             fi
2771         fi
2772     }
2773     _dnews() { _files -W /usr/share/doc -/ }
2774     compdef _dnews dnews
2775
2776     #f1# View upstream's changelog of a given package
2777     uchange() {
2778         if [[ -r /usr/share/doc/${1}/changelog.gz ]] ; then
2779             $PAGER /usr/share/doc/${1}/changelog.gz
2780         else
2781             echo "No changelog for package $1 found, sorry."
2782             return 1
2783         fi
2784     }
2785     _uchange() { _files -W /usr/share/doc -/ }
2786     compdef _uchange uchange
2787 fi
2788
2789 # zsh profiling
2790 profile() {
2791     ZSH_PROFILE_RC=1 $SHELL "$@"
2792 }
2793
2794 #f1# Edit an alias via zle
2795 edalias() {
2796     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2797 }
2798 compdef _aliases edalias
2799
2800 #f1# Edit a function via zle
2801 edfunc() {
2802     [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
2803 }
2804 compdef _functions edfunc
2805
2806 # use it e.g. via 'Restart apache2'
2807 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2808 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2809 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2810 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2811 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2812 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2813     __start_stop() {
2814         local action_="${1:l}"  # e.g Start/Stop/Restart
2815         local service_="$2"
2816         local param_="$3"
2817
2818         local service_target_="$(readlink /etc/init.d/$service_)"
2819         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2820             # runit
2821             case "${action_}" in
2822                 start) if [[ ! -e /etc/service/$service_ ]]; then
2823                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2824                        else
2825                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2826                        fi ;;
2827                 # there is no reload in runits sysv emulation
2828                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2829                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2830             esac
2831         else
2832             # sysvinit
2833             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2834         fi
2835     }
2836
2837     for i in Start Restart Stop Force-Reload Reload ; do
2838         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2839     done
2840 fi
2841
2842 #f1# Provides useful information on globbing
2843 H-Glob() {
2844     echo -e "
2845     /      directories
2846     .      plain files
2847     @      symbolic links
2848     =      sockets
2849     p      named pipes (FIFOs)
2850     *      executable plain files (0100)
2851     %      device files (character or block special)
2852     %b     block special files
2853     %c     character special files
2854     r      owner-readable files (0400)
2855     w      owner-writable files (0200)
2856     x      owner-executable files (0100)
2857     A      group-readable files (0040)
2858     I      group-writable files (0020)
2859     E      group-executable files (0010)
2860     R      world-readable files (0004)
2861     W      world-writable files (0002)
2862     X      world-executable files (0001)
2863     s      setuid files (04000)
2864     S      setgid files (02000)
2865     t      files with the sticky bit (01000)
2866
2867   print *(m-1)          # Files modified up to a day ago
2868   print *(a1)           # Files accessed a day ago
2869   print *(@)            # Just symlinks
2870   print *(Lk+50)        # Files bigger than 50 kilobytes
2871   print *(Lk-50)        # Files smaller than 50 kilobytes
2872   print **/*.c          # All *.c files recursively starting in \$PWD
2873   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2874   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2875   print *~*.*           # All Files that do not contain a dot
2876   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2877   print -l *(.c|.h)     # Lists *.c and *.h
2878   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2879   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2880 }
2881 alias help-zshglob=H-Glob
2882
2883 check_com -c qma && alias ?='qma zshall'
2884
2885 # grep for running process, like: 'any vim'
2886 any() {
2887     if [[ -z "$1" ]] ; then
2888         echo "any - grep for process(es) by keyword" >&2
2889         echo "Usage: any <keyword>" >&2 ; return 1
2890     else
2891         local STRING=$1
2892         local LENGTH=$(expr length $STRING)
2893         local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
2894         local REST=$(echo $(expr substr $STRING 2 $LENGTH))
2895         ps xauwww| grep "[$FIRSCHAR]$REST"
2896     fi
2897 }
2898
2899 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2900 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2901 [[ -r /proc/1/maps ]] && \
2902 deswap() {
2903     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2904     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2905     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2906 }
2907
2908 # print hex value of a number
2909 hex() {
2910     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2911 }
2912
2913 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2914 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2915 peval() {
2916     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2917     perl -e "print eval($CALC),\"\n\";"
2918 }
2919 functions peval &>/dev/null && alias calc=peval
2920
2921 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2922 # certain circumstances, so work around it, no matter which environment we have
2923 brltty() {
2924     if [[ -z "$DISPLAY" ]] ; then
2925         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2926         command brltty "$@"
2927     else
2928         command brltty "$@"
2929     fi
2930 }
2931
2932 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2933 aoeu() {
2934     echo -n 'Switching to us keyboard layout: '
2935     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2936     echo 'Done'
2937 }
2938 asdf() {
2939     echo -n 'Switching to dvorak keyboard layout: '
2940     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2941     echo 'Done'
2942 }
2943 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2944 uiae() {
2945     echo -n 'Switching to us keyboard layout: '
2946     setxkbmap us && echo 'Done' || echo 'Failed'
2947 }
2948
2949 # set up an ipv6 tunnel
2950 ipv6-tunnel() {
2951     case $1 in
2952         start)
2953             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2954                 print 'ipv6 tunnel already set up, nothing to be done.'
2955                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2956             else
2957                 [[ -n "$PUBLIC_IP" ]] || \
2958                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2959                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2960
2961                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2962                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2963                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2964                 ifconfig sit0 tunnel ::192.88.99.1 up
2965                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2966             fi
2967             ;;
2968         status)
2969             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2970                 print 'ipv6 tunnel available' ; return 0
2971             else
2972                 print 'ipv6 tunnel not available' ; return 1
2973             fi
2974             ;;
2975         stop)
2976             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2977                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2978                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2979             else
2980                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2981             fi
2982             ;;
2983         *)
2984             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2985             ;;
2986     esac
2987 }
2988
2989 # run dhclient for wireless device
2990 iwclient() {
2991     salias dhclient "$(wavemon -d | awk '/device/{print $2}')"
2992 }
2993
2994 # spawn a minimally set up ksh - useful if you want to umount /usr/.
2995 minimal-shell() {
2996     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
2997 }
2998
2999 # a wrapper for vim, that deals with title setting
3000 #   VIM_OPTIONS
3001 #       set this array to a set of options to vim you always want
3002 #       to have set when calling vim (in .zshrc.local), like:
3003 #           VIM_OPTIONS=( -p )
3004 #       This will cause vim to send every file given on the
3005 #       commandline to be send to it's own tab (needs vim7).
3006 vim() {
3007     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
3008 }
3009
3010 # make a backup of a file
3011 bk() {
3012     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
3013 }
3014
3015 #f1# grep for patterns in grml's zsh setup
3016 zg() {
3017 #{{{
3018     LANG=C perl -e '
3019
3020 sub usage {
3021     print "usage: zg -[anr] <pattern>\n";
3022     print " Search for patterns in grml'\''s zshrc.\n";
3023     print " zg takes no or exactly one option plus a non empty pattern.\n\n";
3024     print "   options:\n";
3025     print "     --  no options (use if your pattern starts in with a dash.\n";
3026     print "     -a  search for the pattern in all code regions\n";
3027     print "     -n  search for the pattern in non-root code only\n";
3028     print "     -r  search in code for everyone (also root) only\n\n";
3029     print "   The default is -a for non-root users and -r for root.\n\n";
3030     print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
3031     print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
3032     print " ...in case you copied the file to that location.\n\n";
3033     exit 1;
3034 }
3035
3036 if ($ENV{GRML_ZSHRC} ne "") {
3037     $RC = $ENV{GRML_ZSHRC};
3038 } else {
3039     $RC = "/etc/zsh/zshrc";
3040 }
3041
3042 usage if ($#ARGV < 0 || $#ARGV > 1);
3043 if ($> == 0) { $mode = "allonly"; }
3044 else { $mode = "all"; }
3045
3046 $opt = $ARGV[0];
3047 if ($opt eq "--")     { shift; }
3048 elsif ($opt eq "-a")  { $mode = "all"; shift; }
3049 elsif ($opt eq "-n")  { $mode = "nonroot"; shift; }
3050 elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
3051 elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
3052
3053 $pattern = $ARGV[0];
3054 usage() if ($pattern eq "");
3055
3056 open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
3057 while ($line = <FH>) {
3058     chomp $line;
3059     if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
3060     next if ($mode eq "nonroot" && markerfound == 0);
3061     break if ($mode eq "allonly" && markerfound == 1);
3062     print $line, "\n" if ($line =~ /$pattern/);
3063 }
3064 close FH;
3065 exit 0;
3066
3067     ' -- "$@"
3068 #}}}
3069     return $?
3070 }
3071
3072 # }}}
3073
3074 # {{{ make sure our environment is clean regarding colors
3075 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
3076 # }}}
3077
3078 # "persistent history" {{{
3079 # just write important commands you always need to ~/.important_commands
3080 if [[ -r ~/.important_commands ]] ; then
3081     fc -R ~/.important_commands
3082 fi
3083 # }}}
3084
3085 #:grep:marker:for:mika: :-)
3086 ### non-root (EUID != 0) code below
3087 ###
3088
3089 if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
3090     zrclocal
3091     return 0
3092 fi
3093
3094
3095 # variables {{{
3096
3097 # set terminal property (used e.g. by msgid-chooser)
3098 export COLORTERM="yes"
3099
3100 # set default browser
3101 if [[ -z "$BROWSER" ]] ; then
3102     if [[ -n "$DISPLAY" ]] ; then
3103         #v# If X11 is running
3104         check_com -c firefox && export BROWSER=firefox
3105     else
3106         #v# If no X11 is running
3107         check_com -c w3m && export BROWSER=w3m
3108     fi
3109 fi
3110
3111 #m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
3112 [[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
3113 [[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
3114
3115 # support running 'jikes *.java && jamvm HelloWorld' OOTB:
3116 #v# [for non-root only]
3117 [[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
3118 # }}}
3119
3120 # aliases {{{
3121
3122 # Xterm resizing-fu.
3123 # Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
3124 alias hide='echo -en "\033]50;nil2\007"'
3125 alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
3126 alias small='echo -en "\033]50;6x10\007"'
3127 alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
3128 alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
3129 alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
3130 alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
3131 alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
3132 alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
3133
3134 # general
3135 #a2# Execute \kbd{du -sch}
3136 alias da='du -sch'
3137 #a2# Execute \kbd{jobs -l}
3138 alias j='jobs -l'
3139
3140 # compile stuff
3141 #a2# Execute \kbd{./configure}
3142 alias CO="./configure"
3143 #a2# Execute \kbd{./configure --help}
3144 alias CH="./configure --help"
3145
3146 # arch/tla stuff
3147 if check_com -c tla ; then
3148     #a2# Execute \kbd{tla what-changed --diffs | less}
3149     alias tdi='tla what-changed --diffs | less'
3150     #a2# Execute \kbd{tla-buildpackage}
3151     alias tbp='tla-buildpackage'
3152     #a2# Execute \kbd{tla archive-mirror}
3153     alias tmi='tla archive-mirror'
3154     #a2# Execute \kbd{tla commit}
3155     alias tco='tla commit'
3156     #a2# Execute \kbd{tla star-merge}
3157     alias tme='tla star-merge'
3158 fi
3159
3160 # listing stuff
3161 #a2# Execute \kbd{ls -lSrah}
3162 alias dir="ls -lSrah"
3163 #a2# Only show dot-directories
3164 alias lad='ls -d .*(/)'                # only show dot-directories
3165 #a2# Only show dot-files
3166 alias lsa='ls -a .*(.)'                # only show dot-files
3167 #a2# Only files with setgid/setuid/sticky flag
3168 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
3169 #a2# Only show 1st ten symlinks
3170 alias lsl='ls -l *(@[1,10])'           # only symlinks
3171 #a2# Display only executables
3172 alias lsx='ls -l *(*[1,10])'           # only executables
3173 #a2# Display world-{readable,writable,executable} files
3174 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
3175 #a2# Display the ten biggest files
3176 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
3177 #a2# Only show directories
3178 alias lsd='ls -d *(/)'                 # only show directories
3179 #a2# Only show empty directories
3180 alias lse='ls -d *(/^F)'               # only show empty directories
3181 #a2# Display the ten newest files
3182 alias lsnew="ls -rl *(D.om[1,10])"     # display the newest files
3183 #a2# Display the ten oldest files
3184 alias lsold="ls -rtlh *(D.om[1,10])"   # display the oldest files
3185 #a2# Display the ten smallest files
3186 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
3187
3188 # chmod
3189 #a2# Execute \kbd{chmod 600}
3190 alias rw-='chmod 600'
3191 #a2# Execute \kbd{chmod 700}
3192 alias rwx='chmod 700'
3193 #m# a2 r-{}- Execute \kbd{chmod 644}
3194 alias r--='chmod 644'
3195 #a2# Execute \kbd{chmod 755}
3196 alias r-x='chmod 755'
3197
3198 # some useful aliases
3199 #a2# Execute \kbd{mkdir -o}
3200 alias md='mkdir -p'
3201
3202 check_com -c ipython && alias ips='ipython -p sh'
3203
3204 # console stuff
3205 #a2# Execute \kbd{mplayer -vo fbdev}
3206 alias cmplayer='mplayer -vo fbdev'
3207 #a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
3208 alias fbmplayer='mplayer -vo fbdev -fs -zoom'
3209 #a2# Execute \kbd{links2 -driver fb}
3210 alias fblinks='links2 -driver fb'
3211
3212 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3213 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3214 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3215
3216 # simple webserver
3217 check_com -c python && alias http="python -m SimpleHTTPServer"
3218
3219 # Use 'g' instead of 'git':
3220 check_com g || alias g='git'
3221
3222 # check whether Debian's package management (dpkg) is running
3223 if check_com salias ; then
3224     #a2# Check whether a dpkg instance is currently running
3225     salias check_dpkg_running="dpkg_running"
3226 fi
3227
3228 # work around non utf8 capable software in utf environment via $LANG and luit
3229 if check_com isutfenv && check_com luit ; then
3230     if check_com -c mrxvt ; then
3231         isutfenv && [[ -n "$LANG" ]] && \
3232             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3233     fi
3234
3235     if check_com -c aterm ; then
3236         isutfenv && [[ -n "$LANG" ]] && \
3237             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3238     fi
3239
3240     if check_com -c centericq ; then
3241         isutfenv && [[ -n "$LANG" ]] && \
3242             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3243     fi
3244 fi
3245 # }}}
3246
3247 # useful functions {{{
3248
3249 # searching
3250 #f4# Search for newspostings from authors
3251 agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
3252 #f4# Search Debian Bug Tracking System
3253 debbug()  {
3254     setopt localoptions extendedglob
3255     if [[ $# -eq 1 ]]; then
3256         case "$1" in
3257             ([0-9]##)
3258             ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
3259             ;;
3260             (*@*)
3261             ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
3262             ;;
3263             (*)
3264             ${=BROWSER} "http://bugs.debian.org/$*"
3265             ;;
3266         esac
3267     else
3268         print "$0 needs one argument"
3269         return 1
3270     fi
3271 }
3272 #f4# Search Debian Bug Tracking System in mbox format
3273 debbugm() { bts show --mbox $1 } # provide bugnummer as "$1"
3274 #f4# Search DMOZ
3275 dmoz()    { ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_} }
3276 #f4# Search German   Wiktionary
3277 dwicti()  { ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_} }
3278 #f4# Search English  Wiktionary
3279 ewicti()  { ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_} }
3280 #f4# Search Google Groups
3281 ggogle()  { ${=BROWSER} "http://groups.google.com/groups?q=$*" }
3282 #f4# Search Google
3283 google()  { ${=BROWSER} "http://www.google.com/search?&num=100&q=$*" }
3284 #f4# Search Google Groups for MsgID
3285 mggogle() { ${=BROWSER} "http://groups.google.com/groups?selm=$*" }
3286 #f4# Search Netcraft
3287 netcraft(){ ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1" }
3288 #f4# Use German Wikipedia's full text search
3289 swiki()   { ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1} }
3290 #f4# search \kbd{dict.leo.org}
3291 oleo()    { ${=BROWSER} "http://dict.leo.org/?search=$*" }
3292 #f4# Search German   Wikipedia
3293 wikide()  { ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}" }
3294 #f4# Search English  Wikipedia
3295 wikien()  { ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}" }
3296 #f4# Search official debs
3297 wodeb()   { ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all" }
3298
3299 #m# f4 gex() Exact search via Google
3300 check_com google && gex () { google "\"[ $1]\" $*" } # exact search at google
3301
3302 # misc
3303 #f5# Backup \kbd{file {\rm to} file\_timestamp}
3304 bk()      { cp -b ${1} ${1}_`date --iso-8601=m` }
3305 #f5# Copied diff
3306 cdiff()   { diff -crd "$*" | egrep -v "^Only in |^Binary files " }
3307 #f5# cd to directoy and list files
3308 cl()      { cd $1 && ls -a }        # cd && ls
3309 #f5# Cvs add
3310 cvsa()    { cvs add $* && cvs com -m 'initial checkin' $* }
3311 #f5# Cvs diff
3312 cvsd()    { cvs diff -N $* |& $PAGER }
3313 #f5# Cvs log
3314 cvsl()    { cvs log $* |& $PAGER }
3315 #f5# Cvs update
3316 cvsq()    { cvs -nq update }
3317 #f5# Rcs2log
3318 cvsr()    { rcs2log $* | $PAGER }
3319 #f5# Cvs status
3320 cvss()    { cvs status -v $* }
3321 #f5# Disassemble source files using gcc and as
3322 disassemble(){ gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null }
3323 #f5# Firefox remote control - open given URL
3324 fir()     { firefox -a firefox -remote "openURL($1)" }
3325 #f5# Create Directoy and \kbd{cd} to it
3326 mcd()     { mkdir -p "$@"; cd "$@" } # mkdir && cd
3327 #f5# Unified diff to timestamped outputfile
3328 mdiff()   { diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1" }
3329 #f5# Memory overview
3330 memusage(){ ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc }
3331 #f5# Show contents of tar file
3332 shtar()   { gunzip -c $1 | tar -tf - -- | $PAGER }
3333 #f5# Show contents of tgz file
3334 shtgz()   { tar -ztf $1 | $PAGER }
3335 #f5# Show contents of zip file
3336 shzip()   { unzip -l $1 | $PAGER }
3337 #f5# Greps signature from file
3338 sig()     { agrep -d '^-- $' "$*" ~/.Signature }
3339 #f5# Unified diff
3340 udiff()   { diff -urd $* | egrep -v "^Only in |^Binary files " }
3341 #f5# (Mis)use \kbd{vim} as \kbd{less}
3342 viless()  { vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}" }
3343
3344 # download video from youtube
3345 ytdl() {
3346     if ! [[ -n "$2" ]] ; then
3347         print "Usage: ydtl http://youtube.com/watch?v=.... outputfile.flv">&2
3348         return 1
3349     else
3350         wget -O${2} "http://youtube.com/get_video?"${${${"$(wget -o/dev/null -O- "${1}" | grep -e watch_fullscreen)"}##*watch_fullscreen\?}%%\&fs=*}
3351     fi
3352 }
3353
3354 # Function Usage: uopen $URL/$file
3355 #f5# Download a file and display it locally
3356 uopen() {
3357     if ! [[ -n "$1" ]] ; then
3358         print "Usage: uopen \$URL/\$file">&2
3359         return 1
3360     else
3361         FILE=$1
3362         MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
3363         MIME=${MIME%$'\r'}
3364         curl $FILE | see ${MIME}:-
3365     fi
3366 }
3367
3368 # Function Usage: doc packagename
3369 #f5# \kbd{cd} to /usr/share/doc/\textit{package}
3370 doc() { cd /usr/share/doc/$1 && ls }
3371 _doc() { _files -W /usr/share/doc -/ }
3372 check_com compdef && compdef _doc doc
3373
3374 #f5# Make screenshot
3375 sshot() {
3376     [[ ! -d ~/shots  ]] && mkdir ~/shots
3377     #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
3378     cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
3379 }
3380
3381 # list images only
3382 limg() {
3383     local -a images
3384     images=( *.{jpg,gif,png}(.N) )
3385
3386     if [[ $#images -eq 0 ]] ; then
3387         print "No image files found"
3388     else
3389         ls "$@" "$images[@]"
3390     fi
3391 }
3392
3393 #f5# Create PDF file from source code
3394 makereadable() {
3395     output=$1
3396     shift
3397     a2ps --medium A4dj -E -o $output $*
3398     ps2pdf $output
3399 }
3400
3401 # zsh with perl-regex - use it e.g. via:
3402 # regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
3403 #f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
3404 regcheck() {
3405     zmodload -i zsh/pcre
3406     pcre_compile $1 && \
3407     pcre_match $2 && echo "regex matches" || echo "regex does not match"
3408 }
3409
3410 #f5# List files which have been modified within the last {\it n} days
3411 new() { print -l *(m-$1) }
3412
3413 #f5# Grep in history
3414 greph() { history 0 | grep $1 }
3415 # use colors when GNU grep with color-support
3416 #a2# Execute \kbd{grep -{}-color=auto}
3417 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
3418 #a2# Execute \kbd{grep -i -{}-color=auto}
3419 alias GREP='grep -i --color=auto'
3420
3421 #f5# Watch manpages in a stretched style
3422 man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
3423
3424 # d():Copyright 2005 Nikolai Weibull <nikolai@bitwi.se>
3425 # note: option AUTO_PUSHD has to be set
3426 #f5# Jump between directories
3427 d() {
3428     emulate -L zsh
3429     autoload -U colors
3430     local color=$fg_bold[blue]
3431     integer i=0
3432     dirs -p | while read dir; do
3433         local num="${$(printf "%-4d " $i)/ /.}"
3434         printf " %s  $color%s$reset_color\n" $num $dir
3435         (( i++ ))
3436     done
3437     integer dir=-1
3438     read -r 'dir?Jump to directory: ' || return
3439     (( dir == -1 )) && return
3440     if (( dir < 0 || dir >= i )); then
3441         echo d: no such directory stack entry: $dir
3442         return 1
3443     fi
3444     cd ~$dir
3445 }
3446
3447 # usage example: 'lcheck strcpy'
3448 #f5# Find out which libs define a symbol
3449 lcheck() {
3450     if [[ -n "$1" ]] ; then
3451         nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
3452     else
3453         echo "Usage: lcheck <function>" >&2
3454     fi
3455 }
3456
3457 #f5# Clean up directory - remove well known tempfiles
3458 purge() {
3459     FILES=(*~(N) .*~(N) \#*\#(N) *.o(N) a.out(N) *.core(N) *.cmo(N) *.cmi(N) .*.swp(N))
3460     NBFILES=${#FILES}
3461     if [[ $NBFILES > 0 ]] ; then
3462         print $FILES
3463         local ans
3464         echo -n "Remove these files? [y/n] "
3465         read -q ans
3466         if [[ $ans == "y" ]] ; then
3467             rm ${FILES}
3468             echo ">> $PWD purged, $NBFILES files removed"
3469         else
3470             echo "Ok. .. than not.."
3471         fi
3472     fi
3473 }
3474
3475 # Translate DE<=>EN
3476 # 'translate' looks up fot a word in a file with language-to-language
3477 # translations (field separator should be " : "). A typical wordlist looks
3478 # like at follows:
3479 #  | english-word : german-transmission
3480 # It's also only possible to translate english to german but not reciprocal.
3481 # Use the following oneliner to turn back the sort order:
3482 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3483 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3484 #f5# Translates a word
3485 trans() {
3486     case "$1" in
3487         -[dD]*)
3488             translate -l de-en $2
3489             ;;
3490         -[eE]*)
3491             translate -l en-de $2
3492             ;;
3493         *)
3494             echo "Usage: $0 { -D | -E }"
3495             echo "         -D == German to English"
3496             echo "         -E == English to German"
3497     esac
3498 }
3499
3500 #f5# List all occurrences of programm in current PATH
3501 plap() {
3502     if [[ $# = 0 ]] ; then
3503         echo "Usage:    $0 program"
3504         echo "Example:  $0 zsh"
3505         echo "Lists all occurrences of program in the current PATH."
3506     else
3507         ls -l ${^path}/*$1*(*N)
3508     fi
3509 }
3510
3511 # Found in the mailinglistarchive from Zsh (IIRC ~1996)
3512 #f5# Select items for specific command(s) from history
3513 selhist() {
3514     emulate -L zsh
3515     local TAB=$'\t';
3516     (( $# < 1 )) && {
3517         echo "Usage: $0 command"
3518         return 1
3519     };
3520     cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
3521     print -l $cmd | less -F
3522     echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
3523     local answer
3524     read answer
3525     print -z "${cmd[$answer]#*$TAB}"
3526 }
3527
3528 # Use vim to convert plaintext to HTML
3529 #f5# Transform files to html with highlighting
3530 2html() { vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null }
3531
3532 # Usage: simple-extract <file>
3533 #f5# Smart archive extractor
3534 simple-extract () {
3535     if [[ -f $1 ]] ; then
3536         case $1 in
3537             *.tar.bz2)  bzip2 -v -d $1      ;;
3538             *.tar.gz)   tar -xvzf $1        ;;
3539             *.rar)      unrar $1            ;;
3540             *.deb)      ar -x $1            ;;
3541             *.bz2)      bzip2 -d $1         ;;
3542             *.lzh)      lha x $1            ;;
3543             *.gz)       gunzip -d $1        ;;
3544             *.tar)      tar -xvf $1         ;;
3545             *.tgz)      gunzip -d $1        ;;
3546             *.tbz2)     tar -jxvf $1        ;;
3547             *.zip)      unzip $1            ;;
3548             *.Z)        uncompress $1       ;;
3549             *)          echo "'$1' Error. Please go away" ;;
3550         esac
3551     else
3552         echo "'$1' is not a valid file"
3553     fi
3554 }
3555
3556 # Usage: smartcompress <file> (<type>)
3557 #f5# Smart archive creator
3558 smartcompress() {
3559     if [[ -n $2 ]] ; then
3560         case $2 in
3561             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
3562             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
3563             tar.Z)          tar -Zcvf$1.$2 $1 ;;
3564             tar)            tar -cvf$1.$2  $1 ;;
3565             gz | gzip)      gzip           $1 ;;
3566             bz2 | bzip2)    bzip2          $1 ;;
3567             *)
3568                 echo "Error: $2 is not a valid compression type"
3569                 ;;
3570         esac
3571     else
3572         smartcompress $1 tar.gz
3573     fi
3574 }
3575
3576 # Usage: show-archive <archive>
3577 #f5# List an archive's content
3578 show-archive() {
3579     if [[ -f $1 ]] ; then
3580         case $1 in
3581             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
3582             *.tar)         tar -tf $1 ;;
3583             *.tgz)         tar -ztf $1 ;;
3584             *.zip)         unzip -l $1 ;;
3585             *.bz2)         bzless $1 ;;
3586             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
3587             *)             echo "'$1' Error. Please go away" ;;
3588         esac
3589     else
3590         echo "'$1' is not a valid archive"
3591     fi
3592 }
3593
3594 # It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
3595 #f5# Use \kbd{vim} as your manpage reader
3596 vman() { man $* | col -b | view -c 'set ft=man nomod nolist' - }
3597
3598 # function readme() { $PAGER -- (#ia3)readme* }
3599 #f5# View all README-like files in current directory in pager
3600 readme() {
3601     local files
3602     files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
3603     if (($#files)) ; then
3604         $PAGER $files
3605     else
3606         print 'No README files.'
3607     fi
3608 }
3609
3610 # function ansi-colors()
3611 #f5# Display ANSI colors
3612 ansi-colors() {
3613     typeset esc="\033[" line1 line2
3614     echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
3615     for fore in 30 31 32 33 34 35 36 37; do
3616         line1="$fore "
3617         line2="   "
3618         for back in 40 41 42 43 44 45 46 47 49; do
3619             line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
3620             line2="${line2}${esc}${back};${fore};1m Bold   ${esc}0m"
3621         done
3622         echo -e "$line1\n$line2"
3623     done
3624 }
3625
3626 # suidfind() { ls -latg $path | grep '^...s' }
3627 #f5# Find all files in \$PATH with setuid bit set
3628 suidfind() { ls -latg $path/*(sN) }
3629
3630 # See above but this is /better/ ... anywise ..
3631 findsuid() {
3632     print 'Output will be written to ~/suid_* ...'
3633     $SUDO find / -type f \( -perm -4000 -o -perm -2000 \) -ls > ~/suid_suidfiles.`date "+%Y-%m-%d"`.out 2>&1
3634     $SUDO find / -type d \( -perm -4000 -o -perm -2000 \) -ls > ~/suid_suiddirs.`date "+%Y-%m-%d"`.out 2>&1
3635     $SUDO find / -type f \( -perm -2 -o -perm -20 \) -ls > ~/suid_writefiles.`date "+%Y-%m-%d"`.out 2>&1
3636     $SUDO find / -type d \( -perm -2 -o -perm -20 \) -ls > ~/suid_writedirs.`date "+%Y-%m-%d"`.out 2>&1
3637     print 'Finished'
3638 }
3639
3640 #f5# Reload given functions
3641 refunc() {
3642     for func in $argv ; do
3643         unfunction $func
3644         autoload $func
3645     done
3646 }
3647
3648 # a small check to see which DIR is located on which server/partition.
3649 # stolen and modified from Sven's zshrc.forall
3650 #f5# Report diskusage of a directory
3651 dirspace() {
3652     if [[ -n "$1" ]] ; then
3653         for dir in $* ; do
3654             if [[ -d "$dir" ]] ; then
3655                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3656             else
3657                 echo "warning: $dir does not exist" >&2
3658             fi
3659         done
3660     else
3661         for dir in $path; do
3662             if [[ -d "$dir" ]] ; then
3663                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3664             else
3665                 echo "warning: $dir does not exist" >&2
3666             fi
3667         done
3668     fi
3669 }
3670
3671 # % slow_print `cat /etc/passwd`
3672 #f5# Slowly print out parameters
3673 slow_print() {
3674     for argument in "${@}" ; do
3675         for ((i = 1; i <= ${#1} ;i++)) ; do
3676             print -n "${argument[i]}"
3677             sleep 0.08
3678         done
3679         print -n " "
3680     done
3681     print ""
3682 }
3683
3684 #f5# Show some status info
3685 status() {
3686     print ""
3687     print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")""
3688     print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
3689     print "Term..: $TTY ($TERM), ${BAUD:+$BAUD bauds, }$COLUMNS x $LINES cars"
3690     print "Login.: $LOGNAME (UID = $EUID) on $HOST"
3691     print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
3692     print "Uptime:$(uptime)"
3693     print ""
3694 }
3695
3696 # Rip an audio CD
3697 #f5# Rip an audio CD
3698 audiorip() {
3699     mkdir -p ~/ripps
3700     cd ~/ripps
3701     cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
3702     cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
3703     echo " * Would you like to burn the cd now? (yes/no)"
3704     read input
3705     if [[ "$input" = "yes" ]] ; then
3706         echo " ! Burning Audio CD"
3707         audioburn
3708         echo " * done."
3709     else
3710         echo " ! Invalid response."
3711     fi
3712 }
3713
3714 # and burn it
3715 #f5# Burn an audio CD (in combination with audiorip)
3716 audioburn() {
3717     cd ~/ripps
3718     cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
3719     echo " * Should I remove the temporary files? (yes/no)"
3720     read input
3721     if [[ "$input" = "yes" ]] ; then
3722         echo " ! Removing Temporary Files."
3723         cd ~
3724         rm -rf ~/ripps
3725         echo " * done."
3726     else
3727         echo " ! Invalid response."
3728     fi
3729 }
3730
3731 #f5# Make an audio CD from all mp3 files
3732 mkaudiocd() {
3733     # TODO: do the renaming more zshish, possibly with zmv()
3734     cd ~/ripps
3735     for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
3736     for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
3737     for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
3738     normalize -m *.wav
3739     for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
3740 }
3741
3742 #f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
3743 mkiso() {
3744     echo " * Volume name "
3745     read volume
3746     echo " * ISO Name (ie. tmp.iso)"
3747     read iso
3748     echo " * Directory or File"
3749     read files
3750     mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
3751 }
3752
3753 #f5# Simple thumbnails generator
3754 genthumbs() {
3755     rm -rf thumb-* index.html
3756     echo "
3757 <html>
3758   <head>
3759     <title>Images</title>
3760   </head>
3761   <body>" > index.html
3762     for f in *.(gif|jpeg|jpg|png) ; do
3763         convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
3764         echo "    <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
3765     done
3766     echo "
3767   </body>
3768 </html>" >> index.html
3769 }
3770
3771 #f5# Set all ulimit parameters to \kbd{unlimited}
3772 allulimit() {
3773     ulimit -c unlimited
3774     ulimit -d unlimited
3775     ulimit -f unlimited
3776     ulimit -l unlimited
3777     ulimit -n unlimited
3778     ulimit -s unlimited
3779     ulimit -t unlimited
3780 }
3781
3782 # ogg2mp3 with bitrate of 192
3783 ogg2mp3_192() {
3784     oggdec -o - ${1} | lame -b 192 - ${1:r}.mp3
3785 }
3786
3787 #f5# RFC 2396 URL encoding in Z-Shell
3788 urlencode() {
3789     setopt localoptions extendedglob
3790     input=( ${(s::)1} )
3791     print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
3792 }
3793
3794 #f5# Install x-lite (VoIP software)
3795 getxlite() {
3796     setopt local_options
3797     setopt errreturn
3798     [[ -d ~/tmp ]] || mkdir ~/tmp
3799     cd ~/tmp
3800
3801     echo "Downloading http://www.counterpath.com/download/X-Lite_Install.tar.gz and storing it in ~/tmp:"
3802     if wget http://www.counterpath.com/download/X-Lite_Install.tar.gz ; then
3803         unp X-Lite_Install.tar.gz && echo done || echo failed
3804     else
3805         echo "Error while downloading." ; return 1
3806     fi
3807
3808     if [[ -x xten-xlite/xtensoftphone ]] ; then
3809         echo "Execute xten-xlite/xtensoftphone to start xlite."
3810     fi
3811 }
3812
3813 #f5# Install skype
3814 getskype() {
3815     setopt local_options
3816     setopt errreturn
3817     echo "Downloading debian package of skype."
3818     echo "Notice: If you want to use a more recent skype version run 'getskypebeta'."
3819     wget http://www.skype.com/go/getskype-linux-deb
3820     $SUDO dpkg -i skype*.deb && echo "skype installed."
3821 }
3822
3823 #f5# Install beta-version of skype
3824 getskypebeta() {
3825     setopt local_options
3826     setopt errreturn
3827     echo "Downloading debian package of skype (beta version)."
3828     wget http://www.skype.com/go/getskype-linux-beta-deb
3829     $SUDO dpkg -i skype-beta*.deb && echo "skype installed."
3830 }
3831
3832 #f5# Install gizmo (VoIP software)
3833 getgizmo() {
3834     setopt local_options
3835     setopt errreturn
3836     echo "libgtk2.0-0, gconf2, libstdc++6, libasound2 and zlib1g have to be available. Installing."
3837     $SUDO apt-get update
3838     $SUDO apt-get install libgtk2.0-0 gconf2 libstdc++6 libasound2 zlib1g
3839     wget "$(lynx --dump http://gizmo5.com/pc/download/linux/ | awk '/libstdc\+\+6.*\.deb/ {print $2}')"
3840     $SUDO dpkg -i gizmo-project*.deb && echo "gizmo installed."
3841 }
3842
3843 #f5# Get and run AIR (Automated Image and Restore)
3844 getair() {
3845     setopt local_options
3846     setopt errreturn
3847     [[ -w . ]] || { echo 'Error: you do not have write permissions in this directory. Exiting.' ; return 1 }
3848     local VER='1.2.8'
3849     wget http://puzzle.dl.sourceforge.net/sourceforge/air-imager/air-$VER.tar.gz
3850     tar zxf air-$VER.tar.gz
3851     cd air-$VER
3852     INTERACTIVE=no $SUDO ./install-air-1.2.8
3853     [[ -x /usr/local/bin/air ]] && [[ -n "$DISPLAY" ]] && $SUDO air
3854 }
3855
3856 #f5# Get specific git commitdiff
3857 git-get-diff() {
3858     if [[ -z $GITTREE ]] ; then
3859         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3860     fi
3861     if ! [[ -z $1 ]] ; then
3862         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commitdiff;h=$1"
3863     else
3864         echo "Usage: git-get-diff <commit>"
3865     fi
3866 }
3867
3868 #f5# Get specific git commit
3869 git-get-commit() {
3870     if [[ -z $GITTREE ]] ; then
3871         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3872     fi
3873     if ! [[ -z $1 ]] ; then
3874         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commit;h=$1"
3875     else
3876         echo "Usage: git-get-commit <commit>"
3877     fi
3878 }
3879
3880 #f5# Get specific git diff
3881 git-get-plaindiff () {
3882     if [[ -z $GITTREE ]] ; then
3883        GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3884     fi
3885     if [[ -z $1 ]] ; then
3886        echo 'Usage: git-get-plaindiff '
3887     else
3888        echo -n "Downloading $1.diff ... "
3889        # avoid "generating ..." stuff from kernel.org server:
3890        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O /dev/null
3891        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O $1.diff \
3892             && echo done || echo failed
3893     fi
3894 }
3895
3896
3897 # http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
3898 #f5# Log 'make install' output
3899 mmake() {
3900     [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
3901     make -n install > ~/.errorlogs/${PWD##*/}-makelog
3902 }
3903
3904 #f5# Indent source code
3905 smart-indent() {
3906     indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs $*
3907 }
3908
3909 # highlight important stuff in diff output, usage example: hg diff | hidiff
3910 #m# a2 hidiff \kbd{histring} oneliner for diffs
3911 check_com -c histring && \
3912     alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
3913
3914 # rename pictures based on information found in exif headers
3915 #f5# Rename pictures based on information found in exif headers
3916 exirename() {
3917     if [[ $# -lt 1 ]] ; then
3918         echo 'Usage: jpgrename $FILES' >& 2
3919         return 1
3920     else
3921         echo -n 'Checking for jhead with version newer than 1.9: '
3922         jhead_version=`jhead -h | grep 'used by most Digital Cameras.  v.*' | awk '{print $6}' | tr -d v`
3923         if [[ $jhead_version > '1.9' ]]; then
3924             echo 'success - now running jhead.'
3925             jhead -n%Y-%m-%d_%Hh%M_%f $*
3926         else
3927             echo 'failed - exiting.'
3928         fi
3929     fi
3930 }
3931
3932 # open file in vim and jump to line
3933 # http://www.downgra.de/archives/2007/05/08/T19_21_11/
3934 j2v() {
3935     local -a params
3936     params=(${*//(#m):[0-9]*:/\\n+${MATCH//:/}}) # replace ':23:' to '\n+23'
3937     params=(${(s|\n|)${(j|\n|)params}}) # join array using '\n', then split on all '\n'
3938     vim ${params}
3939 }
3940
3941 # get_ic() - queries imap servers for capabilities; real simple. no imaps
3942 ic_get() {
3943     local port
3944     if [[ ! -z $1 ]] ; then
3945         port=${2:-143}
3946         print "querying imap server on $1:${port}...\n";
3947         print "a1 capability\na2 logout\n" | nc $1 ${port}
3948     else
3949         print "usage:\n  $0 <imap-server> [port]"
3950     fi
3951 }
3952
3953 # creates a Maildir/ with its {new,cur,tmp} subdirs
3954 mkmaildir() {
3955     local root subdir
3956     root=${MAILDIR_ROOT:-${HOME}/Mail}
3957     if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
3958     subdir=${1}
3959     mkdir -p ${root}/${subdir}/{cur,new,tmp}
3960 }
3961
3962 #f5# Change the xterm title from within GNU-screen
3963 xtrename() {
3964     if [[ ${1} != "-f" ]] ; then
3965         if [[ -z ${DISPLAY} ]] ; then
3966             printf 'xtrename only makes sense in X11.\n'
3967             return 1
3968         fi
3969     else
3970         shift
3971     fi
3972     if [[ -z ${1} ]] ; then
3973         printf 'usage: xtrename [-f] "title for xterm"\n'
3974         printf '  renames the title of xterm from _within_ screen.\n'
3975         printf '  also works without screen.\n'
3976         printf '  will not work if DISPLAY is unset, use -f to override.\n'
3977         return 0
3978     fi
3979     print -n "\eP\e]0;${1}\C-G\e\\"
3980     return 0
3981 }
3982
3983 # hl() highlighted less
3984 # http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
3985 if check_com -c highlight ; then
3986     function hl() {
3987         local theme lang
3988         theme=${HL_THEME:-""}
3989         case ${1} in
3990             (-l|--list)
3991                 ( printf 'available languages (syntax parameter):\n\n' ;
3992                     highlight --list-langs ; ) | less -SMr
3993                 ;;
3994             (-t|--themes)
3995                 ( printf 'available themes (style parameter):\n\n' ;
3996                     highlight --list-themes ; ) | less -SMr
3997                 ;;
3998             (-h|--help)
3999                 printf 'usage: hl <syntax[:theme]> <file>\n'
4000                 printf '    available options: --list (-l), --themes (-t), --help (-h)\n\n'
4001                 printf '  Example: hl c main.c\n'
4002                 ;;
4003             (*)
4004                 if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
4005                     printf 'usage: hl <syntax[:theme]> <file>\n'
4006                     printf '    available options: --list (-l), --themes (-t), --help (-h)\n'
4007                     (( ${#argv} > 2 )) && printf '  Too many arguments.\n'
4008                     return 1
4009                 fi
4010                 lang=${1%:*}
4011                 [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
4012                 if [[ -n ${theme} ]] ; then
4013                     highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
4014                 else
4015                     highlight --ansi --syntax ${lang} ${2} | less -SMr
4016                 fi
4017                 ;;
4018         esac
4019         return 0
4020     }
4021     # ... and a proper completion for hl()
4022     # needs 'highlight' as well, so it fits fine in here.
4023     function _hl_genarg()  {
4024         local expl
4025         if [[ -prefix 1 *: ]] ; then
4026             local themes
4027             themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
4028             compset -P 1 '*:'
4029             _wanted -C list themes expl theme compadd ${themes}
4030         else
4031             local langs
4032             langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
4033             _wanted -C list languages expl languages compadd -S ':' -q ${langs}
4034         fi
4035     }
4036     function _hl_complete() {
4037         _arguments -s '1: :_hl_genarg' '2:files:_path_files'
4038     }
4039     compdef _hl_complete hl
4040 fi
4041
4042 # Create small urls via http://tinyurl.com using wget(1).
4043 function zurl() {
4044     [[ -z ${1} ]] && { print "USAGE: zurl <URL>" ; return 1 }
4045
4046     local PN url tiny grabber search result preview
4047     PN=${0}
4048     url=${1}
4049 #   Check existence of given URL with the help of ping(1).
4050 #   N.B. ping(1) only works without an eventual given protocol.
4051     ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
4052         read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
4053
4054     if (( $? == 0 )) ; then
4055 #           Prepend 'http://' to given URL where necessary for later output.
4056             [[ ${url} != http(s|)://* ]] && url='http://'${url}
4057             tiny='http://tinyurl.com/create.php?url='
4058             if check_com -c wget ; then
4059                 grabber='wget -O- -o/dev/null'
4060             else
4061                 print "wget is not available, but mandatory for ${PN}. Aborting."
4062             fi
4063 #           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
4064             search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
4065             result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
4066 #           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
4067             preview='http://preview.'${result#http://}
4068
4069             printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
4070             printf '%s\t%s\n\n' 'Given URL:' ${url}
4071             printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
4072     else
4073         return 1
4074     fi
4075 }
4076
4077 #f2# Print a specific line of file(s).
4078 linenr () {
4079 # {{{
4080     if [ $# -lt 2 ] ; then
4081        print "Usage: linenr <number>[,<number>] <file>" ; return 1
4082     elif [ $# -eq 2 ] ; then
4083          local number=$1
4084          local file=$2
4085          command ed -s $file <<< "${number}n"
4086     else
4087          local number=$1
4088          shift
4089          for file in "$@" ; do
4090              if [ ! -d $file ] ; then
4091                 echo "${file}:"
4092                 command ed -s $file <<< "${number}n" 2> /dev/null
4093              else
4094                 continue
4095              fi
4096          done | less
4097     fi
4098 # }}}
4099 }
4100
4101 #f2# Find history events by search pattern and list them by date.
4102 whatwhen()  {
4103 # {{{
4104     local usage help ident format_l format_s first_char remain first last
4105     usage='USAGE: whatwhen [options] <searchstring> <search range>'
4106     help='Use' \`'whatwhen -h'\'' for further explanations.'
4107     ident=${(l,${#${:-Usage: }},, ,)}
4108     format_l="${ident}%s\t\t\t%s\n"
4109     format_s="${format_l//(\\t)##/\\t}"
4110     # Make the first char of the word to search for case
4111     # insensitive; e.g. [aA]
4112     first_char=[${(L)1[1]}${(U)1[1]}]
4113     remain=${1[2,-1]}
4114     # Default search range is `-100'.
4115     first=${2:-\-100}
4116     # Optional, just used for `<first> <last>' given.
4117     last=$3
4118     case $1 in
4119         ("")
4120             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
4121             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4122         ;;
4123         (-h)
4124             printf '%s\n\n' ${usage}
4125             print 'OPTIONS:'
4126             printf $format_l '-h' 'show help text'
4127             print '\f'
4128             print 'SEARCH RANGE:'
4129             printf $format_l "'0'" 'the whole history,'
4130             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
4131             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
4132             printf '\n%s\n' 'EXAMPLES:'
4133             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
4134             printf $format_l 'whatwhen zsh -250'
4135             printf $format_l 'whatwhen foo 1 99'
4136         ;;
4137         (\?)
4138             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4139         ;;
4140         (*)
4141             # -l list results on stout rather than invoking $EDITOR.
4142             # -i Print dates as in YYYY-MM-DD.
4143             # -m Search for a - quoted - pattern within the history.
4144             fc -li -m "*${first_char}${remain}*" $first $last
4145         ;;
4146     esac
4147 # }}}
4148 }
4149
4150 # change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
4151 fluxkey-change() {
4152     [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
4153     if ! [[ -r "$FLUXKEYS" ]] ; then
4154         echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
4155         return 1
4156     else
4157         if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
4158             echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
4159             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
4160         elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
4161             echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
4162             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
4163         else
4164             echo 'Sorry, do not know what to do.'
4165             return 1
4166         fi
4167     fi
4168 }
4169
4170 # retrieve weather information on the console
4171 # Usage example: 'weather LOWG'
4172 weather() {
4173     [[ -n "$1" ]] || {
4174         print 'Usage: weather <station_id>' >&2
4175         print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
4176         return 1
4177     }
4178
4179     local PLACE="${1:u}"
4180     local FILE="$HOME/.weather/$PLACE"
4181     local LOG="$HOME/.weather/log"
4182
4183     [[ -d $HOME/.weather ]] || {
4184         print -n "Creating $HOME/.weather: "
4185         mkdir $HOME/.weather
4186         print 'done'
4187     }
4188
4189     print "Retrieving information for ${PLACE}:"
4190     print
4191     wget -T 10 --no-verbose --output-file=$LOG --output-document=$FILE --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
4192
4193     if [[ $? -eq 0 ]] ; then
4194         if [[ -n "$VERBOSE" ]] ; then
4195             cat $FILE
4196         else
4197             DATE=$(grep 'UTC' $FILE | sed 's#.* /##')
4198             TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' $FILE| tr -d '(')
4199             echo "date: $DATE"
4200             echo "temp:  $TEMPERATURE"
4201         fi
4202     else
4203         print "There was an error retrieving the weather information for $PLACE" >&2
4204         cat $LOG
4205         return 1
4206     fi
4207 }
4208 # }}}
4209
4210 # mercurial related stuff {{{
4211 if check_com -c hg ; then
4212     # gnu like diff for mercurial
4213     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
4214     #f5# GNU like diff for mercurial
4215     hgdi() {
4216         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
4217     }
4218
4219     # build debian package
4220     #a2# Alias for \kbd{hg-buildpackage}
4221     alias hbp='hg-buildpackage'
4222
4223     # execute commands on the versioned patch-queue from the current repos
4224     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
4225
4226     # diffstat for specific version of a mercurial repository
4227     #   hgstat      => display diffstat between last revision and tip
4228     #   hgstat 1234 => display diffstat between revision 1234 and tip
4229     #f5# Diffstat for specific version of a mercurial repos
4230     hgstat() {
4231         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
4232     }
4233
4234     #f5# Get current mercurial tip via hg itself
4235     gethgclone() {
4236         setopt local_options
4237         setopt errreturn
4238         if [[ -f mercurial-tree/.hg ]] ; then
4239             cd mercurial-tree
4240             echo "Running hg pull for retreiving latest version..."
4241             hg pull
4242             echo "Finished update. Building mercurial"
4243             make local
4244             echo "Setting \$PATH to $PWD:\$PATH..."
4245             export PATH="$PWD:$PATH"
4246         else
4247             echo "Downloading mercurial via hg"
4248             hg clone http://selenic.com/repo/hg mercurial-tree
4249             cd mercurial-tree
4250             echo "Building mercurial"
4251             make local
4252             echo "Setting \$PATH to $PWD:\$PATH..."
4253             export PATH="$PWD:$PATH"
4254             echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4255             # echo "Setting \$PYTHONPATH to PYTHONPATH=\${HOME}/lib/python,"
4256             # export PYTHONPATH=${HOME}/lib/python
4257         fi
4258     }
4259
4260 fi # end of check whether we have the 'hg'-executable
4261
4262 # get current mercurial snapshot
4263 #f5# Get current mercurial snapshot
4264 gethgsnap() {
4265     setopt local_options
4266     setopt errreturn
4267     if [[ -f mercurial-snapshot.tar.gz ]] ; then
4268          echo "mercurial-snapshot.tar.gz exists already, skipping download."
4269     else
4270         echo "Downloading mercurial snapshot"
4271         wget http://www.selenic.com/mercurial/mercurial-snapshot.tar.gz
4272     fi
4273     echo "Unpacking mercurial-snapshot.tar.gz"
4274     tar zxf mercurial-snapshot.tar.gz
4275     cd mercurial-snapshot/
4276     echo "Installing required build-dependencies"
4277     $SUDO apt-get update
4278     $SUDO apt-get install python2.4-dev
4279     echo "Building mercurial"
4280     make local
4281     echo "Setting \$PATH to $PWD:\$PATH..."
4282     export PATH="$PWD:$PATH"
4283     echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4284 }
4285 # }}}
4286
4287 # some useful commands often hard to remember - let's grep for them {{{
4288 # actually use our zg() function now. :)
4289
4290 # Work around ion/xterm resize bug.
4291 #if [[ "$SHLVL" -eq 1 ]]; then
4292 #       if check_com -c resize ; then
4293 #               eval `resize </dev/null`
4294 #       fi
4295 #fi
4296
4297 # enable jackd:
4298 #  /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
4299 # now play audio file:
4300 #  alsaplayer -o jack foobar.mp3
4301
4302 # send files via netcat
4303 # on sending side:
4304 #  send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
4305 #  send dir* $HOST
4306 #  alias receive='nc -vlp 51330 | tar xzvp'
4307
4308 # debian stuff:
4309 # dh_make -e foo@localhost -f $1
4310 # dpkg-buildpackage -rfakeroot
4311 # lintian *.deb
4312 # dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
4313 # dpkg-scansources . | gzip > Sources.gz
4314 # grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
4315
4316 # other stuff:
4317 # convert -geometry 200x200 -interlace LINE -verbose
4318 # ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
4319 # ps -ao user,pcpu,start,command
4320 # gpg --keyserver blackhole.pca.dfn.de --recv-keys
4321 # xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
4322 # nc -vz $1 1-1024   # portscan via netcat
4323 # wget --mirror --no-parent --convert-links
4324 # pal -d `date +%d`
4325 # autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
4326 #
4327 # modify console cursor
4328 # see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
4329 # print $'\e[?96;0;64c'
4330 # }}}
4331
4332 # grml-small cleanups {{{
4333
4334 # The following is used to remove zsh-config-items that do not work
4335 # in grml-small by default.
4336 # If you do not want these adjustments (for whatever reason), set
4337 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
4338 # sources if it is there).
4339
4340 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
4341
4342     unset abk[V]
4343     unalias    'V'      &> /dev/null
4344     unfunction vman     &> /dev/null
4345     unfunction vimpm    &> /dev/null
4346     unfunction vimhelp  &> /dev/null
4347     unfunction viless   &> /dev/null
4348     unfunction 2html    &> /dev/null
4349
4350     # manpages are not in grmlsmall
4351     unfunction manzsh   &> /dev/null
4352     unalias    man2     &> /dev/null
4353     unalias    man      &> /dev/null
4354     unfunction man2     &> /dev/null
4355
4356 fi
4357
4358 #}}}
4359
4360 zrclocal
4361
4362 ## genrefcard.pl settings {{{
4363
4364 ### doc strings for external functions from files
4365 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
4366
4367 ### example: split functions-search 8,16,24,32
4368 #@# split functions-search 8
4369
4370 ## }}}
4371
4372 ## END OF FILE #################################################################
4373 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4