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