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