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