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