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