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