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