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