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