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