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