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