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