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