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