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