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