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