zshrc: Don't unset `nomatch' anymore
[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 # zsh profiling
106 # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
107 if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
108     zmodload zsh/zprof
109 fi
110
111 # load .zshrc.pre to give the user the chance to overwrite the defaults
112 [[ -r ${HOME}/.zshrc.pre ]] && source ${HOME}/.zshrc.pre
113
114 # check for version/system
115 # check for versions (compatibility reasons)
116 is4(){
117     [[ $ZSH_VERSION == <4->* ]] && return 0
118     return 1
119 }
120
121 is41(){
122     [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
123     return 1
124 }
125
126 is42(){
127     [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
128     return 1
129 }
130
131 is425(){
132     [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
133     return 1
134 }
135
136 is43(){
137     [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
138     return 1
139 }
140
141 is433(){
142     [[ $ZSH_VERSION == 4.3.<3->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
143     return 1
144 }
145
146 is439(){
147     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
148     return 1
149 }
150
151 #f1# Checks whether or not you're running grml
152 isgrml(){
153     [[ -f /etc/grml_version ]] && return 0
154     return 1
155 }
156
157 #f1# Checks whether or not you're running a grml cd
158 isgrmlcd(){
159     [[ -f /etc/grml_cd ]] && return 0
160     return 1
161 }
162
163 if isgrml ; then
164 #f1# Checks whether or not you're running grml-small
165     isgrmlsmall() {
166         [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]] && return 0 ; return 1
167     }
168 else
169     isgrmlsmall() { return 1 }
170 fi
171
172 isdarwin(){
173     [[ $OSTYPE == darwin* ]] && return 0
174     return 1
175 }
176
177 #f1# are we running within an utf environment?
178 isutfenv() {
179     case "$LANG $CHARSET $LANGUAGE" in
180         *utf*) return 0 ;;
181         *UTF*) return 0 ;;
182         *)     return 1 ;;
183     esac
184 }
185
186 # check for user, if not running as root set $SUDO to sudo
187 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
188
189 # change directory to home on first invocation of zsh
190 # important for rungetty -> autologin
191 # Thanks go to Bart Schaefer!
192 isgrml && checkhome() {
193     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
194         export ALREADY_DID_CD_HOME=$HOME
195         cd
196     fi
197 }
198
199 # check for zsh v3.1.7+
200
201 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
202      || ${ZSH_VERSION} == 3.<2->.<->*    \
203      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
204
205     printf '-!-\n'
206     printf '-!- In this configuration we try to make use of features, that only\n'
207     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
208     printf '-!- used with a wide range of zsh versions, while using fairly\n'
209     printf '-!- advanced features in all supported versions.\n'
210     printf '-!-\n'
211     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
212     printf '-!-\n'
213     printf '-!- While this *may* work, it might as well fail.\n'
214     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
215     printf '-!-\n'
216     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
217     printf '-!- If it does today, you'\''ve been lucky.\n'
218     printf '-!-\n'
219     printf '-!- Ye been warned!\n'
220     printf '-!-\n'
221
222     function zstyle() { : }
223 fi
224
225 # autoload wrapper - use this one instead of autoload directly
226 # We need to define this function as early as this, because autoloading
227 # 'is-at-least()' needs it.
228 function zrcautoload() {
229     emulate -L zsh
230     setopt extended_glob
231     local fdir ffile
232     local -i ffound
233
234     ffile=$1
235     (( found = 0 ))
236     for fdir in ${fpath} ; do
237         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
238     done
239
240     (( ffound == 0 )) && return 1
241     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
242         autoload -U ${ffile} || return 1
243     else
244         autoload ${ffile} || return 1
245     fi
246     return 0
247 }
248
249 # Load is-at-least() for more precise version checks
250 # Note that this test will *always* fail, if the is-at-least
251 # function could not be marked for autoloading.
252 zrcautoload is-at-least || is-at-least() { return 1 }
253
254 # set some important options (as early as possible)
255 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
256 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
257 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
258 is4 && setopt histignorealldups # If  a  new  command  line being added to the history
259                             # list duplicates an older one, the older command is removed from the list
260 setopt histignorespace      # remove command lines from the history list when
261                             # the first character on the line is a space
262 setopt auto_cd              # if a command is issued that can't be executed as a normal command,
263                             # and the command is the name of a directory, perform the cd command to that directory
264 setopt extended_glob        # in order to use #, ~ and ^ for filename generation
265                             # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
266                             # -> searches for word not in compressed files
267                             # don't forget to quote '^', '~' and '#'!
268 setopt longlistjobs         # display PID when suspending processes as well
269 setopt notify               # report the status of backgrounds jobs immediately
270 setopt hash_list_all        # Whenever a command completion is attempted, make sure \
271                             # the entire command path is hashed first.
272 setopt completeinword       # not just at the end
273 setopt nohup                # and don't kill them, either
274 setopt auto_pushd           # make cd push the old directory onto the directory stack.
275 setopt nobeep               # avoid "beep"ing
276 setopt pushd_ignore_dups    # don't push the same dir twice.
277 setopt noglobdots           # * shouldn't match dotfiles. ever.
278 setopt noshwordsplit        # use zsh style word splitting
279 setopt unset                # don't error out when unset parameters are used
280
281 # setting some default values
282
283 NOCOR=${NOCOR:-0}
284 NOMENU=${NOMENU:-0}
285 NOPRECMD=${NOPRECMD:-0}
286 COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
287 GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
288 BATTERY=${BATTERY:-0}
289 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
290 GRML_ALWAYS_LOAD_ALL=${GRML_ALWAYS_LOAD_ALL:-0}
291 ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
292
293 # utility functions
294 # this function checks if a command exists and returns either true
295 # or false. This avoids using 'which' and 'whence', which will
296 # avoid problems with aliases for which on certain weird systems. :-)
297 # Usage: check_com [-c|-g] word
298 #   -c  only checks for external commands
299 #   -g  does the usual tests and also checks for global aliases
300 check_com() {
301     emulate -L zsh
302     local -i comonly gatoo
303
304     if [[ $1 == '-c' ]] ; then
305         (( comonly = 1 ))
306         shift
307     elif [[ $1 == '-g' ]] ; then
308         (( gatoo = 1 ))
309     else
310         (( comonly = 0 ))
311         (( gatoo = 0 ))
312     fi
313
314     if (( ${#argv} != 1 )) ; then
315         printf 'usage: check_com [-c] <command>\n' >&2
316         return 1
317     fi
318
319     if (( comonly > 0 )) ; then
320         [[ -n ${commands[$1]}  ]] && return 0
321         return 1
322     fi
323
324     if   [[ -n ${commands[$1]}    ]] \
325       || [[ -n ${functions[$1]}   ]] \
326       || [[ -n ${aliases[$1]}     ]] \
327       || [[ -n ${reswords[(r)$1]} ]] ; then
328
329         return 0
330     fi
331
332     if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
333         return 0
334     fi
335
336     return 1
337 }
338
339 # creates an alias and precedes the command with
340 # sudo if $EUID is not zero.
341 salias() {
342     emulate -L zsh
343     local only=0 ; local multi=0
344     while [[ $1 == -* ]] ; do
345         case $1 in
346             (-o) only=1 ;;
347             (-a) multi=1 ;;
348             (--) shift ; break ;;
349             (-h)
350                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
351                 printf '  -h      shows this help text.\n'
352                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
353                 printf '          be careful using this option.\n'
354                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
355                 return 0
356                 ;;
357             (*) printf "unkown option: '%s'\n" "$1" ; return 1 ;;
358         esac
359         shift
360     done
361
362     if (( ${#argv} > 1 )) ; then
363         printf 'Too many arguments %s\n' "${#argv}"
364         return 1
365     fi
366
367     key="${1%%\=*}" ;  val="${1#*\=}"
368     if (( EUID == 0 )) && (( only == 0 )); then
369         alias -- "${key}=${val}"
370     elif (( EUID > 0 )) ; then
371         (( multi > 0 )) && val="${val// ; / ; sudo }"
372         alias -- "${key}=sudo ${val}"
373     fi
374
375     return 0
376 }
377
378 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
379 # usage: uprint foo
380 #   Where foo is the *name* of the parameter you want printed.
381 #   Note that foo is no typo; $foo would be wrong here!
382 if ! is42 ; then
383     uprint () {
384         emulate -L zsh
385         local -a u
386         local w
387         local parameter=$1
388
389         if [[ -z ${parameter} ]] ; then
390             printf 'usage: uprint <parameter>\n'
391             return 1
392         fi
393
394         for w in ${(P)parameter} ; do
395             [[ -z ${(M)u:#$w} ]] && u=( $u $w )
396         done
397
398         builtin print -l $u
399     }
400 fi
401
402 # Check if we can read given files and source those we can.
403 xsource() {
404     if (( ${#argv} < 1 )) ; then
405         printf 'usage: xsource FILE(s)...\n' >&2
406         return 1
407     fi
408
409     while (( ${#argv} > 0 )) ; do
410         [[ -r "$1" ]] && source "$1"
411         shift
412     done
413     return 0
414 }
415
416 # Check if we can read a given file and 'cat(1)' it.
417 xcat() {
418     emulate -L zsh
419     if (( ${#argv} != 1 )) ; then
420         printf 'usage: xcat FILE\n' >&2
421         return 1
422     fi
423
424     [[ -r $1 ]] && cat $1
425     return 0
426 }
427
428 # Remove these functions again, they are of use only in these
429 # setup files. This should be called at the end of .zshrc.
430 xunfunction() {
431     emulate -L zsh
432     local -a funcs
433     funcs=(salias xcat xsource xunfunction zrcautoload)
434
435     for func in $funcs ; do
436         [[ -n ${functions[$func]} ]] \
437             && unfunction $func
438     done
439     return 0
440 }
441
442 # this allows us to stay in sync with grml's zshrc and put own
443 # modifications in ~/.zshrc.local
444 zrclocal() {
445     xsource "/etc/zsh/zshrc.local"
446     xsource "${HOME}/.zshrc.local"
447     return 0
448 }
449
450 # locale setup
451 if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
452     xsource "/etc/default/locale"
453 fi
454
455 for var in LANG LC_ALL LC_MESSAGES ; do
456     [[ -n ${(P)var} ]] && export $var
457 done
458
459 xsource "/etc/sysconfig/keyboard"
460
461 TZ=$(xcat /etc/timezone)
462
463 # set some variables
464 if check_com -c vim ; then
465 #v#
466     export EDITOR=${EDITOR:-vim}
467 else
468     export EDITOR=${EDITOR:-vi}
469 fi
470
471 #v#
472 export PAGER=${PAGER:-less}
473
474 #v#
475 export MAIL=${MAIL:-/var/mail/$USER}
476
477 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
478 export SHELL='/bin/zsh'
479
480 # color setup for ls:
481 check_com -c dircolors && eval $(dircolors -b)
482 # color setup for ls on OS X:
483 isdarwin && export CLICOLOR=1
484
485 # do MacPorts setup on darwin
486 if isdarwin && [[ -d /opt/local ]]; then
487     # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
488     # zshenv.
489     PATH="/opt/local/bin:/opt/local/sbin:$PATH"
490     MANPATH="/opt/local/share/man:$MANPATH"
491 fi
492 # do Fink setup on darwin
493 isdarwin && xsource /sw/bin/init.sh
494
495 # load our function and completion directories
496 for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
497     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
498     if [[ ${fpath} == '/usr/share/grml/zsh/functions' ]] ; then
499         for func in ${fdir}/**/[^_]*[^~](N.) ; do
500             zrcautoload ${func:t}
501         done
502     fi
503 done
504 unset fdir func
505
506 # support colors in less
507 export LESS_TERMCAP_mb=$'\E[01;31m'
508 export LESS_TERMCAP_md=$'\E[01;31m'
509 export LESS_TERMCAP_me=$'\E[0m'
510 export LESS_TERMCAP_se=$'\E[0m'
511 export LESS_TERMCAP_so=$'\E[01;44;33m'
512 export LESS_TERMCAP_ue=$'\E[0m'
513 export LESS_TERMCAP_us=$'\E[01;32m'
514
515 MAILCHECK=30       # mailchecks
516 REPORTTIME=5       # report about cpu-/system-/user-time of command if running longer than 5 seconds
517 watch=(notme root) # watch for everyone but me and root
518
519 # automatically remove duplicates from these arrays
520 typeset -U path cdpath fpath manpath
521
522 # keybindings
523 if [[ "$TERM" != emacs ]] ; then
524     [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
525     [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
526     [[ -z "$terminfo[kend]"  ]] || bindkey -M emacs "$terminfo[kend]"  end-of-line
527     [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
528     [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
529     [[ -z "$terminfo[kend]"  ]] || bindkey -M vicmd "$terminfo[kend]"  vi-end-of-line
530     [[ -z "$terminfo[cuu1]"  ]] || bindkey -M viins "$terminfo[cuu1]"  vi-up-line-or-history
531     [[ -z "$terminfo[cuf1]"  ]] || bindkey -M viins "$terminfo[cuf1]"  vi-forward-char
532     [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
533     [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
534     [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
535     [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
536     # ncurses stuff:
537     [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
538     [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
539     [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
540     [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
541     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
542     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}"  end-of-line
543     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
544     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line
545 fi
546
547 ## keybindings (run 'bindkeys' for details, more details via man zshzle)
548 # use emacs style per default:
549 bindkey -e
550 # use vi style:
551 # bindkey -v
552
553 ## beginning-of-line OR beginning-of-buffer OR beginning of history
554 ## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
555 beginning-or-end-of-somewhere() {
556     local hno=$HISTNO
557     if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
558       ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
559         zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
560     else
561         zle .${WIDGET:s/somewhere/line-hist/} "$@"
562         if (( HISTNO != hno )); then
563             zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
564         fi
565     fi
566 }
567 zle -N beginning-of-somewhere beginning-or-end-of-somewhere
568 zle -N end-of-somewhere beginning-or-end-of-somewhere
569
570
571 #if [[ "$TERM" == screen ]] ; then
572
573 ## with HOME/END, move to beginning/end of line (on multiline) on first keypress
574 ## to beginning/end of buffer on second keypress
575 ## and to beginning/end of history on (at most) the third keypress
576 # terminator & non-debian xterm
577 bindkey '\eOH' beginning-of-somewhere  # home
578 bindkey '\eOF' end-of-somewhere        # end
579 # freebsd console
580 bindkey '\e[H' beginning-of-somewhere   # home
581 bindkey '\e[F' end-of-somewhere         # end
582 # xterm,gnome-terminal,quake,etc
583 bindkey '^[[1~' beginning-of-somewhere  # home
584 bindkey '^[[4~' end-of-somewhere        # end
585 # if terminal type is set to 'rxvt':
586 bindkey '\e[7~' beginning-of-somewhere  # home
587 bindkey '\e[8~' end-of-somewhere        # end
588 #fi
589
590 bindkey '\e[A'  up-line-or-search       # cursor up
591 bindkey '\e[B'  down-line-or-search     # <ESC>-
592
593 ## alt-backspace is already the default for backwards-delete-word
594 ## let's also set alt-delete for deleting current word (right of cursor)
595 #k# Kill right-side word
596 bindkey "3~" delete-word
597
598 ## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on the CL
599 bindkey "\e[5C" forward-word
600 bindkey "\e[5D" backward-word
601 bindkey "\e[1;5C" forward-word
602 bindkey "\e[1;5D" backward-word
603 ## the same for alt-left-arrow and alt-right-arrow
604 bindkey '^[[1;3C' forward-word
605 bindkey '^[[1;3D' backward-word
606
607 # Search backward in the history for a line beginning with the current
608 # line up to the cursor and move the cursor to the end of the line then
609 zle -N history-beginning-search-backward-end history-search-end
610 zle -N history-beginning-search-forward-end  history-search-end
611 #k# search history backward for entry beginning with typed text
612 bindkey '^xp'   history-beginning-search-backward-end
613 #k# search history forward for entry beginning with typed text
614 bindkey '^xP'   history-beginning-search-forward-end
615 #k# search history backward for entry beginning with typed text
616 bindkey "\e[5~" history-beginning-search-backward-end # PageUp
617 #k# search history forward for entry beginning with typed text
618 bindkey "\e[6~" history-beginning-search-forward-end  # PageDown
619
620 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
621 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
622
623 # insert unicode character
624 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
625 # See for example http://unicode.org/charts/ for unicode characters code
626 zrcautoload insert-unicode-char
627 zle -N insert-unicode-char
628 #k# Insert Unicode character
629 bindkey '^Xi' insert-unicode-char
630
631 #m# k Shift-tab Perform backwards menu completion
632 if [[ -n "$terminfo[kcbt]" ]]; then
633     bindkey "$terminfo[kcbt]" reverse-menu-complete
634 elif [[ -n "$terminfo[cbt]" ]]; then # required for GNU screen
635     bindkey "$terminfo[cbt]"  reverse-menu-complete
636 fi
637
638 ## toggle the ,. abbreviation feature on/off
639 # NOABBREVIATION: default abbreviation-state
640 #                 0 - enabled (default)
641 #                 1 - disabled
642 NOABBREVIATION=${NOABBREVIATION:-0}
643
644 grml_toggle_abbrev() {
645     if (( ${NOABBREVIATION} > 0 )) ; then
646         NOABBREVIATION=0
647     else
648         NOABBREVIATION=1
649     fi
650 }
651
652 zle -N grml_toggle_abbrev
653 bindkey '^xA' grml_toggle_abbrev
654
655 # add a command line to the shells history without executing it
656 commit-to-history() {
657     print -s ${(z)BUFFER}
658     zle send-break
659 }
660 zle -N commit-to-history
661 bindkey "^x^h" commit-to-history
662
663 # only slash should be considered as a word separator:
664 slash-backward-kill-word() {
665     local WORDCHARS="${WORDCHARS:s@/@}"
666     # zle backward-word
667     zle backward-kill-word
668 }
669 zle -N slash-backward-kill-word
670
671 #k# Kill left-side word or everything up to next slash
672 bindkey '\ev' slash-backward-kill-word
673 #k# Kill left-side word or everything up to next slash
674 bindkey '\e^h' slash-backward-kill-word
675 #k# Kill left-side word or everything up to next slash
676 bindkey '\e^?' slash-backward-kill-word
677
678 # use the new *-pattern-* widgets for incremental history search
679 if is439 ; then
680     bindkey '^r' history-incremental-pattern-search-backward
681     bindkey '^s' history-incremental-pattern-search-forward
682 fi
683
684 # a generic accept-line wrapper
685
686 # This widget can prevent unwanted autocorrections from command-name
687 # to _command-name, rehash automatically on enter and call any number
688 # of builtin and user-defined widgets in different contexts.
689 #
690 # For a broader description, see:
691 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
692 #
693 # The code is imported from the file 'zsh/functions/accept-line' from
694 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
695 # distributed under the same terms as zsh itself.
696
697 # A newly added command will may not be found or will cause false
698 # correction attempts, if you got auto-correction set. By setting the
699 # following style, we force accept-line() to rehash, if it cannot
700 # find the first word on the command line in the $command[] hash.
701 zstyle ':acceptline:*' rehash true
702
703 function Accept-Line() {
704     setopt localoptions noksharrays
705     local -a subs
706     local -xi aldone
707     local sub
708     local alcontext=${1:-$alcontext}
709
710     zstyle -a ":acceptline:${alcontext}" actions subs
711
712     (( ${#subs} < 1 )) && return 0
713
714     (( aldone = 0 ))
715     for sub in ${subs} ; do
716         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
717         zle ${sub}
718
719         (( aldone > 0 )) && break
720     done
721 }
722
723 function Accept-Line-getdefault() {
724     emulate -L zsh
725     local default_action
726
727     zstyle -s ":acceptline:${alcontext}" default_action default_action
728     case ${default_action} in
729         ((accept-line|))
730             printf ".accept-line"
731             ;;
732         (*)
733             printf ${default_action}
734             ;;
735     esac
736 }
737
738 function Accept-Line-HandleContext() {
739     zle Accept-Line
740
741     default_action=$(Accept-Line-getdefault)
742     zstyle -T ":acceptline:${alcontext}" call_default \
743         && zle ${default_action}
744 }
745
746 function accept-line() {
747     setopt localoptions noksharrays
748     local -ax cmdline
749     local -x alcontext
750     local buf com fname format msg default_action
751
752     alcontext='default'
753     buf="${BUFFER}"
754     cmdline=(${(z)BUFFER})
755     com="${cmdline[1]}"
756     fname="_${com}"
757
758     Accept-Line 'preprocess'
759
760     zstyle -t ":acceptline:${alcontext}" rehash \
761         && [[ -z ${commands[$com]} ]]           \
762         && rehash
763
764     if    [[ -n ${com}               ]] \
765        && [[ -n ${reswords[(r)$com]} ]] \
766        || [[ -n ${aliases[$com]}     ]] \
767        || [[ -n ${functions[$com]}   ]] \
768        || [[ -n ${builtins[$com]}    ]] \
769        || [[ -n ${commands[$com]}    ]] ; then
770
771         # there is something sensible to execute, just do it.
772         alcontext='normal'
773         Accept-Line-HandleContext
774
775         return
776     fi
777
778     if    [[ -o correct              ]] \
779        || [[ -o correctall           ]] \
780        && [[ -n ${functions[$fname]} ]] ; then
781
782         # nothing there to execute but there is a function called
783         # _command_name; a completion widget. Makes no sense to
784         # call it on the commandline, but the correct{,all} options
785         # will ask for it nevertheless, so warn the user.
786         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
787             # Okay, we warned the user before, he called us again,
788             # so have it his way.
789             alcontext='force'
790             Accept-Line-HandleContext
791
792             return
793         fi
794
795         if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
796             alcontext='normal'
797             Accept-Line-HandleContext
798         else
799             # prepare warning message for the user, configurable via zstyle.
800             zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
801
802             if [[ -z ${msg} ]] ; then
803                 msg="%c will not execute and completion %f exists."
804             fi
805
806             zformat -f msg "${msg}" "c:${com}" "f:${fname}"
807
808             zle -M -- "${msg}"
809         fi
810         return
811     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
812         # If we are here, the commandline contains something that is not
813         # executable, which is neither subject to _command_name correction
814         # and is not empty. might be a variable assignment
815         alcontext='misc'
816         Accept-Line-HandleContext
817
818         return
819     fi
820
821     # If we got this far, the commandline only contains whitespace, or is empty.
822     alcontext='empty'
823     Accept-Line-HandleContext
824 }
825
826 zle -N accept-line
827 zle -N Accept-Line
828 zle -N Accept-Line-HandleContext
829
830 # power completion - abbreviation expansion
831 # power completion / abbreviation expansion / buffer expansion
832 # see http://zshwiki.org/home/examples/zleiab for details
833 # less risky than the global aliases but powerful as well
834 # just type the abbreviation key and afterwards ',.' to expand it
835 declare -A abk
836 setopt extendedglob
837 setopt interactivecomments
838 abk=(
839 #   key   # value                  (#d additional doc string)
840 #A# start
841     '...'  '../..'
842     '....' '../../..'
843     'BG'   '& exit'
844     'C'    '| wc -l'
845     'G'    '|& grep --color=auto '
846     'H'    '| head'
847     'Hl'   ' --help |& less -r'    #d (Display help in pager)
848     'L'    '| less'
849     'LL'   '|& less -r'
850     'M'    '| most'
851     'N'    '&>/dev/null'           #d (No Output)
852     'R'    '| tr A-z N-za-m'       #d (ROT13)
853     'SL'   '| sort | less'
854     'S'    '| sort -u'
855     'T'    '| tail'
856     'V'    '|& vim -'
857 #A# end
858     'co'   './configure && make && sudo make install'
859 )
860
861 zleiab() {
862     emulate -L zsh
863     setopt extendedglob
864     local MATCH
865
866     if (( NOABBREVIATION > 0 )) ; then
867         LBUFFER="${LBUFFER},."
868         return 0
869     fi
870
871     matched_chars='[.-|_a-zA-Z0-9]#'
872     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
873     LBUFFER+=${abk[$MATCH]:-$MATCH}
874 }
875
876 zle -N zleiab
877 bindkey ",." zleiab
878
879 # autoloading
880 zrcautoload zmv    # who needs mmv or rename?
881 zrcautoload history-search-end
882
883 # we don't want to quote/espace URLs on our own...
884 # if autoload -U url-quote-magic ; then
885 #    zle -N self-insert url-quote-magic
886 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
887 # else
888 #    print 'Notice: no url-quote-magic available :('
889 # fi
890 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
891
892 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
893 alias run-help >&/dev/null && unalias run-help
894 for rh in run-help{,-git,-svk,-svn}; do
895     zrcautoload $rh
896 done; unset rh
897
898 # completion system
899 if zrcautoload compinit ; then
900     compinit || print 'Notice: no compinit available :('
901 else
902     print 'Notice: no compinit available :('
903     function zstyle { }
904     function compdef { }
905 fi
906
907 is4 && zrcautoload zed # use ZLE editor to edit a file or function
908
909 is4 && \
910 for mod in complist deltochar mathfunc ; do
911     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
912 done
913
914 # autoload zsh modules when they are referenced
915 if is4 ; then
916     zmodload -a  zsh/stat    zstat
917     zmodload -a  zsh/zpty    zpty
918     zmodload -ap zsh/mapfile mapfile
919 fi
920
921 if is4 && zrcautoload insert-files && zle -N insert-files ; then
922     #k# Insert files and test globbing
923     bindkey "^Xf" insert-files # C-x-f
924 fi
925
926 bindkey ' '   magic-space    # also do history expansion on space
927 #k# Trigger menu-complete
928 bindkey '\ei' menu-complete  # menu completion via esc-i
929
930 # press esc-e for editing command line in $EDITOR or $VISUAL
931 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
932     #k# Edit the current line in \kbd{\$EDITOR}
933     bindkey '\ee' edit-command-line
934 fi
935
936 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
937     #k# menu selection: pick item but stay in the menu
938     bindkey -M menuselect '\e^M' accept-and-menu-complete
939     # also use + and INSERT since it's easier to press repeatedly
940     bindkey -M menuselect "+" accept-and-menu-complete
941     bindkey -M menuselect "^[[2~" accept-and-menu-complete
942
943     # accept a completion and try to complete again by using menu
944     # completion; very useful with completing directories
945     # by using 'undo' one's got a simple file browser
946     bindkey -M menuselect '^o' accept-and-infer-next-history
947 fi
948
949 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
950 insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
951 zle -N insert-datestamp
952
953 #k# Insert a timestamp on the command line (yyyy-mm-dd)
954 bindkey '^Ed' insert-datestamp
955
956 # press esc-m for inserting last typed word again (thanks to caphuso!)
957 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
958 zle -N insert-last-typed-word;
959
960 #k# Insert last typed word
961 bindkey "\em" insert-last-typed-word
962
963 function grml-zsh-fg() {
964   if (( ${#jobstates} )); then
965     zle .push-input
966     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
967     BUFFER="${BUFFER}fg"
968     zle .accept-line
969   else
970     zle -M 'No background jobs. Doing nothing.'
971   fi
972 }
973 zle -N grml-zsh-fg
974 #k# A smart shortcut for \kbd{fg<enter>}
975 bindkey '^z' grml-zsh-fg
976
977 # run command line as user root via sudo:
978 sudo-command-line() {
979     [[ -z $BUFFER ]] && zle up-history
980     if [[ $BUFFER != sudo\ * ]]; then
981         BUFFER="sudo $BUFFER"
982         CURSOR=$(( CURSOR+5 ))
983     fi
984 }
985 zle -N sudo-command-line
986
987 #k# prepend the current command with "sudo"
988 bindkey "^Os" sudo-command-line
989
990 ### jump behind the first word on the cmdline.
991 ### useful to add options.
992 function jump_after_first_word() {
993     local words
994     words=(${(z)BUFFER})
995
996     if (( ${#words} <= 1 )) ; then
997         CURSOR=${#BUFFER}
998     else
999         CURSOR=${#${words[1]}}
1000     fi
1001 }
1002 zle -N jump_after_first_word
1003 #k# jump to after first word (for adding options)
1004 bindkey '^x1' jump_after_first_word
1005
1006 # complete word from history with menu (from Book: ZSH, OpenSource-Press)
1007 zle -C hist-complete complete-word _generic
1008 zstyle ':completion:hist-complete:*' completer _history
1009 #k# complete word from history with menu
1010 bindkey "^X^X" hist-complete
1011
1012 ## complete word from currently visible Screen or Tmux buffer.
1013 if check_com -c screen || check_com -c tmux; then
1014     _complete_screen_display() {
1015         [[ "$TERM" != "screen" ]] && return 1
1016
1017         local TMPFILE=$(mktemp)
1018         local -U -a _screen_display_wordlist
1019         trap "rm -f $TMPFILE" EXIT
1020
1021         # fill array with contents from screen hardcopy
1022         if ((${+TMUX})); then
1023             #works, but crashes tmux below version 1.4
1024             #luckily tmux -V option to ask for version, was also added in 1.4
1025             tmux -V &>/dev/null || return
1026             tmux -q capture-pane \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
1027         else
1028             screen -X hardcopy $TMPFILE
1029             #screen sucks, it dumps in latin1, apparently always. so recode it to system charset
1030             check_com recode && recode latin1 $TMPFILE
1031         fi
1032         _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1033         # remove PREFIX to be completed from that array
1034         _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1035         compadd -a _screen_display_wordlist
1036     }
1037     #k# complete word from currently visible GNU screen buffer
1038     bindkey -r "^XS"
1039     compdef -k _complete_screen_display complete-word '^XS'
1040 fi
1041
1042 # history
1043
1044 ZSHDIR=$HOME/.zsh
1045
1046 #v#
1047 HISTFILE=$HOME/.zsh_history
1048 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
1049 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
1050
1051 # dirstack handling
1052
1053 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1054 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
1055
1056 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1057     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1058     # "cd -" won't work after login by just setting $OLDPWD, so
1059     [[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
1060 fi
1061
1062 chpwd() {
1063     local -ax my_stack
1064     my_stack=( ${PWD} ${dirstack} )
1065     if is42 ; then
1066         builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
1067     else
1068         uprint my_stack >! ${DIRSTACKFILE}
1069     fi
1070 }
1071
1072 # directory based profiles
1073
1074 if is433 ; then
1075
1076 CHPWD_PROFILE='default'
1077 function chpwd_profiles() {
1078     # Say you want certain settings to be active in certain directories.
1079     # This is what you want.
1080     #
1081     # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
1082     # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1083     #
1084     # When that's done and you enter a directory that matches the pattern
1085     # in the third part of the context, a function called chpwd_profile_grml,
1086     # for example, is called (if it exists).
1087     #
1088     # If no pattern matches (read: no profile is detected) the profile is
1089     # set to 'default', which means chpwd_profile_default is attempted to
1090     # be called.
1091     #
1092     # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
1093     # command) which is used: The third part in the context is matched against
1094     # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
1095     # Because that way the profile is detected for all these values of ${PWD}:
1096     #   /foo/bar
1097     #   /foo/bar/
1098     #   /foo/bar/baz
1099     # So, if you want to make double damn sure a profile works in /foo/bar
1100     # and everywhere deeper in that tree, just use (|/|/*) and be happy.
1101     #
1102     # The name of the detected profile will be available in a variable called
1103     # 'profile' in your functions. You don't need to do anything, it'll just
1104     # be there.
1105     #
1106     # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
1107     # was is currently active. That way you can avoid running code for a
1108     # profile that is already active, by running code such as the following
1109     # at the start of your function:
1110     #
1111     # function chpwd_profile_grml() {
1112     #     [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1113     #   ...
1114     # }
1115     #
1116     # The initial value for $CHPWD_PROFILE is 'default'.
1117     #
1118     # Version requirement:
1119     #   This feature requires zsh 4.3.3 or newer.
1120     #   If you use this feature and need to know whether it is active in your
1121     #   current shell, there are several ways to do that. Here are two simple
1122     #   ways:
1123     #
1124     #   a) If knowing if the profiles feature is active when zsh starts is
1125     #      good enough for you, you can put the following snippet into your
1126     #      .zshrc.local:
1127     #
1128     #   (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
1129     #
1130     #   b) If that is not good enough, and you would prefer to be notified
1131     #      whenever a profile changes, you can solve that by making sure you
1132     #      start *every* profile function you create like this:
1133     #
1134     #   function chpwd_profile_myprofilename() {
1135     #       [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1136     #       print "chpwd(): Switching to profile: $profile"
1137     #     ...
1138     #   }
1139     #
1140     #      That makes sure you only get notified if a profile is *changed*,
1141     #      not everytime you change directory, which would probably piss
1142     #      you off fairly quickly. :-)
1143     #
1144     # There you go. Now have fun with that.
1145     local -x profile
1146
1147     zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
1148     if (( ${+functions[chpwd_profile_$profile]} )) ; then
1149         chpwd_profile_${profile}
1150     fi
1151
1152     CHPWD_PROFILE="${profile}"
1153     return 0
1154 }
1155 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1156
1157 fi # is433
1158
1159 # display battery status on right side of prompt via running 'BATTERY=1 zsh'
1160 if [[ $BATTERY -gt 0 ]] ; then
1161     if ! check_com -c acpi ; then
1162         BATTERY=0
1163     fi
1164 fi
1165
1166 battery() {
1167 if [[ $BATTERY -gt 0 ]] ; then
1168     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1169     if [[ -z "$PERCENT" ]] ; then
1170         PERCENT='acpi not present'
1171     else
1172         if [[ "$PERCENT" -lt 20 ]] ; then
1173             PERCENT="warning: ${PERCENT}%%"
1174         else
1175             PERCENT="${PERCENT}%%"
1176         fi
1177     fi
1178 fi
1179 }
1180 # set colors for use in prompts
1181 if zrcautoload colors && colors 2>/dev/null ; then
1182     BLUE="%{${fg[blue]}%}"
1183     RED="%{${fg_bold[red]}%}"
1184     GREEN="%{${fg[green]}%}"
1185     CYAN="%{${fg[cyan]}%}"
1186     MAGENTA="%{${fg[magenta]}%}"
1187     YELLOW="%{${fg[yellow]}%}"
1188     WHITE="%{${fg[white]}%}"
1189     NO_COLOUR="%{${reset_color}%}"
1190 else
1191     BLUE=$'%{\e[1;34m%}'
1192     RED=$'%{\e[1;31m%}'
1193     GREEN=$'%{\e[1;32m%}'
1194     CYAN=$'%{\e[1;36m%}'
1195     WHITE=$'%{\e[1;37m%}'
1196     MAGENTA=$'%{\e[1;35m%}'
1197     YELLOW=$'%{\e[1;33m%}'
1198     NO_COLOUR=$'%{\e[0m%}'
1199 fi
1200
1201 # gather version control information for inclusion in a prompt
1202
1203 if zrcautoload vcs_info; then
1204     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
1205     # function, which can cause a lot of trouble with our directory-based
1206     # profiles. So:
1207     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
1208         function VCS_INFO_realpath () {
1209             setopt localoptions NO_shwordsplit chaselinks
1210             ( builtin cd -q $1 2> /dev/null && pwd; )
1211         }
1212     fi
1213
1214     zstyle ':vcs_info:*' max-exports 2
1215
1216     if [[ -o restricted ]]; then
1217         zstyle ':vcs_info:*' enable NONE
1218     fi
1219 fi
1220
1221 # Change vcs_info formats for the grml prompt. The 2nd format sets up
1222 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1223 # TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
1224 #       That needs to be the use of $VCS_INFO_message_N_ needs to be changed
1225 #       to $vcs_info_msg_N_ as soon as we use the included version.
1226 if [[ "$TERM" == dumb ]] ; then
1227     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
1228     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "    "zsh: %r"
1229 else
1230     # these are the same, just with a lot of colours:
1231     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
1232                                        "zsh: %r"
1233     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
1234                                        "zsh: %r"
1235     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1236 fi
1237
1238 # command not found handling
1239
1240 (( ${COMMAND_NOT_FOUND} == 1 )) &&
1241 function command_not_found_handler() {
1242     emulate -L zsh
1243     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1244         ${GRML_ZSH_CNF_HANDLER} $1
1245     fi
1246     return 1
1247 }
1248
1249 # set prompt
1250 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1251     promptinit # people should be able to use their favourite prompt
1252 else
1253     print 'Notice: no promptinit available :('
1254 fi
1255
1256 setopt prompt_subst
1257
1258 # make sure to use right prompt only when not running a command
1259 is41 && setopt transient_rprompt
1260
1261
1262 function ESC_print () {
1263     info_print $'\ek' $'\e\\' "$@"
1264 }
1265 function set_title () {
1266     info_print  $'\e]0;' $'\a' "$@"
1267 }
1268
1269 function info_print () {
1270     local esc_begin esc_end
1271     esc_begin="$1"
1272     esc_end="$2"
1273     shift 2
1274     printf '%s' ${esc_begin}
1275     printf '%s' "$*"
1276     printf '%s' "${esc_end}"
1277 }
1278
1279 # TODO: revise all these NO* variables and especially their documentation
1280 #       in zsh-help() below.
1281 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1282     [[ $NOPRECMD -gt 0 ]] && return 0
1283     # update VCS information
1284     (( ${+functions[vcs_info]} )) && vcs_info
1285
1286     if [[ $TERM == screen* ]] ; then
1287         if [[ -n ${vcs_info_msg_1_} ]] ; then
1288             ESC_print ${vcs_info_msg_1_}
1289         else
1290             ESC_print "zsh"
1291         fi
1292     fi
1293     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1294     if [[ ${DONTSETRPROMPT:-} -eq 0 ]] ; then
1295         if [[ $BATTERY -gt 0 ]] ; then
1296             # update battery (dropped into $PERCENT) information
1297             battery
1298             RPROMPT="%(?..:() ${PERCENT}"
1299         else
1300             RPROMPT="%(?..:() "
1301         fi
1302     fi
1303     # adjust title of xterm
1304     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1305     [[ ${NOTITLE:-} -gt 0 ]] && return 0
1306     case $TERM in
1307         (xterm*|rxvt*)
1308             set_title ${(%):-"%n@%m: %~"}
1309             ;;
1310     esac
1311 }
1312
1313 # preexec() => a function running before every command
1314 is4 && [[ $NOPRECMD -eq 0 ]] && \
1315 preexec () {
1316     [[ $NOPRECMD -gt 0 ]] && return 0
1317 # set hostname if not running on host with name 'grml'
1318     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1319        NAME="@$HOSTNAME"
1320     fi
1321 # get the name of the program currently running and hostname of local machine
1322 # set screen window title if running in a screen
1323     if [[ "$TERM" == screen* ]] ; then
1324         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1325         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1326         ESC_print ${CMD}
1327     fi
1328 # adjust title of xterm
1329     [[ ${NOTITLE} -gt 0 ]] && return 0
1330     case $TERM in
1331         (xterm*|rxvt*)
1332             set_title "${(%):-"%n@%m:"}" "$1"
1333             ;;
1334     esac
1335 }
1336
1337 EXITCODE="%(?..%?%1v )"
1338 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
1339 PS3='?# '         # selection prompt used within a select loop.
1340 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1341
1342 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1343 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1344     debian_chroot=$(cat /etc/debian_chroot)
1345 fi
1346
1347 # don't use colors on dumb terminals (like emacs):
1348 if [[ "$TERM" == dumb ]] ; then
1349     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "
1350 else
1351     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
1352     # set variable identifying the chroot you work in (used in the prompt below)
1353     if [[ $GRMLPROMPT -gt 0 ]] ; then
1354         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1355 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1356     else
1357         # This assembles the primary prompt string
1358         if (( EUID != 0 )); then
1359             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1360         else
1361             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1362         fi
1363     fi
1364 fi
1365
1366 PROMPT="${PROMPT}"'${vcs_info_msg_0_}'"%# "
1367
1368 # if we are inside a grml-chroot set a specific prompt theme
1369 if [[ -n "$GRML_CHROOT" ]] ; then
1370     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1371 fi
1372
1373 # 'hash' some often used directories
1374 #d# start
1375 hash -d deb=/var/cache/apt/archives
1376 hash -d doc=/usr/share/doc
1377 hash -d linux=/lib/modules/$(command uname -r)/build/
1378 hash -d log=/var/log
1379 hash -d slog=/var/log/syslog
1380 hash -d src=/usr/src
1381 hash -d templ=/usr/share/doc/grml-templates
1382 hash -d tt=/usr/share/doc/texttools-doc
1383 hash -d www=/var/www
1384 #d# end
1385
1386 # some aliases
1387 if check_com -c screen ; then
1388     if [[ $UID -eq 0 ]] ; then
1389         [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
1390     elif [[ -r $HOME/.screenrc ]] ; then
1391         alias screen="${commands[screen]} -c $HOME/.screenrc"
1392     else
1393         if [[ -r /etc/grml/screenrc_grml ]]; then
1394             alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
1395         else
1396             [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
1397         fi
1398     fi
1399 fi
1400
1401 # do we have GNU ls with color-support?
1402 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
1403     #a1# execute \kbd{@a@}:\quad ls with colors
1404     alias ls='ls -b -CF --color=auto'
1405     #a1# execute \kbd{@a@}:\quad list all files, with colors
1406     alias la='ls -la --color=auto'
1407     #a1# long colored list, without dotfiles (@a@)
1408     alias ll='ls -l --color=auto'
1409     #a1# long colored list, human readable sizes (@a@)
1410     alias lh='ls -hAl --color=auto'
1411     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
1412     alias l='ls -lF --color=auto'
1413 else
1414     alias ls='ls -b -CF'
1415     alias la='ls -la'
1416     alias ll='ls -l'
1417     alias lh='ls -hAl'
1418     alias l='ls -lF'
1419 fi
1420
1421 alias mdstat='cat /proc/mdstat'
1422 alias ...='cd ../../'
1423
1424 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
1425 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
1426     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
1427 fi
1428
1429 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
1430 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
1431 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
1432
1433 # make sure it is not assigned yet
1434 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
1435 utf2iso() {
1436     if isutfenv ; then
1437         for ENV in $(env | command grep -i '.utf') ; do
1438             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
1439         done
1440     fi
1441 }
1442
1443 # make sure it is not assigned yet
1444 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
1445 iso2utf() {
1446     if ! isutfenv ; then
1447         for ENV in $(env | command grep -i '\.iso') ; do
1448             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
1449         done
1450     fi
1451 }
1452
1453 # especially for roadwarriors using GNU screen and ssh:
1454 if ! check_com asc &>/dev/null ; then
1455   asc() { autossh -t "$@" 'screen -RdU' }
1456   compdef asc=ssh
1457 fi
1458
1459 #f1# Hints for the use of zsh on grml
1460 zsh-help() {
1461     print "$bg[white]$fg[black]
1462 zsh-help - hints for use of zsh on grml
1463 =======================================$reset_color"
1464
1465     print '
1466 Main configuration of zsh happens in /etc/zsh/zshrc.
1467 That file is part of the package grml-etc-core, if you want to
1468 use them on a non-grml-system just get the tar.gz from
1469 http://deb.grml.org/ or (preferably) get it from the git repository:
1470
1471   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
1472
1473 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
1474 The file is still there, but it is empty for backwards compatibility.
1475
1476 For your own changes use these two files:
1477     $HOME/.zshrc.pre
1478     $HOME/.zshrc.local
1479
1480 The former is sourced very early in our zshrc, the latter is sourced
1481 very lately.
1482
1483 System wide configuration without touching configuration files of grml
1484 can take place in /etc/zsh/zshrc.local.
1485
1486 Normally, the root user (EUID == 0) does not get the whole grml setup.
1487 If you want to force the whole setup for that user, too, set
1488 GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
1489
1490 For information regarding zsh start at http://grml.org/zsh/
1491
1492 Take a look at grml'\''s zsh refcard:
1493 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
1494
1495 Check out the main zsh refcard:
1496 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
1497
1498 And of course visit the zsh-lovers:
1499 % man zsh-lovers
1500
1501 You can adjust some options through environment variables when
1502 invoking zsh without having to edit configuration files.
1503 Basically meant for bash users who are not used to the power of
1504 the zsh yet. :)
1505
1506   "NOCOR=1    zsh" => deactivate automatic correction
1507   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
1508   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
1509   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
1510                       preexec() and precmd() completely
1511   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
1512   "COMMAND_NOT_FOUND=1 zsh"
1513                    => Enable a handler if an external command was not found
1514                       The command called in the handler can be altered by setting
1515                       the GRML_ZSH_CNF_HANDLER variable, the default is:
1516                       "/usr/share/command-not-found/command-not-found"
1517
1518 A value greater than 0 is enables a feature; a value equal to zero
1519 disables it. If you like one or the other of these settings, you can
1520 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
1521 zshrc.'
1522
1523     print "
1524 $bg[white]$fg[black]
1525 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
1526 Enjoy your grml system with the zsh!$reset_color"
1527 }
1528
1529 # debian stuff
1530 if [[ -r /etc/debian_version ]] ; then
1531     #a3# Execute \kbd{apt-cache search}
1532     alias acs='apt-cache search'
1533     #a3# Execute \kbd{apt-cache show}
1534     alias acsh='apt-cache show'
1535     #a3# Execute \kbd{apt-cache policy}
1536     alias acp='apt-cache policy'
1537     #a3# Execute \kbd{apt-get dist-upgrade}
1538     salias adg="apt-get dist-upgrade"
1539     #a3# Execute \kbd{apt-get install}
1540     salias agi="apt-get install"
1541     #a3# Execute \kbd{aptitude install}
1542     salias ati="aptitude install"
1543     #a3# Execute \kbd{apt-get upgrade}
1544     salias ag="apt-get upgrade"
1545     #a3# Execute \kbd{apt-get update}
1546     salias au="apt-get update"
1547     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
1548     salias -a up="aptitude update ; aptitude safe-upgrade"
1549     #a3# Execute \kbd{dpkg-buildpackage}
1550     alias dbp='dpkg-buildpackage'
1551     #a3# Execute \kbd{grep-excuses}
1552     alias ge='grep-excuses'
1553
1554     # get a root shell as normal user in live-cd mode:
1555     if isgrmlcd && [[ $UID -ne 0 ]] ; then
1556        alias su="sudo su"
1557      fi
1558
1559     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
1560     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
1561     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
1562     salias tlog="tail -f /var/log/syslog"    # follow the syslog
1563 fi
1564
1565 # sort installed Debian-packages by size
1566 if check_com -c dpkg-query ; then
1567     #a3# List installed Debian-packages sorted by size
1568     alias debs-by-size="dpkg-query -Wf 'x \${Installed-Size} \${Package} \${Status}\n' | sed -ne '/^x  /d' -e '/^x \(.*\) install ok installed$/s//\1/p' | sort -nr"
1569 fi
1570
1571 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
1572 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
1573     if check_com -c wodim; then
1574         cdrecord() {
1575             cat <<EOMESS
1576 cdrecord is not provided under its original name by Debian anymore.
1577 See #377109 in the BTS of Debian for more details.
1578
1579 Please use the wodim binary instead
1580 EOMESS
1581             return 1
1582         }
1583     fi
1584 fi
1585
1586 # Use hard limits, except for a smaller stack and no core dumps
1587 unlimit
1588 is425 && limit stack 8192
1589 isgrmlcd && limit core 0 # important for a live-cd-system
1590 limit -s
1591
1592 # completion system
1593
1594 # called later (via is4 && grmlcomp)
1595 # note: use 'zstyle' for getting current settings
1596 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
1597 grmlcomp() {
1598     # TODO: This could use some additional information
1599
1600     # allow one error for every three characters typed in approximate completer
1601     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
1602
1603     # don't complete backup files as executables
1604     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
1605
1606     # start menu completion only if it could find no unambiguous initial string
1607     zstyle ':completion:*:correct:*'       insert-unambiguous true
1608     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
1609     zstyle ':completion:*:correct:*'       original true
1610
1611     # activate color-completion
1612     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
1613
1614     # format on completion
1615     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
1616
1617     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
1618     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
1619
1620     # insert all expansions for expand completer
1621     zstyle ':completion:*:expand:*'        tag-order all-expansions
1622     zstyle ':completion:*:history-words'   list false
1623
1624     # activate menu
1625     zstyle ':completion:*:history-words'   menu yes
1626
1627     # ignore duplicate entries
1628     zstyle ':completion:*:history-words'   remove-all-dups yes
1629     zstyle ':completion:*:history-words'   stop yes
1630
1631     # match uppercase from lowercase
1632     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
1633
1634     # separate matches into groups
1635     zstyle ':completion:*:matches'         group 'yes'
1636     zstyle ':completion:*'                 group-name ''
1637
1638     if [[ "$NOMENU" -eq 0 ]] ; then
1639         # if there are more than 5 options allow selecting from a menu
1640         zstyle ':completion:*'               menu select=5
1641     else
1642         # don't use any menus at all
1643         setopt no_auto_menu
1644     fi
1645
1646     zstyle ':completion:*:messages'        format '%d'
1647     zstyle ':completion:*:options'         auto-description '%d'
1648
1649     # describe options in full
1650     zstyle ':completion:*:options'         description 'yes'
1651
1652     # on processes completion complete all user processes
1653     zstyle ':completion:*:processes'       command 'ps -au$USER'
1654
1655     # offer indexes before parameters in subscripts
1656     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
1657
1658     # provide verbose completion information
1659     zstyle ':completion:*'                 verbose true
1660
1661     # recent (as of Dec 2007) zsh versions are able to provide descriptions
1662     # for commands (read: 1st word in the line) that it will list for the user
1663     # to choose from. The following disables that, because it's not exactly fast.
1664     zstyle ':completion:*:-command-:*:'    verbose false
1665
1666     # set format for warnings
1667     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
1668
1669     # define files to ignore for zcompile
1670     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
1671     zstyle ':completion:correct:'          prompt 'correct to: %e'
1672
1673     # Ignore completion functions for commands you don't have:
1674     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
1675
1676     # Provide more processes in completion of programs like killall:
1677     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
1678
1679     # complete manual by their section
1680     zstyle ':completion:*:manuals'    separate-sections true
1681     zstyle ':completion:*:manuals.*'  insert-sections   true
1682     zstyle ':completion:*:man:*'      menu yes select
1683
1684     # provide .. as a completion
1685     zstyle ':completion:*' special-dirs ..
1686
1687     # run rehash on completion so new installed program are found automatically:
1688     _force_rehash() {
1689         (( CURRENT == 1 )) && rehash
1690         return 1
1691     }
1692
1693     ## correction
1694     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
1695     if [[ "$NOCOR" -gt 0 ]] ; then
1696         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
1697         setopt nocorrect
1698     else
1699         # try to be smart about when to use what completer...
1700         setopt correct
1701         zstyle -e ':completion:*' completer '
1702             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
1703                 _last_try="$HISTNO$BUFFER$CURSOR"
1704                 reply=(_complete _match _ignored _prefix _files)
1705             else
1706                 if [[ $words[1] == (rm|mv) ]] ; then
1707                     reply=(_complete _files)
1708                 else
1709                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
1710                 fi
1711             fi'
1712     fi
1713
1714     # command for process lists, the local web server details and host completion
1715     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
1716
1717     # caching
1718     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
1719                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
1720
1721     # host completion
1722     if is42 ; then
1723         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
1724         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
1725     else
1726         _ssh_hosts=()
1727         _etc_hosts=()
1728     fi
1729     hosts=(
1730         $(hostname)
1731         "$_ssh_hosts[@]"
1732         "$_etc_hosts[@]"
1733         grml.org
1734         localhost
1735     )
1736     zstyle ':completion:*:hosts' hosts $hosts
1737     # TODO: so, why is this here?
1738     #  zstyle '*' hosts $hosts
1739
1740     # use generic completion system for programs not yet defined; (_gnu_generic works
1741     # with commands that provide a --help option with "standard" gnu-like output.)
1742     for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
1743                    pal stow tail uname ; do
1744         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
1745     done; unset compcom
1746
1747     # see upgrade function in this file
1748     compdef _hosts upgrade
1749 }
1750
1751 # grmlstuff
1752 grmlstuff() {
1753 # people should use 'grml-x'!
1754     if check_com -c 915resolution; then
1755         855resolution() {
1756             echo "Please use 915resolution as resolution modifying tool for Intel \
1757 graphic chipset."
1758             return -1
1759         }
1760     fi
1761
1762     #a1# Output version of running grml
1763     alias grml-version='cat /etc/grml_version'
1764
1765     if check_com -c rebuildfstab ; then
1766         #a1# Rebuild /etc/fstab
1767         alias grml-rebuildfstab='rebuildfstab -v -r -config'
1768     fi
1769
1770     if check_com -c grml-debootstrap ; then
1771         debian2hd() {
1772             echo "Installing debian to harddisk is possible by using grml-debootstrap."
1773             return 1
1774         }
1775     fi
1776 }
1777
1778 # now run the functions
1779 isgrml && checkhome
1780 is4    && isgrml    && grmlstuff
1781 is4    && grmlcomp
1782
1783 # keephack
1784 is4 && xsource "/etc/zsh/keephack"
1785
1786 # wonderful idea of using "e" glob qualifier by Peter Stephenson
1787 # You use it as follows:
1788 # $ NTREF=/reference/file
1789 # $ ls -l *(e:nt:)
1790 # This lists all the files in the current directory newer than the reference file.
1791 # You can also specify the reference file inline; note quotes:
1792 # $ ls -l *(e:'nt ~/.zshenv':)
1793 is4 && nt() {
1794     if [[ -n $1 ]] ; then
1795         local NTREF=${~1}
1796     fi
1797     [[ $REPLY -nt $NTREF ]]
1798 }
1799
1800 # shell functions
1801
1802 #f1# Reload an autoloadable function
1803 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
1804 compdef _functions freload
1805
1806 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
1807 sll() {
1808     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
1809     for file in "$@" ; do
1810         while [[ -h "$file" ]] ; do
1811             ls -l $file
1812             file=$(readlink "$file")
1813         done
1814     done
1815 }
1816
1817 # TODO: Is it supported to use pager settings like this?
1818 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
1819 # with respect to wordsplitting. (ie. ${=PAGER})
1820 if check_com -c $PAGER ; then
1821     #f1# View Debian's changelog of a given package
1822     dchange() {
1823         emulate -L zsh
1824         if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
1825             $PAGER /usr/share/doc/$1/changelog.Debian.gz
1826         elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
1827             $PAGER /usr/share/doc/$1/changelog.gz
1828         else
1829             if check_com -c aptitude ; then
1830                 echo "No changelog for package $1 found, using aptitude to retrieve it."
1831                 if isgrml ; then
1832                     aptitude -t unstable changelog $1
1833                 else
1834                     aptitude changelog $1
1835                 fi
1836             else
1837                 echo "No changelog for package $1 found, sorry."
1838                 return 1
1839             fi
1840         fi
1841     }
1842     _dchange() { _files -W /usr/share/doc -/ }
1843     compdef _dchange dchange
1844
1845     #f1# View Debian's NEWS of a given package
1846     dnews() {
1847         emulate -L zsh
1848         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
1849             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
1850         else
1851             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
1852                 $PAGER /usr/share/doc/$1/NEWS.gz
1853             else
1854                 echo "No NEWS file for package $1 found, sorry."
1855                 return 1
1856             fi
1857         fi
1858     }
1859     _dnews() { _files -W /usr/share/doc -/ }
1860     compdef _dnews dnews
1861
1862     #f1# View upstream's changelog of a given package
1863     uchange() {
1864         emulate -L zsh
1865         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
1866             $PAGER /usr/share/doc/$1/changelog.gz
1867         else
1868             echo "No changelog for package $1 found, sorry."
1869             return 1
1870         fi
1871     }
1872     _uchange() { _files -W /usr/share/doc -/ }
1873     compdef _uchange uchange
1874 fi
1875
1876 # zsh profiling
1877 profile() {
1878     ZSH_PROFILE_RC=1 $SHELL "$@"
1879 }
1880
1881 #f1# Edit an alias via zle
1882 edalias() {
1883     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
1884 }
1885 compdef _aliases edalias
1886
1887 #f1# Edit a function via zle
1888 edfunc() {
1889     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
1890 }
1891 compdef _functions edfunc
1892
1893 # use it e.g. via 'Restart apache2'
1894 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
1895 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
1896 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
1897 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
1898 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
1899 if [[ -d /etc/init.d || -d /etc/service ]] ; then
1900     __start_stop() {
1901         local action_="${1:l}"  # e.g Start/Stop/Restart
1902         local service_="$2"
1903         local param_="$3"
1904
1905         local service_target_="$(readlink /etc/init.d/$service_)"
1906         if [[ $service_target_ == "/usr/bin/sv" ]]; then
1907             # runit
1908             case "${action_}" in
1909                 start) if [[ ! -e /etc/service/$service_ ]]; then
1910                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
1911                        else
1912                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
1913                        fi ;;
1914                 # there is no reload in runits sysv emulation
1915                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
1916                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
1917             esac
1918         else
1919             # sysvinit
1920             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
1921         fi
1922     }
1923
1924     _grmlinitd() {
1925         local -a scripts
1926         scripts=( /etc/init.d/*(x:t) )
1927         _describe "service startup script" scripts
1928     }
1929
1930     for i in Start Restart Stop Force-Reload Reload ; do
1931         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
1932         compdef _grmlinitd $i
1933     done
1934 fi
1935
1936 #f1# Provides useful information on globbing
1937 H-Glob() {
1938     echo -e "
1939     /      directories
1940     .      plain files
1941     @      symbolic links
1942     =      sockets
1943     p      named pipes (FIFOs)
1944     *      executable plain files (0100)
1945     %      device files (character or block special)
1946     %b     block special files
1947     %c     character special files
1948     r      owner-readable files (0400)
1949     w      owner-writable files (0200)
1950     x      owner-executable files (0100)
1951     A      group-readable files (0040)
1952     I      group-writable files (0020)
1953     E      group-executable files (0010)
1954     R      world-readable files (0004)
1955     W      world-writable files (0002)
1956     X      world-executable files (0001)
1957     s      setuid files (04000)
1958     S      setgid files (02000)
1959     t      files with the sticky bit (01000)
1960
1961   print *(m-1)          # Files modified up to a day ago
1962   print *(a1)           # Files accessed a day ago
1963   print *(@)            # Just symlinks
1964   print *(Lk+50)        # Files bigger than 50 kilobytes
1965   print *(Lk-50)        # Files smaller than 50 kilobytes
1966   print **/*.c          # All *.c files recursively starting in \$PWD
1967   print **/*.c~file.c   # Same as above, but excluding 'file.c'
1968   print (foo|bar).*     # Files starting with 'foo' or 'bar'
1969   print *~*.*           # All Files that do not contain a dot
1970   chmod 644 *(.^x)      # make all plain non-executable files publically readable
1971   print -l *(.c|.h)     # Lists *.c and *.h
1972   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
1973   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
1974 }
1975 alias help-zshglob=H-Glob
1976
1977 #v1# set number of lines to display per page
1978 HELP_LINES_PER_PAGE=20
1979 #v1# set location of help-zle cache file
1980 HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
1981 #f1# helper function for help-zle, actually generates the help text
1982 help_zle_parse_keybindings()
1983 {
1984     emulate -L zsh
1985     setopt extendedglob
1986     unsetopt ksharrays  #indexing starts at 1
1987
1988     #v1# choose files that help-zle will parse for keybindings
1989     ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
1990
1991     if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
1992         local load_cache=0
1993         for f ($KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
1994         [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
1995     fi
1996
1997     #fill with default keybindings, possibly to be overwriten in a file later
1998     #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
1999     local -A help_zle_keybindings
2000     help_zle_keybindings['<Ctrl>@']="set MARK"
2001     help_zle_keybindings['<Ctrl>X<Ctrl>J']="vi-join lines"
2002     help_zle_keybindings['<Ctrl>X<Ctrl>B']="jump to matching brace"
2003     help_zle_keybindings['<Ctrl>X<Ctrl>U']="undo"
2004     help_zle_keybindings['<Ctrl>_']="undo"
2005     help_zle_keybindings['<Ctrl>X<Ctrl>F<c>']="find <c> in cmdline"
2006     help_zle_keybindings['<Ctrl>A']="goto beginning of line"
2007     help_zle_keybindings['<Ctrl>E']="goto end of line"
2008     help_zle_keybindings['<Ctrl>t']="transpose charaters"
2009     help_zle_keybindings['<Alt>T']="transpose words"
2010     help_zle_keybindings['<Alt>s']="spellcheck word"
2011     help_zle_keybindings['<Ctrl>K']="backward kill buffer"
2012     help_zle_keybindings['<Ctrl>U']="forward kill buffer"
2013     help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
2014     help_zle_keybindings["<Alt>'"]="quote line"
2015     help_zle_keybindings['<Alt>"']="quote from mark to cursor"
2016     help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
2017     help_zle_keybindings['<Alt>U']="make next word Uppercase"
2018     help_zle_keybindings['<Alt>l']="make next word lowercase"
2019     help_zle_keybindings['<Ctrl>Xd']="preview expansion under cursor"
2020     help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
2021     help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
2022     help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
2023     help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
2024     help_zle_keybindings['<Ctrl>V']="insert next keypress symbol literally (e.g. for bindkey)"
2025     help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
2026     help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
2027     help_zle_keybindings['<Alt>H']="run help on current command"
2028
2029     #init global variables
2030     unset help_zle_lines help_zle_sln
2031     typeset -g -a help_zle_lines
2032     typeset -g help_zle_sln=1
2033
2034     local k v
2035     local lastkeybind_desc contents     #last description starting with #k# that we found
2036     local num_lines_elapsed=0            #number of lines between last description and keybinding
2037     #search config files in the order they a called (and thus the order in which they overwrite keybindings)
2038     for f in $HELPZLE_KEYBINDING_FILES; do
2039         [[ -r "$f" ]] || continue   #not readable ? skip it
2040         contents="$(<$f)"
2041         for cline in "${(f)contents}"; do
2042             #zsh pattern: matches lines like: #k# ..............
2043             if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
2044                 lastkeybind_desc="$match[*]"
2045                 num_lines_elapsed=0
2046             #zsh pattern: matches lines that set a keybinding using bindkey or compdef -k
2047             #             ignores lines that are commentend out
2048             #             grabs first in '' or "" enclosed string with length between 1 and 6 characters
2049             elif [[ "$cline" == [^#]#(bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*)  ]]; then
2050                 #description prevously found ? description not more than 2 lines away ? keybinding not empty ?
2051                 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
2052                     #substitute keybinding string with something readable
2053                     k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
2054                     #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
2055                     #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
2056                     help_zle_keybindings[${k}]=$lastkeybind_desc
2057                 fi
2058                 lastkeybind_desc=""
2059             else
2060               ((num_lines_elapsed++))
2061             fi
2062         done
2063     done
2064     unset contents
2065     #calculate length of keybinding column
2066     local kstrlen=0
2067     for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
2068     #convert the assoc array into preformated lines, which we are able to sort
2069     for k v in ${(kv)help_zle_keybindings[@]}; do
2070         #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
2071         help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
2072     done
2073     #sort lines alphabetically
2074     help_zle_lines=("${(i)help_zle_lines[@]}")
2075     [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
2076     echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
2077     zcompile $HELP_ZLE_CACHE_FILE
2078 }
2079 typeset -g help_zle_sln
2080 typeset -g -a help_zle_lines
2081
2082 #f1# Provides (partially autogenerated) help on keybindings and the zsh line editor
2083 help-zle()
2084 {
2085     emulate -L zsh
2086     unsetopt ksharrays  #indexing starts at 1
2087     #help lines already generated ? no ? then do it
2088     [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
2089     #already displayed all lines ? go back to the start
2090     [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
2091     local sln=$help_zle_sln
2092     #note that help_zle_sln is a global var, meaning we remember the last page we viewed
2093     help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
2094     zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
2095 }
2096 #k# display help for keybindings and ZLE (cycle pages with consecutive use)
2097 zle -N help-zle && bindkey '^Xz' help-zle
2098
2099 # grep for running process, like: 'any vim'
2100 any() {
2101     emulate -L zsh
2102     unsetopt KSH_ARRAYS
2103     if [[ -z "$1" ]] ; then
2104         echo "any - grep for process(es) by keyword" >&2
2105         echo "Usage: any <keyword>" >&2 ; return 1
2106     else
2107         ps xauwww | grep -i --color=auto "[${1[1]}]${1[2,-1]}"
2108     fi
2109 }
2110
2111
2112 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2113 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2114 [[ -r /proc/1/maps ]] && \
2115 deswap() {
2116     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2117     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2118     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2119 }
2120
2121 # a wrapper for vim, that deals with title setting
2122 #   VIM_OPTIONS
2123 #       set this array to a set of options to vim you always want
2124 #       to have set when calling vim (in .zshrc.local), like:
2125 #           VIM_OPTIONS=( -p )
2126 #       This will cause vim to send every file given on the
2127 #       commandline to be send to it's own tab (needs vim7).
2128 vim() {
2129     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2130 }
2131
2132 # make a backup of a file
2133 bk() {
2134     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2135 }
2136
2137 ssl_hashes=( sha512 sha256 sha1 md5 )
2138
2139 for sh in ${ssl_hashes}; do
2140     eval 'ssl-cert-'${sh}'() {
2141         emulate -L zsh
2142         if [[ -z $1 ]] ; then
2143             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2144             return 1
2145         fi
2146         openssl x509 -noout -fingerprint -'${sh}' -in $1
2147     }'
2148 done; unset sh
2149
2150 ssl-cert-fingerprints() {
2151     emulate -L zsh
2152     local i
2153     if [[ -z $1 ]] ; then
2154         printf 'usage: ssl-cert-fingerprints <file>\n'
2155         return 1
2156     fi
2157     for i in ${ssl_hashes}
2158         do ssl-cert-$i $1;
2159     done
2160 }
2161
2162 ssl-cert-info() {
2163     emulate -L zsh
2164     if [[ -z $1 ]] ; then
2165         printf 'usage: ssl-cert-info <file>\n'
2166         return 1
2167     fi
2168     openssl x509 -noout -text -in $1
2169     ssl-cert-fingerprints $1
2170 }
2171
2172 # make sure our environment is clean regarding colors
2173 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2174
2175 # "persistent history"
2176 # just write important commands you always need to ~/.important_commands
2177 if [[ -r ~/.important_commands ]] ; then
2178     fc -R ~/.important_commands
2179 fi
2180
2181 # load the lookup subsystem if it's available on the system
2182 zrcautoload lookupinit && lookupinit
2183
2184 ### non-root (EUID != 0) code below
2185 ###
2186
2187 if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
2188     zrclocal
2189     return 0
2190 fi
2191
2192 # variables
2193
2194 # set terminal property (used e.g. by msgid-chooser)
2195 export COLORTERM="yes"
2196
2197 # aliases
2198
2199 # general
2200 #a2# Execute \kbd{du -sch}
2201 alias da='du -sch'
2202 #a2# Execute \kbd{jobs -l}
2203 alias j='jobs -l'
2204
2205 # listing stuff
2206 #a2# Execute \kbd{ls -lSrah}
2207 alias dir="ls -lSrah"
2208 #a2# Only show dot-directories
2209 alias lad='ls -d .*(/)'                # only show dot-directories
2210 #a2# Only show dot-files
2211 alias lsa='ls -a .*(.)'                # only show dot-files
2212 #a2# Only files with setgid/setuid/sticky flag
2213 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
2214 #a2# Only show 1st ten symlinks
2215 alias lsl='ls -l *(@)'                 # only symlinks
2216 #a2# Display only executables
2217 alias lsx='ls -l *(*)'                 # only executables
2218 #a2# Display world-{readable,writable,executable} files
2219 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
2220 #a2# Display the ten biggest files
2221 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
2222 #a2# Only show directories
2223 alias lsd='ls -d *(/)'                 # only show directories
2224 #a2# Only show empty directories
2225 alias lse='ls -d *(/^F)'               # only show empty directories
2226 #a2# Display the ten newest files
2227 alias lsnew="ls -rtlh *(D.om[1,10])"   # display the newest files
2228 #a2# Display the ten oldest files
2229 alias lsold="ls -rtlh *(D.Om[1,10])"   # display the oldest files
2230 #a2# Display the ten smallest files
2231 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
2232
2233 # some useful aliases
2234 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir $OLDCWD}
2235 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
2236
2237 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
2238 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2239 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2240
2241 # simple webserver
2242 check_com -c python && alias http="python -m SimpleHTTPServer"
2243
2244 # work around non utf8 capable software in utf environment via $LANG and luit
2245 if check_com isutfenv && check_com luit ; then
2246     if check_com -c mrxvt ; then
2247         isutfenv && [[ -n "$LANG" ]] && \
2248             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
2249     fi
2250
2251     if check_com -c aterm ; then
2252         isutfenv && [[ -n "$LANG" ]] && \
2253             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
2254     fi
2255
2256     if check_com -c centericq ; then
2257         isutfenv && [[ -n "$LANG" ]] && \
2258             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
2259     fi
2260 fi
2261
2262 # useful functions
2263
2264 #f5# Backup \kbd{file {\rm to} file\_timestamp}
2265 bk() {
2266     emulate -L zsh
2267     cp -b $1 $1_`date --iso-8601=m`
2268 }
2269
2270 #f5# cd to directoy and list files
2271 cl() {
2272     emulate -L zsh
2273     cd $1 && ls -a
2274 }
2275
2276 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
2277 cd() {
2278     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
2279         [[ ! -e ${1:h} ]] && return 1
2280         print "Correcting ${1} to ${1:h}"
2281         builtin cd ${1:h}
2282     else
2283         builtin cd "$@"
2284     fi
2285 }
2286
2287 #f5# Create Directoy and \kbd{cd} to it
2288 mkcd() {
2289     mkdir -p "$@" && cd "$@"
2290 }
2291
2292 #f5# Create temporary directory and \kbd{cd} to it
2293 cdt() {
2294     local t
2295     t=$(mktemp -d)
2296     echo "$t"
2297     builtin cd "$t"
2298 }
2299
2300 #f5# Create directory under cursor or the selected area
2301 # Press ctrl-xM to create the directory under the cursor or the selected area.
2302 # To select an area press ctrl-@ or ctrl-space and use the cursor.
2303 # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
2304 # directory does not exist yet -> press ctrl-XM and problem solved
2305 inplaceMkDirs() {
2306     local PATHTOMKDIR
2307     if ((REGION_ACTIVE==1)); then
2308         local F=$MARK T=$CURSOR
2309         if [[ $F -gt $T ]]; then
2310             F=${CURSOR}
2311             T=${MARK}
2312         fi
2313         # get marked area from buffer and eliminate whitespace
2314         PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
2315         PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
2316     else
2317         local bufwords iword
2318         bufwords=(${(z)LBUFFER})
2319         iword=${#bufwords}
2320         bufwords=(${(z)BUFFER})
2321         PATHTOMKDIR="${(Q)bufwords[iword]}"
2322     fi
2323     [[ -z "${PATHTOMKDIR}" ]] && return 1
2324     if [[ -e "${PATHTOMKDIR}" ]]; then
2325         zle -M " path already exists, doing nothing"
2326     else
2327         zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
2328         zle end-of-line
2329     fi
2330 }
2331 #k# mkdir -p <dir> from string under cursor or marked area
2332 zle -N inplaceMkDirs && bindkey '^XM' inplaceMkDirs
2333
2334 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
2335 accessed() {
2336     emulate -L zsh
2337     print -l -- *(a-${1:-1})
2338 }
2339
2340 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
2341 changed() {
2342     emulate -L zsh
2343     print -l -- *(c-${1:-1})
2344 }
2345
2346 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
2347 modified() {
2348     emulate -L zsh
2349     print -l -- *(m-${1:-1})
2350 }
2351 # modified() was named new() in earlier versions, add an alias for backwards compatibility
2352 check_com new || alias new=modified
2353
2354 # use colors when GNU grep with color-support
2355 #a2# Execute \kbd{grep -{}-color=auto}
2356 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
2357
2358 # Translate DE<=>EN
2359 # 'translate' looks up fot a word in a file with language-to-language
2360 # translations (field separator should be " : "). A typical wordlist looks
2361 # like at follows:
2362 #  | english-word : german-transmission
2363 # It's also only possible to translate english to german but not reciprocal.
2364 # Use the following oneliner to turn back the sort order:
2365 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
2366 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
2367 #f5# Translates a word
2368 trans() {
2369     emulate -L zsh
2370     case "$1" in
2371         -[dD]*)
2372             translate -l de-en $2
2373             ;;
2374         -[eE]*)
2375             translate -l en-de $2
2376             ;;
2377         *)
2378             echo "Usage: $0 { -D | -E }"
2379             echo "         -D == German to English"
2380             echo "         -E == English to German"
2381     esac
2382 }
2383
2384 # Usage: simple-extract <file>
2385 # Using option -d deletes the original archive file.
2386 #f5# Smart archive extractor
2387 simple-extract() {
2388     emulate -L zsh
2389     setopt extended_glob noclobber
2390     local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
2391     local RC=0
2392     zparseopts -D -E "d=DELETE_ORIGINAL"
2393     for ARCHIVE in "${@}"; do
2394         case $ARCHIVE in
2395             *.(tar.bz2|tbz2|tbz))
2396                 DECOMP_CMD="tar -xvjf -"
2397                 USES_STDIN=true
2398                 USES_STDOUT=false
2399                 ;;
2400             *.(tar.gz|tgz))
2401                 DECOMP_CMD="tar -xvzf -"
2402                 USES_STDIN=true
2403                 USES_STDOUT=false
2404                 ;;
2405             *.(tar.xz|txz|tar.lzma))
2406                 DECOMP_CMD="tar -xvJf -"
2407                 USES_STDIN=true
2408                 USES_STDOUT=false
2409                 ;;
2410             *.tar)
2411                 DECOMP_CMD="tar -xvf -"
2412                 USES_STDIN=true
2413                 USES_STDOUT=false
2414                 ;;
2415             *.rar)
2416                 DECOMP_CMD="unrar x"
2417                 USES_STDIN=false
2418                 USES_STDOUT=false
2419                 ;;
2420             *.lzh)
2421                 DECOMP_CMD="lha x"
2422                 USES_STDIN=false
2423                 USES_STDOUT=false
2424                 ;;
2425             *.7z)
2426                 DECOMP_CMD="7z x"
2427                 USES_STDIN=false
2428                 USES_STDOUT=false
2429                 ;;
2430             *.(zip|jar))
2431                 DECOMP_CMD="unzip"
2432                 USES_STDIN=false
2433                 USES_STDOUT=false
2434                 ;;
2435             *.deb)
2436                 DECOMP_CMD="ar -x"
2437                 USES_STDIN=false
2438                 USES_STDOUT=false
2439                 ;;
2440             *.bz2)
2441                 DECOMP_CMD="bzip2 -d -c -"
2442                 USES_STDIN=true
2443                 USES_STDOUT=true
2444                 ;;
2445             *.(gz|Z))
2446                 DECOMP_CMD="gzip -d -c -"
2447                 USES_STDIN=true
2448                 USES_STDOUT=true
2449                 ;;
2450             *.(xz|lzma))
2451                 DECOMP_CMD="xz -d -c -"
2452                 USES_STDIN=true
2453                 USES_STDOUT=true
2454                 ;;
2455             *)
2456                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
2457                 RC=$((RC+1))
2458                 continue
2459                 ;;
2460         esac
2461
2462         if ! check_com ${DECOMP_CMD[(w)1]}; then
2463             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
2464             RC=$((RC+2))
2465             continue
2466         fi
2467
2468         GZTARGET="${ARCHIVE:t:r}"
2469         if [[ -f $ARCHIVE ]] ; then
2470
2471             print "Extracting '$ARCHIVE' ..."
2472             if $USES_STDIN; then
2473                 if $USES_STDOUT; then
2474                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
2475                 else
2476                     ${=DECOMP_CMD} < "$ARCHIVE"
2477                 fi
2478             else
2479                 if $USES_STDOUT; then
2480                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
2481                 else
2482                     ${=DECOMP_CMD} "$ARCHIVE"
2483                 fi
2484             fi
2485             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
2486
2487         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
2488             if check_com curl; then
2489                 WGET_CMD="curl -L -k -s -o -"
2490             elif check_com wget; then
2491                 WGET_CMD="wget -q -O - --no-check-certificate"
2492             else
2493                 print "ERROR: neither wget nor curl is installed" >&2
2494                 RC=$((RC+4))
2495                 continue
2496             fi
2497             print "Downloading and Extracting '$ARCHIVE' ..."
2498             if $USES_STDIN; then
2499                 if $USES_STDOUT; then
2500                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
2501                     RC=$((RC+$?))
2502                 else
2503                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
2504                     RC=$((RC+$?))
2505                 fi
2506             else
2507                 if $USES_STDOUT; then
2508                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
2509                 else
2510                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
2511                 fi
2512             fi
2513
2514         else
2515             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
2516             RC=$((RC+8))
2517         fi
2518     done
2519     return $RC
2520 }
2521
2522 __archive_or_uri()
2523 {
2524     _alternative \
2525         'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
2526         '_urls:Remote Archives:_urls'
2527 }
2528
2529 _simple_extract()
2530 {
2531     _arguments \
2532         '-d[delete original archivefile after extraction]' \
2533         '*:Archive Or Uri:__archive_or_uri'
2534 }
2535 compdef _simple_extract simple-extract
2536 alias se=simple-extract
2537
2538 # Usage: smartcompress <file> (<type>)
2539 #f5# Smart archive creator
2540 smartcompress() {
2541     emulate -L zsh
2542     if [[ -n $2 ]] ; then
2543         case $2 in
2544             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
2545             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
2546             tar.Z)          tar -Zcvf$1.$2 $1 ;;
2547             tar)            tar -cvf$1.$2  $1 ;;
2548             gz | gzip)      gzip           $1 ;;
2549             bz2 | bzip2)    bzip2          $1 ;;
2550             *)
2551                 echo "Error: $2 is not a valid compression type"
2552                 ;;
2553         esac
2554     else
2555         smartcompress $1 tar.gz
2556     fi
2557 }
2558
2559 # Usage: show-archive <archive>
2560 #f5# List an archive's content
2561 show-archive() {
2562     emulate -L zsh
2563     if [[ -f $1 ]] ; then
2564         case $1 in
2565             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
2566             *.tar)         tar -tf $1 ;;
2567             *.tgz)         tar -ztf $1 ;;
2568             *.zip)         unzip -l $1 ;;
2569             *.bz2)         bzless $1 ;;
2570             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
2571             *)             echo "'$1' Error. Please go away" ;;
2572         esac
2573     else
2574         echo "'$1' is not a valid archive"
2575     fi
2576 }
2577
2578 # TODO: So, this is the third incarnation of this function!?
2579 #f5# Reload given functions
2580 refunc() {
2581     for func in $argv ; do
2582         unfunction $func
2583         autoload $func
2584     done
2585 }
2586 compdef _functions refunc
2587
2588 #f5# Set all ulimit parameters to \kbd{unlimited}
2589 allulimit() {
2590     ulimit -c unlimited
2591     ulimit -d unlimited
2592     ulimit -f unlimited
2593     ulimit -l unlimited
2594     ulimit -n unlimited
2595     ulimit -s unlimited
2596     ulimit -t unlimited
2597 }
2598
2599 #f5# Change the xterm title from within GNU-screen
2600 xtrename() {
2601     emulate -L zsh
2602     if [[ $1 != "-f" ]] ; then
2603         if [[ -z ${DISPLAY} ]] ; then
2604             printf 'xtrename only makes sense in X11.\n'
2605             return 1
2606         fi
2607     else
2608         shift
2609     fi
2610     if [[ -z $1 ]] ; then
2611         printf 'usage: xtrename [-f] "title for xterm"\n'
2612         printf '  renames the title of xterm from _within_ screen.\n'
2613         printf '  also works without screen.\n'
2614         printf '  will not work if DISPLAY is unset, use -f to override.\n'
2615         return 0
2616     fi
2617     print -n "\eP\e]0;${1}\C-G\e\\"
2618     return 0
2619 }
2620
2621 # TODO:
2622 # Rewrite this by either using tinyurl.com's API
2623 # or using another shortening service to comply with
2624 # tinyurl.com's policy.
2625 #
2626 # Create small urls via http://tinyurl.com using wget(1).
2627 #function zurl() {
2628 #    emulate -L zsh
2629 #    [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
2630 #
2631 #    local PN url tiny grabber search result preview
2632 #    PN=$0
2633 #    url=$1
2634 ##   Check existence of given URL with the help of ping(1).
2635 ##   N.B. ping(1) only works without an eventual given protocol.
2636 #    ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
2637 #        read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
2638 #
2639 #    if (( $? == 0 )) ; then
2640 ##           Prepend 'http://' to given URL where necessary for later output.
2641 #            [[ ${url} != http(s|)://* ]] && url='http://'${url}
2642 #            tiny='http://tinyurl.com/create.php?url='
2643 #            if check_com -c wget ; then
2644 #                grabber='wget -O- -o/dev/null'
2645 #            else
2646 #                print "wget is not available, but mandatory for ${PN}. Aborting."
2647 #            fi
2648 ##           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
2649 #            search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
2650 #            result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
2651 ##           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
2652 #            preview='http://preview.'${result#http://}
2653 #
2654 #            printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
2655 #            printf '%s\t%s\n\n' 'Given URL:' ${url}
2656 #            printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
2657 #    else
2658 #        return 1
2659 #    fi
2660 #}
2661
2662 #f2# Find history events by search pattern and list them by date.
2663 whatwhen()  {
2664     emulate -L zsh
2665     local usage help ident format_l format_s first_char remain first last
2666     usage='USAGE: whatwhen [options] <searchstring> <search range>'
2667     help='Use `whatwhen -h'\'' for further explanations.'
2668     ident=${(l,${#${:-Usage: }},, ,)}
2669     format_l="${ident}%s\t\t\t%s\n"
2670     format_s="${format_l//(\\t)##/\\t}"
2671     # Make the first char of the word to search for case
2672     # insensitive; e.g. [aA]
2673     first_char=[${(L)1[1]}${(U)1[1]}]
2674     remain=${1[2,-1]}
2675     # Default search range is `-100'.
2676     first=${2:-\-100}
2677     # Optional, just used for `<first> <last>' given.
2678     last=$3
2679     case $1 in
2680         ("")
2681             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
2682             printf '%s\n%s\n\n' ${usage} ${help} && return 1
2683         ;;
2684         (-h)
2685             printf '%s\n\n' ${usage}
2686             print 'OPTIONS:'
2687             printf $format_l '-h' 'show help text'
2688             print '\f'
2689             print 'SEARCH RANGE:'
2690             printf $format_l "'0'" 'the whole history,'
2691             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
2692             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
2693             printf '\n%s\n' 'EXAMPLES:'
2694             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
2695             printf $format_l 'whatwhen zsh -250'
2696             printf $format_l 'whatwhen foo 1 99'
2697         ;;
2698         (\?)
2699             printf '%s\n%s\n\n' ${usage} ${help} && return 1
2700         ;;
2701         (*)
2702             # -l list results on stout rather than invoking $EDITOR.
2703             # -i Print dates as in YYYY-MM-DD.
2704             # -m Search for a - quoted - pattern within the history.
2705             fc -li -m "*${first_char}${remain}*" $first $last
2706         ;;
2707     esac
2708 }
2709
2710 # mercurial related stuff
2711 if check_com -c hg ; then
2712     # gnu like diff for mercurial
2713     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
2714     #f5# GNU like diff for mercurial
2715     hgdi() {
2716         emulate -L zsh
2717         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
2718     }
2719
2720     # build debian package
2721     #a2# Alias for \kbd{hg-buildpackage}
2722     alias hbp='hg-buildpackage'
2723
2724     # execute commands on the versioned patch-queue from the current repos
2725     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
2726
2727     # diffstat for specific version of a mercurial repository
2728     #   hgstat      => display diffstat between last revision and tip
2729     #   hgstat 1234 => display diffstat between revision 1234 and tip
2730     #f5# Diffstat for specific version of a mercurial repos
2731     hgstat() {
2732         emulate -L zsh
2733         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
2734     }
2735
2736 fi # end of check whether we have the 'hg'-executable
2737
2738 # grml-small cleanups
2739
2740 # The following is used to remove zsh-config-items that do not work
2741 # in grml-small by default.
2742 # If you do not want these adjustments (for whatever reason), set
2743 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
2744 # sources if it is there).
2745
2746 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
2747
2748     unset abk[V]
2749     unalias    'V'      &> /dev/null
2750     unfunction vman     &> /dev/null
2751     unfunction viless   &> /dev/null
2752     unfunction 2html    &> /dev/null
2753
2754     # manpages are not in grmlsmall
2755     unfunction manzsh   &> /dev/null
2756     unfunction man2     &> /dev/null
2757
2758 fi
2759
2760 zrclocal
2761
2762 ## genrefcard.pl settings
2763
2764 ### doc strings for external functions from files
2765 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
2766
2767 ### example: split functions-search 8,16,24,32
2768 #@# split functions-search 8
2769
2770 ## END OF FILE #################################################################
2771 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
2772 # Local variables:
2773 # mode: sh
2774 # End: