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