More sanity checks for vcs_info
[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         [[ -r ${realbasedir} ]] || return 1
1735         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
1736             [[ -d ${basedir}/${dirname} ]] && \
1737             [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
1738                 break
1739         else
1740             [[ -d ${basedir}/${dirname} ]] && break
1741         fi
1742
1743         basedir=${basedir}/..
1744         realbasedir="$(VCS_INFO_realpath ${basedir})"
1745     done
1746
1747     [[ ${realbasedir} == "/" ]] && return 1
1748     vcs_comm[basedir]=${realbasedir}
1749     return 0
1750 }
1751 # }}}
1752 VCS_INFO_bzr_detect() { #{{{
1753     VCS_INFO_check_com bzr || return 1
1754     vcs_comm[detect_need_file]=branch/format
1755     VCS_INFO_detect_by_dir '.bzr'
1756     return $?
1757 }
1758 # }}}
1759 VCS_INFO_cdv_detect() { #{{{
1760     VCS_INFO_check_com cdv || return 1
1761     vcs_comm[detect_need_file]=format
1762     VCS_INFO_detect_by_dir '.cdv'
1763     return $?
1764 }
1765 # }}}
1766 VCS_INFO_cvs_detect() { #{{{
1767     VCS_INFO_check_com svn || return 1
1768     [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
1769     return 1
1770 }
1771 # }}}
1772 VCS_INFO_darcs_detect() { #{{{
1773     VCS_INFO_check_com darcs || return 1
1774     vcs_comm[detect_need_file]=format
1775     VCS_INFO_detect_by_dir '_darcs'
1776     return $?
1777 }
1778 # }}}
1779 VCS_INFO_git_detect() { #{{{
1780     if VCS_INFO_check_com git && git rev-parse --is-inside-work-tree &> /dev/null ; then
1781         vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
1782         if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
1783         elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
1784         return 0
1785     fi
1786     return 1
1787 }
1788 # }}}
1789 VCS_INFO_hg_detect() { #{{{
1790     VCS_INFO_check_com hg || return 1
1791     vcs_comm[detect_need_file]=store
1792     VCS_INFO_detect_by_dir '.hg'
1793     return $?
1794 }
1795 # }}}
1796 VCS_INFO_mtn_detect() { #{{{
1797     VCS_INFO_check_com mtn || return 1
1798     vcs_comm[detect_need_file]=revision
1799     VCS_INFO_detect_by_dir '_MTN'
1800     return $?
1801 }
1802 # }}}
1803 VCS_INFO_svk_detect() { #{{{
1804     setopt localoptions noksharrays extendedglob
1805     local -a info
1806     local -i fhash
1807     fhash=0
1808
1809     VCS_INFO_check_com svk || return 1
1810     [[ -f ~/.svk/config ]] || return 1
1811
1812     # This detection function is a bit different from the others.
1813     # We need to read svk's config file to detect a svk repository
1814     # in the first place. Therefore, we'll just proceed and read
1815     # the other information, too. This is more then any of the
1816     # other detections do but this takes only one file open for
1817     # svk at most. VCS_INFO_svk_get_data() get simpler, too. :-)
1818     while IFS= read -r line ; do
1819         if [[ -n ${vcs_comm[basedir]} ]] ; then
1820             line=${line## ##}
1821             [[ ${line} == depotpath:* ]] && vcs_comm[branch]=${line##*/}
1822             [[ ${line} == revision:* ]] && vcs_comm[revision]=${line##*[[:space:]]##}
1823             [[ -n ${vcs_comm[branch]} ]] && [[ -n ${vcs_comm[revision]} ]] && break
1824             continue
1825         fi
1826         (( fhash > 0 )) && [[ ${line} == '  '[^[:space:]]*:* ]] && break
1827         [[ ${line} == '  hash:'* ]] && fhash=1 && continue
1828         (( fhash == 0 )) && continue
1829         [[ ${PWD}/ == ${${line## ##}%:*}/* ]] && vcs_comm[basedir]=${${line## ##}%:*}
1830     done < ~/.svk/config
1831
1832     [[ -n ${vcs_comm[basedir]} ]]  && \
1833     [[ -n ${vcs_comm[branch]} ]]   && \
1834     [[ -n ${vcs_comm[revision]} ]] && return 0
1835     return 1
1836 }
1837 # }}}
1838 VCS_INFO_svn_detect() { #{{{
1839     VCS_INFO_check_com svn || return 1
1840     [[ -d ".svn" ]] && return 0
1841     return 1
1842 }
1843 # }}}
1844 VCS_INFO_tla_detect() { #{{{
1845     VCS_INFO_check_com tla || return 1
1846     vcs_comm[basedir]="$(tla tree-root 2> /dev/null)" && return 0
1847     return 1
1848 }
1849 # }}}
1850 # public API
1851 vcs_info_printsys () { # {{{
1852     vcs_info print_systems_
1853 }
1854 # }}}
1855 vcs_info_lastmsg () { # {{{
1856     emulate -L zsh
1857     local -i i
1858
1859     VCS_INFO_maxexports
1860     for i in {0..$((maxexports - 1))} ; do
1861         printf '$VCS_INFO_message_%d_: "' $i
1862         if zstyle -T ':vcs_info:formats:command' use-prompt-escapes ; then
1863             print -nP ${(P)${:-VCS_INFO_message_${i}_}}
1864         else
1865             print -n ${(P)${:-VCS_INFO_message_${i}_}}
1866         fi
1867         printf '"\n'
1868     done
1869 }
1870 # }}}
1871 vcs_info () { # {{{
1872     emulate -L zsh
1873     setopt extendedglob
1874
1875     [[ -r . ]] || return 1
1876
1877     local pat
1878     local -i found
1879     local -a VCSs disabled dps
1880     local -x vcs usercontext
1881     local -ix maxexports
1882     local -ax msgs
1883     local -Ax vcs_comm
1884
1885     vcs="init"
1886     VCSs=(git hg bzr darcs svk mtn svn cvs cdv tla)
1887     case $1 in
1888         (print_systems_)
1889             zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1890             print -l '# list of supported version control backends:' \
1891                      '# disabled systems are prefixed by a hash sign (#)'
1892             for vcs in ${VCSs} ; do
1893                 [[ -n ${(M)disabled:#${vcs}} ]] && printf '#'
1894                 printf '%s\n' ${vcs}
1895             done
1896             print -l '# flavours (cannot be used in the disable style; they' \
1897                      '# are disabled with their master [git-svn -> git]):'   \
1898                      git-{p4,svn}
1899             return 0
1900             ;;
1901         ('')
1902             [[ -z ${usercontext} ]] && usercontext=default
1903             ;;
1904         (*) [[ -z ${usercontext} ]] && usercontext=$1
1905             ;;
1906     esac
1907
1908     zstyle -T ":vcs_info:${vcs}:${usercontext}" "enable" || {
1909         [[ -n ${VCS_INFO_message_0_} ]] && VCS_INFO_set --clear
1910         return 0
1911     }
1912     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1913
1914     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable-patterns" dps
1915     for pat in ${dps} ; do
1916         if [[ ${PWD} == ${~pat} ]] ; then
1917             [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear
1918             return 0
1919         fi
1920     done
1921
1922     VCS_INFO_maxexports
1923
1924     (( found = 0 ))
1925     for vcs in ${VCSs} ; do
1926         [[ -n ${(M)disabled:#${vcs}} ]] && continue
1927         vcs_comm=()
1928         VCS_INFO_${vcs}_detect && (( found = 1 )) && break
1929     done
1930
1931     (( found == 0 )) && {
1932         VCS_INFO_set --nvcs
1933         return 0
1934     }
1935
1936     VCS_INFO_${vcs}_get_data || {
1937         VCS_INFO_set --nvcs
1938         return 1
1939     }
1940
1941     VCS_INFO_set
1942     return 0
1943 }
1944
1945 VCS_INFO_set --nvcs preinit
1946 # }}}
1947
1948 # Change vcs_info formats for the grml prompt. The 2nd format sets up
1949 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1950 # TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
1951 #       That needs to be the use of $VCS_INFO_message_N_ needs to be changed
1952 #       to $vcs_info_msg_N_ as soon as we use the included version.
1953 if [[ "$TERM" == dumb ]] ; then
1954     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
1955     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "    "zsh: %r"
1956 else
1957     # these are the same, just with a lot of colours:
1958     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
1959                                        "zsh: %r"
1960     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
1961                                        "zsh: %r"
1962     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1963 fi
1964
1965 # }}}
1966
1967 # command not found handling {{{
1968
1969 (( ${COMMAND_NOT_FOUND} == 1 )) &&
1970 function command_not_found_handler() {
1971     emulate -L zsh
1972     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1973         ${GRML_ZSH_CNF_HANDLER} $1
1974     fi
1975     return 1
1976 }
1977
1978 # }}}
1979
1980 # {{{ set prompt
1981 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1982     promptinit # people should be able to use their favourite prompt
1983 else
1984     print 'Notice: no promptinit available :('
1985 fi
1986
1987 setopt prompt_subst
1988
1989 # make sure to use right prompt only when not running a command
1990 is41 && setopt transient_rprompt
1991
1992 # TODO: revise all these NO* variables and especially their documentation
1993 #       in zsh-help() below.
1994 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1995     [[ $NOPRECMD -gt 0 ]] && return 0
1996     # update VCS information
1997     vcs_info
1998
1999     if [[ $TERM == screen* ]] ; then
2000         if [[ -n ${VCS_INFO_message_1_} ]] ; then
2001             print -nP "\ek${VCS_INFO_message_1_}\e\\"
2002         else
2003             print -nP "\ekzsh\e\\"
2004         fi
2005     fi
2006     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
2007     if [[ $DONTSETRPROMPT -eq 0 ]] ; then
2008         if [[ $BATTERY -gt 0 ]] ; then
2009             # update battery (dropped into $PERCENT) information
2010             battery
2011             RPROMPT="%(?..:() ${PERCENT}"
2012         else
2013             RPROMPT="%(?..:() "
2014         fi
2015     fi
2016     # adjust title of xterm
2017     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2018     [[ ${NOTITLE} -gt 0 ]] && return 0
2019     case $TERM in
2020         (xterm*|rxvt*)
2021             print -Pn "\e]0;%n@%m: %~\a"
2022             ;;
2023     esac
2024 }
2025
2026 # preexec() => a function running before every command
2027 is4 && [[ $NOPRECMD -eq 0 ]] && \
2028 preexec () {
2029     [[ $NOPRECMD -gt 0 ]] && return 0
2030 # set hostname if not running on host with name 'grml'
2031     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
2032        NAME="@$HOSTNAME"
2033     fi
2034 # get the name of the program currently running and hostname of local machine
2035 # set screen window title if running in a screen
2036     if [[ "$TERM" == screen* ]] ; then
2037         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
2038         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
2039         echo -ne "\ek$CMD\e\\"
2040     fi
2041 # adjust title of xterm
2042     [[ ${NOTITLE} -gt 0 ]] && return 0
2043     case $TERM in
2044         (xterm*|rxvt*)
2045             print -Pn "\e]0;%n@%m: $1\a"
2046             ;;
2047     esac
2048 }
2049
2050 EXITCODE="%(?..%?%1v )"
2051 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
2052 PS3='?# '         # selection prompt used within a select loop.
2053 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
2054
2055 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
2056 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
2057     debian_chroot=$(cat /etc/debian_chroot)
2058 fi
2059
2060 # don't use colors on dumb terminals (like emacs):
2061 if [[ "$TERM" == dumb ]] ; then
2062     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
2063 else
2064     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
2065     # set variable identifying the chroot you work in (used in the prompt below)
2066     if [[ $GRMLPROMPT -gt 0 ]] ; then
2067         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
2068 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
2069     else
2070         # This assembles the primary prompt string
2071         if (( EUID != 0 )); then
2072             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
2073         else
2074             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "'${VCS_INFO_message_0_}'"%# "
2075         fi
2076     fi
2077 fi
2078
2079 # if we are inside a grml-chroot set a specific prompt theme
2080 if [[ -n "$GRML_CHROOT" ]] ; then
2081     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
2082 fi
2083 # }}}
2084
2085 # {{{ 'hash' some often used directories
2086 #d# start
2087 hash -d deb=/var/cache/apt/archives
2088 hash -d doc=/usr/share/doc
2089 hash -d linux=/lib/modules/$(command uname -r)/build/
2090 hash -d log=/var/log
2091 hash -d slog=/var/log/syslog
2092 hash -d src=/usr/src
2093 hash -d templ=/usr/share/doc/grml-templates
2094 hash -d tt=/usr/share/doc/texttools-doc
2095 hash -d www=/var/www
2096 #d# end
2097 # }}}
2098
2099 # {{{ some aliases
2100 if check_com -c screen ; then
2101     if [[ $UID -eq 0 ]] ; then
2102         [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
2103     elif [[ -r $HOME/.screenrc ]] ; then
2104         alias screen="${commands[screen]} -c $HOME/.screenrc"
2105     else
2106         [[ -r /etc/grml/screenrc_grml ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
2107     fi
2108 fi
2109
2110 # do we have GNU ls with color-support?
2111 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
2112     #a1# execute \kbd{@a@}:\quad ls with colors
2113     alias ls='ls -b -CF --color=auto'
2114     #a1# execute \kbd{@a@}:\quad list all files, with colors
2115     alias la='ls -la --color=auto'
2116     #a1# long colored list, without dotfiles (@a@)
2117     alias ll='ls -l --color=auto'
2118     #a1# long colored list, human readable sizes (@a@)
2119     alias lh='ls -hAl --color=auto'
2120     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2121     alias l='ls -lF --color=auto'
2122 else
2123     alias ls='ls -b -CF'
2124     alias la='ls -la'
2125     alias ll='ls -l'
2126     alias lh='ls -hAl'
2127     alias l='ls -lF'
2128 fi
2129
2130 alias mdstat='cat /proc/mdstat'
2131 alias ...='cd ../../'
2132
2133 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2134 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2135     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2136 fi
2137
2138 alias cp='nocorrect cp'         # no spelling correction on cp
2139 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
2140 alias mv='nocorrect mv'         # no spelling correction on mv
2141 alias rm='nocorrect rm'         # no spelling correction on rm
2142
2143 #a1# Execute \kbd{rmdir}
2144 alias rd='rmdir'
2145 #a1# Execute \kbd{mkdir}
2146 alias md='mkdir'
2147
2148 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2149 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2150 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2151
2152 # make sure it is not assigned yet
2153 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
2154 utf2iso() {
2155     if isutfenv ; then
2156         for ENV in $(env | command grep -i '.utf') ; do
2157             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2158         done
2159     fi
2160 }
2161
2162 # make sure it is not assigned yet
2163 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
2164 iso2utf() {
2165     if ! isutfenv ; then
2166         for ENV in $(env | command grep -i '\.iso') ; do
2167             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2168         done
2169     fi
2170 }
2171
2172 # set up software synthesizer via speakup
2173 swspeak() {
2174     if [ -x /usr/sbin/swspeak-setup ] ; then
2175        setopt singlelinezle
2176        unsetopt prompt_cr
2177        export PS1="%m%# "
2178        /usr/sbin/swspeak-setup $@
2179      else # old version:
2180         if ! [[ -r /dev/softsynth ]] ; then
2181             flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
2182             return 1
2183         else
2184            setopt singlelinezle
2185            unsetopt prompt_cr
2186            export PS1="%m%# "
2187             nice -n -20 speechd-up
2188             sleep 2
2189             flite -o play -t "Finished setting up software synthesizer"
2190         fi
2191      fi
2192 }
2193
2194 # I like clean prompt, so provide simple way to get that
2195 check_com 0 || alias 0='return 0'
2196
2197 # for really lazy people like mika:
2198 check_com S &>/dev/null || alias S='screen'
2199 check_com s &>/dev/null || alias s='ssh'
2200
2201 # get top 10 shell commands:
2202 alias top10='print -l ? ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
2203
2204 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
2205 if check_com -c truecrypt ; then
2206     if isutfenv ; then
2207         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
2208     else
2209         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
2210     fi
2211 fi
2212
2213 #f1# Hints for the use of zsh on grml
2214 zsh-help() {
2215     print "$bg[white]$fg[black]
2216 zsh-help - hints for use of zsh on grml
2217 =======================================$reset_color"
2218
2219     print '
2220 Main configuration of zsh happens in /etc/zsh/zshrc.
2221 That file is part of the package grml-etc-core, if you want to
2222 use them on a non-grml-system just get the tar.gz from
2223 http://deb.grml.org/ or (preferably) get it from the git repository:
2224
2225   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2226
2227 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2228 The file is still there, but it is empty for backwards compatibility.
2229
2230 For your own changes use these two files:
2231     $HOME/.zshrc.pre
2232     $HOME/.zshrc.local
2233
2234 The former is sourced very early in our zshrc, the latter is sourced
2235 very lately.
2236
2237 System wide configuration without touching configuration files of grml
2238 can take place in /etc/zsh/zshrc.local.
2239
2240 Normally, the root user (EUID == 0) does not get the whole grml setup.
2241 If you want to force the whole setup for that user, too, set
2242 GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
2243
2244 For information regarding zsh start at http://grml.org/zsh/
2245
2246 Take a look at grml'\''s zsh refcard:
2247 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2248
2249 Check out the main zsh refcard:
2250 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2251
2252 And of course visit the zsh-lovers:
2253 % man zsh-lovers
2254
2255 You can adjust some options through environment variables when
2256 invoking zsh without having to edit configuration files.
2257 Basically meant for bash users who are not used to the power of
2258 the zsh yet. :)
2259
2260   "NOCOR=1    zsh" => deactivate automatic correction
2261   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
2262   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2263   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
2264                       preexec() and precmd() completely
2265   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
2266   "COMMAND_NOT_FOUND=1 zsh"
2267                    => Enable a handler if an external command was not found
2268                       The command called in the handler can be altered by setting
2269                       the GRML_ZSH_CNF_HANDLER variable, the default is:
2270                       "/usr/share/command-not-found/command-not-found"
2271
2272 A value greater than 0 is enables a feature; a value equal to zero
2273 disables it. If you like one or the other of these settings, you can
2274 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2275 zshrc.'
2276
2277     print "
2278 $bg[white]$fg[black]
2279 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2280 Enjoy your grml system with the zsh!$reset_color"
2281 }
2282
2283 # debian stuff
2284 if [[ -r /etc/debian_version ]] ; then
2285     #a3# Execute \kbd{apt-cache search}
2286     alias acs='apt-cache search'
2287     #a3# Execute \kbd{apt-cache show}
2288     alias acsh='apt-cache show'
2289     #a3# Execute \kbd{apt-cache policy}
2290     alias acp='apt-cache policy'
2291     #a3# Execute \kbd{apt-get dist-upgrade}
2292     salias adg="apt-get dist-upgrade"
2293     #a3# Execute \kbd{apt-get install}
2294     salias agi="apt-get install"
2295     #a3# Execute \kbd{aptitude install}
2296     salias ati="aptitude install"
2297     #a3# Execute \kbd{apt-get upgrade}
2298     salias ag="apt-get upgrade"
2299     #a3# Execute \kbd{apt-get update}
2300     salias au="apt-get update"
2301     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2302     salias -a up="aptitude update ; aptitude safe-upgrade"
2303     #a3# Execute \kbd{dpkg-buildpackage}
2304     alias dbp='dpkg-buildpackage'
2305     #a3# Execute \kbd{grep-excuses}
2306     alias ge='grep-excuses'
2307
2308     # debian upgrade
2309     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
2310     upgrade() {
2311         emulate -L zsh
2312         if [[ -z $1 ]] ; then
2313             $SUDO apt-get update
2314             $SUDO apt-get -u upgrade
2315         else
2316             ssh $1 $SUDO apt-get update
2317             # ask before the upgrade
2318             local dummy
2319             ssh $1 $SUDO apt-get --no-act upgrade
2320             echo -n 'Process the upgrade?'
2321             read -q dummy
2322             if [[ $dummy == "y" ]] ; then
2323                 ssh $1 $SUDO apt-get -u upgrade --yes
2324             fi
2325         fi
2326     }
2327
2328     # get a root shell as normal user in live-cd mode:
2329     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2330        alias su="sudo su"
2331      fi
2332
2333     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2334     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2335     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2336     salias tlog="tail -f /var/log/syslog"    # follow the syslog
2337 fi
2338
2339 # sort installed Debian-packages by size
2340 if check_com -c grep-status ; then
2341     #a3# List installed Debian-packages sorted by size
2342     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
2343 fi
2344
2345 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2346 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
2347     if check_com -c wodim; then
2348         cdrecord() {
2349             cat <<EOMESS
2350 cdrecord is not provided under its original name by Debian anymore.
2351 See #377109 in the BTS of Debian for more details.
2352
2353 Please use the wodim binary instead
2354 EOMESS
2355             return 1
2356         }
2357     fi
2358 fi
2359
2360 # get_tw_cli has been renamed into get_3ware
2361 if check_com -c get_3ware ; then
2362     get_tw_cli() {
2363         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
2364         get_3ware
2365     }
2366 fi
2367
2368 # I hate lacking backward compatibility, so provide an alternative therefore
2369 if ! check_com -c apache2-ssl-certificate ; then
2370
2371     apache2-ssl-certificate() {
2372
2373     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
2374     print 'You might want to take a look at Debian the package ssl-cert as well.'
2375     print 'To generate a certificate for use with apache2 follow the instructions:'
2376
2377     echo '
2378
2379 export RANDFILE=/dev/random
2380 mkdir /etc/apache2/ssl/
2381 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
2382 chmod 600 /etc/apache2/ssl/apache.pem
2383
2384 Run "grml-tips ssl-certificate" if you need further instructions.
2385 '
2386     }
2387 fi
2388 # }}}
2389
2390 # {{{ Use hard limits, except for a smaller stack and no core dumps
2391 unlimit
2392 is425 && limit stack 8192
2393 isgrmlcd && limit core 0 # important for a live-cd-system
2394 limit -s
2395 # }}}
2396
2397 # {{{ completion system
2398
2399 # called later (via is4 && grmlcomp)
2400 # note: use 'zstyle' for getting current settings
2401 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
2402 grmlcomp() {
2403     # TODO: This could use some additional information
2404
2405     # allow one error for every three characters typed in approximate completer
2406     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
2407
2408     # don't complete backup files as executables
2409     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
2410
2411     # start menu completion only if it could find no unambiguous initial string
2412     zstyle ':completion:*:correct:*'       insert-unambiguous true
2413     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
2414     zstyle ':completion:*:correct:*'       original true
2415
2416     # activate color-completion
2417     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
2418
2419     # format on completion
2420     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
2421
2422     # complete 'cd -<tab>' with menu
2423     zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
2424
2425     # insert all expansions for expand completer
2426     zstyle ':completion:*:expand:*'        tag-order all-expansions
2427     zstyle ':completion:*:history-words'   list false
2428
2429     # activate menu
2430     zstyle ':completion:*:history-words'   menu yes
2431
2432     # ignore duplicate entries
2433     zstyle ':completion:*:history-words'   remove-all-dups yes
2434     zstyle ':completion:*:history-words'   stop yes
2435
2436     # match uppercase from lowercase
2437     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
2438
2439     # separate matches into groups
2440     zstyle ':completion:*:matches'         group 'yes'
2441     zstyle ':completion:*'                 group-name ''
2442
2443     if [[ "$NOMENU" -eq 0 ]] ; then
2444         # if there are more than 5 options allow selecting from a menu
2445         zstyle ':completion:*'               menu select=5
2446     else
2447         # don't use any menus at all
2448         setopt no_auto_menu
2449     fi
2450
2451     zstyle ':completion:*:messages'        format '%d'
2452     zstyle ':completion:*:options'         auto-description '%d'
2453
2454     # describe options in full
2455     zstyle ':completion:*:options'         description 'yes'
2456
2457     # on processes completion complete all user processes
2458     zstyle ':completion:*:processes'       command 'ps -au$USER'
2459
2460     # offer indexes before parameters in subscripts
2461     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
2462
2463     # provide verbose completion information
2464     zstyle ':completion:*'                 verbose true
2465
2466     # recent (as of Dec 2007) zsh versions are able to provide descriptions
2467     # for commands (read: 1st word in the line) that it will list for the user
2468     # to choose from. The following disables that, because it's not exactly fast.
2469     zstyle ':completion:*:-command-:*:'    verbose false
2470
2471     # set format for warnings
2472     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
2473
2474     # define files to ignore for zcompile
2475     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
2476     zstyle ':completion:correct:'          prompt 'correct to: %e'
2477
2478     # Ignore completion functions for commands you don't have:
2479     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
2480
2481     # Provide more processes in completion of programs like killall:
2482     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
2483
2484     # complete manual by their section
2485     zstyle ':completion:*:manuals'    separate-sections true
2486     zstyle ':completion:*:manuals.*'  insert-sections   true
2487     zstyle ':completion:*:man:*'      menu yes select
2488
2489     # provide .. as a completion
2490     zstyle ':completion:*' special-dirs ..
2491
2492     # run rehash on completion so new installed program are found automatically:
2493     _force_rehash() {
2494         (( CURRENT == 1 )) && rehash
2495         return 1
2496     }
2497
2498     ## correction
2499     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
2500     if [[ "$NOCOR" -gt 0 ]] ; then
2501         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
2502         setopt nocorrect
2503     else
2504         # try to be smart about when to use what completer...
2505         setopt correct
2506         zstyle -e ':completion:*' completer '
2507             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
2508                 _last_try="$HISTNO$BUFFER$CURSOR"
2509                 reply=(_complete _match _ignored _prefix _files)
2510             else
2511                 if [[ $words[1] == (rm|mv) ]] ; then
2512                     reply=(_complete _files)
2513                 else
2514                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
2515                 fi
2516             fi'
2517     fi
2518
2519     # command for process lists, the local web server details and host completion
2520     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
2521
2522     # caching
2523     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
2524                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
2525
2526     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
2527     if is42 ; then
2528         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
2529         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
2530     else
2531         _ssh_hosts=()
2532         _etc_hosts=()
2533     fi
2534     hosts=(
2535         $(hostname)
2536         "$_ssh_hosts[@]"
2537         "$_etc_hosts[@]"
2538         grml.org
2539         localhost
2540     )
2541     zstyle ':completion:*:hosts' hosts $hosts
2542     # TODO: so, why is this here?
2543     #  zstyle '*' hosts $hosts
2544
2545     # use generic completion system for programs not yet defined; (_gnu_generic works
2546     # with commands that provide a --help option with "standard" gnu-like output.)
2547     for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
2548                    pal stow tail uname ; do
2549         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
2550     done; unset compcom
2551
2552     # see upgrade function in this file
2553     compdef _hosts upgrade
2554 }
2555 # }}}
2556
2557 # {{{ grmlstuff
2558 grmlstuff() {
2559 # people should use 'grml-x'!
2560     startx() {
2561         if [[ -e /etc/X11/xorg.conf ]] ; then
2562             [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
2563         else
2564             echo "Please use the script \"grml-x\" for starting the X Window System
2565 because there does not exist /etc/X11/xorg.conf yet.
2566 If you want to use startx anyway please call \"/usr/bin/startx\"."
2567             return -1
2568         fi
2569     }
2570
2571     xinit() {
2572         if [[ -e /etc/X11/xorg.conf ]] ; then
2573             [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
2574         else
2575             echo "Please use the script \"grml-x\" for starting the X Window System.
2576 because there does not exist /etc/X11/xorg.conf yet.
2577 If you want to use xinit anyway please call \"/usr/bin/xinit\"."
2578             return -1
2579         fi
2580     }
2581
2582     if check_com -c 915resolution; then
2583         855resolution() {
2584             echo "Please use 915resolution as resolution modifying tool for Intel \
2585 graphic chipset."
2586             return -1
2587         }
2588     fi
2589
2590     #a1# Output version of running grml
2591     alias grml-version='cat /etc/grml_version'
2592
2593     if check_com -c rebuildfstab ; then
2594         #a1# Rebuild /etc/fstab
2595         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2596     fi
2597
2598     if check_com -c grml-debootstrap ; then
2599         debian2hd() {
2600             echo "Installing debian to harddisk is possible by using grml-debootstrap."
2601             return 1
2602         }
2603     fi
2604 }
2605 # }}}
2606
2607 # {{{ now run the functions
2608 isgrml && checkhome
2609 is4    && isgrml    && grmlstuff
2610 is4    && grmlcomp
2611 # }}}
2612
2613 # {{{ keephack
2614 is4 && xsource "/etc/zsh/keephack"
2615 # }}}
2616
2617 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2618 # You use it as follows:
2619 # $ NTREF=/reference/file
2620 # $ ls -l *(e:nt:)
2621 # This lists all the files in the current directory newer than the reference file.
2622 # You can also specify the reference file inline; note quotes:
2623 # $ ls -l *(e:'nt ~/.zshenv':)
2624 is4 && nt() {
2625     if [[ -n $1 ]] ; then
2626         local NTREF=${~1}
2627     fi
2628     [[ $REPLY -nt $NTREF ]]
2629 }
2630 # }}}
2631
2632 # shell functions {{{
2633
2634 #f1# Provide csh compatibility
2635 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2636
2637 #f1# Reload an autoloadable function
2638 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2639 compdef _functions freload
2640
2641 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2642 sll() {
2643     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2644     for file in "$@" ; do
2645         while [[ -h "$file" ]] ; do
2646             ls -l $file
2647             file=$(readlink "$file")
2648         done
2649     done
2650 }
2651
2652 # fast manual access
2653 if check_com qma ; then
2654     #f1# View the zsh manual
2655     manzsh()  { qma zshall "$1" }
2656     compdef _man qma
2657 else
2658     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2659 fi
2660
2661 # TODO: Is it supported to use pager settings like this?
2662 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
2663 # with respect to wordsplitting. (ie. ${=PAGER})
2664 if check_com -c $PAGER ; then
2665     #f1# View Debian's changelog of a given package
2666     dchange() {
2667         emulate -L zsh
2668         if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
2669             $PAGER /usr/share/doc/$1/changelog.Debian.gz
2670         elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2671             $PAGER /usr/share/doc/$1/changelog.gz
2672         else
2673             if check_com -c aptitude ; then
2674                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2675                 if isgrml ; then
2676                     aptitude -t unstable changelog $1
2677                 else
2678                     aptitude changelog $1
2679                 fi
2680             else
2681                 echo "No changelog for package $1 found, sorry."
2682                 return 1
2683             fi
2684         fi
2685     }
2686     _dchange() { _files -W /usr/share/doc -/ }
2687     compdef _dchange dchange
2688
2689     #f1# View Debian's NEWS of a given package
2690     dnews() {
2691         emulate -L zsh
2692         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2693             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2694         else
2695             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2696                 $PAGER /usr/share/doc/$1/NEWS.gz
2697             else
2698                 echo "No NEWS file for package $1 found, sorry."
2699                 return 1
2700             fi
2701         fi
2702     }
2703     _dnews() { _files -W /usr/share/doc -/ }
2704     compdef _dnews dnews
2705
2706     #f1# View upstream's changelog of a given package
2707     uchange() {
2708         emulate -L zsh
2709         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2710             $PAGER /usr/share/doc/$1/changelog.gz
2711         else
2712             echo "No changelog for package $1 found, sorry."
2713             return 1
2714         fi
2715     }
2716     _uchange() { _files -W /usr/share/doc -/ }
2717     compdef _uchange uchange
2718 fi
2719
2720 # zsh profiling
2721 profile() {
2722     ZSH_PROFILE_RC=1 $SHELL "$@"
2723 }
2724
2725 #f1# Edit an alias via zle
2726 edalias() {
2727     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2728 }
2729 compdef _aliases edalias
2730
2731 #f1# Edit a function via zle
2732 edfunc() {
2733     [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
2734 }
2735 compdef _functions edfunc
2736
2737 # use it e.g. via 'Restart apache2'
2738 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2739 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2740 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2741 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2742 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2743 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2744     __start_stop() {
2745         local action_="${1:l}"  # e.g Start/Stop/Restart
2746         local service_="$2"
2747         local param_="$3"
2748
2749         local service_target_="$(readlink /etc/init.d/$service_)"
2750         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2751             # runit
2752             case "${action_}" in
2753                 start) if [[ ! -e /etc/service/$service_ ]]; then
2754                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2755                        else
2756                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2757                        fi ;;
2758                 # there is no reload in runits sysv emulation
2759                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2760                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2761             esac
2762         else
2763             # sysvinit
2764             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2765         fi
2766     }
2767
2768     for i in Start Restart Stop Force-Reload Reload ; do
2769         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2770     done
2771 fi
2772
2773 #f1# Provides useful information on globbing
2774 H-Glob() {
2775     echo -e "
2776     /      directories
2777     .      plain files
2778     @      symbolic links
2779     =      sockets
2780     p      named pipes (FIFOs)
2781     *      executable plain files (0100)
2782     %      device files (character or block special)
2783     %b     block special files
2784     %c     character special files
2785     r      owner-readable files (0400)
2786     w      owner-writable files (0200)
2787     x      owner-executable files (0100)
2788     A      group-readable files (0040)
2789     I      group-writable files (0020)
2790     E      group-executable files (0010)
2791     R      world-readable files (0004)
2792     W      world-writable files (0002)
2793     X      world-executable files (0001)
2794     s      setuid files (04000)
2795     S      setgid files (02000)
2796     t      files with the sticky bit (01000)
2797
2798   print *(m-1)          # Files modified up to a day ago
2799   print *(a1)           # Files accessed a day ago
2800   print *(@)            # Just symlinks
2801   print *(Lk+50)        # Files bigger than 50 kilobytes
2802   print *(Lk-50)        # Files smaller than 50 kilobytes
2803   print **/*.c          # All *.c files recursively starting in \$PWD
2804   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2805   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2806   print *~*.*           # All Files that do not contain a dot
2807   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2808   print -l *(.c|.h)     # Lists *.c and *.h
2809   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2810   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2811 }
2812 alias help-zshglob=H-Glob
2813
2814 check_com -c qma && alias ?='qma zshall'
2815
2816 # grep for running process, like: 'any vim'
2817 any() {
2818     emulate -L zsh
2819     if [[ -z "$1" ]] ; then
2820         echo "any - grep for process(es) by keyword" >&2
2821         echo "Usage: any <keyword>" >&2 ; return 1
2822     else
2823         local STRING=$1
2824         local LENGTH=$(expr length $STRING)
2825         local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
2826         local REST=$(echo $(expr substr $STRING 2 $LENGTH))
2827         ps xauwww| grep "[$FIRSCHAR]$REST"
2828     fi
2829 }
2830
2831 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2832 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2833 [[ -r /proc/1/maps ]] && \
2834 deswap() {
2835     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2836     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2837     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2838 }
2839
2840 # print hex value of a number
2841 hex() {
2842     emulate -L zsh
2843     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2844 }
2845
2846 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2847 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2848 peval() {
2849     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2850     perl -e "print eval($CALC),\"\n\";"
2851 }
2852 functions peval &>/dev/null && alias calc=peval
2853
2854 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2855 # certain circumstances, so work around it, no matter which environment we have
2856 brltty() {
2857     if [[ -z "$DISPLAY" ]] ; then
2858         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2859         command brltty "$@"
2860     else
2861         command brltty "$@"
2862     fi
2863 }
2864
2865 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2866 aoeu() {
2867     echo -n 'Switching to us keyboard layout: '
2868     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2869     echo 'Done'
2870 }
2871 asdf() {
2872     echo -n 'Switching to dvorak keyboard layout: '
2873     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2874     echo 'Done'
2875 }
2876 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2877 uiae() {
2878     echo -n 'Switching to us keyboard layout: '
2879     setxkbmap us && echo 'Done' || echo 'Failed'
2880 }
2881
2882 # set up an ipv6 tunnel
2883 ipv6-tunnel() {
2884     emulate -L zsh
2885     case $1 in
2886         start)
2887             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2888                 print 'ipv6 tunnel already set up, nothing to be done.'
2889                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2890             else
2891                 [[ -n "$PUBLIC_IP" ]] || \
2892                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2893                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2894
2895                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2896                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2897                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2898                 ifconfig sit0 tunnel ::192.88.99.1 up
2899                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2900             fi
2901             ;;
2902         status)
2903             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2904                 print 'ipv6 tunnel available' ; return 0
2905             else
2906                 print 'ipv6 tunnel not available' ; return 1
2907             fi
2908             ;;
2909         stop)
2910             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2911                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2912                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2913             else
2914                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2915             fi
2916             ;;
2917         *)
2918             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2919             ;;
2920     esac
2921 }
2922
2923 # run dhclient for wireless device
2924 iwclient() {
2925     salias dhclient "$(wavemon -d | awk '/device/{print $2}')"
2926 }
2927
2928 # spawn a minimally set up ksh - useful if you want to umount /usr/.
2929 minimal-shell() {
2930     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
2931 }
2932
2933 # a wrapper for vim, that deals with title setting
2934 #   VIM_OPTIONS
2935 #       set this array to a set of options to vim you always want
2936 #       to have set when calling vim (in .zshrc.local), like:
2937 #           VIM_OPTIONS=( -p )
2938 #       This will cause vim to send every file given on the
2939 #       commandline to be send to it's own tab (needs vim7).
2940 vim() {
2941     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2942 }
2943
2944 # make a backup of a file
2945 bk() {
2946     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2947 }
2948
2949 #f1# grep for patterns in grml's zsh setup
2950 zg() {
2951 #{{{
2952     LANG=C perl -e '
2953
2954 sub usage {
2955     print "usage: zg -[anr] <pattern>\n";
2956     print " Search for patterns in grml'\''s zshrc.\n";
2957     print " zg takes no or exactly one option plus a non empty pattern.\n\n";
2958     print "   options:\n";
2959     print "     --  no options (use if your pattern starts in with a dash.\n";
2960     print "     -a  search for the pattern in all code regions\n";
2961     print "     -n  search for the pattern in non-root code only\n";
2962     print "     -r  search in code for everyone (also root) only\n\n";
2963     print "   The default is -a for non-root users and -r for root.\n\n";
2964     print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
2965     print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
2966     print " ...in case you copied the file to that location.\n\n";
2967     exit 1;
2968 }
2969
2970 if ($ENV{GRML_ZSHRC} ne "") {
2971     $RC = $ENV{GRML_ZSHRC};
2972 } else {
2973     $RC = "/etc/zsh/zshrc";
2974 }
2975
2976 usage if ($#ARGV < 0 || $#ARGV > 1);
2977 if ($> == 0) { $mode = "allonly"; }
2978 else { $mode = "all"; }
2979
2980 $opt = $ARGV[0];
2981 if ($opt eq "--")     { shift; }
2982 elsif ($opt eq "-a")  { $mode = "all"; shift; }
2983 elsif ($opt eq "-n")  { $mode = "nonroot"; shift; }
2984 elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
2985 elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
2986
2987 $pattern = $ARGV[0];
2988 usage() if ($pattern eq "");
2989
2990 open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
2991 while ($line = <FH>) {
2992     chomp $line;
2993     if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
2994     next if ($mode eq "nonroot" && markerfound == 0);
2995     break if ($mode eq "allonly" && markerfound == 1);
2996     print $line, "\n" if ($line =~ /$pattern/);
2997 }
2998 close FH;
2999 exit 0;
3000
3001     ' -- "$@"
3002 #}}}
3003     return $?
3004 }
3005
3006 ssl_hashes=( sha512 sha256 sha1 md5 )
3007
3008 for sh in ${ssl_hashes}; do
3009     ssl-cert-${sh}() {
3010         emulate -L zsh
3011         if [[ -z $1 ]] ; then
3012             printf 'usage: %s <file>\n' "ssh-cert-${sh}"
3013             return 1
3014         fi
3015         openssl x509 -noout -fingerprint -${sh} -in $1
3016     }
3017 done; unset sh
3018
3019 ssl-cert-fingerprints() {
3020     emulate -L zsh
3021     local i
3022     if [[ -z $1 ]] ; then
3023         printf 'usage: ssl-cert-fingerprints <file>\n'
3024         return 1
3025     fi
3026     for i in ${ssl_hashes}
3027         do ssl-cert-$i $1;
3028     done
3029 }
3030
3031 ssl-cert-info() {
3032     emulate -L zsh
3033     if [[ -z $1 ]] ; then
3034         printf 'usage: ssl-cert-info <file>\n'
3035         return 1
3036     fi
3037     openssl x509 -noout -text -in $1
3038     ssl-cert-fingerprints $1
3039 }
3040
3041 # }}}
3042
3043 # {{{ make sure our environment is clean regarding colors
3044 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
3045 # }}}
3046
3047 # "persistent history" {{{
3048 # just write important commands you always need to ~/.important_commands
3049 if [[ -r ~/.important_commands ]] ; then
3050     fc -R ~/.important_commands
3051 fi
3052 # }}}
3053
3054 #:grep:marker:for:mika: :-)
3055 ### non-root (EUID != 0) code below
3056 ###
3057
3058 if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
3059     zrclocal
3060     return 0
3061 fi
3062
3063
3064 # variables {{{
3065
3066 # set terminal property (used e.g. by msgid-chooser)
3067 export COLORTERM="yes"
3068
3069 # set default browser
3070 if [[ -z "$BROWSER" ]] ; then
3071     if [[ -n "$DISPLAY" ]] ; then
3072         #v# If X11 is running
3073         check_com -c firefox && export BROWSER=firefox
3074     else
3075         #v# If no X11 is running
3076         check_com -c w3m && export BROWSER=w3m
3077     fi
3078 fi
3079
3080 #m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
3081 [[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
3082 [[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
3083
3084 # support running 'jikes *.java && jamvm HelloWorld' OOTB:
3085 #v# [for non-root only]
3086 [[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
3087 # }}}
3088
3089 # aliases {{{
3090
3091 # Xterm resizing-fu.
3092 # Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
3093 alias hide='echo -en "\033]50;nil2\007"'
3094 alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
3095 alias small='echo -en "\033]50;6x10\007"'
3096 alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
3097 alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
3098 alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
3099 alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
3100 alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
3101 alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
3102
3103 # general
3104 #a2# Execute \kbd{du -sch}
3105 alias da='du -sch'
3106 #a2# Execute \kbd{jobs -l}
3107 alias j='jobs -l'
3108
3109 # compile stuff
3110 #a2# Execute \kbd{./configure}
3111 alias CO="./configure"
3112 #a2# Execute \kbd{./configure --help}
3113 alias CH="./configure --help"
3114
3115 # listing stuff
3116 #a2# Execute \kbd{ls -lSrah}
3117 alias dir="ls -lSrah"
3118 #a2# Only show dot-directories
3119 alias lad='ls -d .*(/)'                # only show dot-directories
3120 #a2# Only show dot-files
3121 alias lsa='ls -a .*(.)'                # only show dot-files
3122 #a2# Only files with setgid/setuid/sticky flag
3123 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
3124 #a2# Only show 1st ten symlinks
3125 alias lsl='ls -l *(@)'                 # only symlinks
3126 #a2# Display only executables
3127 alias lsx='ls -l *(*)'                 # only executables
3128 #a2# Display world-{readable,writable,executable} files
3129 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
3130 #a2# Display the ten biggest files
3131 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
3132 #a2# Only show directories
3133 alias lsd='ls -d *(/)'                 # only show directories
3134 #a2# Only show empty directories
3135 alias lse='ls -d *(/^F)'               # only show empty directories
3136 #a2# Display the ten newest files
3137 alias lsnew="ls -rl *(D.om[1,10])"     # display the newest files
3138 #a2# Display the ten oldest files
3139 alias lsold="ls -rtlh *(D.om[1,10])"   # display the oldest files
3140 #a2# Display the ten smallest files
3141 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
3142
3143 # chmod
3144 #a2# Execute \kbd{chmod 600}
3145 alias rw-='chmod 600'
3146 #a2# Execute \kbd{chmod 700}
3147 alias rwx='chmod 700'
3148 #m# a2 r-{}- Execute \kbd{chmod 644}
3149 alias r--='chmod 644'
3150 #a2# Execute \kbd{chmod 755}
3151 alias r-x='chmod 755'
3152
3153 # some useful aliases
3154 #a2# Execute \kbd{mkdir -o}
3155 alias md='mkdir -p'
3156
3157 # console stuff
3158 #a2# Execute \kbd{mplayer -vo fbdev}
3159 alias cmplayer='mplayer -vo fbdev'
3160 #a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
3161 alias fbmplayer='mplayer -vo fbdev -fs -zoom'
3162 #a2# Execute \kbd{links2 -driver fb}
3163 alias fblinks='links2 -driver fb'
3164
3165 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3166 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3167 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3168
3169 # simple webserver
3170 check_com -c python && alias http="python -m SimpleHTTPServer"
3171
3172 # Use 'g' instead of 'git':
3173 check_com g || alias g='git'
3174
3175 # work around non utf8 capable software in utf environment via $LANG and luit
3176 if check_com isutfenv && check_com luit ; then
3177     if check_com -c mrxvt ; then
3178         isutfenv && [[ -n "$LANG" ]] && \
3179             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3180     fi
3181
3182     if check_com -c aterm ; then
3183         isutfenv && [[ -n "$LANG" ]] && \
3184             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3185     fi
3186
3187     if check_com -c centericq ; then
3188         isutfenv && [[ -n "$LANG" ]] && \
3189             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3190     fi
3191 fi
3192 # }}}
3193
3194 # useful functions {{{
3195
3196 # searching
3197 #f4# Search for newspostings from authors
3198 agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
3199 #f4# Search Debian Bug Tracking System
3200 debbug()  {
3201     emulate -L zsh
3202     setopt extendedglob
3203     if [[ $# -eq 1 ]]; then
3204         case "$1" in
3205             ([0-9]##)
3206             ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
3207             ;;
3208             (*@*)
3209             ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
3210             ;;
3211             (*)
3212             ${=BROWSER} "http://bugs.debian.org/$*"
3213             ;;
3214         esac
3215     else
3216         print "$0 needs one argument"
3217         return 1
3218     fi
3219 }
3220 #f4# Search Debian Bug Tracking System in mbox format
3221 debbugm() {
3222     emulate -L zsh
3223     bts show --mbox $1
3224 }
3225 #f4# Search DMOZ
3226 dmoz()    {
3227     emulate -L zsh
3228     ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_}
3229 }
3230 #f4# Search German   Wiktionary
3231 dwicti()  {
3232     emulate -L zsh
3233     ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_}
3234 }
3235 #f4# Search English  Wiktionary
3236 ewicti()  {
3237     emulate -L zsh
3238     ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_}
3239 }
3240 #f4# Search Google Groups
3241 ggogle()  {
3242     emulate -L zsh
3243     ${=BROWSER} "http://groups.google.com/groups?q=$*"
3244 }
3245 #f4# Search Google
3246 google()  {
3247     emulate -L zsh
3248     ${=BROWSER} "http://www.google.com/search?&num=100&q=$*"
3249 }
3250 #f4# Search Google Groups for MsgID
3251 mggogle() {
3252     emulate -L zsh
3253     ${=BROWSER} "http://groups.google.com/groups?selm=$*"
3254 }
3255 #f4# Search Netcraft
3256 netcraft(){
3257     emulate -L zsh
3258     ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1"
3259 }
3260 #f4# Use German Wikipedia's full text search
3261 swiki()   {
3262     emulate -L zsh
3263     ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1}
3264 }
3265 #f4# search \kbd{dict.leo.org}
3266 oleo()    {
3267     emulate -L zsh
3268     ${=BROWSER} "http://dict.leo.org/?search=$*"
3269 }
3270 #f4# Search German   Wikipedia
3271 wikide()  {
3272     emulate -L zsh
3273     ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}"
3274 }
3275 #f4# Search English  Wikipedia
3276 wikien()  {
3277     emulate -L zsh
3278     ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}"
3279 }
3280 #f4# Search official debs
3281 wodeb()   {
3282     emulate -L zsh
3283     ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all"
3284 }
3285
3286 #m# f4 gex() Exact search via Google
3287 check_com google && gex () {
3288     google "\"[ $1]\" $*"
3289 }
3290
3291 # misc
3292 #f5# Backup \kbd{file {\rm to} file\_timestamp}
3293 bk() {
3294     emulate -L zsh
3295     cp -b $1 $1_`date --iso-8601=m`
3296 }
3297 #f5# Copied diff
3298 cdiff() {
3299     emulate -L zsh
3300     diff -crd "$*" | egrep -v "^Only in |^Binary files "
3301 }
3302 #f5# cd to directoy and list files
3303 cl() {
3304     emulate -L zsh
3305     cd $1 && ls -a
3306 }
3307 #f5# Cvs add
3308 cvsa() {
3309     emulate -L zsh
3310     cvs add $* && cvs com -m 'initial checkin' $*
3311 }
3312 #f5# Cvs diff
3313 cvsd() {
3314     emulate -L zsh
3315     cvs diff -N $* |& $PAGER
3316 }
3317 #f5# Cvs log
3318 cvsl() {
3319     emulate -L zsh
3320     cvs log $* |& $PAGER
3321 }
3322 #f5# Cvs update
3323 cvsq() {
3324     emulate -L zsh
3325     cvs -nq update
3326 }
3327 #f5# Rcs2log
3328 cvsr() {
3329     emulate -L zsh
3330     rcs2log $* | $PAGER
3331 }
3332 #f5# Cvs status
3333 cvss() {
3334     emulate -L zsh
3335     cvs status -v $*
3336 }
3337 #f5# Disassemble source files using gcc and as
3338 disassemble(){
3339     emulate -L zsh
3340     gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null
3341 }
3342 #f5# Firefox remote control - open given URL
3343 fir() {
3344     if [ -e /etc/debian_version ]; then
3345         firefox -a iceweasel -remote "openURL($1)" || firefox ${1}&
3346     else
3347         firefox -a firefox -remote "openURL($1)" || firefox ${1}&
3348     fi
3349 }
3350 #f5# Create Directoy and \kbd{cd} to it
3351 mcd() {
3352     mkdir -p "$@" && cd "$@"
3353 }
3354 #f5# Unified diff to timestamped outputfile
3355 mdiff() {
3356     diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1"
3357 }
3358 #f5# Memory overview
3359 memusage() {
3360     ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc
3361 }
3362 #f5# Show contents of gzipped tar file
3363 shtar() {
3364     emulate -L zsh
3365     gunzip -c $1 | tar -tf - -- | $PAGER
3366 }
3367 #f5# Show contents of zip file
3368 shzip() {
3369     emulate -L zsh
3370     unzip -l $1 | $PAGER
3371 }
3372 #f5# Unified diff
3373 udiff() {
3374     emulate -L zsh
3375     diff -urd $* | egrep -v "^Only in |^Binary files "
3376 }
3377 #f5# (Mis)use \kbd{vim} as \kbd{less}
3378 viless() {
3379     emulate -L zsh
3380     vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}"
3381 }
3382
3383 # Function Usage: uopen $URL/$file
3384 #f5# Download a file and display it locally
3385 uopen() {
3386     emulate -L zsh
3387     if ! [[ -n "$1" ]] ; then
3388         print "Usage: uopen \$URL/\$file">&2
3389         return 1
3390     else
3391         FILE=$1
3392         MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
3393         MIME=${MIME%$'\r'}
3394         curl $FILE | see ${MIME}:-
3395     fi
3396 }
3397
3398 # Function Usage: doc packagename
3399 #f5# \kbd{cd} to /usr/share/doc/\textit{package}
3400 doc() {
3401     emulate -L zsh
3402     cd /usr/share/doc/$1 && ls
3403 }
3404 _doc() { _files -W /usr/share/doc -/ }
3405 check_com compdef && compdef _doc doc
3406
3407 #f5# Make screenshot
3408 sshot() {
3409     [[ ! -d ~/shots  ]] && mkdir ~/shots
3410     #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
3411     cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
3412 }
3413
3414 # list images only
3415 limg() {
3416     local -a images
3417     images=( *.{jpg,gif,png}(.N) )
3418
3419     if [[ $#images -eq 0 ]] ; then
3420         print "No image files found"
3421     else
3422         ls "$images[@]"
3423     fi
3424 }
3425
3426 #f5# Create PDF file from source code
3427 makereadable() {
3428     emulate -L zsh
3429     output=$1
3430     shift
3431     a2ps --medium A4dj -E -o $output $*
3432     ps2pdf $output
3433 }
3434
3435 # zsh with perl-regex - use it e.g. via:
3436 # regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
3437 #f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
3438 regcheck() {
3439     emulate -L zsh
3440     zmodload -i zsh/pcre
3441     pcre_compile $1 && \
3442     pcre_match $2 && echo "regex matches" || echo "regex does not match"
3443 }
3444
3445 #f5# List files which have been modified within the last {\it n} days
3446 new() {
3447     emulate -L zsh
3448     print -l *(m-$1)
3449 }
3450
3451 #f5# Grep in history
3452 greph() {
3453     emulate -L zsh
3454     history 0 | grep $1
3455 }
3456 # use colors when GNU grep with color-support
3457 #a2# Execute \kbd{grep -{}-color=auto}
3458 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
3459 #a2# Execute \kbd{grep -i -{}-color=auto}
3460 alias GREP='grep -i --color=auto'
3461
3462 #f5# Watch manpages in a stretched style
3463 man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
3464
3465 # d():Copyright 2005 Nikolai Weibull <nikolai@bitwi.se>
3466 # note: option AUTO_PUSHD has to be set
3467 #f5# Jump between directories
3468 d() {
3469     emulate -L zsh
3470     autoload -U colors
3471     local color=$fg_bold[blue]
3472     integer i=0
3473     dirs -p | while read dir; do
3474         local num="${$(printf "%-4d " $i)/ /.}"
3475         printf " %s  $color%s$reset_color\n" $num $dir
3476         (( i++ ))
3477     done
3478     integer dir=-1
3479     read -r 'dir?Jump to directory: ' || return
3480     (( dir == -1 )) && return
3481     if (( dir < 0 || dir >= i )); then
3482         echo d: no such directory stack entry: $dir
3483         return 1
3484     fi
3485     cd ~$dir
3486 }
3487
3488 # usage example: 'lcheck strcpy'
3489 #f5# Find out which libs define a symbol
3490 lcheck() {
3491     if [[ -n "$1" ]] ; then
3492         nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
3493     else
3494         echo "Usage: lcheck <function>" >&2
3495     fi
3496 }
3497
3498 #f5# Clean up directory - remove well known tempfiles
3499 purge() {
3500     FILES=(*~(N) .*~(N) \#*\#(N) *.o(N) a.out(N) *.core(N) *.cmo(N) *.cmi(N) .*.swp(N))
3501     NBFILES=${#FILES}
3502     if [[ $NBFILES > 0 ]] ; then
3503         print $FILES
3504         local ans
3505         echo -n "Remove these files? [y/n] "
3506         read -q ans
3507         if [[ $ans == "y" ]] ; then
3508             rm ${FILES}
3509             echo ">> $PWD purged, $NBFILES files removed"
3510         else
3511             echo "Ok. .. then not.."
3512         fi
3513     fi
3514 }
3515
3516 # Translate DE<=>EN
3517 # 'translate' looks up fot a word in a file with language-to-language
3518 # translations (field separator should be " : "). A typical wordlist looks
3519 # like at follows:
3520 #  | english-word : german-transmission
3521 # It's also only possible to translate english to german but not reciprocal.
3522 # Use the following oneliner to turn back the sort order:
3523 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3524 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3525 #f5# Translates a word
3526 trans() {
3527     emulate -L zsh
3528     case "$1" in
3529         -[dD]*)
3530             translate -l de-en $2
3531             ;;
3532         -[eE]*)
3533             translate -l en-de $2
3534             ;;
3535         *)
3536             echo "Usage: $0 { -D | -E }"
3537             echo "         -D == German to English"
3538             echo "         -E == English to German"
3539     esac
3540 }
3541
3542 #f5# List all occurrences of programm in current PATH
3543 plap() {
3544     emulate -L zsh
3545     if [[ $# = 0 ]] ; then
3546         echo "Usage:    $0 program"
3547         echo "Example:  $0 zsh"
3548         echo "Lists all occurrences of program in the current PATH."
3549     else
3550         ls -l ${^path}/*$1*(*N)
3551     fi
3552 }
3553
3554 # Found in the mailinglistarchive from Zsh (IIRC ~1996)
3555 #f5# Select items for specific command(s) from history
3556 selhist() {
3557     emulate -L zsh
3558     local TAB=$'\t';
3559     (( $# < 1 )) && {
3560         echo "Usage: $0 command"
3561         return 1
3562     };
3563     cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
3564     print -l $cmd | less -F
3565     echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
3566     local answer
3567     read answer
3568     print -z "${cmd[$answer]#*$TAB}"
3569 }
3570
3571 # Use vim to convert plaintext to HTML
3572 #f5# Transform files to html with highlighting
3573 2html() {
3574     emulate -L zsh
3575     vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null
3576 }
3577
3578 # Usage: simple-extract <file>
3579 #f5# Smart archive extractor
3580 simple-extract () {
3581     emulate -L zsh
3582     if [[ -f $1 ]] ; then
3583         case $1 in
3584             *.tar.bz2)  bzip2 -v -d $1      ;;
3585             *.tar.gz)   tar -xvzf $1        ;;
3586             *.rar)      unrar $1            ;;
3587             *.deb)      ar -x $1            ;;
3588             *.bz2)      bzip2 -d $1         ;;
3589             *.lzh)      lha x $1            ;;
3590             *.gz)       gunzip -d $1        ;;
3591             *.tar)      tar -xvf $1         ;;
3592             *.tgz)      gunzip -d $1        ;;
3593             *.tbz2)     tar -jxvf $1        ;;
3594             *.zip)      unzip $1            ;;
3595             *.Z)        uncompress $1       ;;
3596             *)          echo "'$1' Error. Please go away" ;;
3597         esac
3598     else
3599         echo "'$1' is not a valid file"
3600     fi
3601 }
3602
3603 # Usage: smartcompress <file> (<type>)
3604 #f5# Smart archive creator
3605 smartcompress() {
3606     emulate -L zsh
3607     if [[ -n $2 ]] ; then
3608         case $2 in
3609             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
3610             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
3611             tar.Z)          tar -Zcvf$1.$2 $1 ;;
3612             tar)            tar -cvf$1.$2  $1 ;;
3613             gz | gzip)      gzip           $1 ;;
3614             bz2 | bzip2)    bzip2          $1 ;;
3615             *)
3616                 echo "Error: $2 is not a valid compression type"
3617                 ;;
3618         esac
3619     else
3620         smartcompress $1 tar.gz
3621     fi
3622 }
3623
3624 # Usage: show-archive <archive>
3625 #f5# List an archive's content
3626 show-archive() {
3627     emulate -L zsh
3628     if [[ -f $1 ]] ; then
3629         case $1 in
3630             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
3631             *.tar)         tar -tf $1 ;;
3632             *.tgz)         tar -ztf $1 ;;
3633             *.zip)         unzip -l $1 ;;
3634             *.bz2)         bzless $1 ;;
3635             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
3636             *)             echo "'$1' Error. Please go away" ;;
3637         esac
3638     else
3639         echo "'$1' is not a valid archive"
3640     fi
3641 }
3642
3643 # It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
3644 #f5# Use \kbd{vim} as your manpage reader
3645 vman() {
3646     emulate -L zsh
3647     man $* | col -b | view -c 'set ft=man nomod nolist' -
3648 }
3649
3650 # function readme() { $PAGER -- (#ia3)readme* }
3651 #f5# View all README-like files in current directory in pager
3652 readme() {
3653     emulate -L zsh
3654     local files
3655     files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
3656     if (($#files)) ; then
3657         $PAGER $files
3658     else
3659         print 'No README files.'
3660     fi
3661 }
3662
3663 # function ansi-colors()
3664 #f5# Display ANSI colors
3665 ansi-colors() {
3666     typeset esc="\033[" line1 line2
3667     echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
3668     for fore in 30 31 32 33 34 35 36 37; do
3669         line1="$fore "
3670         line2="   "
3671         for back in 40 41 42 43 44 45 46 47 49; do
3672             line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
3673             line2="${line2}${esc}${back};${fore};1m Bold   ${esc}0m"
3674         done
3675         echo -e "$line1\n$line2"
3676     done
3677 }
3678
3679 #f5# Find all files in \$PATH with setuid bit set
3680 suidfind() { ls -latg $path | grep '^...s' }
3681
3682 # TODO: So, this is the third incarnation of this function!?
3683 #f5# Reload given functions
3684 refunc() {
3685     for func in $argv ; do
3686         unfunction $func
3687         autoload $func
3688     done
3689 }
3690
3691 # a small check to see which DIR is located on which server/partition.
3692 # stolen and modified from Sven's zshrc.forall
3693 #f5# Report diskusage of a directory
3694 dirspace() {
3695     emulate -L zsh
3696     if [[ -n "$1" ]] ; then
3697         for dir in "$@" ; do
3698             if [[ -d "$dir" ]] ; then
3699                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3700             else
3701                 echo "warning: $dir does not exist" >&2
3702             fi
3703         done
3704     else
3705         for dir in $path; do
3706             if [[ -d "$dir" ]] ; then
3707                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3708             else
3709                 echo "warning: $dir does not exist" >&2
3710             fi
3711         done
3712     fi
3713 }
3714
3715 # % slow_print `cat /etc/passwd`
3716 #f5# Slowly print out parameters
3717 slow_print() {
3718     for argument in "$@" ; do
3719         for ((i = 1; i <= ${#1} ;i++)) ; do
3720             print -n "${argument[i]}"
3721             sleep 0.08
3722         done
3723         print -n " "
3724     done
3725     print ""
3726 }
3727
3728 #f5# Show some status info
3729 status() {
3730     print
3731     print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")
3732     print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
3733     print "Term..: $TTY ($TERM), ${BAUD:+$BAUD bauds, }$COLUMNS x $LINES chars"
3734     print "Login.: $LOGNAME (UID = $EUID) on $HOST"
3735     print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
3736     print "Uptime:$(uptime)"
3737     print
3738 }
3739
3740 # Rip an audio CD
3741 #f5# Rip an audio CD
3742 audiorip() {
3743     mkdir -p ~/ripps
3744     cd ~/ripps
3745     cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
3746     cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
3747     echo " * Would you like to burn the cd now? (yes/no)"
3748     read input
3749     if [[ "$input" = "yes" ]] ; then
3750         echo " ! Burning Audio CD"
3751         audioburn
3752         echo " * done."
3753     else
3754         echo " ! Invalid response."
3755     fi
3756 }
3757
3758 # and burn it
3759 #f5# Burn an audio CD (in combination with audiorip)
3760 audioburn() {
3761     cd ~/ripps
3762     cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
3763     echo " * Should I remove the temporary files? (yes/no)"
3764     read input
3765     if [[ "$input" = "yes" ]] ; then
3766         echo " ! Removing Temporary Files."
3767         cd ~
3768         rm -rf ~/ripps
3769         echo " * done."
3770     else
3771         echo " ! Invalid response."
3772     fi
3773 }
3774
3775 #f5# Make an audio CD from all mp3 files
3776 mkaudiocd() {
3777     # TODO: do the renaming more zshish, possibly with zmv()
3778     emulate -L zsh
3779     cd ~/ripps
3780     for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
3781     for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
3782     for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
3783     normalize -m *.wav
3784     for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
3785 }
3786
3787 #f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
3788 mkiso() {
3789     emulate -L zsh
3790     echo " * Volume name "
3791     read volume
3792     echo " * ISO Name (ie. tmp.iso)"
3793     read iso
3794     echo " * Directory or File"
3795     read files
3796     mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
3797 }
3798
3799 #f5# Simple thumbnails generator
3800 genthumbs() {
3801     rm -rf thumb-* index.html
3802     echo "
3803 <html>
3804   <head>
3805     <title>Images</title>
3806   </head>
3807   <body>" > index.html
3808     for f in *.(gif|jpeg|jpg|png) ; do
3809         convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
3810         echo "    <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
3811     done
3812     echo "
3813   </body>
3814 </html>" >> index.html
3815 }
3816
3817 #f5# Set all ulimit parameters to \kbd{unlimited}
3818 allulimit() {
3819     ulimit -c unlimited
3820     ulimit -d unlimited
3821     ulimit -f unlimited
3822     ulimit -l unlimited
3823     ulimit -n unlimited
3824     ulimit -s unlimited
3825     ulimit -t unlimited
3826 }
3827
3828 # ogg2mp3 with bitrate of 192
3829 ogg2mp3_192() {
3830     emulate -L zsh
3831     oggdec -o - $1 | lame -b 192 - ${1:r}.mp3
3832 }
3833
3834 #f5# RFC 2396 URL encoding in Z-Shell
3835 urlencode() {
3836     emulate -L zsh
3837     setopt extendedglob
3838     input=( ${(s::)1} )
3839     print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
3840 }
3841
3842 #f5# Install x-lite (VoIP software)
3843 getxlite() {
3844     emulate -L zsh
3845     setopt errreturn
3846     [[ -d ~/tmp ]] || mkdir ~/tmp
3847     cd ~/tmp
3848
3849     echo "Downloading http://www.counterpath.com/download/X-Lite_Install.tar.gz and storing it in ~/tmp:"
3850     if wget http://www.counterpath.com/download/X-Lite_Install.tar.gz ; then
3851         unp X-Lite_Install.tar.gz && echo done || echo failed
3852     else
3853         echo "Error while downloading." ; return 1
3854     fi
3855
3856     if [[ -x xten-xlite/xtensoftphone ]] ; then
3857         echo "Execute xten-xlite/xtensoftphone to start xlite."
3858     fi
3859 }
3860
3861 #f5# Install skype
3862 getskype() {
3863     emulate -L zsh
3864     setopt errreturn
3865     echo "Downloading debian package of skype."
3866     echo "Notice: If you want to use a more recent skype version run 'getskypebeta'."
3867     wget http://www.skype.com/go/getskype-linux-deb
3868     $SUDO dpkg -i skype*.deb && echo "skype installed."
3869 }
3870
3871 #f5# Install beta-version of skype
3872 getskypebeta() {
3873     emulate -L zsh
3874     setopt errreturn
3875     echo "Downloading debian package of skype (beta version)."
3876     wget http://www.skype.com/go/getskype-linux-beta-deb
3877     $SUDO dpkg -i skype-beta*.deb && echo "skype installed."
3878 }
3879
3880 #f5# Install gizmo (VoIP software)
3881 getgizmo() {
3882     emulate -L zsh
3883     setopt errreturn
3884     echo "libgtk2.0-0, gconf2, libstdc++6, libasound2 and zlib1g have to be available. Installing."
3885     $SUDO apt-get update
3886     $SUDO apt-get install libgtk2.0-0 gconf2 libstdc++6 libasound2 zlib1g
3887     wget "$(lynx --dump http://gizmo5.com/pc/download/linux/ | awk '/libstdc\+\+6.*\.deb/ {print $2}')"
3888     $SUDO dpkg -i gizmo-project*.deb && echo "gizmo installed."
3889 }
3890
3891 #f5# Get and run AIR (Automated Image and Restore)
3892 getair() {
3893     emulate -L zsh
3894     setopt errreturn
3895     [[ -w . ]] || { echo 'Error: you do not have write permissions in this directory. Exiting.' ; return 1 }
3896     local VER='1.2.8'
3897     wget http://puzzle.dl.sourceforge.net/sourceforge/air-imager/air-$VER.tar.gz
3898     tar zxf air-$VER.tar.gz
3899     cd air-$VER
3900     INTERACTIVE=no $SUDO ./install-air-1.2.8
3901     [[ -x /usr/local/bin/air ]] && [[ -n "$DISPLAY" ]] && $SUDO air
3902 }
3903
3904 #f5# Get specific git commitdiff
3905 git-get-diff() {
3906     emulate -L zsh
3907     if [[ -z $GITTREE ]] ; then
3908         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3909     fi
3910     if ! [[ -z $1 ]] ; then
3911         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commitdiff;h=$1"
3912     else
3913         echo "Usage: git-get-diff <commit>"
3914     fi
3915 }
3916
3917 #f5# Get specific git commit
3918 git-get-commit() {
3919     emulate -L zsh
3920     if [[ -z $GITTREE ]] ; then
3921         GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3922     fi
3923     if ! [[ -z $1 ]] ; then
3924         ${=BROWSER} "http://kernel.org/git/?p=$GITTREE;a=commit;h=$1"
3925     else
3926         echo "Usage: git-get-commit <commit>"
3927     fi
3928 }
3929
3930 #f5# Get specific git diff
3931 git-get-plaindiff () {
3932     emulate -L zsh
3933     if [[ -z $GITTREE ]] ; then
3934        GITTREE='linux/kernel/git/torvalds/linux-2.6.git'
3935     fi
3936     if [[ -z $1 ]] ; then
3937        echo 'Usage: git-get-plaindiff '
3938     else
3939        echo -n "Downloading $1.diff ... "
3940        # avoid "generating ..." stuff from kernel.org server:
3941        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O /dev/null
3942        wget --quiet "http://kernel.org/git/?p=$GITTREE;a=commitdiff_plain;h=$1" -O $1.diff \
3943             && echo done || echo failed
3944     fi
3945 }
3946
3947
3948 # http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
3949 #f5# Log 'make install' output
3950 mmake() {
3951     emulate -L zsh
3952     [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
3953     make -n install > ~/.errorlogs/${PWD##*/}-makelog
3954 }
3955
3956 #f5# Indent source code
3957 smart-indent() {
3958     indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
3959 }
3960
3961 # highlight important stuff in diff output, usage example: hg diff | hidiff
3962 #m# a2 hidiff \kbd{histring} oneliner for diffs
3963 check_com -c histring && \
3964     alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
3965
3966 # rename pictures based on information found in exif headers
3967 #f5# Rename pictures based on information found in exif headers
3968 exirename() {
3969     emulate -L zsh
3970     if [[ $# -lt 1 ]] ; then
3971         echo 'Usage: jpgrename $FILES' >& 2
3972         return 1
3973     else
3974         echo -n 'Checking for jhead with version newer than 1.9: '
3975         jhead_version=`jhead -h | grep 'used by most Digital Cameras.  v.*' | awk '{print $6}' | tr -d v`
3976         if [[ $jhead_version > '1.9' ]]; then
3977             echo 'success - now running jhead.'
3978             jhead -n%Y-%m-%d_%Hh%M_%f $*
3979         else
3980             echo 'failed - exiting.'
3981         fi
3982     fi
3983 }
3984
3985 # open file in vim and jump to line
3986 # http://www.downgra.de/archives/2007/05/08/T19_21_11/
3987 j2v() {
3988     emulate -L zsh
3989     local -a params
3990     params=(${*//(#m):[0-9]*:/\\n+${MATCH//:/}}) # replace ':23:' to '\n+23'
3991     params=(${(s|\n|)${(j|\n|)params}}) # join array using '\n', then split on all '\n'
3992     vim ${params}
3993 }
3994
3995 # get_ic() - queries imap servers for capabilities; real simple. no imaps
3996 ic_get() {
3997     emulate -L zsh
3998     local port
3999     if [[ ! -z $1 ]] ; then
4000         port=${2:-143}
4001         print "querying imap server on $1:${port}...\n";
4002         print "a1 capability\na2 logout\n" | nc $1 ${port}
4003     else
4004         print "usage:\n  $0 <imap-server> [port]"
4005     fi
4006 }
4007
4008 # creates a Maildir/ with its {new,cur,tmp} subdirs
4009 mkmaildir() {
4010     emulate -L zsh
4011     local root subdir
4012     root=${MAILDIR_ROOT:-${HOME}/Mail}
4013     if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
4014     subdir=${1}
4015     mkdir -p ${root}/${subdir}/{cur,new,tmp}
4016 }
4017
4018 #f5# Change the xterm title from within GNU-screen
4019 xtrename() {
4020     emulate -L zsh
4021     if [[ $1 != "-f" ]] ; then
4022         if [[ -z ${DISPLAY} ]] ; then
4023             printf 'xtrename only makes sense in X11.\n'
4024             return 1
4025         fi
4026     else
4027         shift
4028     fi
4029     if [[ -z $1 ]] ; then
4030         printf 'usage: xtrename [-f] "title for xterm"\n'
4031         printf '  renames the title of xterm from _within_ screen.\n'
4032         printf '  also works without screen.\n'
4033         printf '  will not work if DISPLAY is unset, use -f to override.\n'
4034         return 0
4035     fi
4036     print -n "\eP\e]0;${1}\C-G\e\\"
4037     return 0
4038 }
4039
4040 # hl() highlighted less
4041 # http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
4042 if check_com -c highlight ; then
4043     function hl() {
4044     emulate -L zsh
4045         local theme lang
4046         theme=${HL_THEME:-""}
4047         case ${1} in
4048             (-l|--list)
4049                 ( printf 'available languages (syntax parameter):\n\n' ;
4050                     highlight --list-langs ; ) | less -SMr
4051                 ;;
4052             (-t|--themes)
4053                 ( printf 'available themes (style parameter):\n\n' ;
4054                     highlight --list-themes ; ) | less -SMr
4055                 ;;
4056             (-h|--help)
4057                 printf 'usage: hl <syntax[:theme]> <file>\n'
4058                 printf '    available options: --list (-l), --themes (-t), --help (-h)\n\n'
4059                 printf '  Example: hl c main.c\n'
4060                 ;;
4061             (*)
4062                 if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
4063                     printf 'usage: hl <syntax[:theme]> <file>\n'
4064                     printf '    available options: --list (-l), --themes (-t), --help (-h)\n'
4065                     (( ${#argv} > 2 )) && printf '  Too many arguments.\n'
4066                     return 1
4067                 fi
4068                 lang=${1%:*}
4069                 [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
4070                 if [[ -n ${theme} ]] ; then
4071                     highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
4072                 else
4073                     highlight --ansi --syntax ${lang} ${2} | less -SMr
4074                 fi
4075                 ;;
4076         esac
4077         return 0
4078     }
4079     # ... and a proper completion for hl()
4080     # needs 'highlight' as well, so it fits fine in here.
4081     function _hl_genarg()  {
4082         local expl
4083         if [[ -prefix 1 *: ]] ; then
4084             local themes
4085             themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
4086             compset -P 1 '*:'
4087             _wanted -C list themes expl theme compadd ${themes}
4088         else
4089             local langs
4090             langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
4091             _wanted -C list languages expl languages compadd -S ':' -q ${langs}
4092         fi
4093     }
4094     function _hl_complete() {
4095         _arguments -s '1: :_hl_genarg' '2:files:_path_files'
4096     }
4097     compdef _hl_complete hl
4098 fi
4099
4100 # Create small urls via http://tinyurl.com using wget(1).
4101 function zurl() {
4102     emulate -L zsh
4103     [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
4104
4105     local PN url tiny grabber search result preview
4106     PN=$0
4107     url=$1
4108 #   Check existence of given URL with the help of ping(1).
4109 #   N.B. ping(1) only works without an eventual given protocol.
4110     ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
4111         read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
4112
4113     if (( $? == 0 )) ; then
4114 #           Prepend 'http://' to given URL where necessary for later output.
4115             [[ ${url} != http(s|)://* ]] && url='http://'${url}
4116             tiny='http://tinyurl.com/create.php?url='
4117             if check_com -c wget ; then
4118                 grabber='wget -O- -o/dev/null'
4119             else
4120                 print "wget is not available, but mandatory for ${PN}. Aborting."
4121             fi
4122 #           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
4123             search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
4124             result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
4125 #           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
4126             preview='http://preview.'${result#http://}
4127
4128             printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
4129             printf '%s\t%s\n\n' 'Given URL:' ${url}
4130             printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
4131     else
4132         return 1
4133     fi
4134 }
4135
4136 #f2# Print a specific line of file(s).
4137 linenr () {
4138 # {{{
4139     emulate -L zsh
4140     if [ $# -lt 2 ] ; then
4141        print "Usage: linenr <number>[,<number>] <file>" ; return 1
4142     elif [ $# -eq 2 ] ; then
4143          local number=$1
4144          local file=$2
4145          command ed -s $file <<< "${number}n"
4146     else
4147          local number=$1
4148          shift
4149          for file in "$@" ; do
4150              if [ ! -d $file ] ; then
4151                 echo "${file}:"
4152                 command ed -s $file <<< "${number}n" 2> /dev/null
4153              else
4154                 continue
4155              fi
4156          done | less
4157     fi
4158 # }}}
4159 }
4160
4161 #f2# Find history events by search pattern and list them by date.
4162 whatwhen()  {
4163 # {{{
4164     emulate -L zsh
4165     local usage help ident format_l format_s first_char remain first last
4166     usage='USAGE: whatwhen [options] <searchstring> <search range>'
4167     help='Use' \`'whatwhen -h'\'' for further explanations.'
4168     ident=${(l,${#${:-Usage: }},, ,)}
4169     format_l="${ident}%s\t\t\t%s\n"
4170     format_s="${format_l//(\\t)##/\\t}"
4171     # Make the first char of the word to search for case
4172     # insensitive; e.g. [aA]
4173     first_char=[${(L)1[1]}${(U)1[1]}]
4174     remain=${1[2,-1]}
4175     # Default search range is `-100'.
4176     first=${2:-\-100}
4177     # Optional, just used for `<first> <last>' given.
4178     last=$3
4179     case $1 in
4180         ("")
4181             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
4182             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4183         ;;
4184         (-h)
4185             printf '%s\n\n' ${usage}
4186             print 'OPTIONS:'
4187             printf $format_l '-h' 'show help text'
4188             print '\f'
4189             print 'SEARCH RANGE:'
4190             printf $format_l "'0'" 'the whole history,'
4191             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
4192             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
4193             printf '\n%s\n' 'EXAMPLES:'
4194             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
4195             printf $format_l 'whatwhen zsh -250'
4196             printf $format_l 'whatwhen foo 1 99'
4197         ;;
4198         (\?)
4199             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4200         ;;
4201         (*)
4202             # -l list results on stout rather than invoking $EDITOR.
4203             # -i Print dates as in YYYY-MM-DD.
4204             # -m Search for a - quoted - pattern within the history.
4205             fc -li -m "*${first_char}${remain}*" $first $last
4206         ;;
4207     esac
4208 # }}}
4209 }
4210
4211 # change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
4212 fluxkey-change() {
4213     emulate -L zsh
4214     [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
4215     if ! [[ -r "$FLUXKEYS" ]] ; then
4216         echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
4217         return 1
4218     else
4219         if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
4220             echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
4221             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
4222         elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
4223             echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
4224             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
4225         else
4226             echo 'Sorry, do not know what to do.'
4227             return 1
4228         fi
4229     fi
4230 }
4231
4232 # retrieve weather information on the console
4233 # Usage example: 'weather LOWG'
4234 weather() {
4235     emulate -L zsh
4236     [[ -n "$1" ]] || {
4237         print 'Usage: weather <station_id>' >&2
4238         print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
4239         return 1
4240     }
4241
4242     local PLACE="${1:u}"
4243     local FILE="$HOME/.weather/$PLACE"
4244     local LOG="$HOME/.weather/log"
4245
4246     [[ -d $HOME/.weather ]] || {
4247         print -n "Creating $HOME/.weather: "
4248         mkdir $HOME/.weather
4249         print 'done'
4250     }
4251
4252     print "Retrieving information for ${PLACE}:"
4253     print
4254     wget -T 10 --no-verbose --output-file=$LOG --output-document=$FILE --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
4255
4256     if [[ $? -eq 0 ]] ; then
4257         if [[ -n "$VERBOSE" ]] ; then
4258             cat $FILE
4259         else
4260             DATE=$(grep 'UTC' $FILE | sed 's#.* /##')
4261             TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' $FILE| tr -d '(')
4262             echo "date: $DATE"
4263             echo "temp:  $TEMPERATURE"
4264         fi
4265     else
4266         print "There was an error retrieving the weather information for $PLACE" >&2
4267         cat $LOG
4268         return 1
4269     fi
4270 }
4271 # }}}
4272
4273 # mercurial related stuff {{{
4274 if check_com -c hg ; then
4275     # gnu like diff for mercurial
4276     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
4277     #f5# GNU like diff for mercurial
4278     hgdi() {
4279         emulate -L zsh
4280         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
4281     }
4282
4283     # build debian package
4284     #a2# Alias for \kbd{hg-buildpackage}
4285     alias hbp='hg-buildpackage'
4286
4287     # execute commands on the versioned patch-queue from the current repos
4288     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
4289
4290     # diffstat for specific version of a mercurial repository
4291     #   hgstat      => display diffstat between last revision and tip
4292     #   hgstat 1234 => display diffstat between revision 1234 and tip
4293     #f5# Diffstat for specific version of a mercurial repos
4294     hgstat() {
4295         emulate -L zsh
4296         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
4297     }
4298
4299     #f5# Get current mercurial tip via hg itself
4300     gethgclone() {
4301         emulate -L zsh
4302         setopt errreturn
4303         if [[ -f mercurial-tree/.hg ]] ; then
4304             cd mercurial-tree
4305             echo "Running hg pull for retreiving latest version..."
4306             hg pull
4307             echo "Finished update. Building mercurial"
4308             make local
4309             echo "Setting \$PATH to $PWD:\$PATH..."
4310             export PATH="$PWD:$PATH"
4311         else
4312             echo "Downloading mercurial via hg"
4313             hg clone http://selenic.com/repo/hg mercurial-tree
4314             cd mercurial-tree
4315             echo "Building mercurial"
4316             make local
4317             echo "Setting \$PATH to $PWD:\$PATH..."
4318             export PATH="$PWD:$PATH"
4319             echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4320             # echo "Setting \$PYTHONPATH to PYTHONPATH=\${HOME}/lib/python,"
4321             # export PYTHONPATH=${HOME}/lib/python
4322         fi
4323     }
4324
4325 fi # end of check whether we have the 'hg'-executable
4326
4327 # get current mercurial snapshot
4328 #f5# Get current mercurial snapshot
4329 gethgsnap() {
4330     emulate -L zsh
4331     setopt errreturn
4332     if [[ -f mercurial-snapshot.tar.gz ]] ; then
4333          echo "mercurial-snapshot.tar.gz exists already, skipping download."
4334     else
4335         echo "Downloading mercurial snapshot"
4336         wget http://www.selenic.com/mercurial/mercurial-snapshot.tar.gz
4337     fi
4338     echo "Unpacking mercurial-snapshot.tar.gz"
4339     tar zxf mercurial-snapshot.tar.gz
4340     cd mercurial-snapshot/
4341     echo "Installing required build-dependencies"
4342     $SUDO apt-get update
4343     $SUDO apt-get install python2.4-dev
4344     echo "Building mercurial"
4345     make local
4346     echo "Setting \$PATH to $PWD:\$PATH..."
4347     export PATH="$PWD:$PATH"
4348     echo "make sure you set it permanent via ~/.zshrc if you plan to use it permanently."
4349 }
4350 # }}}
4351
4352 # some useful commands often hard to remember - let's grep for them {{{
4353 # actually use our zg() function now. :)
4354
4355 # Work around ion/xterm resize bug.
4356 #if [[ "$SHLVL" -eq 1 ]]; then
4357 #       if check_com -c resize ; then
4358 #               eval `resize </dev/null`
4359 #       fi
4360 #fi
4361
4362 # enable jackd:
4363 #  /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
4364 # now play audio file:
4365 #  alsaplayer -o jack foobar.mp3
4366
4367 # send files via netcat
4368 # on sending side:
4369 #  send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
4370 #  send dir* $HOST
4371 #  alias receive='nc -vlp 51330 | tar xzvp'
4372
4373 # debian stuff:
4374 # dh_make -e foo@localhost -f $1
4375 # dpkg-buildpackage -rfakeroot
4376 # lintian *.deb
4377 # dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
4378 # dpkg-scansources . | gzip > Sources.gz
4379 # grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
4380
4381 # other stuff:
4382 # convert -geometry 200x200 -interlace LINE -verbose
4383 # ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
4384 # ps -ao user,pcpu,start,command
4385 # gpg --keyserver blackhole.pca.dfn.de --recv-keys
4386 # xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
4387 # nc -vz $1 1-1024   # portscan via netcat
4388 # wget --mirror --no-parent --convert-links
4389 # pal -d `date +%d`
4390 # autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
4391 #
4392 # modify console cursor
4393 # see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
4394 # print $'\e[?96;0;64c'
4395 # }}}
4396
4397 # grml-small cleanups {{{
4398
4399 # The following is used to remove zsh-config-items that do not work
4400 # in grml-small by default.
4401 # If you do not want these adjustments (for whatever reason), set
4402 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
4403 # sources if it is there).
4404
4405 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
4406
4407     unset abk[V]
4408     unalias    'V'      &> /dev/null
4409     unfunction vman     &> /dev/null
4410     unfunction viless   &> /dev/null
4411     unfunction 2html    &> /dev/null
4412
4413     # manpages are not in grmlsmall
4414     unfunction manzsh   &> /dev/null
4415     unfunction man2     &> /dev/null
4416
4417 fi
4418
4419 #}}}
4420
4421 zrclocal
4422
4423 ## genrefcard.pl settings {{{
4424
4425 ### doc strings for external functions from files
4426 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
4427
4428 ### example: split functions-search 8,16,24,32
4429 #@# split functions-search 8
4430
4431 ## }}}
4432
4433 ## END OF FILE #################################################################
4434 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
4435 # Local variables:
4436 # mode: sh
4437 # End: