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