zshrc: bk gets a remove option that cleans backups
[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 ${ZDOTDIR:-${HOME}}/.zshrc.pre ]] && source ${ZDOTDIR:-${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 is437(){
148     [[ $ZSH_VERSION == 4.3.<7->* || $ZSH_VERSION == 4.<4->* \
149                                  || $ZSH_VERSION == <5->* ]] && return 0
150     return 1
151 }
152
153 is439(){
154     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
155                                  || $ZSH_VERSION == <5->* ]] && return 0
156     return 1
157 }
158
159 #f1# Checks whether or not you're running grml
160 isgrml(){
161     [[ -f /etc/grml_version ]] && return 0
162     return 1
163 }
164
165 #f1# Checks whether or not you're running a grml cd
166 isgrmlcd(){
167     [[ -f /etc/grml_cd ]] && return 0
168     return 1
169 }
170
171 if isgrml ; then
172 #f1# Checks whether or not you're running grml-small
173     isgrmlsmall() {
174         if [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]]; then
175             return 0
176         fi
177         return 1
178     }
179 else
180     isgrmlsmall() { return 1 }
181 fi
182
183 GRML_OSTYPE=$(uname -s)
184
185 islinux(){
186     [[ $GRML_OSTYPE == "Linux" ]]
187 }
188
189 isdarwin(){
190     [[ $GRML_OSTYPE == "Darwin" ]]
191 }
192
193 isfreebsd(){
194     [[ $GRML_OSTYPE == "FreeBSD" ]]
195 }
196
197 isopenbsd(){
198     [[ $GRML_OSTYPE == "OpenBSD" ]]
199 }
200
201 #f1# are we running within an utf environment?
202 isutfenv() {
203     case "$LANG $CHARSET $LANGUAGE" in
204         *utf*) return 0 ;;
205         *UTF*) return 0 ;;
206         *)     return 1 ;;
207     esac
208 }
209
210 # check for user, if not running as root set $SUDO to sudo
211 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
212
213 # change directory to home on first invocation of zsh
214 # important for rungetty -> autologin
215 # Thanks go to Bart Schaefer!
216 isgrml && checkhome() {
217     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
218         export ALREADY_DID_CD_HOME=$HOME
219         cd
220     fi
221 }
222
223 # check for zsh v3.1.7+
224
225 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
226      || ${ZSH_VERSION} == 3.<2->.<->*    \
227      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
228
229     printf '-!-\n'
230     printf '-!- In this configuration we try to make use of features, that only\n'
231     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
232     printf '-!- used with a wide range of zsh versions, while using fairly\n'
233     printf '-!- advanced features in all supported versions.\n'
234     printf '-!-\n'
235     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
236     printf '-!-\n'
237     printf '-!- While this *may* work, it might as well fail.\n'
238     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
239     printf '-!-\n'
240     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
241     printf '-!- If it does today, you'\''ve been lucky.\n'
242     printf '-!-\n'
243     printf '-!- Ye been warned!\n'
244     printf '-!-\n'
245
246     function zstyle() { : }
247 fi
248
249 # autoload wrapper - use this one instead of autoload directly
250 # We need to define this function as early as this, because autoloading
251 # 'is-at-least()' needs it.
252 function zrcautoload() {
253     emulate -L zsh
254     setopt extended_glob
255     local fdir ffile
256     local -i ffound
257
258     ffile=$1
259     (( ffound = 0 ))
260     for fdir in ${fpath} ; do
261         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
262     done
263
264     (( ffound == 0 )) && return 1
265     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
266         autoload -U ${ffile} || return 1
267     else
268         autoload ${ffile} || return 1
269     fi
270     return 0
271 }
272
273 # Load is-at-least() for more precise version checks Note that this test will
274 # *always* fail, if the is-at-least function could not be marked for
275 # autoloading.
276 zrcautoload is-at-least || is-at-least() { return 1 }
277
278 # set some important options (as early as possible)
279
280 # append history list to the history file; this is the default but we make sure
281 # because it's required for share_history.
282 setopt append_history
283
284 # import new commands from the history file also in other zsh-session
285 is4 && setopt share_history
286
287 # save each command's beginning timestamp and the duration to the history file
288 setopt extended_history
289
290 # If a new command line being added to the history list duplicates an older
291 # one, the older command is removed from the list
292 is4 && setopt histignorealldups
293
294 # remove command lines from the history list when the first character on the
295 # line is a space
296 setopt histignorespace
297
298 # if a command is issued that can't be executed as a normal command, and the
299 # command is the name of a directory, perform the cd command to that directory.
300 setopt auto_cd
301
302 # in order to use #, ~ and ^ for filename generation grep word
303 # *~(*.gz|*.bz|*.bz2|*.zip|*.Z) -> searches for word not in compressed files
304 # don't forget to quote '^', '~' and '#'!
305 setopt extended_glob
306
307 # display PID when suspending processes as well
308 setopt longlistjobs
309
310 # try to avoid the 'zsh: no matches found...'
311 setopt nonomatch
312
313 # report the status of backgrounds jobs immediately
314 setopt notify
315
316 # whenever a command completion is attempted, make sure the entire command path
317 # is hashed first.
318 setopt hash_list_all
319
320 # not just at the end
321 setopt completeinword
322
323 # Don't send SIGHUP to background processes when the shell exits.
324 setopt nohup
325
326 # make cd push the old directory onto the directory stack.
327 setopt auto_pushd
328
329 # avoid "beep"ing
330 setopt nobeep
331
332 # don't push the same dir twice.
333 setopt pushd_ignore_dups
334
335 # * shouldn't match dotfiles. ever.
336 setopt noglobdots
337
338 # use zsh style word splitting
339 setopt noshwordsplit
340
341 # don't error out when unset parameters are used
342 setopt unset
343
344 # setting some default values
345 NOCOR=${NOCOR:-0}
346 NOMENU=${NOMENU:-0}
347 NOPRECMD=${NOPRECMD:-0}
348 COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
349 GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
350 GRML_DISPLAY_BATTERY=${GRML_DISPLAY_BATTERY:-${BATTERY:-0}}
351 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
352 ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
353
354 typeset -ga ls_options
355 typeset -ga grep_options
356 if ls --color=auto / >/dev/null 2>&1; then
357     ls_options=( --color=auto )
358 elif ls -G / >/dev/null 2>&1; then
359     ls_options=( -G )
360 fi
361 if grep --color=auto -q "a" <<< "a" >/dev/null 2>&1; then
362     grep_options=( --color=auto )
363 fi
364
365 # utility functions
366 # this function checks if a command exists and returns either true
367 # or false. This avoids using 'which' and 'whence', which will
368 # avoid problems with aliases for which on certain weird systems. :-)
369 # Usage: check_com [-c|-g] word
370 #   -c  only checks for external commands
371 #   -g  does the usual tests and also checks for global aliases
372 check_com() {
373     emulate -L zsh
374     local -i comonly gatoo
375
376     if [[ $1 == '-c' ]] ; then
377         (( comonly = 1 ))
378         shift
379     elif [[ $1 == '-g' ]] ; then
380         (( gatoo = 1 ))
381     else
382         (( comonly = 0 ))
383         (( gatoo = 0 ))
384     fi
385
386     if (( ${#argv} != 1 )) ; then
387         printf 'usage: check_com [-c] <command>\n' >&2
388         return 1
389     fi
390
391     if (( comonly > 0 )) ; then
392         [[ -n ${commands[$1]}  ]] && return 0
393         return 1
394     fi
395
396     if   [[ -n ${commands[$1]}    ]] \
397       || [[ -n ${functions[$1]}   ]] \
398       || [[ -n ${aliases[$1]}     ]] \
399       || [[ -n ${reswords[(r)$1]} ]] ; then
400
401         return 0
402     fi
403
404     if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
405         return 0
406     fi
407
408     return 1
409 }
410
411 # creates an alias and precedes the command with
412 # sudo if $EUID is not zero.
413 salias() {
414     emulate -L zsh
415     local only=0 ; local multi=0
416     local key val
417     while [[ $1 == -* ]] ; do
418         case $1 in
419             (-o) only=1 ;;
420             (-a) multi=1 ;;
421             (--) shift ; break ;;
422             (-h)
423                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
424                 printf '  -h      shows this help text.\n'
425                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
426                 printf '          be careful using this option.\n'
427                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
428                 return 0
429                 ;;
430             (*) printf "unkown option: '%s'\n" "$1" ; return 1 ;;
431         esac
432         shift
433     done
434
435     if (( ${#argv} > 1 )) ; then
436         printf 'Too many arguments %s\n' "${#argv}"
437         return 1
438     fi
439
440     key="${1%%\=*}" ;  val="${1#*\=}"
441     if (( EUID == 0 )) && (( only == 0 )); then
442         alias -- "${key}=${val}"
443     elif (( EUID > 0 )) ; then
444         (( multi > 0 )) && val="${val// ; / ; sudo }"
445         alias -- "${key}=sudo ${val}"
446     fi
447
448     return 0
449 }
450
451 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
452 # usage: uprint foo
453 #   Where foo is the *name* of the parameter you want printed.
454 #   Note that foo is no typo; $foo would be wrong here!
455 if ! is42 ; then
456     uprint () {
457         emulate -L zsh
458         local -a u
459         local w
460         local parameter=$1
461
462         if [[ -z ${parameter} ]] ; then
463             printf 'usage: uprint <parameter>\n'
464             return 1
465         fi
466
467         for w in ${(P)parameter} ; do
468             [[ -z ${(M)u:#$w} ]] && u=( $u $w )
469         done
470
471         builtin print -l $u
472     }
473 fi
474
475 # Check if we can read given files and source those we can.
476 xsource() {
477     if (( ${#argv} < 1 )) ; then
478         printf 'usage: xsource FILE(s)...\n' >&2
479         return 1
480     fi
481
482     while (( ${#argv} > 0 )) ; do
483         [[ -r "$1" ]] && source "$1"
484         shift
485     done
486     return 0
487 }
488
489 # Check if we can read a given file and 'cat(1)' it.
490 xcat() {
491     emulate -L zsh
492     if (( ${#argv} != 1 )) ; then
493         printf 'usage: xcat FILE\n' >&2
494         return 1
495     fi
496
497     [[ -r $1 ]] && cat $1
498     return 0
499 }
500
501 # Remove these functions again, they are of use only in these
502 # setup files. This should be called at the end of .zshrc.
503 xunfunction() {
504     emulate -L zsh
505     local -a funcs
506     funcs=(salias xcat xsource xunfunction zrcautoload zrcautozle)
507     for func in $funcs ; do
508         [[ -n ${functions[$func]} ]] \
509             && unfunction $func
510     done
511     return 0
512 }
513
514 # this allows us to stay in sync with grml's zshrc and put own
515 # modifications in ~/.zshrc.local
516 zrclocal() {
517     xsource "/etc/zsh/zshrc.local"
518     xsource "${ZDOTDIR:-${HOME}}/.zshrc.local"
519     return 0
520 }
521
522 # locale setup
523 if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
524     xsource "/etc/default/locale"
525 fi
526
527 for var in LANG LC_ALL LC_MESSAGES ; do
528     [[ -n ${(P)var} ]] && export $var
529 done
530
531 # set some variables
532 if check_com -c vim ; then
533 #v#
534     export EDITOR=${EDITOR:-vim}
535 else
536     export EDITOR=${EDITOR:-vi}
537 fi
538
539 #v#
540 export PAGER=${PAGER:-less}
541
542 #v#
543 export MAIL=${MAIL:-/var/mail/$USER}
544
545 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
546 if [[ -z "$SHELL" ]] ; then
547   SHELL="$(which zsh)"
548   if [[ -x "$SHELL" ]] ; then
549     export SHELL
550   fi
551 fi
552
553 # color setup for ls:
554 check_com -c dircolors && eval $(dircolors -b)
555 # color setup for ls on OS X / FreeBSD:
556 isdarwin && export CLICOLOR=1
557 isfreebsd && export CLICOLOR=1
558
559 # do MacPorts setup on darwin
560 if isdarwin && [[ -d /opt/local ]]; then
561     # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
562     # zshenv.
563     PATH="/opt/local/bin:/opt/local/sbin:$PATH"
564     MANPATH="/opt/local/share/man:$MANPATH"
565 fi
566 # do Fink setup on darwin
567 isdarwin && xsource /sw/bin/init.sh
568
569 # load our function and completion directories
570 for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
571     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
572     if [[ ${fdir} == '/usr/share/grml/zsh/functions' ]] ; then
573         for func in ${fdir}/**/[^_]*[^~](N.) ; do
574             zrcautoload ${func:t}
575         done
576     fi
577 done
578 unset fdir func
579
580 # support colors in less
581 export LESS_TERMCAP_mb=$'\E[01;31m'
582 export LESS_TERMCAP_md=$'\E[01;31m'
583 export LESS_TERMCAP_me=$'\E[0m'
584 export LESS_TERMCAP_se=$'\E[0m'
585 export LESS_TERMCAP_so=$'\E[01;44;33m'
586 export LESS_TERMCAP_ue=$'\E[0m'
587 export LESS_TERMCAP_us=$'\E[01;32m'
588
589 # mailchecks
590 MAILCHECK=30
591
592 # report about cpu-/system-/user-time of command if running longer than
593 # 5 seconds
594 REPORTTIME=5
595
596 # watch for everyone but me and root
597 watch=(notme root)
598
599 # automatically remove duplicates from these arrays
600 typeset -U path cdpath fpath manpath
601
602 # Load a few modules
603 is4 && \
604 for mod in parameter complist deltochar mathfunc ; do
605     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
606 done
607
608 # autoload zsh modules when they are referenced
609 if is4 ; then
610     zmodload -a  zsh/stat    zstat
611     zmodload -a  zsh/zpty    zpty
612     zmodload -ap zsh/mapfile mapfile
613 fi
614
615 # completion system
616 COMPDUMPFILE=${COMPDUMPFILE:-${ZDOTDIR:-${HOME}}/.zcompdump}
617 if zrcautoload compinit ; then
618     compinit -d ${COMPDUMPFILE} || print 'Notice: no compinit available :('
619 else
620     print 'Notice: no compinit available :('
621     function compdef { }
622 fi
623
624 # completion system
625
626 # called later (via is4 && grmlcomp)
627 # note: use 'zstyle' for getting current settings
628 #         press ^xh (control-x h) for getting tags in context; ^x? (control-x ?) to run complete_debug with trace output
629 grmlcomp() {
630     # TODO: This could use some additional information
631
632     # Make sure the completion system is initialised
633     (( ${+_comps} )) || return 1
634
635     # allow one error for every three characters typed in approximate completer
636     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
637
638     # don't complete backup files as executables
639     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
640
641     # start menu completion only if it could find no unambiguous initial string
642     zstyle ':completion:*:correct:*'       insert-unambiguous true
643     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
644     zstyle ':completion:*:correct:*'       original true
645
646     # activate color-completion
647     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
648
649     # format on completion
650     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
651
652     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
653     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
654
655     # insert all expansions for expand completer
656     zstyle ':completion:*:expand:*'        tag-order all-expansions
657     zstyle ':completion:*:history-words'   list false
658
659     # activate menu
660     zstyle ':completion:*:history-words'   menu yes
661
662     # ignore duplicate entries
663     zstyle ':completion:*:history-words'   remove-all-dups yes
664     zstyle ':completion:*:history-words'   stop yes
665
666     # match uppercase from lowercase
667     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
668
669     # separate matches into groups
670     zstyle ':completion:*:matches'         group 'yes'
671     zstyle ':completion:*'                 group-name ''
672
673     if [[ "$NOMENU" -eq 0 ]] ; then
674         # if there are more than 5 options allow selecting from a menu
675         zstyle ':completion:*'               menu select=5
676     else
677         # don't use any menus at all
678         setopt no_auto_menu
679     fi
680
681     zstyle ':completion:*:messages'        format '%d'
682     zstyle ':completion:*:options'         auto-description '%d'
683
684     # describe options in full
685     zstyle ':completion:*:options'         description 'yes'
686
687     # on processes completion complete all user processes
688     zstyle ':completion:*:processes'       command 'ps -au$USER'
689
690     # offer indexes before parameters in subscripts
691     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
692
693     # provide verbose completion information
694     zstyle ':completion:*'                 verbose true
695
696     # recent (as of Dec 2007) zsh versions are able to provide descriptions
697     # for commands (read: 1st word in the line) that it will list for the user
698     # to choose from. The following disables that, because it's not exactly fast.
699     zstyle ':completion:*:-command-:*:'    verbose false
700
701     # set format for warnings
702     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
703
704     # define files to ignore for zcompile
705     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
706     zstyle ':completion:correct:'          prompt 'correct to: %e'
707
708     # Ignore completion functions for commands you don't have:
709     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
710
711     # Provide more processes in completion of programs like killall:
712     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
713
714     # complete manual by their section
715     zstyle ':completion:*:manuals'    separate-sections true
716     zstyle ':completion:*:manuals.*'  insert-sections   true
717     zstyle ':completion:*:man:*'      menu yes select
718
719     # Search path for sudo completion
720     zstyle ':completion:*:sudo:*' command-path /usr/local/sbin \
721                                                /usr/local/bin  \
722                                                /usr/sbin       \
723                                                /usr/bin        \
724                                                /sbin           \
725                                                /bin            \
726                                                /usr/X11R6/bin
727
728     # provide .. as a completion
729     zstyle ':completion:*' special-dirs ..
730
731     # run rehash on completion so new installed program are found automatically:
732     _force_rehash() {
733         (( CURRENT == 1 )) && rehash
734         return 1
735     }
736
737     ## correction
738     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
739     if [[ "$NOCOR" -gt 0 ]] ; then
740         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
741         setopt nocorrect
742     else
743         # try to be smart about when to use what completer...
744         setopt correct
745         zstyle -e ':completion:*' completer '
746             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
747                 _last_try="$HISTNO$BUFFER$CURSOR"
748                 reply=(_complete _match _ignored _prefix _files)
749             else
750                 if [[ $words[1] == (rm|mv) ]] ; then
751                     reply=(_complete _files)
752                 else
753                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
754                 fi
755             fi'
756     fi
757
758     # command for process lists, the local web server details and host completion
759     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
760
761     # caching
762     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
763                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
764
765     # host completion
766     if is42 ; then
767         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
768         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
769     else
770         _ssh_hosts=()
771         _etc_hosts=()
772     fi
773     hosts=(
774         $(hostname)
775         "$_ssh_hosts[@]"
776         "$_etc_hosts[@]"
777         localhost
778     )
779     zstyle ':completion:*:hosts' hosts $hosts
780     # TODO: so, why is this here?
781     #  zstyle '*' hosts $hosts
782
783     # use generic completion system for programs not yet defined; (_gnu_generic works
784     # with commands that provide a --help option with "standard" gnu-like output.)
785     for compcom in cp deborphan df feh fetchipac gpasswd head hnb ipacsum mv \
786                    pal stow tail uname ; do
787         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
788     done; unset compcom
789
790     # see upgrade function in this file
791     compdef _hosts upgrade
792 }
793
794 # Keyboard setup: The following is based on the same code, we wrote for
795 # debian's setup. It ensures the terminal is in the right mode, when zle is
796 # active, so the values from $terminfo are valid. Therefore, this setup should
797 # work on all systems, that have support for `terminfo'. It also requires the
798 # zsh in use to have the `zsh/terminfo' module built.
799 #
800 # If you are customising your `zle-line-init()' or `zle-line-finish()'
801 # functions, make sure you call the following utility functions in there:
802 #
803 #     - zle-line-init():      zle-smkx
804 #     - zle-line-finish():    zle-rmkx
805
806 # Use emacs-like key bindings by default:
807 bindkey -e
808
809 # Custom widgets:
810
811 ## beginning-of-line OR beginning-of-buffer OR beginning of history
812 ## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
813 beginning-or-end-of-somewhere() {
814     local hno=$HISTNO
815     if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
816       ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
817         zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
818     else
819         zle .${WIDGET:s/somewhere/line-hist/} "$@"
820         if (( HISTNO != hno )); then
821             zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
822         fi
823     fi
824 }
825 zle -N beginning-of-somewhere beginning-or-end-of-somewhere
826 zle -N end-of-somewhere beginning-or-end-of-somewhere
827
828 # add a command line to the shells history without executing it
829 commit-to-history() {
830     print -s ${(z)BUFFER}
831     zle send-break
832 }
833 zle -N commit-to-history
834
835 # only slash should be considered as a word separator:
836 slash-backward-kill-word() {
837     local WORDCHARS="${WORDCHARS:s@/@}"
838     # zle backward-word
839     zle backward-kill-word
840 }
841 zle -N slash-backward-kill-word
842
843 # a generic accept-line wrapper
844
845 # This widget can prevent unwanted autocorrections from command-name
846 # to _command-name, rehash automatically on enter and call any number
847 # of builtin and user-defined widgets in different contexts.
848 #
849 # For a broader description, see:
850 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
851 #
852 # The code is imported from the file 'zsh/functions/accept-line' from
853 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
854 # distributed under the same terms as zsh itself.
855
856 # A newly added command will may not be found or will cause false
857 # correction attempts, if you got auto-correction set. By setting the
858 # following style, we force accept-line() to rehash, if it cannot
859 # find the first word on the command line in the $command[] hash.
860 zstyle ':acceptline:*' rehash true
861
862 function Accept-Line() {
863     setopt localoptions noksharrays
864     local -a subs
865     local -xi aldone
866     local sub
867     local alcontext=${1:-$alcontext}
868
869     zstyle -a ":acceptline:${alcontext}" actions subs
870
871     (( ${#subs} < 1 )) && return 0
872
873     (( aldone = 0 ))
874     for sub in ${subs} ; do
875         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
876         zle ${sub}
877
878         (( aldone > 0 )) && break
879     done
880 }
881
882 function Accept-Line-getdefault() {
883     emulate -L zsh
884     local default_action
885
886     zstyle -s ":acceptline:${alcontext}" default_action default_action
887     case ${default_action} in
888         ((accept-line|))
889             printf ".accept-line"
890             ;;
891         (*)
892             printf ${default_action}
893             ;;
894     esac
895 }
896
897 function Accept-Line-HandleContext() {
898     zle Accept-Line
899
900     default_action=$(Accept-Line-getdefault)
901     zstyle -T ":acceptline:${alcontext}" call_default \
902         && zle ${default_action}
903 }
904
905 function accept-line() {
906     setopt localoptions noksharrays
907     local -ax cmdline
908     local -x alcontext
909     local buf com fname format msg default_action
910
911     alcontext='default'
912     buf="${BUFFER}"
913     cmdline=(${(z)BUFFER})
914     com="${cmdline[1]}"
915     fname="_${com}"
916
917     Accept-Line 'preprocess'
918
919     zstyle -t ":acceptline:${alcontext}" rehash \
920         && [[ -z ${commands[$com]} ]]           \
921         && rehash
922
923     if    [[ -n ${com}               ]] \
924        && [[ -n ${reswords[(r)$com]} ]] \
925        || [[ -n ${aliases[$com]}     ]] \
926        || [[ -n ${functions[$com]}   ]] \
927        || [[ -n ${builtins[$com]}    ]] \
928        || [[ -n ${commands[$com]}    ]] ; then
929
930         # there is something sensible to execute, just do it.
931         alcontext='normal'
932         Accept-Line-HandleContext
933
934         return
935     fi
936
937     if    [[ -o correct              ]] \
938        || [[ -o correctall           ]] \
939        && [[ -n ${functions[$fname]} ]] ; then
940
941         # nothing there to execute but there is a function called
942         # _command_name; a completion widget. Makes no sense to
943         # call it on the commandline, but the correct{,all} options
944         # will ask for it nevertheless, so warn the user.
945         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
946             # Okay, we warned the user before, he called us again,
947             # so have it his way.
948             alcontext='force'
949             Accept-Line-HandleContext
950
951             return
952         fi
953
954         if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
955             alcontext='normal'
956             Accept-Line-HandleContext
957         else
958             # prepare warning message for the user, configurable via zstyle.
959             zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
960
961             if [[ -z ${msg} ]] ; then
962                 msg="%c will not execute and completion %f exists."
963             fi
964
965             zformat -f msg "${msg}" "c:${com}" "f:${fname}"
966
967             zle -M -- "${msg}"
968         fi
969         return
970     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
971         # If we are here, the commandline contains something that is not
972         # executable, which is neither subject to _command_name correction
973         # and is not empty. might be a variable assignment
974         alcontext='misc'
975         Accept-Line-HandleContext
976
977         return
978     fi
979
980     # If we got this far, the commandline only contains whitespace, or is empty.
981     alcontext='empty'
982     Accept-Line-HandleContext
983 }
984
985 zle -N accept-line
986 zle -N Accept-Line
987 zle -N Accept-Line-HandleContext
988
989 # power completion / abbreviation expansion / buffer expansion
990 # see http://zshwiki.org/home/examples/zleiab for details
991 # less risky than the global aliases but powerful as well
992 # just type the abbreviation key and afterwards 'ctrl-x .' to expand it
993 declare -A abk
994 setopt extendedglob
995 setopt interactivecomments
996 abk=(
997 #   key   # value                  (#d additional doc string)
998 #A# start
999     '...'  '../..'
1000     '....' '../../..'
1001     'BG'   '& exit'
1002     'C'    '| wc -l'
1003     'G'    '|& grep '${grep_options:+"${grep_options[*]}"}
1004     'H'    '| head'
1005     'Hl'   ' --help |& less -r'    #d (Display help in pager)
1006     'L'    '| less'
1007     'LL'   '|& less -r'
1008     'M'    '| most'
1009     'N'    '&>/dev/null'           #d (No Output)
1010     'R'    '| tr A-z N-za-m'       #d (ROT13)
1011     'SL'   '| sort | less'
1012     'S'    '| sort -u'
1013     'T'    '| tail'
1014     'V'    '|& vim -'
1015 #A# end
1016     'co'   './configure && make && sudo make install'
1017 )
1018
1019 zleiab() {
1020     emulate -L zsh
1021     setopt extendedglob
1022     local MATCH
1023
1024     LBUFFER=${LBUFFER%%(#m)[.\-+:|_a-zA-Z0-9]#}
1025     LBUFFER+=${abk[$MATCH]:-$MATCH}
1026 }
1027
1028 zle -N zleiab
1029
1030 help-show-abk()
1031 {
1032   zle -M "$(print "Available abbreviations for expansion:"; print -a -C 2 ${(kv)abk})"
1033 }
1034
1035 zle -N help-show-abk
1036
1037 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
1038 insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
1039 zle -N insert-datestamp
1040
1041 # press esc-m for inserting last typed word again (thanks to caphuso!)
1042 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
1043 zle -N insert-last-typed-word;
1044
1045 function grml-zsh-fg() {
1046   if (( ${#jobstates} )); then
1047     zle .push-input
1048     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
1049     BUFFER="${BUFFER}fg"
1050     zle .accept-line
1051   else
1052     zle -M 'No background jobs. Doing nothing.'
1053   fi
1054 }
1055 zle -N grml-zsh-fg
1056
1057 # run command line as user root via sudo:
1058 sudo-command-line() {
1059     [[ -z $BUFFER ]] && zle up-history
1060     if [[ $BUFFER != sudo\ * ]]; then
1061         BUFFER="sudo $BUFFER"
1062         CURSOR=$(( CURSOR+5 ))
1063     fi
1064 }
1065 zle -N sudo-command-line
1066
1067 ### jump behind the first word on the cmdline.
1068 ### useful to add options.
1069 function jump_after_first_word() {
1070     local words
1071     words=(${(z)BUFFER})
1072
1073     if (( ${#words} <= 1 )) ; then
1074         CURSOR=${#BUFFER}
1075     else
1076         CURSOR=${#${words[1]}}
1077     fi
1078 }
1079 zle -N jump_after_first_word
1080
1081 #f5# Create directory under cursor or the selected area
1082 inplaceMkDirs() {
1083     # Press ctrl-xM to create the directory under the cursor or the selected area.
1084     # To select an area press ctrl-@ or ctrl-space and use the cursor.
1085     # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
1086     # directory does not exist yet -> press ctrl-XM and problem solved
1087     local PATHTOMKDIR
1088     if ((REGION_ACTIVE==1)); then
1089         local F=$MARK T=$CURSOR
1090         if [[ $F -gt $T ]]; then
1091             F=${CURSOR}
1092             T=${MARK}
1093         fi
1094         # get marked area from buffer and eliminate whitespace
1095         PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
1096         PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
1097     else
1098         local bufwords iword
1099         bufwords=(${(z)LBUFFER})
1100         iword=${#bufwords}
1101         bufwords=(${(z)BUFFER})
1102         PATHTOMKDIR="${(Q)bufwords[iword]}"
1103     fi
1104     [[ -z "${PATHTOMKDIR}" ]] && return 1
1105     PATHTOMKDIR=${~PATHTOMKDIR}
1106     if [[ -e "${PATHTOMKDIR}" ]]; then
1107         zle -M " path already exists, doing nothing"
1108     else
1109         zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
1110         zle end-of-line
1111     fi
1112 }
1113
1114 zle -N inplaceMkDirs
1115
1116 #v1# set number of lines to display per page
1117 HELP_LINES_PER_PAGE=20
1118 #v1# set location of help-zle cache file
1119 HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
1120 # helper function for help-zle, actually generates the help text
1121 help_zle_parse_keybindings()
1122 {
1123     emulate -L zsh
1124     setopt extendedglob
1125     unsetopt ksharrays  #indexing starts at 1
1126
1127     #v1# choose files that help-zle will parse for keybindings
1128     ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
1129
1130     if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
1131         local load_cache=0
1132         for f ($HELPZLE_KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
1133         [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
1134     fi
1135
1136     #fill with default keybindings, possibly to be overwriten in a file later
1137     #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
1138     local -A help_zle_keybindings
1139     help_zle_keybindings['<Ctrl>@']="set MARK"
1140     help_zle_keybindings['<Ctrl>x<Ctrl>j']="vi-join lines"
1141     help_zle_keybindings['<Ctrl>x<Ctrl>b']="jump to matching brace"
1142     help_zle_keybindings['<Ctrl>x<Ctrl>u']="undo"
1143     help_zle_keybindings['<Ctrl>_']="undo"
1144     help_zle_keybindings['<Ctrl>x<Ctrl>f<c>']="find <c> in cmdline"
1145     help_zle_keybindings['<Ctrl>a']="goto beginning of line"
1146     help_zle_keybindings['<Ctrl>e']="goto end of line"
1147     help_zle_keybindings['<Ctrl>t']="transpose charaters"
1148     help_zle_keybindings['<Alt>t']="transpose words"
1149     help_zle_keybindings['<Alt>s']="spellcheck word"
1150     help_zle_keybindings['<Ctrl>k']="backward kill buffer"
1151     help_zle_keybindings['<Ctrl>u']="forward kill buffer"
1152     help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
1153     help_zle_keybindings["<Alt>'"]="quote line"
1154     help_zle_keybindings['<Alt>"']="quote from mark to cursor"
1155     help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
1156     help_zle_keybindings['<Alt>u']="make next word Uppercase"
1157     help_zle_keybindings['<Alt>l']="make next word lowercase"
1158     help_zle_keybindings['<Ctrl>xd']="preview expansion under cursor"
1159     help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
1160     help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
1161     help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
1162     help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
1163     help_zle_keybindings['<Ctrl>v']="insert next keypress symbol literally (e.g. for bindkey)"
1164     help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
1165     help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
1166     help_zle_keybindings['<Alt>h']="show help/manpage for current command"
1167
1168     #init global variables
1169     unset help_zle_lines help_zle_sln
1170     typeset -g -a help_zle_lines
1171     typeset -g help_zle_sln=1
1172
1173     local k v
1174     local lastkeybind_desc contents     #last description starting with #k# that we found
1175     local num_lines_elapsed=0            #number of lines between last description and keybinding
1176     #search config files in the order they a called (and thus the order in which they overwrite keybindings)
1177     for f in $HELPZLE_KEYBINDING_FILES; do
1178         [[ -r "$f" ]] || continue   #not readable ? skip it
1179         contents="$(<$f)"
1180         for cline in "${(f)contents}"; do
1181             #zsh pattern: matches lines like: #k# ..............
1182             if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
1183                 lastkeybind_desc="$match[*]"
1184                 num_lines_elapsed=0
1185             #zsh pattern: matches lines that set a keybinding using bind2map, bindkey or compdef -k
1186             #             ignores lines that are commentend out
1187             #             grabs first in '' or "" enclosed string with length between 1 and 6 characters
1188             elif [[ "$cline" == [^#]#(bind2maps[[:space:]](*)-s|bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*)  ]]; then
1189                 #description prevously found ? description not more than 2 lines away ? keybinding not empty ?
1190                 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
1191                     #substitute keybinding string with something readable
1192                     k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
1193                     #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
1194                     #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
1195                     help_zle_keybindings[${k}]=$lastkeybind_desc
1196                 fi
1197                 lastkeybind_desc=""
1198             else
1199               ((num_lines_elapsed++))
1200             fi
1201         done
1202     done
1203     unset contents
1204     #calculate length of keybinding column
1205     local kstrlen=0
1206     for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
1207     #convert the assoc array into preformated lines, which we are able to sort
1208     for k v in ${(kv)help_zle_keybindings[@]}; do
1209         #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
1210         help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
1211     done
1212     #sort lines alphabetically
1213     help_zle_lines=("${(i)help_zle_lines[@]}")
1214     [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
1215     echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
1216     zcompile $HELP_ZLE_CACHE_FILE
1217 }
1218 typeset -g help_zle_sln
1219 typeset -g -a help_zle_lines
1220
1221 # Provides (partially autogenerated) help on keybindings and the zsh line editor
1222 help-zle()
1223 {
1224     emulate -L zsh
1225     unsetopt ksharrays  #indexing starts at 1
1226     #help lines already generated ? no ? then do it
1227     [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
1228     #already displayed all lines ? go back to the start
1229     [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
1230     local sln=$help_zle_sln
1231     #note that help_zle_sln is a global var, meaning we remember the last page we viewed
1232     help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
1233     zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
1234 }
1235 zle -N help-zle
1236
1237 ## complete word from currently visible Screen or Tmux buffer.
1238 if check_com -c screen || check_com -c tmux; then
1239     _complete_screen_display() {
1240         [[ "$TERM" != "screen" ]] && return 1
1241
1242         local TMPFILE=$(mktemp)
1243         local -U -a _screen_display_wordlist
1244         trap "rm -f $TMPFILE" EXIT
1245
1246         # fill array with contents from screen hardcopy
1247         if ((${+TMUX})); then
1248             #works, but crashes tmux below version 1.4
1249             #luckily tmux -V option to ask for version, was also added in 1.4
1250             tmux -V &>/dev/null || return
1251             tmux -q capture-pane \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
1252         else
1253             screen -X hardcopy $TMPFILE
1254             # screen sucks, it dumps in latin1, apparently always. so recode it
1255             # to system charset
1256             check_com recode && recode latin1 $TMPFILE
1257         fi
1258         _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1259         # remove PREFIX to be completed from that array
1260         _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1261         compadd -a _screen_display_wordlist
1262     }
1263     #m# k CTRL-x\,\,\,S Complete word from GNU screen buffer
1264     bindkey -r "^xS"
1265     compdef -k _complete_screen_display complete-word '^xS'
1266 fi
1267
1268 # Load a few more functions and tie them to widgets, so they can be bound:
1269
1270 function zrcautozle() {
1271     emulate -L zsh
1272     local fnc=$1
1273     zrcautoload $fnc && zle -N $fnc
1274 }
1275
1276 function zrcgotwidget() {
1277     (( ${+widgets[$1]} ))
1278 }
1279
1280 function zrcgotkeymap() {
1281     [[ -n ${(M)keymaps:#$1} ]]
1282 }
1283
1284 zrcautozle insert-files
1285 zrcautozle edit-command-line
1286 zrcautozle insert-unicode-char
1287 if zrcautoload history-search-end; then
1288     zle -N history-beginning-search-backward-end history-search-end
1289     zle -N history-beginning-search-forward-end  history-search-end
1290 fi
1291 zle -C hist-complete complete-word _generic
1292 zstyle ':completion:hist-complete:*' completer _history
1293
1294 # The actual terminal setup hooks and bindkey-calls:
1295
1296 # An array to note missing features to ease diagnosis in case of problems.
1297 typeset -ga grml_missing_features
1298
1299 function zrcbindkey() {
1300     if (( ARGC )) && zrcgotwidget ${argv[-1]}; then
1301         bindkey "$@"
1302     fi
1303 }
1304
1305 function bind2maps () {
1306     local i sequence widget
1307     local -a maps
1308
1309     while [[ "$1" != "--" ]]; do
1310         maps+=( "$1" )
1311         shift
1312     done
1313     shift
1314
1315     if [[ "$1" == "-s" ]]; then
1316         shift
1317         sequence="$1"
1318     else
1319         sequence="${key[$1]}"
1320     fi
1321     widget="$2"
1322
1323     [[ -z "$sequence" ]] && return 1
1324
1325     for i in "${maps[@]}"; do
1326         zrcbindkey -M "$i" "$sequence" "$widget"
1327     done
1328 }
1329
1330 if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
1331     function zle-smkx () {
1332         emulate -L zsh
1333         printf '%s' ${terminfo[smkx]}
1334     }
1335     function zle-rmkx () {
1336         emulate -L zsh
1337         printf '%s' ${terminfo[rmkx]}
1338     }
1339     function zle-line-init () {
1340         zle-smkx
1341     }
1342     function zle-line-finish () {
1343         zle-rmkx
1344     }
1345     zle -N zle-line-init
1346     zle -N zle-line-finish
1347 else
1348     for i in {s,r}mkx; do
1349         (( ${+terminfo[$i]} )) || grml_missing_features+=($i)
1350     done
1351     unset i
1352 fi
1353
1354 typeset -A key
1355 key=(
1356     Home     "${terminfo[khome]}"
1357     End      "${terminfo[kend]}"
1358     Insert   "${terminfo[kich1]}"
1359     Delete   "${terminfo[kdch1]}"
1360     Up       "${terminfo[kcuu1]}"
1361     Down     "${terminfo[kcud1]}"
1362     Left     "${terminfo[kcub1]}"
1363     Right    "${terminfo[kcuf1]}"
1364     PageUp   "${terminfo[kpp]}"
1365     PageDown "${terminfo[knp]}"
1366     BackTab  "${terminfo[kcbt]}"
1367 )
1368
1369 # Guidelines for adding key bindings:
1370 #
1371 #   - Do not add hardcoded escape sequences, to enable non standard key
1372 #     combinations such as Ctrl-Meta-Left-Cursor. They are not easily portable.
1373 #
1374 #   - Adding Ctrl characters, such as '^b' is okay; note that '^b' and '^B' are
1375 #     the same key.
1376 #
1377 #   - All keys from the $key[] mapping are obviously okay.
1378 #
1379 #   - Most terminals send "ESC x" when Meta-x is pressed. Thus, sequences like
1380 #     '\ex' are allowed in here as well.
1381
1382 bind2maps emacs             -- Home   beginning-of-somewhere
1383 bind2maps       viins vicmd -- Home   vi-beginning-of-line
1384 bind2maps emacs             -- End    end-of-somewhere
1385 bind2maps       viins vicmd -- End    vi-end-of-line
1386 bind2maps emacs viins       -- Insert overwrite-mode
1387 bind2maps             vicmd -- Insert vi-insert
1388 bind2maps emacs             -- Delete delete-char
1389 bind2maps       viins vicmd -- Delete vi-delete-char
1390 bind2maps emacs viins vicmd -- Up     up-line-or-search
1391 bind2maps emacs viins vicmd -- Down   down-line-or-search
1392 bind2maps emacs             -- Left   backward-char
1393 bind2maps       viins vicmd -- Left   vi-backward-char
1394 bind2maps emacs             -- Right  forward-char
1395 bind2maps       viins vicmd -- Right  vi-forward-char
1396 #k# Perform abbreviation expansion
1397 bind2maps emacs viins       -- -s '^x.' zleiab
1398 #k# Display list of abbreviations that would expand
1399 bind2maps emacs viins       -- -s '^xb' help-show-abk
1400 #k# mkdir -p <dir> from string under cursor or marked area
1401 bind2maps emacs viins       -- -s '^xM' inplaceMkDirs
1402 #k# display help for keybindings and ZLE
1403 bind2maps emacs viins       -- -s '^xz' help-zle
1404 #k# Insert files and test globbing
1405 bind2maps emacs viins       -- -s "^xf" insert-files
1406 #k# Edit the current line in \kbd{\$EDITOR}
1407 bind2maps emacs viins       -- -s '\ee' edit-command-line
1408 #k# search history backward for entry beginning with typed text
1409 bind2maps emacs viins       -- -s '^xp' history-beginning-search-backward-end
1410 #k# search history forward for entry beginning with typed text
1411 bind2maps emacs viins       -- -s '^xP' history-beginning-search-forward-end
1412 #k# search history backward for entry beginning with typed text
1413 bind2maps emacs viins       -- PageUp history-beginning-search-backward-end
1414 #k# search history forward for entry beginning with typed text
1415 bind2maps emacs viins       -- PageDown history-beginning-search-forward-end
1416 bind2maps emacs viins       -- -s "^x^h" commit-to-history
1417 #k# Kill left-side word or everything up to next slash
1418 bind2maps emacs viins       -- -s '\ev' slash-backward-kill-word
1419 #k# Kill left-side word or everything up to next slash
1420 bind2maps emacs viins       -- -s '\e^h' slash-backward-kill-word
1421 #k# Kill left-side word or everything up to next slash
1422 bind2maps emacs viins       -- -s '\e^?' slash-backward-kill-word
1423 # Do history expansion on space:
1424 bind2maps emacs viins       -- -s ' ' magic-space
1425 #k# Trigger menu-complete
1426 bind2maps emacs viins       -- -s '\ei' menu-complete  # menu completion via esc-i
1427 #k# Insert a timestamp on the command line (yyyy-mm-dd)
1428 bind2maps emacs viins       -- -s '^ed' insert-datestamp
1429 #k# Insert last typed word
1430 bind2maps emacs viins       -- -s "\em" insert-last-typed-word
1431 #k# A smart shortcut for \kbd{fg<enter>}
1432 bind2maps emacs viins       -- -s '^z' grml-zsh-fg
1433 #k# prepend the current command with "sudo"
1434 bind2maps emacs viins       -- -s "^os" sudo-command-line
1435 #k# jump to after first word (for adding options)
1436 bind2maps emacs viins       -- -s '^x1' jump_after_first_word
1437 #k# complete word from history with menu
1438 bind2maps emacs viins       -- -s "^x^x" hist-complete
1439
1440 # insert unicode character
1441 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an §
1442 # See for example http://unicode.org/charts/ for unicode characters code
1443 #k# Insert Unicode character
1444 bind2maps emacs viins       -- -s '^xi' insert-unicode-char
1445
1446 # use the new *-pattern-* widgets for incremental history search
1447 if zrcgotwidget history-incremental-pattern-search-backward; then
1448     for seq wid in '^r' history-incremental-pattern-search-backward \
1449                    '^s' history-incremental-pattern-search-forward
1450     do
1451         bind2maps emacs viins vicmd -- -s $seq $wid
1452     done
1453 fi
1454
1455 if zrcgotkeymap menuselect; then
1456     #m# k Shift-tab Perform backwards menu completion
1457     bind2maps menuselect -- BackTab reverse-menu-complete
1458
1459     #k# menu selection: pick item but stay in the menu
1460     bind2maps menuselect -- -s '\e^M' accept-and-menu-complete
1461     # also use + and INSERT since it's easier to press repeatedly
1462     bind2maps menuselect -- -s '+' accept-and-menu-complete
1463     bind2maps menuselect -- Insert accept-and-menu-complete
1464
1465     # accept a completion and try to complete again by using menu
1466     # completion; very useful with completing directories
1467     # by using 'undo' one's got a simple file browser
1468     bind2maps menuselect -- -s '^o' accept-and-infer-next-history
1469 fi
1470
1471 # Finally, here are still a few hardcoded escape sequences; Special sequences
1472 # like Ctrl-<Cursor-key> etc do suck a fair bit, because they are not
1473 # standardised and most of the time are not available in a terminals terminfo
1474 # entry.
1475 #
1476 # While we do not encourage adding bindings like these, we will keep these for
1477 # backward compatibility.
1478
1479 ## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on
1480 ## the command line.
1481 # URxvt sequences:
1482 bind2maps emacs viins vicmd -- -s '\eOc' forward-word
1483 bind2maps emacs viins vicmd -- -s '\eOd' backward-word
1484 # These are for xterm:
1485 bind2maps emacs viins vicmd -- -s '\e[1;5C' forward-word
1486 bind2maps emacs viins vicmd -- -s '\e[1;5D' backward-word
1487 ## the same for alt-left-arrow and alt-right-arrow
1488 # URxvt again:
1489 bind2maps emacs viins vicmd -- -s '\e\e[C' forward-word
1490 bind2maps emacs viins vicmd -- -s '\e\e[D' backward-word
1491 # Xterm again:
1492 bind2maps emacs viins vicmd -- -s '^[[1;3C' forward-word
1493 bind2maps emacs viins vicmd -- -s '^[[1;3D' backward-word
1494 # Also try ESC Left/Right:
1495 bind2maps emacs viins vicmd -- -s '\e'${key[Right]} forward-word
1496 bind2maps emacs viins vicmd -- -s '\e'${key[Left]}  backward-word
1497
1498 # autoloading
1499
1500 zrcautoload zmv
1501 zrcautoload zed
1502
1503 # we don't want to quote/espace URLs on our own...
1504 # if autoload -U url-quote-magic ; then
1505 #    zle -N self-insert url-quote-magic
1506 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
1507 # else
1508 #    print 'Notice: no url-quote-magic available :('
1509 # fi
1510 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
1511
1512 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
1513 alias run-help >&/dev/null && unalias run-help
1514 for rh in run-help{,-git,-svk,-svn}; do
1515     zrcautoload $rh
1516 done; unset rh
1517
1518 # command not found handling
1519
1520 (( ${COMMAND_NOT_FOUND} == 1 )) &&
1521 function command_not_found_handler() {
1522     emulate -L zsh
1523     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1524         ${GRML_ZSH_CNF_HANDLER} $1
1525     fi
1526     return 1
1527 }
1528
1529 # history
1530
1531 ZSHDIR=${ZDOTDIR:-${HOME}/.zsh}
1532
1533 #v#
1534 HISTFILE=${ZDOTDIR:-${HOME}}/.zsh_history
1535 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
1536 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
1537
1538 # dirstack handling
1539
1540 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1541 DIRSTACKFILE=${DIRSTACKFILE:-${ZDOTDIR:-${HOME}}/.zdirs}
1542
1543 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1544     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1545     # "cd -" won't work after login by just setting $OLDPWD, so
1546     [[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
1547 fi
1548
1549 chpwd() {
1550     if (( $DIRSTACKSIZE <= 0 )) || [[ -z $DIRSTACKFILE ]]; then return; fi
1551     local -ax my_stack
1552     my_stack=( ${PWD} ${dirstack} )
1553     if is42 ; then
1554         builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
1555     else
1556         uprint my_stack >! ${DIRSTACKFILE}
1557     fi
1558 }
1559
1560 # directory based profiles
1561
1562 if is433 ; then
1563
1564 # chpwd_profiles(): Directory Profiles, Quickstart:
1565 #
1566 # In .zshrc.local:
1567 #
1568 #   zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
1569 #   zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1570 #   chpwd_profiles
1571 #
1572 # For details see the `grmlzshrc.5' manual page.
1573 function chpwd_profiles() {
1574     local profile context
1575     local -i reexecute
1576
1577     context=":chpwd:profiles:$PWD"
1578     zstyle -s "$context" profile profile || profile='default'
1579     zstyle -T "$context" re-execute && reexecute=1 || reexecute=0
1580
1581     if (( ${+parameters[CHPWD_PROFILE]} == 0 )); then
1582         typeset -g CHPWD_PROFILE
1583         local CHPWD_PROFILES_INIT=1
1584         (( ${+functions[chpwd_profiles_init]} )) && chpwd_profiles_init
1585     elif [[ $profile != $CHPWD_PROFILE ]]; then
1586         (( ${+functions[chpwd_leave_profile_$CHPWD_PROFILE]} )) \
1587             && chpwd_leave_profile_${CHPWD_PROFILE}
1588     fi
1589     if (( reexecute )) || [[ $profile != $CHPWD_PROFILE ]]; then
1590         (( ${+functions[chpwd_profile_$profile]} )) && chpwd_profile_${profile}
1591     fi
1592
1593     CHPWD_PROFILE="${profile}"
1594     return 0
1595 }
1596
1597 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1598
1599 fi # is433
1600
1601 # Prompt setup for grml:
1602
1603 # set colors for use in prompts (modern zshs allow for the use of %F{red}foo%f
1604 # in prompts to get a red "foo" embedded, but it's good to keep these for
1605 # backwards compatibility).
1606 if is437; then
1607     BLUE="%F{blue}"
1608     RED="%F{red}"
1609     GREEN="%F{green}"
1610     CYAN="%F{cyan}"
1611     MAGENTA="%F{magenta}"
1612     YELLOW="%F{yellow}"
1613     WHITE="%F{white}"
1614     NO_COLOR="%f"
1615 elif zrcautoload colors && colors 2>/dev/null ; then
1616     BLUE="%{${fg[blue]}%}"
1617     RED="%{${fg_bold[red]}%}"
1618     GREEN="%{${fg[green]}%}"
1619     CYAN="%{${fg[cyan]}%}"
1620     MAGENTA="%{${fg[magenta]}%}"
1621     YELLOW="%{${fg[yellow]}%}"
1622     WHITE="%{${fg[white]}%}"
1623     NO_COLOR="%{${reset_color}%}"
1624 else
1625     BLUE=$'%{\e[1;34m%}'
1626     RED=$'%{\e[1;31m%}'
1627     GREEN=$'%{\e[1;32m%}'
1628     CYAN=$'%{\e[1;36m%}'
1629     WHITE=$'%{\e[1;37m%}'
1630     MAGENTA=$'%{\e[1;35m%}'
1631     YELLOW=$'%{\e[1;33m%}'
1632     NO_COLOR=$'%{\e[0m%}'
1633 fi
1634
1635 # First, the easy ones: PS2..4:
1636
1637 # secondary prompt, printed when the shell needs more information to complete a
1638 # command.
1639 PS2='\`%_> '
1640 # selection prompt used within a select loop.
1641 PS3='?# '
1642 # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1643 PS4='+%N:%i:%_> '
1644
1645 # Some additional features to use with our prompt:
1646 #
1647 #    - battery status
1648 #    - debian_chroot
1649 #    - vcs_info setup and version specific fixes
1650
1651 # display battery status on right side of prompt using 'GRML_DISPLAY_BATTERY=1' in .zshrc.pre
1652
1653 battery() {
1654 if [[ $GRML_DISPLAY_BATTERY -gt 0 ]] ; then
1655     if islinux ; then
1656         batterylinux
1657     elif isopenbsd ; then
1658         batteryopenbsd
1659     elif isfreebsd ; then
1660         batteryfreebsd
1661     elif isdarwin ; then
1662         batterydarwin
1663     else
1664         #not yet supported
1665         GRML_DISPLAY_BATTERY=0
1666     fi
1667 fi
1668 }
1669
1670 batterylinux(){
1671 GRML_BATTERY_LEVEL=''
1672 local batteries bat capacity
1673 batteries=( /sys/class/power_supply/BAT*(N) )
1674 if (( $#batteries > 0 )) ; then
1675     for bat in $batteries ; do
1676         capacity=$(< $bat/capacity)
1677         case $(< $bat/status) in
1678         Charging)
1679             GRML_BATTERY_LEVEL+=" ^"
1680             ;;
1681         Discharging)
1682             if (( capacity < 20 )) ; then
1683                 GRML_BATTERY_LEVEL+=" !v"
1684             else
1685                 GRML_BATTERY_LEVEL+=" v"
1686             fi
1687             ;;
1688         *) # Full, Unknown
1689             GRML_BATTERY_LEVEL+=" ="
1690             ;;
1691         esac
1692         GRML_BATTERY_LEVEL+="${capacity}%%"
1693     done
1694 fi
1695 }
1696
1697 batteryopenbsd(){
1698 GRML_BATTERY_LEVEL=''
1699 local bat batfull batwarn batnow num
1700 for num in 0 1 ; do
1701     bat=$(sysctl -n hw.sensors.acpibat${num} 2>/dev/null)
1702     if [[ -n $bat ]]; then
1703         batfull=${"$(sysctl -n hw.sensors.acpibat${num}.amphour0)"%% *}
1704         batwarn=${"$(sysctl -n hw.sensors.acpibat${num}.amphour1)"%% *}
1705         batnow=${"$(sysctl -n hw.sensors.acpibat${num}.amphour3)"%% *}
1706         case "$(sysctl -n hw.sensors.acpibat${num}.raw0)" in
1707             *" discharging"*)
1708                 if (( batnow < batwarn )) ; then
1709                     GRML_BATTERY_LEVEL+=" !v"
1710                 else
1711                     GRML_BATTERY_LEVEL+=" v"
1712                 fi
1713                 ;;
1714             *" charging"*)
1715                 GRML_BATTERY_LEVEL+=" ^"
1716                 ;;
1717             *)
1718                 GRML_BATTERY_LEVEL+=" ="
1719                 ;;
1720         esac
1721         GRML_BATTERY_LEVEL+="${$(( 100 * batnow / batfull ))%%.*}%%"
1722     fi
1723 done
1724 }
1725
1726 batteryfreebsd(){
1727 GRML_BATTERY_LEVEL=''
1728 local num
1729 local -A table
1730 for num in 0 1 ; do
1731     table=( ${=${${${${${(M)${(f)"$(acpiconf -i $num 2>&1)"}:#(State|Remaining capacity):*}%%( ##|%)}//:[ $'\t']##/@}// /-}//@/ }} )
1732     if [[ -n $table ]] && [[ $table[State] != "not-present" ]] ; then
1733         case $table[State] in
1734             *discharging*)
1735                 if (( $table[Remaining-capacity] < 20 )) ; then
1736                     GRML_BATTERY_LEVEL+=" !v"
1737                 else
1738                     GRML_BATTERY_LEVEL+=" v"
1739                 fi
1740                 ;;
1741             *charging*)
1742                 GRML_BATTERY_LEVEL+=" ^"
1743                 ;;
1744             *)
1745                 GRML_BATTERY_LEVEL+=" ="
1746                 ;;
1747         esac
1748         GRML_BATTERY_LEVEL+="$table[Remaining-capacity]%%"
1749     fi
1750 done
1751 }
1752
1753 batterydarwin(){
1754 GRML_BATTERY_LEVEL=''
1755 local -a table
1756 table=( ${$(pmset -g ps)[(w)7,8]%%(\%|);} )
1757 if [[ -n $table[2] ]] ; then
1758     case $table[2] in
1759         charging)
1760             GRML_BATTERY_LEVEL+=" ^"
1761             ;;
1762         discharging)
1763             if (( $table[1] < 20 )) ; then
1764                 GRML_BATTERY_LEVEL+=" !v"
1765             else
1766                 GRML_BATTERY_LEVEL+=" v"
1767             fi
1768             ;;
1769         *)
1770             GRML_BATTERY_LEVEL+=" ="
1771             ;;
1772     esac
1773     GRML_BATTERY_LEVEL+="$table[1]%%"
1774 fi
1775 }
1776
1777 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1778 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1779     debian_chroot=$(</etc/debian_chroot)
1780 fi
1781
1782 # gather version control information for inclusion in a prompt
1783
1784 if zrcautoload vcs_info; then
1785     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
1786     # function, which can cause a lot of trouble with our directory-based
1787     # profiles. So:
1788     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
1789         function VCS_INFO_realpath () {
1790             setopt localoptions NO_shwordsplit chaselinks
1791             ( builtin cd -q $1 2> /dev/null && pwd; )
1792         }
1793     fi
1794
1795     zstyle ':vcs_info:*' max-exports 2
1796
1797     if [[ -o restricted ]]; then
1798         zstyle ':vcs_info:*' enable NONE
1799     fi
1800 fi
1801
1802 typeset -A grml_vcs_coloured_formats
1803 typeset -A grml_vcs_plain_formats
1804
1805 grml_vcs_plain_formats=(
1806     format "(%s%)-[%b] "    "zsh: %r"
1807     actionformat "(%s%)-[%b|%a] " "zsh: %r"
1808     rev-branchformat "%b:%r"
1809 )
1810
1811 grml_vcs_coloured_formats=(
1812     format "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOR} "
1813     actionformat "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOR} "
1814     rev-branchformat "%b${RED}:${YELLOW}%r"
1815 )
1816
1817 typeset GRML_VCS_COLOUR_MODE=xxx
1818
1819 grml_vcs_info_toggle_colour () {
1820     emulate -L zsh
1821     if [[ $GRML_VCS_COLOUR_MODE == plain ]]; then
1822         grml_vcs_info_set_formats coloured
1823     else
1824         grml_vcs_info_set_formats plain
1825     fi
1826     return 0
1827 }
1828
1829 grml_vcs_info_set_formats () {
1830     emulate -L zsh
1831     #setopt localoptions xtrace
1832     local mode=$1 AF F BF
1833     if [[ $mode == coloured ]]; then
1834         AF=${grml_vcs_coloured_formats[actionformat]}
1835         F=${grml_vcs_coloured_formats[format]}
1836         BF=${grml_vcs_coloured_formats[rev-branchformat]}
1837         GRML_VCS_COLOUR_MODE=coloured
1838     else
1839         AF=${grml_vcs_plain_formats[actionformat]}
1840         F=${grml_vcs_plain_formats[format]}
1841         BF=${grml_vcs_plain_formats[rev-branchformat]}
1842         GRML_VCS_COLOUR_MODE=plain
1843     fi
1844
1845     zstyle ':vcs_info:*'              actionformats "$AF" "zsh: %r"
1846     zstyle ':vcs_info:*'              formats       "$F"  "zsh: %r"
1847     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat  "$BF"
1848     return 0
1849 }
1850
1851 # Change vcs_info formats for the grml prompt. The 2nd format sets up
1852 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1853 if [[ "$TERM" == dumb ]] ; then
1854     grml_vcs_info_set_formats plain
1855 else
1856     grml_vcs_info_set_formats coloured
1857 fi
1858
1859 # Now for the fun part: The grml prompt themes in `promptsys' mode of operation
1860
1861 # This actually defines three prompts:
1862 #
1863 #    - grml
1864 #    - grml-large
1865 #    - grml-chroot
1866 #
1867 # They all share the same code and only differ with respect to which items they
1868 # contain. The main source of documentation is the `prompt_grml_help' function
1869 # below, which gets called when the user does this: prompt -h grml
1870
1871 function prompt_grml_help () {
1872     cat <<__EOF0__
1873   prompt grml
1874
1875     This is the prompt as used by the grml-live system <http://grml.org>. It is
1876     a rather simple one-line prompt, that by default looks something like this:
1877
1878         <user>@<host> <current-working-directory>[ <vcs_info-data>]%
1879
1880     The prompt itself integrates with zsh's prompt themes system (as you are
1881     witnessing right now) and is configurable to a certain degree. In
1882     particular, these aspects are customisable:
1883
1884         - The items used in the prompt (e.g. you can remove \`user' from
1885           the list of activated items, which will cause the user name to
1886           be omitted from the prompt string).
1887
1888         - The attributes used with the items are customisable via strings
1889           used before and after the actual item.
1890
1891     The available items are: at, battery, change-root, date, grml-chroot,
1892     history, host, jobs, newline, path, percent, rc, rc-always, sad-smiley,
1893     shell-level, time, user, vcs
1894
1895     The actual configuration is done via zsh's \`zstyle' mechanism. The
1896     context, that is used while looking up styles is:
1897
1898         ':prompt:grml:<left-or-right>:<subcontext>'
1899
1900     Here <left-or-right> is either \`left' or \`right', signifying whether the
1901     style should affect the left or the right prompt. <subcontext> is either
1902     \`setup' or 'items:<item>', where \`<item>' is one of the available items.
1903
1904     The styles:
1905
1906         - use-rprompt (boolean): If \`true' (the default), print a sad smiley
1907           in $RPROMPT if the last command a returned non-successful error code.
1908           (This in only valid if <left-or-right> is "right"; ignored otherwise)
1909
1910         - items (list): The list of items used in the prompt. If \`vcs' is
1911           present in the list, the theme's code invokes \`vcs_info'
1912           accordingly. Default (left): rc change-root user at host path vcs
1913           percent; Default (right): sad-smiley
1914
1915     Available styles in 'items:<item>' are: pre, post. These are strings that
1916     are inserted before (pre) and after (post) the item in question. Thus, the
1917     following would cause the user name to be printed in red instead of the
1918     default blue:
1919
1920         zstyle ':prompt:grml:*:items:user' pre '%F{red}'
1921
1922     Note, that the \`post' style may remain at its default value, because its
1923     default value is '%f', which turns the foreground text attribute off (which
1924     is exactly, what is still required with the new \`pre' value).
1925 __EOF0__
1926 }
1927
1928 function prompt_grml-chroot_help () {
1929     cat <<__EOF0__
1930   prompt grml-chroot
1931
1932     This is a variation of the grml prompt, see: prompt -h grml
1933
1934     The main difference is the default value of the \`items' style. The rest
1935     behaves exactly the same. Here are the defaults for \`grml-chroot':
1936
1937         - left: grml-chroot user at host path percent
1938         - right: (empty list)
1939 __EOF0__
1940 }
1941
1942 function prompt_grml-large_help () {
1943     cat <<__EOF0__
1944   prompt grml-large
1945
1946     This is a variation of the grml prompt, see: prompt -h grml
1947
1948     The main difference is the default value of the \`items' style. In
1949     particular, this theme uses _two_ lines instead of one with the plain
1950     \`grml' theme. The rest behaves exactly the same. Here are the defaults
1951     for \`grml-large':
1952
1953         - left: rc jobs history shell-level change-root time date newline user
1954                 at host path vcs percent
1955         - right: sad-smiley
1956 __EOF0__
1957 }
1958
1959 function grml_prompt_setup () {
1960     emulate -L zsh
1961     autoload -Uz vcs_info
1962     autoload -Uz add-zsh-hook
1963     add-zsh-hook precmd prompt_$1_precmd
1964 }
1965
1966 function prompt_grml_setup () {
1967     grml_prompt_setup grml
1968 }
1969
1970 function prompt_grml-chroot_setup () {
1971     grml_prompt_setup grml-chroot
1972 }
1973
1974 function prompt_grml-large_setup () {
1975     grml_prompt_setup grml-large
1976 }
1977
1978 # These maps define default tokens and pre-/post-decoration for items to be
1979 # used within the themes. All defaults may be customised in a context sensitive
1980 # matter by using zsh's `zstyle' mechanism.
1981 typeset -gA grml_prompt_pre_default \
1982             grml_prompt_post_default \
1983             grml_prompt_token_default \
1984             grml_prompt_token_function
1985
1986 grml_prompt_pre_default=(
1987     at                ''
1988     battery           ' '
1989     change-root       ''
1990     date              '%F{blue}'
1991     grml-chroot       '%F{red}'
1992     history           '%F{green}'
1993     host              ''
1994     jobs              '%F{cyan}'
1995     newline           ''
1996     path              '%B'
1997     percent           ''
1998     rc                '%B%F{red}'
1999     rc-always         ''
2000     sad-smiley        ''
2001     shell-level       '%F{red}'
2002     time              '%F{blue}'
2003     user              '%B%F{blue}'
2004     vcs               ''
2005 )
2006
2007 grml_prompt_post_default=(
2008     at                ''
2009     battery           ''
2010     change-root       ''
2011     date              '%f'
2012     grml-chroot       '%f '
2013     history           '%f'
2014     host              ''
2015     jobs              '%f'
2016     newline           ''
2017     path              '%b'
2018     percent           ''
2019     rc                '%f%b'
2020     rc-always         ''
2021     sad-smiley        ''
2022     shell-level       '%f'
2023     time              '%f'
2024     user              '%f%b'
2025     vcs               ''
2026 )
2027
2028 grml_prompt_token_default=(
2029     at                '@'
2030     battery           'GRML_BATTERY_LEVEL'
2031     change-root       'debian_chroot'
2032     date              '%D{%Y-%m-%d}'
2033     grml-chroot       'GRML_CHROOT'
2034     history           '{history#%!} '
2035     host              '%m '
2036     jobs              '[%j running job(s)] '
2037     newline           $'\n'
2038     path              '%40<..<%~%<< '
2039     percent           '%# '
2040     rc                '%(?..%? )'
2041     rc-always         '%?'
2042     sad-smiley        '%(?..:()'
2043     shell-level       '%(3L.+ .)'
2044     time              '%D{%H:%M:%S} '
2045     user              '%n'
2046     vcs               '0'
2047 )
2048
2049 function grml_theme_has_token () {
2050     if (( ARGC != 1 )); then
2051         printf 'usage: grml_theme_has_token <name>\n'
2052         return 1
2053     fi
2054     (( ${+grml_prompt_token_default[$1]} ))
2055 }
2056
2057 function GRML_theme_add_token_usage () {
2058     cat <<__EOF__
2059   Usage: grml_theme_add_token <name> [-f|-i] <token/function> [<pre> <post>]
2060
2061     <name> is the name for the newly added token. If the \`-f' or \`-i' options
2062     are used, <token/function> is the name of the function (see below for
2063     details). Otherwise it is the literal token string to be used. <pre> and
2064     <post> are optional.
2065
2066   Options:
2067
2068     -f <function>   Use a function named \`<function>' each time the token
2069                     is to be expanded.
2070
2071     -i <function>   Use a function named \`<function>' to initialise the
2072                     value of the token _once_ at runtime.
2073
2074     The functions are called with one argument: the token's new name. The
2075     return value is expected in the \$REPLY parameter. The use of these
2076     options is mutually exclusive.
2077
2078     There is a utility function \`grml_theme_has_token', which you can use
2079     to test if a token exists before trying to add it. This can be a guard
2080     for situations in which a \`grml_theme_add_token' call may happen more
2081     than once.
2082
2083   Example:
2084
2085     To add a new token \`day' that expands to the current weekday in the
2086     current locale in green foreground colour, use this:
2087
2088       grml_theme_add_token day '%D{%A}' '%F{green}' '%f'
2089
2090     Another example would be support for \$VIRTUAL_ENV:
2091
2092       function virtual_env_prompt () {
2093         REPLY=\${VIRTUAL_ENV+\${VIRTUAL_ENV:t} }
2094       }
2095       grml_theme_add_token virtual-env -f virtual_env_prompt
2096
2097     After that, you will be able to use a changed \`items' style to
2098     assemble your prompt.
2099 __EOF__
2100 }
2101
2102 function grml_theme_add_token () {
2103     emulate -L zsh
2104     local name token pre post
2105     local -i init funcall
2106
2107     if (( ARGC == 0 )); then
2108         GRML_theme_add_token_usage
2109         return 0
2110     fi
2111
2112     init=0
2113     funcall=0
2114     pre=''
2115     post=''
2116     name=$1
2117     shift
2118     if [[ $1 == '-f' ]]; then
2119         funcall=1
2120         shift
2121     elif [[ $1 == '-i' ]]; then
2122         init=1
2123         shift
2124     fi
2125
2126     if (( ARGC == 0 )); then
2127         printf '
2128 grml_theme_add_token: No token-string/function-name provided!\n\n'
2129         GRML_theme_add_token_usage
2130         return 1
2131     fi
2132     token=$1
2133     shift
2134     if (( ARGC != 0 && ARGC != 2 )); then
2135         printf '
2136 grml_theme_add_token: <pre> and <post> need to by specified _both_!\n\n'
2137         GRML_theme_add_token_usage
2138         return 1
2139     fi
2140     if (( ARGC )); then
2141         pre=$1
2142         post=$2
2143         shift 2
2144     fi
2145
2146     if grml_theme_has_token $name; then
2147         printf '
2148 grml_theme_add_token: Token `%s'\'' exists! Giving up!\n\n' $name
2149         GRML_theme_add_token_usage
2150         return 2
2151     fi
2152     if (( init )); then
2153         $token $name
2154         token=$REPLY
2155     fi
2156     grml_prompt_pre_default[$name]=$pre
2157     grml_prompt_post_default[$name]=$post
2158     if (( funcall )); then
2159         grml_prompt_token_function[$name]=$token
2160         grml_prompt_token_default[$name]=23
2161     else
2162         grml_prompt_token_default[$name]=$token
2163     fi
2164 }
2165
2166 function grml_typeset_and_wrap () {
2167     emulate -L zsh
2168     local target="$1"
2169     local new="$2"
2170     local left="$3"
2171     local right="$4"
2172
2173     if (( ${+parameters[$new]} )); then
2174         typeset -g "${target}=${(P)target}${left}${(P)new}${right}"
2175     fi
2176 }
2177
2178 function grml_prompt_addto () {
2179     emulate -L zsh
2180     local target="$1"
2181     local lr it apre apost new v
2182     local -a items
2183     shift
2184
2185     [[ $target == PS1 ]] && lr=left || lr=right
2186     zstyle -a ":prompt:${grmltheme}:${lr}:setup" items items || items=( "$@" )
2187     typeset -g "${target}="
2188     for it in "${items[@]}"; do
2189         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" pre apre \
2190             || apre=${grml_prompt_pre_default[$it]}
2191         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" post apost \
2192             || apost=${grml_prompt_post_default[$it]}
2193         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" token new \
2194             || new=${grml_prompt_token_default[$it]}
2195         typeset -g "${target}=${(P)target}${apre}"
2196         if (( ${+grml_prompt_token_function[$it]} )); then
2197             ${grml_prompt_token_function[$it]} $it
2198             typeset -g "${target}=${(P)target}${REPLY}"
2199         else
2200             case $it in
2201             battery)
2202                 grml_typeset_and_wrap $target $new '' ''
2203                 ;;
2204             change-root)
2205                 grml_typeset_and_wrap $target $new '(' ')'
2206                 ;;
2207             grml-chroot)
2208                 if [[ -n ${(P)new} ]]; then
2209                     typeset -g "${target}=${(P)target}(CHROOT)"
2210                 fi
2211                 ;;
2212             vcs)
2213                 v="vcs_info_msg_${new}_"
2214                 if (( ! vcscalled )); then
2215                     vcs_info
2216                     vcscalled=1
2217                 fi
2218                 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
2219                     typeset -g "${target}=${(P)target}${(P)v}"
2220                 fi
2221                 ;;
2222             *) typeset -g "${target}=${(P)target}${new}" ;;
2223             esac
2224         fi
2225         typeset -g "${target}=${(P)target}${apost}"
2226     done
2227 }
2228
2229 function prompt_grml_precmd () {
2230     emulate -L zsh
2231     local grmltheme=grml
2232     local -a left_items right_items
2233     left_items=(rc change-root user at host path vcs percent)
2234     right_items=(sad-smiley)
2235
2236     prompt_grml_precmd_worker
2237 }
2238
2239 function prompt_grml-chroot_precmd () {
2240     emulate -L zsh
2241     local grmltheme=grml-chroot
2242     local -a left_items right_items
2243     left_items=(grml-chroot user at host path percent)
2244     right_items=()
2245
2246     prompt_grml_precmd_worker
2247 }
2248
2249 function prompt_grml-large_precmd () {
2250     emulate -L zsh
2251     local grmltheme=grml-large
2252     local -a left_items right_items
2253     left_items=(rc jobs history shell-level change-root time date newline
2254                 user at host path vcs percent)
2255     right_items=(sad-smiley)
2256
2257     prompt_grml_precmd_worker
2258 }
2259
2260 function prompt_grml_precmd_worker () {
2261     emulate -L zsh
2262     local -i vcscalled=0
2263
2264     grml_prompt_addto PS1 "${left_items[@]}"
2265     if zstyle -T ":prompt:${grmltheme}:right:setup" use-rprompt; then
2266         grml_prompt_addto RPS1 "${right_items[@]}"
2267     fi
2268 }
2269
2270 grml_prompt_fallback() {
2271     setopt prompt_subst
2272     precmd() {
2273         (( ${+functions[vcs_info]} )) && vcs_info
2274     }
2275
2276     p0="${RED}%(?..%? )${WHITE}${debian_chroot:+($debian_chroot)}"
2277     p1="${BLUE}%n${NO_COLOR}@%m %40<...<%B%~%b%<< "'${vcs_info_msg_0_}'"%# "
2278     if (( EUID == 0 )); then
2279         PROMPT="${BLUE}${p0}${RED}${p1}"
2280     else
2281         PROMPT="${RED}${p0}${BLUE}${p1}"
2282     fi
2283     unset p0 p1
2284 }
2285
2286 if zrcautoload promptinit && promptinit 2>/dev/null ; then
2287     # Since we define the required functions in here and not in files in
2288     # $fpath, we need to stick the theme's name into `$prompt_themes'
2289     # ourselves, since promptinit does not pick them up otherwise.
2290     prompt_themes+=( grml grml-chroot grml-large )
2291     # Also, keep the array sorted...
2292     prompt_themes=( "${(@on)prompt_themes}" )
2293 else
2294     print 'Notice: no promptinit available :('
2295     grml_prompt_fallback
2296 fi
2297
2298 if is437; then
2299     # The prompt themes use modern features of zsh, that require at least
2300     # version 4.3.7 of the shell. Use the fallback otherwise.
2301     if [[ $GRML_DISPLAY_BATTERY -gt 0 ]]; then
2302         zstyle ':prompt:grml:right:setup' items sad-smiley battery
2303         add-zsh-hook precmd battery
2304     fi
2305     if [[ "$TERM" == dumb ]] ; then
2306         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" pre ''
2307         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" post ' '
2308         for i in rc user path jobs history date time shell-level; do
2309             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" pre ''
2310             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" post ''
2311         done
2312         unset i
2313         zstyle ':prompt:grml(|-large|-chroot):right:setup' use-rprompt false
2314     elif (( EUID == 0 )); then
2315         zstyle ':prompt:grml(|-large|-chroot):*:items:user' pre '%B%F{red}'
2316     fi
2317
2318     # Finally enable one of the prompts.
2319     if [[ -n $GRML_CHROOT ]]; then
2320         prompt grml-chroot
2321     elif [[ $GRMLPROMPT -gt 0 ]]; then
2322         prompt grml-large
2323     else
2324         prompt grml
2325     fi
2326 else
2327     grml_prompt_fallback
2328 fi
2329
2330 # Terminal-title wizardry
2331
2332 function ESC_print () {
2333     info_print $'\ek' $'\e\\' "$@"
2334 }
2335 function set_title () {
2336     info_print  $'\e]0;' $'\a' "$@"
2337 }
2338
2339 function info_print () {
2340     local esc_begin esc_end
2341     esc_begin="$1"
2342     esc_end="$2"
2343     shift 2
2344     printf '%s' ${esc_begin}
2345     printf '%s' "$*"
2346     printf '%s' "${esc_end}"
2347 }
2348
2349 function grml_reset_screen_title () {
2350     # adjust title of xterm
2351     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2352     [[ ${NOTITLE:-} -gt 0 ]] && return 0
2353     case $TERM in
2354         (xterm*|rxvt*)
2355             set_title ${(%):-"%n@%m: %~"}
2356             ;;
2357     esac
2358 }
2359
2360 function grml_vcs_to_screen_title () {
2361     if [[ $TERM == screen* ]] ; then
2362         if [[ -n ${vcs_info_msg_1_} ]] ; then
2363             ESC_print ${vcs_info_msg_1_}
2364         else
2365             ESC_print "zsh"
2366         fi
2367     fi
2368 }
2369
2370 function grml_maintain_name () {
2371     # set hostname if not running on host with name 'grml'
2372     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
2373        NAME="@$HOSTNAME"
2374     fi
2375 }
2376
2377 function grml_cmd_to_screen_title () {
2378     # get the name of the program currently running and hostname of local
2379     # machine set screen window title if running in a screen
2380     if [[ "$TERM" == screen* ]] ; then
2381         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME"
2382         ESC_print ${CMD}
2383     fi
2384 }
2385
2386 function grml_control_xterm_title () {
2387     case $TERM in
2388         (xterm*|rxvt*)
2389             set_title "${(%):-"%n@%m:"}" "$1"
2390             ;;
2391     esac
2392 }
2393
2394 zrcautoload add-zsh-hook || add-zsh-hook () { :; }
2395 if [[ $NOPRECMD -eq 0 ]]; then
2396     add-zsh-hook precmd grml_reset_screen_title
2397     add-zsh-hook precmd grml_vcs_to_screen_title
2398     add-zsh-hook preexec grml_maintain_name
2399     add-zsh-hook preexec grml_cmd_to_screen_title
2400     if [[ $NOTITLE -eq 0 ]]; then
2401         add-zsh-hook preexec grml_control_xterm_title
2402     fi
2403 fi
2404
2405 # 'hash' some often used directories
2406 #d# start
2407 hash -d deb=/var/cache/apt/archives
2408 hash -d doc=/usr/share/doc
2409 hash -d linux=/lib/modules/$(command uname -r)/build/
2410 hash -d log=/var/log
2411 hash -d slog=/var/log/syslog
2412 hash -d src=/usr/src
2413 hash -d www=/var/www
2414 #d# end
2415
2416 # some aliases
2417 if check_com -c screen ; then
2418     if [[ $UID -eq 0 ]] ; then
2419         if [[ -r /etc/grml/screenrc ]]; then
2420             alias screen="${commands[screen]} -c /etc/grml/screenrc"
2421         fi
2422     elif [[ -r $HOME/.screenrc ]] ; then
2423         alias screen="${commands[screen]} -c $HOME/.screenrc"
2424     else
2425         if [[ -r /etc/grml/screenrc_grml ]]; then
2426             alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
2427         else
2428             if [[ -r /etc/grml/screenrc ]]; then
2429                 alias screen="${commands[screen]} -c /etc/grml/screenrc"
2430             fi
2431         fi
2432     fi
2433 fi
2434
2435 # do we have GNU ls with color-support?
2436 if [[ "$TERM" != dumb ]]; then
2437     #a1# List files with colors (\kbd{ls -F \ldots})
2438     alias ls='command ls -F '${ls_options:+"${ls_options[*]}"}
2439     #a1# List all files, with colors (\kbd{ls -la \ldots})
2440     alias la='command ls -la '${ls_options:+"${ls_options[*]}"}
2441     #a1# List files with long colored list, without dotfiles (\kbd{ls -l \ldots})
2442     alias ll='command ls -l '${ls_options:+"${ls_options[*]}"}
2443     #a1# List files with long colored list, human readable sizes (\kbd{ls -hAl \ldots})
2444     alias lh='command ls -hAl '${ls_options:+"${ls_options[*]}"}
2445     #a1# List files with long colored list, append qualifier to filenames (\kbd{ls -lF \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2446     alias l='command ls -lF '${ls_options:+"${ls_options[*]}"}
2447 else
2448     alias ls='command ls -F'
2449     alias la='command ls -la'
2450     alias ll='command ls -l'
2451     alias lh='command ls -hAl'
2452     alias l='command ls -lF'
2453 fi
2454
2455 alias mdstat='cat /proc/mdstat'
2456 alias ...='cd ../../'
2457
2458 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2459 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2460     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2461 fi
2462
2463 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2464 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2465 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2466
2467 # make sure it is not assigned yet
2468 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
2469 utf2iso() {
2470     if isutfenv ; then
2471         for ENV in $(env | command grep -i '.utf') ; do
2472             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2473         done
2474     fi
2475 }
2476
2477 # make sure it is not assigned yet
2478 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
2479 iso2utf() {
2480     if ! isutfenv ; then
2481         for ENV in $(env | command grep -i '\.iso') ; do
2482             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2483         done
2484     fi
2485 }
2486
2487 # especially for roadwarriors using GNU screen and ssh:
2488 if ! check_com asc &>/dev/null ; then
2489   asc() { autossh -t "$@" 'screen -RdU' }
2490   compdef asc=ssh
2491 fi
2492
2493 #f1# Hints for the use of zsh on grml
2494 zsh-help() {
2495     print "$bg[white]$fg[black]
2496 zsh-help - hints for use of zsh on grml
2497 =======================================$reset_color"
2498
2499     print '
2500 Main configuration of zsh happens in /etc/zsh/zshrc.
2501 That file is part of the package grml-etc-core, if you want to
2502 use them on a non-grml-system just get the tar.gz from
2503 http://deb.grml.org/ or (preferably) get it from the git repository:
2504
2505   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2506
2507 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2508 The file is still there, but it is empty for backwards compatibility.
2509
2510 For your own changes use these two files:
2511     $HOME/.zshrc.pre
2512     $HOME/.zshrc.local
2513
2514 The former is sourced very early in our zshrc, the latter is sourced
2515 very lately.
2516
2517 System wide configuration without touching configuration files of grml
2518 can take place in /etc/zsh/zshrc.local.
2519
2520 For information regarding zsh start at http://grml.org/zsh/
2521
2522 Take a look at grml'\''s zsh refcard:
2523 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2524
2525 Check out the main zsh refcard:
2526 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2527
2528 And of course visit the zsh-lovers:
2529 % man zsh-lovers
2530
2531 You can adjust some options through environment variables when
2532 invoking zsh without having to edit configuration files.
2533 Basically meant for bash users who are not used to the power of
2534 the zsh yet. :)
2535
2536   "NOCOR=1    zsh" => deactivate automatic correction
2537   "NOMENU=1   zsh" => do not use auto menu completion
2538                       (note: use ctrl-d for completion instead!)
2539   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2540   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
2541                       preexec() and precmd() completely
2542   "GRML_DISPLAY_BATTERY=1  zsh"
2543                    => activate battery status on right side of prompt (WIP)
2544   "COMMAND_NOT_FOUND=1 zsh"
2545                    => Enable a handler if an external command was not found
2546                       The command called in the handler can be altered by setting
2547                       the GRML_ZSH_CNF_HANDLER variable, the default is:
2548                       "/usr/share/command-not-found/command-not-found"
2549
2550 A value greater than 0 is enables a feature; a value equal to zero
2551 disables it. If you like one or the other of these settings, you can
2552 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2553 zshrc.'
2554
2555     print "
2556 $bg[white]$fg[black]
2557 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2558 Enjoy your grml system with the zsh!$reset_color"
2559 }
2560
2561 # debian stuff
2562 if [[ -r /etc/debian_version ]] ; then
2563     #a3# Execute \kbd{apt-cache search}
2564     alias acs='apt-cache search'
2565     #a3# Execute \kbd{apt-cache show}
2566     alias acsh='apt-cache show'
2567     #a3# Execute \kbd{apt-cache policy}
2568     alias acp='apt-cache policy'
2569     #a3# Execute \kbd{apt-get dist-upgrade}
2570     salias adg="apt-get dist-upgrade"
2571     #a3# Execute \kbd{apt-get install}
2572     salias agi="apt-get install"
2573     #a3# Execute \kbd{aptitude install}
2574     salias ati="aptitude install"
2575     #a3# Execute \kbd{apt-get upgrade}
2576     salias ag="apt-get upgrade"
2577     #a3# Execute \kbd{apt-get update}
2578     salias au="apt-get update"
2579     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2580     salias -a up="aptitude update ; aptitude safe-upgrade"
2581     #a3# Execute \kbd{dpkg-buildpackage}
2582     alias dbp='dpkg-buildpackage'
2583     #a3# Execute \kbd{grep-excuses}
2584     alias ge='grep-excuses'
2585
2586     # get a root shell as normal user in live-cd mode:
2587     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2588        alias su="sudo su"
2589      fi
2590
2591     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2592     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2593     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2594     salias tlog="tail -f /var/log/syslog"    # follow the syslog
2595 fi
2596
2597 # sort installed Debian-packages by size
2598 if check_com -c dpkg-query ; then
2599     #a3# List installed Debian-packages sorted by size
2600     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"
2601 fi
2602
2603 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2604 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
2605     if check_com -c wodim; then
2606         cdrecord() {
2607             cat <<EOMESS
2608 cdrecord is not provided under its original name by Debian anymore.
2609 See #377109 in the BTS of Debian for more details.
2610
2611 Please use the wodim binary instead
2612 EOMESS
2613             return 1
2614         }
2615     fi
2616 fi
2617
2618 # Use hard limits, except for a smaller stack and no core dumps
2619 unlimit
2620 is425 && limit stack 8192
2621 isgrmlcd && limit core 0 # important for a live-cd-system
2622 limit -s
2623
2624 # grmlstuff
2625 grmlstuff() {
2626 # people should use 'grml-x'!
2627     if check_com -c 915resolution; then
2628         855resolution() {
2629             echo "Please use 915resolution as resolution modifying tool for Intel \
2630 graphic chipset."
2631             return -1
2632         }
2633     fi
2634
2635     #a1# Output version of running grml
2636     alias grml-version='cat /etc/grml_version'
2637
2638     if check_com -c grml-debootstrap ; then
2639         debian2hd() {
2640             echo "Installing debian to harddisk is possible by using grml-debootstrap."
2641             return 1
2642         }
2643     fi
2644 }
2645
2646 # now run the functions
2647 isgrml && checkhome
2648 is4    && isgrml    && grmlstuff
2649 is4    && grmlcomp
2650
2651 # keephack
2652 is4 && xsource "/etc/zsh/keephack"
2653
2654 # wonderful idea of using "e" glob qualifier by Peter Stephenson
2655 # You use it as follows:
2656 # $ NTREF=/reference/file
2657 # $ ls -l *(e:nt:)
2658 # This lists all the files in the current directory newer than the reference file.
2659 # You can also specify the reference file inline; note quotes:
2660 # $ ls -l *(e:'nt ~/.zshenv':)
2661 is4 && nt() {
2662     if [[ -n $1 ]] ; then
2663         local NTREF=${~1}
2664     fi
2665     [[ $REPLY -nt $NTREF ]]
2666 }
2667
2668 # shell functions
2669
2670 #f1# Reload an autoloadable function
2671 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2672 compdef _functions freload
2673
2674 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2675 sll() {
2676     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2677     local file
2678     for file in "$@" ; do
2679         while [[ -h "$file" ]] ; do
2680             ls -l $file
2681             file=$(readlink "$file")
2682         done
2683     done
2684 }
2685
2686 # TODO: Is it supported to use pager settings like this?
2687 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
2688 # with respect to wordsplitting. (ie. ${=PAGER})
2689 if check_com -c $PAGER ; then
2690     #f3# View Debian's changelog of given package(s)
2691     dchange() {
2692         emulate -L zsh
2693         [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
2694
2695         local package
2696         for package in "$@" ; do
2697             if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
2698                 $PAGER /usr/share/doc/${package}/changelog.Debian.gz
2699             elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
2700                 $PAGER /usr/share/doc/${package}/changelog.gz
2701             elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
2702                 $PAGER /usr/share/doc/${package}/changelog
2703             else
2704                 if check_com -c aptitude ; then
2705                     echo "No changelog for package $package found, using aptitude to retrieve it."
2706                     aptitude changelog "$package"
2707                 elif check_com -c apt-get ; then
2708                     echo "No changelog for package $package found, using apt-get to retrieve it."
2709                     apt-get changelog "$package"
2710                 else
2711                     echo "No changelog for package $package found, sorry."
2712                 fi
2713             fi
2714         done
2715     }
2716     _dchange() { _files -W /usr/share/doc -/ }
2717     compdef _dchange dchange
2718
2719     #f3# View Debian's NEWS of a given package
2720     dnews() {
2721         emulate -L zsh
2722         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2723             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2724         else
2725             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2726                 $PAGER /usr/share/doc/$1/NEWS.gz
2727             else
2728                 echo "No NEWS file for package $1 found, sorry."
2729                 return 1
2730             fi
2731         fi
2732     }
2733     _dnews() { _files -W /usr/share/doc -/ }
2734     compdef _dnews dnews
2735
2736     #f3# View Debian's copyright of a given package
2737     dcopyright() {
2738         emulate -L zsh
2739         if [[ -r /usr/share/doc/$1/copyright ]] ; then
2740             $PAGER /usr/share/doc/$1/copyright
2741         else
2742             echo "No copyright file for package $1 found, sorry."
2743             return 1
2744         fi
2745     }
2746     _dcopyright() { _files -W /usr/share/doc -/ }
2747     compdef _dcopyright dcopyright
2748
2749     #f3# View upstream's changelog of a given package
2750     uchange() {
2751         emulate -L zsh
2752         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2753             $PAGER /usr/share/doc/$1/changelog.gz
2754         else
2755             echo "No changelog for package $1 found, sorry."
2756             return 1
2757         fi
2758     }
2759     _uchange() { _files -W /usr/share/doc -/ }
2760     compdef _uchange uchange
2761 fi
2762
2763 # zsh profiling
2764 profile() {
2765     ZSH_PROFILE_RC=1 $SHELL "$@"
2766 }
2767
2768 #f1# Edit an alias via zle
2769 edalias() {
2770     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2771 }
2772 compdef _aliases edalias
2773
2774 #f1# Edit a function via zle
2775 edfunc() {
2776     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2777 }
2778 compdef _functions edfunc
2779
2780 # use it e.g. via 'Restart apache2'
2781 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2782 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2783 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2784 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2785 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2786 #m# f6 Status() \kbd{/etc/init.d/\em{process}}\quad\kbd{status}
2787 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2788     __start_stop() {
2789         local action_="${1:l}"  # e.g Start/Stop/Restart
2790         local service_="$2"
2791         local param_="$3"
2792
2793         local service_target_="$(readlink /etc/init.d/$service_)"
2794         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2795             # runit
2796             case "${action_}" in
2797                 start) if [[ ! -e /etc/service/$service_ ]]; then
2798                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2799                        else
2800                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2801                        fi ;;
2802                 # there is no reload in runits sysv emulation
2803                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2804                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2805             esac
2806         else
2807             # sysvinit
2808             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2809         fi
2810     }
2811
2812     _grmlinitd() {
2813         local -a scripts
2814         scripts=( /etc/init.d/*(x:t) )
2815         _describe "service startup script" scripts
2816     }
2817
2818     for i in Start Restart Stop Force-Reload Reload Status ; do
2819         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2820         compdef _grmlinitd $i
2821     done
2822 fi
2823
2824 #f1# Provides useful information on globbing
2825 H-Glob() {
2826     echo -e "
2827     /      directories
2828     .      plain files
2829     @      symbolic links
2830     =      sockets
2831     p      named pipes (FIFOs)
2832     *      executable plain files (0100)
2833     %      device files (character or block special)
2834     %b     block special files
2835     %c     character special files
2836     r      owner-readable files (0400)
2837     w      owner-writable files (0200)
2838     x      owner-executable files (0100)
2839     A      group-readable files (0040)
2840     I      group-writable files (0020)
2841     E      group-executable files (0010)
2842     R      world-readable files (0004)
2843     W      world-writable files (0002)
2844     X      world-executable files (0001)
2845     s      setuid files (04000)
2846     S      setgid files (02000)
2847     t      files with the sticky bit (01000)
2848
2849   print *(m-1)          # Files modified up to a day ago
2850   print *(a1)           # Files accessed a day ago
2851   print *(@)            # Just symlinks
2852   print *(Lk+50)        # Files bigger than 50 kilobytes
2853   print *(Lk-50)        # Files smaller than 50 kilobytes
2854   print **/*.c          # All *.c files recursively starting in \$PWD
2855   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2856   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2857   print *~*.*           # All Files that do not contain a dot
2858   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2859   print -l *(.c|.h)     # Lists *.c and *.h
2860   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2861   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2862 }
2863 alias help-zshglob=H-Glob
2864
2865 # grep for running process, like: 'any vim'
2866 any() {
2867     emulate -L zsh
2868     unsetopt KSH_ARRAYS
2869     if [[ -z "$1" ]] ; then
2870         echo "any - grep for process(es) by keyword" >&2
2871         echo "Usage: any <keyword>" >&2 ; return 1
2872     else
2873         ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
2874     fi
2875 }
2876
2877
2878 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2879 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2880 [[ -r /proc/1/maps ]] && \
2881 deswap() {
2882     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2883     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2884     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2885 }
2886
2887 # a wrapper for vim, that deals with title setting
2888 #   VIM_OPTIONS
2889 #       set this array to a set of options to vim you always want
2890 #       to have set when calling vim (in .zshrc.local), like:
2891 #           VIM_OPTIONS=( -p )
2892 #       This will cause vim to send every file given on the
2893 #       commandline to be send to it's own tab (needs vim7).
2894 if check_com vim; then
2895     vim() {
2896         VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2897     }
2898 fi
2899
2900 ssl_hashes=( sha512 sha256 sha1 md5 )
2901
2902 for sh in ${ssl_hashes}; do
2903     eval 'ssl-cert-'${sh}'() {
2904         emulate -L zsh
2905         if [[ -z $1 ]] ; then
2906             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2907             return 1
2908         fi
2909         openssl x509 -noout -fingerprint -'${sh}' -in $1
2910     }'
2911 done; unset sh
2912
2913 ssl-cert-fingerprints() {
2914     emulate -L zsh
2915     local i
2916     if [[ -z $1 ]] ; then
2917         printf 'usage: ssl-cert-fingerprints <file>\n'
2918         return 1
2919     fi
2920     for i in ${ssl_hashes}
2921         do ssl-cert-$i $1;
2922     done
2923 }
2924
2925 ssl-cert-info() {
2926     emulate -L zsh
2927     if [[ -z $1 ]] ; then
2928         printf 'usage: ssl-cert-info <file>\n'
2929         return 1
2930     fi
2931     openssl x509 -noout -text -in $1
2932     ssl-cert-fingerprints $1
2933 }
2934
2935 # make sure our environment is clean regarding colors
2936 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2937
2938 # "persistent history"
2939 # just write important commands you always need to ~/.important_commands
2940 if [[ -r ~/.important_commands ]] ; then
2941     fc -R ~/.important_commands
2942 fi
2943
2944 # load the lookup subsystem if it's available on the system
2945 zrcautoload lookupinit && lookupinit
2946
2947 # variables
2948
2949 # set terminal property (used e.g. by msgid-chooser)
2950 export COLORTERM="yes"
2951
2952 # aliases
2953
2954 # general
2955 #a2# Execute \kbd{du -sch}
2956 alias da='du -sch'
2957
2958 # listing stuff
2959 #a2# Execute \kbd{ls -lSrah}
2960 alias dir="command ls -lSrah"
2961 #a2# Only show dot-directories
2962 alias lad='command ls -d .*(/)'
2963 #a2# Only show dot-files
2964 alias lsa='command ls -a .*(.)'
2965 #a2# Only files with setgid/setuid/sticky flag
2966 alias lss='command ls -l *(s,S,t)'
2967 #a2# Only show symlinks
2968 alias lsl='command ls -l *(@)'
2969 #a2# Display only executables
2970 alias lsx='command ls -l *(*)'
2971 #a2# Display world-{readable,writable,executable} files
2972 alias lsw='command ls -ld *(R,W,X.^ND/)'
2973 #a2# Display the ten biggest files
2974 alias lsbig="command ls -flh *(.OL[1,10])"
2975 #a2# Only show directories
2976 alias lsd='command ls -d *(/)'
2977 #a2# Only show empty directories
2978 alias lse='command ls -d *(/^F)'
2979 #a2# Display the ten newest files
2980 alias lsnew="command ls -rtlh *(D.om[1,10])"
2981 #a2# Display the ten oldest files
2982 alias lsold="command ls -rtlh *(D.Om[1,10])"
2983 #a2# Display the ten smallest files
2984 alias lssmall="command ls -Srl *(.oL[1,10])"
2985 #a2# Display the ten newest directories and ten newest .directories
2986 alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
2987 #a2# Display the ten oldest directories and ten oldest .directories
2988 alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
2989
2990 # some useful aliases
2991 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
2992 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
2993
2994 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
2995 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2996 #a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
2997 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2998
2999 # work around non utf8 capable software in utf environment via $LANG and luit
3000 if check_com isutfenv && check_com luit ; then
3001     if check_com -c mrxvt ; then
3002         isutfenv && [[ -n "$LANG" ]] && \
3003             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3004     fi
3005
3006     if check_com -c aterm ; then
3007         isutfenv && [[ -n "$LANG" ]] && \
3008             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3009     fi
3010
3011     if check_com -c centericq ; then
3012         isutfenv && [[ -n "$LANG" ]] && \
3013             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3014     fi
3015 fi
3016
3017 # useful functions
3018
3019 #f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
3020 bk() {
3021     emulate -L zsh
3022     local current_date=$(date -u "+%Y-%m-%dT%H:%M:%SZ")
3023     local clean keep move verbose result
3024     setopt extended_glob
3025     usage() {
3026         cat << EOT
3027 bk [-hcmv] FILE [FILE ...]
3028 bk -r [-v] [FILE [FILE ...]]
3029 Backup a file or folder in place and append the timestamp
3030 Remove backups of a file or folder, or all backups in the current directory
3031
3032 Usage:
3033 -h    Display this help text
3034 -c    Keep the file/folder as is, create a copy backup using cp(1) (default)
3035 -m    Move the file/folder, using mv(1)
3036 -r    Remove backups of the specified file or directory, using rm(1). If none
3037       is provided, remove all backups in the current directory.
3038 -v    Verbose
3039
3040 The -c, -r and -m options are mutually exclusive. If specified at the same time,
3041 the last one is used.
3042
3043 The return code is the sum of all cp/mv/rm return codes.
3044 EOT
3045     }
3046     keep=1
3047     while getopts ":hcmrv" opt; do
3048         case $opt in
3049             c) unset move clean && (( ++keep ));;
3050             m) unset keep clean && (( ++move ));;
3051             r) unset move keep && (( ++clean ));;
3052             v) verbose="-v";;
3053             h) usage;;
3054             \?) usage >&2; return 1;;
3055         esac
3056     done
3057     shift "$((OPTIND-1))"
3058     if (( keep > 0 )); then
3059         while (( $# > 0 )); do
3060             if islinux || isfreebsd; then
3061                 cp $verbose -a "${1%/}" "${1%/}_$current_date"
3062             else;
3063                 cp $verbose -pR "${1%/}" "${1%/}_$current_date"
3064             fi
3065             (( result += $? ))
3066             shift
3067         done
3068     elif (( move > 0 )); then
3069         while (( $# > 0 )); do
3070             mv $verbose "${1%/}" "${1%/}_$current_date"
3071             (( result += $? ))
3072             shift
3073         done
3074     elif (( clean > 0 )); then
3075         if (( $# > 0 )); then
3076             while (( $# > 0 )); do
3077                 rm $verbose -rf "${1%/}"_[0-9](#c4,)-(0[0-9]|1[0-2])-([0-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3])(:[0-5][0-9])(#c2)Z
3078                 (( result += $? ))
3079                 shift
3080             done
3081         else
3082             rm $verbose -rf *_[0-9](#c4,)-(0[0-9]|1[0-2])-([0-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3])(:[0-5][0-9])(#c2)Z
3083             (( result += $? ))
3084         fi
3085     fi
3086     return $result
3087 }
3088
3089 #f5# cd to directoy and list files
3090 cl() {
3091     emulate -L zsh
3092     cd $1 && ls -a
3093 }
3094
3095 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
3096 cd() {
3097     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
3098         [[ ! -e ${1:h} ]] && return 1
3099         print "Correcting ${1} to ${1:h}"
3100         builtin cd ${1:h}
3101     else
3102         builtin cd "$@"
3103     fi
3104 }
3105
3106 #f5# Create Directoy and \kbd{cd} to it
3107 mkcd() {
3108     if (( ARGC != 1 )); then
3109         printf 'usage: mkcd <new-directory>\n'
3110         return 1;
3111     fi
3112     if [[ ! -d "$1" ]]; then
3113         command mkdir -p "$1"
3114     else
3115         printf '`%s'\'' already exists: cd-ing.\n' "$1"
3116     fi
3117     builtin cd "$1"
3118 }
3119
3120 #f5# Create temporary directory and \kbd{cd} to it
3121 cdt() {
3122     local t
3123     t=$(mktemp -d)
3124     echo "$t"
3125     builtin cd "$t"
3126 }
3127
3128 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3129 accessed() {
3130     emulate -L zsh
3131     print -l -- *(a-${1:-1})
3132 }
3133
3134 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3135 changed() {
3136     emulate -L zsh
3137     print -l -- *(c-${1:-1})
3138 }
3139
3140 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3141 modified() {
3142     emulate -L zsh
3143     print -l -- *(m-${1:-1})
3144 }
3145 # modified() was named new() in earlier versions, add an alias for backwards compatibility
3146 check_com new || alias new=modified
3147
3148 # use colors when GNU grep with color-support
3149 if (( $#grep_options > 0 )); then
3150     o=${grep_options:+"${grep_options[*]}"}
3151     #a2# Execute \kbd{grep -{}-color=auto}
3152     alias grep='grep '$o
3153     alias egrep='egrep '$o
3154     unset o
3155 fi
3156
3157 # Translate DE<=>EN
3158 # 'translate' looks up fot a word in a file with language-to-language
3159 # translations (field separator should be " : "). A typical wordlist looks
3160 # like at follows:
3161 #  | english-word : german-transmission
3162 # It's also only possible to translate english to german but not reciprocal.
3163 # Use the following oneliner to turn back the sort order:
3164 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3165 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3166 #f5# Translates a word
3167 trans() {
3168     emulate -L zsh
3169     case "$1" in
3170         -[dD]*)
3171             translate -l de-en $2
3172             ;;
3173         -[eE]*)
3174             translate -l en-de $2
3175             ;;
3176         *)
3177             echo "Usage: $0 { -D | -E }"
3178             echo "         -D == German to English"
3179             echo "         -E == English to German"
3180     esac
3181 }
3182
3183 # Usage: simple-extract <file>
3184 # Using option -d deletes the original archive file.
3185 #f5# Smart archive extractor
3186 simple-extract() {
3187     emulate -L zsh
3188     setopt extended_glob noclobber
3189     local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
3190     local RC=0
3191     zparseopts -D -E "d=DELETE_ORIGINAL"
3192     for ARCHIVE in "${@}"; do
3193         case $ARCHIVE in
3194             *(tar.bz2|tbz2|tbz))
3195                 DECOMP_CMD="tar -xvjf -"
3196                 USES_STDIN=true
3197                 USES_STDOUT=false
3198                 ;;
3199             *(tar.gz|tgz))
3200                 DECOMP_CMD="tar -xvzf -"
3201                 USES_STDIN=true
3202                 USES_STDOUT=false
3203                 ;;
3204             *(tar.xz|txz|tar.lzma))
3205                 DECOMP_CMD="tar -xvJf -"
3206                 USES_STDIN=true
3207                 USES_STDOUT=false
3208                 ;;
3209             *tar)
3210                 DECOMP_CMD="tar -xvf -"
3211                 USES_STDIN=true
3212                 USES_STDOUT=false
3213                 ;;
3214             *rar)
3215                 DECOMP_CMD="unrar x"
3216                 USES_STDIN=false
3217                 USES_STDOUT=false
3218                 ;;
3219             *lzh)
3220                 DECOMP_CMD="lha x"
3221                 USES_STDIN=false
3222                 USES_STDOUT=false
3223                 ;;
3224             *7z)
3225                 DECOMP_CMD="7z x"
3226                 USES_STDIN=false
3227                 USES_STDOUT=false
3228                 ;;
3229             *(zip|jar))
3230                 DECOMP_CMD="unzip"
3231                 USES_STDIN=false
3232                 USES_STDOUT=false
3233                 ;;
3234             *deb)
3235                 DECOMP_CMD="ar -x"
3236                 USES_STDIN=false
3237                 USES_STDOUT=false
3238                 ;;
3239             *bz2)
3240                 DECOMP_CMD="bzip2 -d -c -"
3241                 USES_STDIN=true
3242                 USES_STDOUT=true
3243                 ;;
3244             *(gz|Z))
3245                 DECOMP_CMD="gzip -d -c -"
3246                 USES_STDIN=true
3247                 USES_STDOUT=true
3248                 ;;
3249             *(xz|lzma))
3250                 DECOMP_CMD="xz -d -c -"
3251                 USES_STDIN=true
3252                 USES_STDOUT=true
3253                 ;;
3254             *)
3255                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3256                 RC=$((RC+1))
3257                 continue
3258                 ;;
3259         esac
3260
3261         if ! check_com ${DECOMP_CMD[(w)1]}; then
3262             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3263             RC=$((RC+2))
3264             continue
3265         fi
3266
3267         GZTARGET="${ARCHIVE:t:r}"
3268         if [[ -f $ARCHIVE ]] ; then
3269
3270             print "Extracting '$ARCHIVE' ..."
3271             if $USES_STDIN; then
3272                 if $USES_STDOUT; then
3273                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3274                 else
3275                     ${=DECOMP_CMD} < "$ARCHIVE"
3276                 fi
3277             else
3278                 if $USES_STDOUT; then
3279                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3280                 else
3281                     ${=DECOMP_CMD} "$ARCHIVE"
3282                 fi
3283             fi
3284             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3285
3286         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3287             if check_com curl; then
3288                 WGET_CMD="curl -L -k -s -o -"
3289             elif check_com wget; then
3290                 WGET_CMD="wget -q -O - --no-check-certificate"
3291             else
3292                 print "ERROR: neither wget nor curl is installed" >&2
3293                 RC=$((RC+4))
3294                 continue
3295             fi
3296             print "Downloading and Extracting '$ARCHIVE' ..."
3297             if $USES_STDIN; then
3298                 if $USES_STDOUT; then
3299                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3300                     RC=$((RC+$?))
3301                 else
3302                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3303                     RC=$((RC+$?))
3304                 fi
3305             else
3306                 if $USES_STDOUT; then
3307                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3308                 else
3309                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3310                 fi
3311             fi
3312
3313         else
3314             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3315             RC=$((RC+8))
3316         fi
3317     done
3318     return $RC
3319 }
3320
3321 __archive_or_uri()
3322 {
3323     _alternative \
3324         '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)"' \
3325         '_urls:Remote Archives:_urls'
3326 }
3327
3328 _simple_extract()
3329 {
3330     _arguments \
3331         '-d[delete original archivefile after extraction]' \
3332         '*:Archive Or Uri:__archive_or_uri'
3333 }
3334 compdef _simple_extract simple-extract
3335 alias se=simple-extract
3336
3337 #f5# Set all ulimit parameters to \kbd{unlimited}
3338 allulimit() {
3339     ulimit -c unlimited
3340     ulimit -d unlimited
3341     ulimit -f unlimited
3342     ulimit -l unlimited
3343     ulimit -n unlimited
3344     ulimit -s unlimited
3345     ulimit -t unlimited
3346 }
3347
3348 #f5# Change the xterm title from within GNU-screen
3349 xtrename() {
3350     emulate -L zsh
3351     if [[ $1 != "-f" ]] ; then
3352         if [[ -z ${DISPLAY} ]] ; then
3353             printf 'xtrename only makes sense in X11.\n'
3354             return 1
3355         fi
3356     else
3357         shift
3358     fi
3359     if [[ -z $1 ]] ; then
3360         printf 'usage: xtrename [-f] "title for xterm"\n'
3361         printf '  renames the title of xterm from _within_ screen.\n'
3362         printf '  also works without screen.\n'
3363         printf '  will not work if DISPLAY is unset, use -f to override.\n'
3364         return 0
3365     fi
3366     print -n "\eP\e]0;${1}\C-G\e\\"
3367     return 0
3368 }
3369
3370 # Create small urls via http://goo.gl using curl(1).
3371 # API reference: https://code.google.com/apis/urlshortener/
3372 function zurl() {
3373     emulate -L zsh
3374     setopt extended_glob
3375
3376     if [[ -z $1 ]]; then
3377         print "USAGE: zurl <URL>"
3378         return 1
3379     fi
3380
3381     local PN url prog api json contenttype item
3382     local -a data
3383     PN=$0
3384     url=$1
3385
3386     # Prepend 'http://' to given URL where necessary for later output.
3387     if [[ ${url} != http(s|)://* ]]; then
3388         url='http://'${url}
3389     fi
3390
3391     if check_com -c curl; then
3392         prog=curl
3393     else
3394         print "curl is not available, but mandatory for ${PN}. Aborting."
3395         return 1
3396     fi
3397     api='https://www.googleapis.com/urlshortener/v1/url'
3398     contenttype="Content-Type: application/json"
3399     json="{\"longUrl\": \"${url}\"}"
3400     data=(${(f)"$($prog --silent -H ${contenttype} -d ${json} $api)"})
3401     # Parse the response
3402     for item in "${data[@]}"; do
3403         case "$item" in
3404             ' '#'"id":'*)
3405                 item=${item#*: \"}
3406                 item=${item%\",*}
3407                 printf '%s\n' "$item"
3408                 return 0
3409                 ;;
3410         esac
3411     done
3412     return 1
3413 }
3414
3415 #f2# Find history events by search pattern and list them by date.
3416 whatwhen()  {
3417     emulate -L zsh
3418     local usage help ident format_l format_s first_char remain first last
3419     usage='USAGE: whatwhen [options] <searchstring> <search range>'
3420     help='Use `whatwhen -h'\'' for further explanations.'
3421     ident=${(l,${#${:-Usage: }},, ,)}
3422     format_l="${ident}%s\t\t\t%s\n"
3423     format_s="${format_l//(\\t)##/\\t}"
3424     # Make the first char of the word to search for case
3425     # insensitive; e.g. [aA]
3426     first_char=[${(L)1[1]}${(U)1[1]}]
3427     remain=${1[2,-1]}
3428     # Default search range is `-100'.
3429     first=${2:-\-100}
3430     # Optional, just used for `<first> <last>' given.
3431     last=$3
3432     case $1 in
3433         ("")
3434             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3435             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3436         ;;
3437         (-h)
3438             printf '%s\n\n' ${usage}
3439             print 'OPTIONS:'
3440             printf $format_l '-h' 'show help text'
3441             print '\f'
3442             print 'SEARCH RANGE:'
3443             printf $format_l "'0'" 'the whole history,'
3444             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3445             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3446             printf '\n%s\n' 'EXAMPLES:'
3447             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3448             printf $format_l 'whatwhen zsh -250'
3449             printf $format_l 'whatwhen foo 1 99'
3450         ;;
3451         (\?)
3452             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3453         ;;
3454         (*)
3455             # -l list results on stout rather than invoking $EDITOR.
3456             # -i Print dates as in YYYY-MM-DD.
3457             # -m Search for a - quoted - pattern within the history.
3458             fc -li -m "*${first_char}${remain}*" $first $last
3459         ;;
3460     esac
3461 }
3462
3463 # mercurial related stuff
3464 if check_com -c hg ; then
3465     # gnu like diff for mercurial
3466     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3467     #f5# GNU like diff for mercurial
3468     hgdi() {
3469         emulate -L zsh
3470         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3471     }
3472
3473     # build debian package
3474     #a2# Alias for \kbd{hg-buildpackage}
3475     alias hbp='hg-buildpackage'
3476
3477     # execute commands on the versioned patch-queue from the current repos
3478     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3479
3480     # diffstat for specific version of a mercurial repository
3481     #   hgstat      => display diffstat between last revision and tip
3482     #   hgstat 1234 => display diffstat between revision 1234 and tip
3483     #f5# Diffstat for specific version of a mercurial repos
3484     hgstat() {
3485         emulate -L zsh
3486         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3487     }
3488
3489 fi # end of check whether we have the 'hg'-executable
3490
3491 # grml-small cleanups
3492
3493 # The following is used to remove zsh-config-items that do not work
3494 # in grml-small by default.
3495 # If you do not want these adjustments (for whatever reason), set
3496 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3497 # sources if it is there).
3498
3499 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3500
3501     unset abk[V]
3502     unalias    'V'      &> /dev/null
3503     unfunction vman     &> /dev/null
3504     unfunction viless   &> /dev/null
3505     unfunction 2html    &> /dev/null
3506
3507     # manpages are not in grmlsmall
3508     unfunction manzsh   &> /dev/null
3509     unfunction man2     &> /dev/null
3510
3511 fi
3512
3513 zrclocal
3514
3515 ## genrefcard.pl settings
3516
3517 ### doc strings for external functions from files
3518 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3519
3520 ### example: split functions-search 8,16,24,32
3521 #@# split functions-search 8
3522
3523 ## END OF FILE #################################################################
3524 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3525 # Local variables:
3526 # mode: sh
3527 # End: