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