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