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