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