zsh: commit-to-history: keep escaped character
[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 -rs ${(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         REPLY=''
2273         $token $name
2274         token=$REPLY
2275     fi
2276     grml_prompt_pre_default[$name]=$pre
2277     grml_prompt_post_default[$name]=$post
2278     if (( funcall )); then
2279         grml_prompt_token_function[$name]=$token
2280         grml_prompt_token_default[$name]=23
2281     else
2282         grml_prompt_token_default[$name]=$token
2283     fi
2284 }
2285
2286 function grml_wrap_reply () {
2287     emulate -L zsh
2288     local target="$1"
2289     local new="$2"
2290     local left="$3"
2291     local right="$4"
2292
2293     if (( ${+parameters[$new]} )); then
2294         REPLY="${left}${(P)new}${right}"
2295     else
2296         REPLY=''
2297     fi
2298 }
2299
2300 function grml_prompt_addto () {
2301     emulate -L zsh
2302     local target="$1"
2303     local lr it apre apost new v REPLY
2304     local -a items
2305     shift
2306
2307     [[ $target == PS1 ]] && lr=left || lr=right
2308     zstyle -a ":prompt:${grmltheme}:${lr}:setup" items items || items=( "$@" )
2309     typeset -g "${target}="
2310     for it in "${items[@]}"; do
2311         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" pre apre \
2312             || apre=${grml_prompt_pre_default[$it]}
2313         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" post apost \
2314             || apost=${grml_prompt_post_default[$it]}
2315         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" token new \
2316             || new=${grml_prompt_token_default[$it]}
2317         if (( ${+grml_prompt_token_function[$it]} )); then
2318             REPLY=''
2319             ${grml_prompt_token_function[$it]} $it
2320         else
2321             case $it in
2322             battery)
2323                 grml_wrap_reply $target $new '' ''
2324                 ;;
2325             change-root)
2326                 grml_wrap_reply $target $new '(' ')'
2327                 ;;
2328             grml-chroot)
2329                 if [[ -n ${(P)new} ]]; then
2330                     REPLY="$CHROOT"
2331                 else
2332                     REPLY=''
2333                 fi
2334                 ;;
2335             vcs)
2336                 v="vcs_info_msg_${new}_"
2337                 if (( ! vcscalled )); then
2338                     vcs_info
2339                     vcscalled=1
2340                 fi
2341                 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
2342                     REPLY="${(P)v}"
2343                 else
2344                     REPLY=''
2345                 fi
2346                 ;;
2347             *) REPLY="$new" ;;
2348             esac
2349         fi
2350         # Strip volatile characters per item. This is off by default. See the
2351         # global stripping code a few lines below for details.
2352         if [[ -o prompt_subst ]] && zstyle -t ":prompt:${grmltheme}:${lr}:items:$it" \
2353                                            strip-sensitive-characters
2354         then
2355             REPLY="${REPLY//[$\`]/}"
2356         fi
2357         typeset -g "${target}=${(P)target}${apre}${REPLY}${apost}"
2358     done
2359
2360     # Per default, strip volatile characters (in the prompt_subst case)
2361     # globally. If the option is off, the style has no effect. For more
2362     # control, this can be turned off and stripping can be configured on a
2363     # per-item basis (see above).
2364     if [[ -o prompt_subst ]] && zstyle -T ":prompt:${grmltheme}:${lr}:setup" \
2365                                        strip-sensitive-characters
2366     then
2367         typeset -g "${target}=${${(P)target}//[$\`]/}"
2368     fi
2369 }
2370
2371 function prompt_grml_precmd () {
2372     emulate -L zsh
2373     local grmltheme=grml
2374     local -a left_items right_items
2375     left_items=(rc change-root user at host path vcs percent)
2376     right_items=(sad-smiley)
2377
2378     prompt_grml_precmd_worker
2379 }
2380
2381 function prompt_grml-chroot_precmd () {
2382     emulate -L zsh
2383     local grmltheme=grml-chroot
2384     local -a left_items right_items
2385     left_items=(grml-chroot user at host path percent)
2386     right_items=()
2387
2388     prompt_grml_precmd_worker
2389 }
2390
2391 function prompt_grml-large_precmd () {
2392     emulate -L zsh
2393     local grmltheme=grml-large
2394     local -a left_items right_items
2395     left_items=(rc jobs history shell-level change-root time date newline
2396                 user at host path vcs percent)
2397     right_items=(sad-smiley)
2398
2399     prompt_grml_precmd_worker
2400 }
2401
2402 function prompt_grml_precmd_worker () {
2403     emulate -L zsh
2404     local -i vcscalled=0
2405
2406     grml_prompt_addto PS1 "${left_items[@]}"
2407     if zstyle -T ":prompt:${grmltheme}:right:setup" use-rprompt; then
2408         grml_prompt_addto RPS1 "${right_items[@]}"
2409     fi
2410 }
2411
2412 function grml_prompt_fallback () {
2413     setopt prompt_subst
2414     local p0 p1
2415
2416     p0="${RED}%(?..%? )${WHITE}${debian_chroot:+($debian_chroot)}"
2417     p1="${BLUE}%n${NO_COLOR}@%m %40<...<%B%~%b%<< "'${vcs_info_msg_0_}'"%# "
2418     if (( EUID == 0 )); then
2419         PROMPT="${BLUE}${p0}${RED}${p1}"
2420     else
2421         PROMPT="${RED}${p0}${BLUE}${p1}"
2422     fi
2423 }
2424
2425 if zrcautoload promptinit && promptinit 2>/dev/null ; then
2426     # Since we define the required functions in here and not in files in
2427     # $fpath, we need to stick the theme's name into `$prompt_themes'
2428     # ourselves, since promptinit does not pick them up otherwise.
2429     prompt_themes+=( grml grml-chroot grml-large )
2430     # Also, keep the array sorted...
2431     prompt_themes=( "${(@on)prompt_themes}" )
2432 else
2433     print 'Notice: no promptinit available :('
2434     grml_prompt_fallback
2435     function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
2436 fi
2437
2438 if is437; then
2439     # The prompt themes use modern features of zsh, that require at least
2440     # version 4.3.7 of the shell. Use the fallback otherwise.
2441     if [[ $GRML_DISPLAY_BATTERY -gt 0 ]]; then
2442         zstyle ':prompt:grml:right:setup' items sad-smiley battery
2443         add-zsh-hook precmd battery
2444     fi
2445     if [[ "$TERM" == dumb ]] ; then
2446         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" pre ''
2447         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" post ' '
2448         for i in rc user path jobs history date time shell-level; do
2449             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" pre ''
2450             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" post ''
2451         done
2452         unset i
2453         zstyle ':prompt:grml(|-large|-chroot):right:setup' use-rprompt false
2454     elif (( EUID == 0 )); then
2455         zstyle ':prompt:grml(|-large|-chroot):*:items:user' pre '%B%F{red}'
2456     fi
2457
2458     # Finally enable one of the prompts.
2459     if [[ -n $GRML_CHROOT ]]; then
2460         prompt grml-chroot
2461     elif [[ $GRMLPROMPT -gt 0 ]]; then
2462         prompt grml-large
2463     else
2464         prompt grml
2465     fi
2466 else
2467     grml_prompt_fallback
2468     function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
2469 fi
2470
2471 # Terminal-title wizardry
2472
2473 function ESC_print () {
2474     info_print $'\ek' $'\e\\' "$@"
2475 }
2476 function set_title () {
2477     info_print  $'\e]0;' $'\a' "$@"
2478 }
2479
2480 function info_print () {
2481     local esc_begin esc_end
2482     esc_begin="$1"
2483     esc_end="$2"
2484     shift 2
2485     printf '%s' ${esc_begin}
2486     printf '%s' "$*"
2487     printf '%s' "${esc_end}"
2488 }
2489
2490 function grml_reset_screen_title () {
2491     # adjust title of xterm
2492     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2493     [[ ${NOTITLE:-} -gt 0 ]] && return 0
2494     case $TERM in
2495         (xterm*|rxvt*)
2496             set_title ${(%):-"%n@%m: %~"}
2497             ;;
2498     esac
2499 }
2500
2501 function grml_vcs_to_screen_title () {
2502     if [[ $TERM == screen* ]] ; then
2503         if [[ -n ${vcs_info_msg_1_} ]] ; then
2504             ESC_print ${vcs_info_msg_1_}
2505         else
2506             ESC_print "zsh"
2507         fi
2508     fi
2509 }
2510
2511 function grml_maintain_name () {
2512     # set hostname if not running on host with name 'grml'
2513     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
2514        NAME="@$HOSTNAME"
2515     fi
2516 }
2517
2518 function grml_cmd_to_screen_title () {
2519     # get the name of the program currently running and hostname of local
2520     # machine set screen window title if running in a screen
2521     if [[ "$TERM" == screen* ]] ; then
2522         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME"
2523         ESC_print ${CMD}
2524     fi
2525 }
2526
2527 function grml_control_xterm_title () {
2528     case $TERM in
2529         (xterm*|rxvt*)
2530             set_title "${(%):-"%n@%m:"}" "$2"
2531             ;;
2532     esac
2533 }
2534
2535 # The following autoload is disabled for now, since this setup includes a
2536 # static version of the â€˜add-zsh-hook’ function above. It needs to be
2537 # re-enabled as soon as that static definition is removed again.
2538 #zrcautoload add-zsh-hook || add-zsh-hook () { :; }
2539 if [[ $NOPRECMD -eq 0 ]]; then
2540     add-zsh-hook precmd grml_reset_screen_title
2541     add-zsh-hook precmd grml_vcs_to_screen_title
2542     add-zsh-hook preexec grml_maintain_name
2543     add-zsh-hook preexec grml_cmd_to_screen_title
2544     if [[ $NOTITLE -eq 0 ]]; then
2545         add-zsh-hook preexec grml_control_xterm_title
2546     fi
2547 fi
2548
2549 # 'hash' some often used directories
2550 #d# start
2551 hash -d deb=/var/cache/apt/archives
2552 hash -d doc=/usr/share/doc
2553 hash -d linux=/lib/modules/$(command uname -r)/build/
2554 hash -d log=/var/log
2555 hash -d slog=/var/log/syslog
2556 hash -d src=/usr/src
2557 hash -d www=/var/www
2558 #d# end
2559
2560 # some aliases
2561 if check_com -c screen ; then
2562     if [[ $UID -eq 0 ]] ; then
2563         if [[ -r /etc/grml/screenrc ]]; then
2564             alias screen='screen -c /etc/grml/screenrc'
2565         fi
2566     elif [[ ! -r $HOME/.screenrc ]] ; then
2567         if [[ -r /etc/grml/screenrc_grml ]]; then
2568             alias screen='screen -c /etc/grml/screenrc_grml'
2569         else
2570             if [[ -r /etc/grml/screenrc ]]; then
2571                 alias screen='screen -c /etc/grml/screenrc'
2572             fi
2573         fi
2574     fi
2575 fi
2576
2577 # do we have GNU ls with color-support?
2578 if [[ "$TERM" != dumb ]]; then
2579     #a1# List files with colors (\kbd{ls \ldots})
2580     alias ls="command ls ${ls_options:+${ls_options[*]}}"
2581     #a1# List all files, with colors (\kbd{ls -la \ldots})
2582     alias la="command ls -la ${ls_options:+${ls_options[*]}}"
2583     #a1# List files with long colored list, without dotfiles (\kbd{ls -l \ldots})
2584     alias ll="command ls -l ${ls_options:+${ls_options[*]}}"
2585     #a1# List files with long colored list, human readable sizes (\kbd{ls -hAl \ldots})
2586     alias lh="command ls -hAl ${ls_options:+${ls_options[*]}}"
2587     #a1# List files with long colored list, append qualifier to filenames (\kbd{ls -l \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2588     alias l="command ls -l ${ls_options:+${ls_options[*]}}"
2589 else
2590     alias la='command ls -la'
2591     alias ll='command ls -l'
2592     alias lh='command ls -hAl'
2593     alias l='command ls -l'
2594 fi
2595
2596 if [[ -r /proc/mdstat ]]; then
2597     alias mdstat='cat /proc/mdstat'
2598 fi
2599
2600 alias ...='cd ../../'
2601
2602 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2603 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2604     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2605 fi
2606
2607 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2608 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2609 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2610
2611 # make sure it is not assigned yet
2612 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
2613 function utf2iso () {
2614     if isutfenv ; then
2615         local ENV
2616         for ENV in $(env | command grep -i '.utf') ; do
2617             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2618         done
2619     fi
2620 }
2621
2622 # make sure it is not assigned yet
2623 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
2624 function iso2utf () {
2625     if ! isutfenv ; then
2626         local ENV
2627         for ENV in $(env | command grep -i '\.iso') ; do
2628             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2629         done
2630     fi
2631 }
2632
2633 # especially for roadwarriors using GNU screen and ssh:
2634 if ! check_com asc &>/dev/null ; then
2635   function asc () { autossh -t "$@" 'screen -RdU' }
2636   compdef asc=ssh
2637 fi
2638
2639 #f1# Hints for the use of zsh on grml
2640 function zsh-help () {
2641     print "$bg[white]$fg[black]
2642 zsh-help - hints for use of zsh on grml
2643 =======================================$reset_color"
2644
2645     print '
2646 Main configuration of zsh happens in /etc/zsh/zshrc.
2647 That file is part of the package grml-etc-core, if you want to
2648 use them on a non-grml-system just get the tar.gz from
2649 http://deb.grml.org/ or (preferably) get it from the git repository:
2650
2651   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2652
2653 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2654 The file is still there, but it is empty for backwards compatibility.
2655
2656 For your own changes use these two files:
2657     $HOME/.zshrc.pre
2658     $HOME/.zshrc.local
2659
2660 The former is sourced very early in our zshrc, the latter is sourced
2661 very lately.
2662
2663 System wide configuration without touching configuration files of grml
2664 can take place in /etc/zsh/zshrc.local.
2665
2666 For information regarding zsh start at http://grml.org/zsh/
2667
2668 Take a look at grml'\''s zsh refcard:
2669 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2670
2671 Check out the main zsh refcard:
2672 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2673
2674 And of course visit the zsh-lovers:
2675 % man zsh-lovers
2676
2677 You can adjust some options through environment variables when
2678 invoking zsh without having to edit configuration files.
2679 Basically meant for bash users who are not used to the power of
2680 the zsh yet. :)
2681
2682   "NOCOR=1    zsh" => deactivate automatic correction
2683   "NOMENU=1   zsh" => do not use auto menu completion
2684                       (note: use ctrl-d for completion instead!)
2685   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2686   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
2687                       preexec() and precmd() completely
2688   "GRML_DISPLAY_BATTERY=1  zsh"
2689                    => activate battery status on right side of prompt (WIP)
2690   "COMMAND_NOT_FOUND=1 zsh"
2691                    => Enable a handler if an external command was not found
2692                       The command called in the handler can be altered by setting
2693                       the GRML_ZSH_CNF_HANDLER variable, the default is:
2694                       "/usr/share/command-not-found/command-not-found"
2695
2696 A value greater than 0 is enables a feature; a value equal to zero
2697 disables it. If you like one or the other of these settings, you can
2698 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2699 zshrc.'
2700
2701     print "
2702 $bg[white]$fg[black]
2703 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2704 Enjoy your grml system with the zsh!$reset_color"
2705 }
2706
2707 # debian stuff
2708 if [[ -r /etc/debian_version ]] ; then
2709     if [[ -z "$GRML_NO_APT_ALIASES" ]]; then
2710         #a3# Execute \kbd{apt-cache policy}
2711         alias acp='apt-cache policy'
2712         if check_com -c apt ; then
2713           #a3# Execute \kbd{apt search}
2714           alias acs='apt search'
2715           #a3# Execute \kbd{apt show}
2716           alias acsh='apt show'
2717           #a3# Execute \kbd{apt dist-upgrade}
2718           salias adg="apt dist-upgrade"
2719           #a3# Execute \kbd{apt upgrade}
2720           salias ag="apt upgrade"
2721           #a3# Execute \kbd{apt install}
2722           salias agi="apt install"
2723           #a3# Execute \kbd{apt update}
2724           salias au="apt update"
2725         else
2726           alias acs='apt-cache search'
2727           alias acsh='apt-cache show'
2728           salias adg="apt-get dist-upgrade"
2729           salias ag="apt-get upgrade"
2730           salias agi="apt-get install"
2731           salias au="apt-get update"
2732         fi
2733         #a3# Execute \kbd{aptitude install}
2734         salias ati="aptitude install"
2735         #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2736         salias -a up="aptitude update ; aptitude safe-upgrade"
2737         #a3# Execute \kbd{dpkg-buildpackage}
2738         alias dbp='dpkg-buildpackage'
2739         #a3# Execute \kbd{grep-excuses}
2740         alias ge='grep-excuses'
2741     fi
2742
2743     # get a root shell as normal user in live-cd mode:
2744     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2745        alias su="sudo su"
2746     fi
2747
2748 fi
2749
2750 # use /var/log/syslog iff present, fallback to journalctl otherwise
2751 if [ -e /var/log/syslog ] ; then
2752   #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog || journalctl}
2753   salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2754   #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog || journalctl}
2755   salias tlog="tail -f /var/log/syslog"    # follow the syslog
2756 elif check_com -c journalctl ; then
2757   salias llog="journalctl"
2758   salias tlog="journalctl -f"
2759 fi
2760
2761 # sort installed Debian-packages by size
2762 if check_com -c dpkg-query ; then
2763     #a3# List installed Debian-packages sorted by size
2764     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"
2765 fi
2766
2767 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2768 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
2769     if check_com -c wodim; then
2770         function cdrecord () {
2771             <<__EOF0__
2772 cdrecord is not provided under its original name by Debian anymore.
2773 See #377109 in the BTS of Debian for more details.
2774
2775 Please use the wodim binary instead
2776 __EOF0__
2777             return 1
2778         }
2779     fi
2780 fi
2781
2782 if isgrmlcd; then
2783     # No core dumps: important for a live-cd-system
2784     limit -s core 0
2785 fi
2786
2787 # grmlstuff
2788 function grmlstuff () {
2789 # people should use 'grml-x'!
2790     if check_com -c 915resolution; then
2791         function 855resolution () {
2792             echo "Please use 915resolution as resolution modifying tool for Intel \
2793 graphic chipset."
2794             return -1
2795         }
2796     fi
2797
2798     #a1# Output version of running grml
2799     alias grml-version='cat /etc/grml_version'
2800
2801     if check_com -c grml-debootstrap ; then
2802         function debian2hd () {
2803             echo "Installing debian to harddisk is possible by using grml-debootstrap."
2804             return 1
2805         }
2806     fi
2807 }
2808
2809 # now run the functions
2810 isgrml && checkhome
2811 is4    && isgrml    && grmlstuff
2812 is4    && grmlcomp
2813
2814 # keephack
2815 is4 && xsource "/etc/zsh/keephack"
2816
2817 # wonderful idea of using "e" glob qualifier by Peter Stephenson
2818 # You use it as follows:
2819 # $ NTREF=/reference/file
2820 # $ ls -l *(e:nt:)
2821 # This lists all the files in the current directory newer than the reference file.
2822 # You can also specify the reference file inline; note quotes:
2823 # $ ls -l *(e:'nt ~/.zshenv':)
2824 is4 && function nt () {
2825     if [[ -n $1 ]] ; then
2826         local NTREF=${~1}
2827     fi
2828     [[ $REPLY -nt $NTREF ]]
2829 }
2830
2831 # shell functions
2832
2833 #f1# Reload an autoloadable function
2834 function freload () { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2835 compdef _functions freload
2836
2837 #
2838 # Usage:
2839 #
2840 #      e.g.:   a -> b -> c -> d  ....
2841 #
2842 #      sll a
2843 #
2844 #
2845 #      if parameter is given with leading '=', lookup $PATH for parameter and resolve that
2846 #
2847 #      sll =java
2848 #
2849 #      Note: limit for recursive symlinks on linux:
2850 #            http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/namei.c?id=refs/heads/master#l808
2851 #            This limits recursive symlink follows to 8,
2852 #            while limiting consecutive symlinks to 40.
2853 #
2854 #      When resolving and displaying information about symlinks, no check is made
2855 #      that the displayed information does make any sense on your OS.
2856 #      We leave that decission to the user.
2857 #
2858 #      The zstat module is used to detect symlink loops. zstat is available since zsh4.
2859 #      With an older zsh you will need to abort with <C-c> in that case.
2860 #      When a symlink loop is detected, a warning ist printed and further processing is stopped.
2861 #
2862 #      Module zstat is loaded by default in grml zshrc, no extra action needed for that.
2863 #
2864 #      Known bugs:
2865 #      If you happen to come across a symlink that points to a destination on another partition
2866 #      with the same inode number, that will be marked as symlink loop though it is not.
2867 #      Two hints for this situation:
2868 #      I)  Play lottery the same day, as you seem to be rather lucky right now.
2869 #      II) Send patches.
2870 #
2871 #      return status:
2872 #      0 upon success
2873 #      1 file/dir not accesible
2874 #      2 symlink loop detected
2875 #
2876 #f1# List symlinks in detail (more detailed version of 'readlink -f', 'whence -s' and 'namei -l')
2877 function sll () {
2878     if [[ -z ${1} ]] ; then
2879         printf 'Usage: %s <symlink(s)>\n' "${0}"
2880         return 1
2881     fi
2882
2883     local file jumpd curdir
2884     local -i 10 RTN LINODE i
2885     local -a    SEENINODES
2886     curdir="${PWD}"
2887     RTN=0
2888
2889     for file in "${@}" ; do
2890         SEENINODES=()
2891         ls -l "${file:a}"   || RTN=1
2892
2893         while [[ -h "$file" ]] ; do
2894             if is4 ; then
2895                 LINODE=$(zstat -L +inode "${file}")
2896                 for i in ${SEENINODES} ; do
2897                     if (( ${i} == ${LINODE} )) ; then
2898                         builtin cd -q "${curdir}"
2899                         print 'link loop detected, aborting!'
2900                         return 2
2901                     fi
2902                 done
2903                 SEENINODES+=${LINODE}
2904             fi
2905             jumpd="${file:h}"
2906             file="${file:t}"
2907
2908             if [[ -d ${jumpd} ]] ; then
2909                 builtin cd -q "${jumpd}"  || RTN=1
2910             fi
2911             file=$(readlink "$file")
2912
2913             jumpd="${file:h}"
2914             file="${file:t}"
2915
2916             if [[ -d ${jumpd} ]] ; then
2917                 builtin cd -q "${jumpd}"  || RTN=1
2918             fi
2919
2920             ls -l "${PWD}/${file}"     || RTN=1
2921         done
2922         shift 1
2923         if (( ${#} >= 1 )) ; then
2924             print ""
2925         fi
2926         builtin cd -q "${curdir}"
2927     done
2928     return ${RTN}
2929 }
2930
2931 # TODO: Is it supported to use pager settings like this?
2932 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
2933 # with respect to wordsplitting. (ie. ${=PAGER})
2934 if check_com -c $PAGER ; then
2935     #f3# View Debian's changelog of given package(s)
2936     function dchange () {
2937         emulate -L zsh
2938         [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
2939
2940         local package
2941         for package in "$@" ; do
2942             if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
2943                 $PAGER /usr/share/doc/${package}/changelog.Debian.gz
2944             elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
2945                 $PAGER /usr/share/doc/${package}/changelog.gz
2946             elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
2947                 $PAGER /usr/share/doc/${package}/changelog
2948             else
2949                 if check_com -c aptitude ; then
2950                     echo "No changelog for package $package found, using aptitude to retrieve it."
2951                     aptitude changelog "$package"
2952                 elif check_com -c apt-get ; then
2953                     echo "No changelog for package $package found, using apt-get to retrieve it."
2954                     apt-get changelog "$package"
2955                 else
2956                     echo "No changelog for package $package found, sorry."
2957                 fi
2958             fi
2959         done
2960     }
2961     function _dchange () { _files -W /usr/share/doc -/ }
2962     compdef _dchange dchange
2963
2964     #f3# View Debian's NEWS of a given package
2965     function dnews () {
2966         emulate -L zsh
2967         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2968             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2969         else
2970             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2971                 $PAGER /usr/share/doc/$1/NEWS.gz
2972             else
2973                 echo "No NEWS file for package $1 found, sorry."
2974                 return 1
2975             fi
2976         fi
2977     }
2978     function _dnews () { _files -W /usr/share/doc -/ }
2979     compdef _dnews dnews
2980
2981     #f3# View Debian's copyright of a given package
2982     function dcopyright () {
2983         emulate -L zsh
2984         if [[ -r /usr/share/doc/$1/copyright ]] ; then
2985             $PAGER /usr/share/doc/$1/copyright
2986         else
2987             echo "No copyright file for package $1 found, sorry."
2988             return 1
2989         fi
2990     }
2991     function _dcopyright () { _files -W /usr/share/doc -/ }
2992     compdef _dcopyright dcopyright
2993
2994     #f3# View upstream's changelog of a given package
2995     function uchange () {
2996         emulate -L zsh
2997         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2998             $PAGER /usr/share/doc/$1/changelog.gz
2999         else
3000             echo "No changelog for package $1 found, sorry."
3001             return 1
3002         fi
3003     }
3004     function _uchange () { _files -W /usr/share/doc -/ }
3005     compdef _uchange uchange
3006 fi
3007
3008 # zsh profiling
3009 function profile () {
3010     ZSH_PROFILE_RC=1 zsh "$@"
3011 }
3012
3013 #f1# Edit an alias via zle
3014 function edalias () {
3015     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
3016 }
3017 compdef _aliases edalias
3018
3019 #f1# Edit a function via zle
3020 function edfunc () {
3021     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
3022 }
3023 compdef _functions edfunc
3024
3025 # use it e.g. via 'Restart apache2'
3026 #m# f6 Start() \kbd{service \em{process}}\quad\kbd{start}
3027 #m# f6 Restart() \kbd{service \em{process}}\quad\kbd{restart}
3028 #m# f6 Stop() \kbd{service \em{process}}\quad\kbd{stop}
3029 #m# f6 Reload() \kbd{service \em{process}}\quad\kbd{reload}
3030 #m# f6 Force-Reload() \kbd{service \em{process}}\quad\kbd{force-reload}
3031 #m# f6 Status() \kbd{service \em{process}}\quad\kbd{status}
3032 if [[ -d /etc/init.d || -d /etc/service ]] ; then
3033     function __start_stop () {
3034         local action_="${1:l}"  # e.g Start/Stop/Restart
3035         local service_="$2"
3036         local param_="$3"
3037
3038         local service_target_="$(readlink /etc/init.d/$service_)"
3039         if [[ $service_target_ == "/usr/bin/sv" ]]; then
3040             # runit
3041             case "${action_}" in
3042                 start) if [[ ! -e /etc/service/$service_ ]]; then
3043                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
3044                        else
3045                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
3046                        fi ;;
3047                 # there is no reload in runits sysv emulation
3048                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
3049                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
3050             esac
3051         else
3052             # sysv/sysvinit-utils, upstart
3053             if check_com -c service ; then
3054               $SUDO service "$service_" "${action_}" "$param_"
3055             else
3056               $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
3057             fi
3058         fi
3059     }
3060
3061     function _grmlinitd () {
3062         local -a scripts
3063         scripts=( /etc/init.d/*(x:t) )
3064         _describe "service startup script" scripts
3065     }
3066
3067     for i in Start Restart Stop Force-Reload Reload Status ; do
3068         eval "function $i () { __start_stop $i \"\$1\" \"\$2\" ; }"
3069         compdef _grmlinitd $i
3070     done
3071     builtin unset -v i
3072 fi
3073
3074 #f1# Provides useful information on globbing
3075 function H-Glob () {
3076     echo -e "
3077     /      directories
3078     .      plain files
3079     @      symbolic links
3080     =      sockets
3081     p      named pipes (FIFOs)
3082     *      executable plain files (0100)
3083     %      device files (character or block special)
3084     %b     block special files
3085     %c     character special files
3086     r      owner-readable files (0400)
3087     w      owner-writable files (0200)
3088     x      owner-executable files (0100)
3089     A      group-readable files (0040)
3090     I      group-writable files (0020)
3091     E      group-executable files (0010)
3092     R      world-readable files (0004)
3093     W      world-writable files (0002)
3094     X      world-executable files (0001)
3095     s      setuid files (04000)
3096     S      setgid files (02000)
3097     t      files with the sticky bit (01000)
3098
3099   print *(m-1)          # Files modified up to a day ago
3100   print *(a1)           # Files accessed a day ago
3101   print *(@)            # Just symlinks
3102   print *(Lk+50)        # Files bigger than 50 kilobytes
3103   print *(Lk-50)        # Files smaller than 50 kilobytes
3104   print **/*.c          # All *.c files recursively starting in \$PWD
3105   print **/*.c~file.c   # Same as above, but excluding 'file.c'
3106   print (foo|bar).*     # Files starting with 'foo' or 'bar'
3107   print *~*.*           # All Files that do not contain a dot
3108   chmod 644 *(.^x)      # make all plain non-executable files publically readable
3109   print -l *(.c|.h)     # Lists *.c and *.h
3110   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
3111   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
3112 }
3113 alias help-zshglob=H-Glob
3114
3115 # grep for running process, like: 'any vim'
3116 function any () {
3117     emulate -L zsh
3118     unsetopt KSH_ARRAYS
3119     if [[ -z "$1" ]] ; then
3120         echo "any - grep for process(es) by keyword" >&2
3121         echo "Usage: any <keyword>" >&2 ; return 1
3122     else
3123         ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
3124     fi
3125 }
3126
3127
3128 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
3129 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
3130 [[ -r /proc/1/maps ]] && \
3131 function deswap () {
3132     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
3133     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
3134     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
3135 }
3136
3137 # a wrapper for vim, that deals with title setting
3138 #   VIM_OPTIONS
3139 #       set this array to a set of options to vim you always want
3140 #       to have set when calling vim (in .zshrc.local), like:
3141 #           VIM_OPTIONS=( -p )
3142 #       This will cause vim to send every file given on the
3143 #       commandline to be send to it's own tab (needs vim7).
3144 if check_com vim; then
3145     function vim () {
3146         VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
3147     }
3148 fi
3149
3150 ssl_hashes=( sha512 sha256 sha1 md5 )
3151
3152 for sh in ${ssl_hashes}; do
3153     eval 'ssl-cert-'${sh}'() {
3154         emulate -L zsh
3155         if [[ -z $1 ]] ; then
3156             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
3157             return 1
3158         fi
3159         openssl x509 -noout -fingerprint -'${sh}' -in $1
3160     }'
3161 done; unset sh
3162
3163 function ssl-cert-fingerprints () {
3164     emulate -L zsh
3165     local i
3166     if [[ -z $1 ]] ; then
3167         printf 'usage: ssl-cert-fingerprints <file>\n'
3168         return 1
3169     fi
3170     for i in ${ssl_hashes}
3171         do ssl-cert-$i $1;
3172     done
3173 }
3174
3175 function ssl-cert-info () {
3176     emulate -L zsh
3177     if [[ -z $1 ]] ; then
3178         printf 'usage: ssl-cert-info <file>\n'
3179         return 1
3180     fi
3181     openssl x509 -noout -text -in $1
3182     ssl-cert-fingerprints $1
3183 }
3184
3185 # make sure our environment is clean regarding colors
3186 builtin unset -v BLUE RED GREEN CYAN YELLOW MAGENTA WHITE NO_COLOR
3187
3188 # "persistent history"
3189 # just write important commands you always need to $GRML_IMPORTANT_COMMANDS
3190 # defaults for backward compatibility to ~/.important_commands
3191 if [[ -r ~/.important_commands ]] ; then
3192     GRML_IMPORTANT_COMMANDS=~/.important_commands
3193 else
3194     GRML_IMPORTANT_COMMANDS=${GRML_IMPORTANT_COMMANDS:-${ZDOTDIR:-${HOME}}/.important_commands}
3195 fi
3196 [[ -r ${GRML_IMPORTANT_COMMANDS} ]] && builtin fc -R ${GRML_IMPORTANT_COMMANDS}
3197
3198 # load the lookup subsystem if it's available on the system
3199 zrcautoload lookupinit && lookupinit
3200
3201 # variables
3202
3203 # set terminal property (used e.g. by msgid-chooser)
3204 export COLORTERM="yes"
3205
3206 # aliases
3207
3208 # general
3209 #a2# Execute \kbd{du -sch}
3210 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias da='du -sch'
3211
3212 # listing stuff
3213 #a2# Execute \kbd{ls -lSrah}
3214 alias dir="command ls -lSrah"
3215 #a2# Only show dot-directories
3216 alias lad='command ls -d .*(/)'
3217 #a2# Only show dot-files
3218 alias lsa='command ls -a .*(.)'
3219 #a2# Only files with setgid/setuid/sticky flag
3220 alias lss='command ls -l *(s,S,t)'
3221 #a2# Only show symlinks
3222 alias lsl='command ls -l *(@)'
3223 #a2# Display only executables
3224 alias lsx='command ls -l *(*)'
3225 #a2# Display world-{readable,writable,executable} files
3226 alias lsw='command ls -ld *(R,W,X.^ND/)'
3227 #a2# Display the ten biggest files
3228 alias lsbig="command ls -flh *(.OL[1,10])"
3229 #a2# Only show directories
3230 alias lsd='command ls -d *(/)'
3231 #a2# Only show empty directories
3232 alias lse='command ls -d *(/^F)'
3233 #a2# Display the ten newest files
3234 alias lsnew="command ls -rtlh *(D.om[1,10])"
3235 #a2# Display the ten oldest files
3236 alias lsold="command ls -rtlh *(D.Om[1,10])"
3237 #a2# Display the ten smallest files
3238 alias lssmall="command ls -Srl *(.oL[1,10])"
3239 #a2# Display the ten newest directories and ten newest .directories
3240 alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
3241 #a2# Display the ten oldest directories and ten oldest .directories
3242 alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
3243
3244 # some useful aliases
3245 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
3246 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
3247
3248 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3249 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3250 #a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3251 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3252
3253 # work around non utf8 capable software in utf environment via $LANG and luit
3254 if check_com isutfenv && check_com luit ; then
3255     if check_com -c mrxvt ; then
3256         isutfenv && [[ -n "$LANG" ]] && \
3257             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3258     fi
3259
3260     if check_com -c aterm ; then
3261         isutfenv && [[ -n "$LANG" ]] && \
3262             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3263     fi
3264
3265     if check_com -c centericq ; then
3266         isutfenv && [[ -n "$LANG" ]] && \
3267             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3268     fi
3269 fi
3270
3271 # useful functions
3272
3273 #f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
3274 function bk () {
3275     emulate -L zsh
3276     local current_date=$(date -u "+%Y%m%dT%H%M%SZ")
3277     local clean keep move verbose result all to_bk
3278     setopt extended_glob
3279     keep=1
3280     while getopts ":hacmrv" opt; do
3281         case $opt in
3282             a) (( all++ ));;
3283             c) unset move clean && (( ++keep ));;
3284             m) unset keep clean && (( ++move ));;
3285             r) unset move keep && (( ++clean ));;
3286             v) verbose="-v";;
3287             h) <<__EOF0__
3288 bk [-hcmv] FILE [FILE ...]
3289 bk -r [-av] [FILE [FILE ...]]
3290 Backup a file or folder in place and append the timestamp
3291 Remove backups of a file or folder, or all backups in the current directory
3292
3293 Usage:
3294 -h    Display this help text
3295 -c    Keep the file/folder as is, create a copy backup using cp(1) (default)
3296 -m    Move the file/folder, using mv(1)
3297 -r    Remove backups of the specified file or directory, using rm(1). If none
3298       is provided, remove all backups in the current directory.
3299 -a    Remove all (even hidden) backups.
3300 -v    Verbose
3301
3302 The -c, -r and -m options are mutually exclusive. If specified at the same time,
3303 the last one is used.
3304
3305 The return code is the sum of all cp/mv/rm return codes.
3306 __EOF0__
3307 return 0;;
3308             \?) bk -h >&2; return 1;;
3309         esac
3310     done
3311     shift "$((OPTIND-1))"
3312     if (( keep > 0 )); then
3313         if islinux || isfreebsd; then
3314             for to_bk in "$@"; do
3315                 cp $verbose -a "${to_bk%/}" "${to_bk%/}_$current_date"
3316                 (( result += $? ))
3317             done
3318         else
3319             for to_bk in "$@"; do
3320                 cp $verbose -pR "${to_bk%/}" "${to_bk%/}_$current_date"
3321                 (( result += $? ))
3322             done
3323         fi
3324     elif (( move > 0 )); then
3325         while (( $# > 0 )); do
3326             mv $verbose "${1%/}" "${1%/}_$current_date"
3327             (( result += $? ))
3328             shift
3329         done
3330     elif (( clean > 0 )); then
3331         if (( $# > 0 )); then
3332             for to_bk in "$@"; do
3333                 rm $verbose -rf "${to_bk%/}"_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3334                 (( result += $? ))
3335             done
3336         else
3337             if (( all > 0 )); then
3338                 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z(D)
3339             else
3340                 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
3341             fi
3342             (( result += $? ))
3343         fi
3344     fi
3345     return $result
3346 }
3347
3348 #f5# cd to directory and list files
3349 function cl () {
3350     emulate -L zsh
3351     cd $1 && ls -a
3352 }
3353
3354 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
3355 function cd () {
3356     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
3357         [[ ! -e ${1:h} ]] && return 1
3358         print "Correcting ${1} to ${1:h}"
3359         builtin cd ${1:h}
3360     else
3361         builtin cd "$@"
3362     fi
3363 }
3364
3365 #f5# Create Directory and \kbd{cd} to it
3366 function mkcd () {
3367     if (( ARGC != 1 )); then
3368         printf 'usage: mkcd <new-directory>\n'
3369         return 1;
3370     fi
3371     if [[ ! -d "$1" ]]; then
3372         command mkdir -p "$1"
3373     else
3374         printf '`%s'\'' already exists: cd-ing.\n' "$1"
3375     fi
3376     builtin cd "$1"
3377 }
3378
3379 #f5# Create temporary directory and \kbd{cd} to it
3380 function cdt () {
3381     builtin cd "$(mktemp -d)"
3382     builtin pwd
3383 }
3384
3385 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3386 function accessed () {
3387     emulate -L zsh
3388     print -l -- *(a-${1:-1})
3389 }
3390
3391 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3392 function changed () {
3393     emulate -L zsh
3394     print -l -- *(c-${1:-1})
3395 }
3396
3397 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3398 function modified () {
3399     emulate -L zsh
3400     print -l -- *(m-${1:-1})
3401 }
3402 # modified() was named new() in earlier versions, add an alias for backwards compatibility
3403 check_com new || alias new=modified
3404
3405 # use colors when GNU grep with color-support
3406 if (( $#grep_options > 0 )); then
3407     o=${grep_options:+"${grep_options[*]}"}
3408     #a2# Execute \kbd{grep -{}-color=auto}
3409     alias grep='grep '$o
3410     alias egrep='egrep '$o
3411     unset o
3412 fi
3413
3414 # Translate DE<=>EN
3415 # 'translate' looks up a word in a file with language-to-language
3416 # translations (field separator should be " : "). A typical wordlist looks
3417 # like the following:
3418 #  | english-word : german-translation
3419 # It's also only possible to translate english to german but not reciprocal.
3420 # Use the following oneliner to reverse the sort order:
3421 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3422 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3423 #f5# Translates a word
3424 function trans () {
3425     emulate -L zsh
3426     case "$1" in
3427         -[dD]*)
3428             translate -l de-en $2
3429             ;;
3430         -[eE]*)
3431             translate -l en-de $2
3432             ;;
3433         *)
3434             echo "Usage: $0 { -D | -E }"
3435             echo "         -D == German to English"
3436             echo "         -E == English to German"
3437     esac
3438 }
3439
3440 # Usage: simple-extract <file>
3441 # Using option -d deletes the original archive file.
3442 #f5# Smart archive extractor
3443 function simple-extract () {
3444     emulate -L zsh
3445     setopt extended_glob noclobber
3446     local ARCHIVE DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
3447     local RC=0
3448     zparseopts -D -E "d=DELETE_ORIGINAL"
3449     for ARCHIVE in "${@}"; do
3450         case $ARCHIVE in
3451             *(tar.bz2|tbz2|tbz))
3452                 DECOMP_CMD="tar -xvjf -"
3453                 USES_STDIN=true
3454                 USES_STDOUT=false
3455                 ;;
3456             *(tar.gz|tgz))
3457                 DECOMP_CMD="tar -xvzf -"
3458                 USES_STDIN=true
3459                 USES_STDOUT=false
3460                 ;;
3461             *(tar.xz|txz|tar.lzma))
3462                 DECOMP_CMD="tar -xvJf -"
3463                 USES_STDIN=true
3464                 USES_STDOUT=false
3465                 ;;
3466             *tar)
3467                 DECOMP_CMD="tar -xvf -"
3468                 USES_STDIN=true
3469                 USES_STDOUT=false
3470                 ;;
3471             *rar)
3472                 DECOMP_CMD="unrar x"
3473                 USES_STDIN=false
3474                 USES_STDOUT=false
3475                 ;;
3476             *lzh)
3477                 DECOMP_CMD="lha x"
3478                 USES_STDIN=false
3479                 USES_STDOUT=false
3480                 ;;
3481             *7z)
3482                 DECOMP_CMD="7z x"
3483                 USES_STDIN=false
3484                 USES_STDOUT=false
3485                 ;;
3486             *(zip|jar))
3487                 DECOMP_CMD="unzip"
3488                 USES_STDIN=false
3489                 USES_STDOUT=false
3490                 ;;
3491             *deb)
3492                 DECOMP_CMD="ar -x"
3493                 USES_STDIN=false
3494                 USES_STDOUT=false
3495                 ;;
3496             *bz2)
3497                 DECOMP_CMD="bzip2 -d -c -"
3498                 USES_STDIN=true
3499                 USES_STDOUT=true
3500                 ;;
3501             *(gz|Z))
3502                 DECOMP_CMD="gzip -d -c -"
3503                 USES_STDIN=true
3504                 USES_STDOUT=true
3505                 ;;
3506             *(xz|lzma))
3507                 DECOMP_CMD="xz -d -c -"
3508                 USES_STDIN=true
3509                 USES_STDOUT=true
3510                 ;;
3511             *)
3512                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3513                 RC=$((RC+1))
3514                 continue
3515                 ;;
3516         esac
3517
3518         if ! check_com ${DECOMP_CMD[(w)1]}; then
3519             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3520             RC=$((RC+2))
3521             continue
3522         fi
3523
3524         GZTARGET="${ARCHIVE:t:r}"
3525         if [[ -f $ARCHIVE ]] ; then
3526
3527             print "Extracting '$ARCHIVE' ..."
3528             if $USES_STDIN; then
3529                 if $USES_STDOUT; then
3530                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3531                 else
3532                     ${=DECOMP_CMD} < "$ARCHIVE"
3533                 fi
3534             else
3535                 if $USES_STDOUT; then
3536                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3537                 else
3538                     ${=DECOMP_CMD} "$ARCHIVE"
3539                 fi
3540             fi
3541             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3542
3543         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3544             if check_com curl; then
3545                 WGET_CMD="curl -L -s -o -"
3546             elif check_com wget; then
3547                 WGET_CMD="wget -q -O -"
3548             elif check_com fetch; then
3549                 WGET_CMD="fetch -q -o -"
3550             else
3551                 print "ERROR: neither wget, curl nor fetch is installed" >&2
3552                 RC=$((RC+4))
3553                 continue
3554             fi
3555             print "Downloading and Extracting '$ARCHIVE' ..."
3556             if $USES_STDIN; then
3557                 if $USES_STDOUT; then
3558                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3559                     RC=$((RC+$?))
3560                 else
3561                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3562                     RC=$((RC+$?))
3563                 fi
3564             else
3565                 if $USES_STDOUT; then
3566                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3567                 else
3568                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3569                 fi
3570             fi
3571
3572         else
3573             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3574             RC=$((RC+8))
3575         fi
3576     done
3577     return $RC
3578 }
3579
3580 function __archive_or_uri () {
3581     _alternative \
3582         '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)"' \
3583         '_urls:Remote Archives:_urls'
3584 }
3585
3586 function _simple_extract () {
3587     _arguments \
3588         '-d[delete original archivefile after extraction]' \
3589         '*:Archive Or Uri:__archive_or_uri'
3590 }
3591 compdef _simple_extract simple-extract
3592 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias se=simple-extract
3593
3594 #f5# Change the xterm title from within GNU-screen
3595 function xtrename () {
3596     emulate -L zsh
3597     if [[ $1 != "-f" ]] ; then
3598         if [[ -z ${DISPLAY} ]] ; then
3599             printf 'xtrename only makes sense in X11.\n'
3600             return 1
3601         fi
3602     else
3603         shift
3604     fi
3605     if [[ -z $1 ]] ; then
3606         printf 'usage: xtrename [-f] "title for xterm"\n'
3607         printf '  renames the title of xterm from _within_ screen.\n'
3608         printf '  also works without screen.\n'
3609         printf '  will not work if DISPLAY is unset, use -f to override.\n'
3610         return 0
3611     fi
3612     print -n "\eP\e]0;${1}\C-G\e\\"
3613     return 0
3614 }
3615
3616 # Create small urls via http://goo.gl using curl(1).
3617 # API reference: https://code.google.com/apis/urlshortener/
3618 function zurl () {
3619     emulate -L zsh
3620     setopt extended_glob
3621
3622     if [[ -z $1 ]]; then
3623         print "USAGE: zurl <URL>"
3624         return 1
3625     fi
3626
3627     local PN url prog api json contenttype item
3628     local -a data
3629     PN=$0
3630     url=$1
3631
3632     # Prepend 'http://' to given URL where necessary for later output.
3633     if [[ ${url} != http(s|)://* ]]; then
3634         url='http://'${url}
3635     fi
3636
3637     if check_com -c curl; then
3638         prog=curl
3639     else
3640         print "curl is not available, but mandatory for ${PN}. Aborting."
3641         return 1
3642     fi
3643     api='https://www.googleapis.com/urlshortener/v1/url'
3644     contenttype="Content-Type: application/json"
3645     json="{\"longUrl\": \"${url}\"}"
3646     data=(${(f)"$($prog --silent -H ${contenttype} -d ${json} $api)"})
3647     # Parse the response
3648     for item in "${data[@]}"; do
3649         case "$item" in
3650             ' '#'"id":'*)
3651                 item=${item#*: \"}
3652                 item=${item%\",*}
3653                 printf '%s\n' "$item"
3654                 return 0
3655                 ;;
3656         esac
3657     done
3658     return 1
3659 }
3660
3661 #f2# Find history events by search pattern and list them by date.
3662 function whatwhen () {
3663     emulate -L zsh
3664     local usage help ident format_l format_s first_char remain first last
3665     usage='USAGE: whatwhen [options] <searchstring> <search range>'
3666     help='Use `whatwhen -h'\'' for further explanations.'
3667     ident=${(l,${#${:-Usage: }},, ,)}
3668     format_l="${ident}%s\t\t\t%s\n"
3669     format_s="${format_l//(\\t)##/\\t}"
3670     # Make the first char of the word to search for case
3671     # insensitive; e.g. [aA]
3672     first_char=[${(L)1[1]}${(U)1[1]}]
3673     remain=${1[2,-1]}
3674     # Default search range is `-100'.
3675     first=${2:-\-100}
3676     # Optional, just used for `<first> <last>' given.
3677     last=$3
3678     case $1 in
3679         ("")
3680             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3681             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3682         ;;
3683         (-h)
3684             printf '%s\n\n' ${usage}
3685             print 'OPTIONS:'
3686             printf $format_l '-h' 'show help text'
3687             print '\f'
3688             print 'SEARCH RANGE:'
3689             printf $format_l "'0'" 'the whole history,'
3690             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3691             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3692             printf '\n%s\n' 'EXAMPLES:'
3693             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3694             printf $format_l 'whatwhen zsh -250'
3695             printf $format_l 'whatwhen foo 1 99'
3696         ;;
3697         (\?)
3698             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3699         ;;
3700         (*)
3701             # -l list results on stout rather than invoking $EDITOR.
3702             # -i Print dates as in YYYY-MM-DD.
3703             # -m Search for a - quoted - pattern within the history.
3704             fc -li -m "*${first_char}${remain}*" $first $last
3705         ;;
3706     esac
3707 }
3708
3709 # mercurial related stuff
3710 if check_com -c hg ; then
3711     # gnu like diff for mercurial
3712     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3713     #f5# GNU like diff for mercurial
3714     function hgdi () {
3715         emulate -L zsh
3716         local i
3717         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3718     }
3719
3720     # build debian package
3721     #a2# Alias for \kbd{hg-buildpackage}
3722     alias hbp='hg-buildpackage'
3723
3724     # execute commands on the versioned patch-queue from the current repos
3725     [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3726
3727     # diffstat for specific version of a mercurial repository
3728     #   hgstat      => display diffstat between last revision and tip
3729     #   hgstat 1234 => display diffstat between revision 1234 and tip
3730     #f5# Diffstat for specific version of a mercurial repos
3731     function hgstat () {
3732         emulate -L zsh
3733         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3734     }
3735
3736 fi # end of check whether we have the 'hg'-executable
3737
3738 # disable bracketed paste mode for dumb terminals
3739 [[ "$TERM" == dumb ]] && unset zle_bracketed_paste
3740
3741 # grml-small cleanups and workarounds
3742
3743 # The following is used to remove zsh-config-items that do not work
3744 # in grml-small by default.
3745 # If you do not want these adjustments (for whatever reason), set
3746 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3747 # sources if it is there).
3748
3749 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3750
3751     # Clean up
3752
3753     unset "abk[V]"
3754     unalias    'V'      &> /dev/null
3755     unfunction vman     &> /dev/null
3756     unfunction viless   &> /dev/null
3757     unfunction 2html    &> /dev/null
3758
3759     # manpages are not in grmlsmall
3760     unfunction manzsh   &> /dev/null
3761     unfunction man2     &> /dev/null
3762
3763     # Workarounds
3764
3765     # See https://github.com/grml/grml/issues/56
3766     if ! [[ -x ${commands[dig]} ]]; then
3767         function dig_after_all () {
3768             unfunction dig
3769             unfunction _dig
3770             autoload -Uz _dig
3771             unfunction dig_after_all
3772         }
3773         function dig () {
3774             if [[ -x ${commands[dig]} ]]; then
3775                 dig_after_all
3776                 command dig "$@"
3777                 return "$!"
3778             fi
3779             printf 'This installation does not include `dig'\'' for size reasons.\n'
3780             printf 'Try `drill'\'' as a light weight alternative.\n'
3781             return 0
3782         }
3783         function _dig () {
3784             if [[ -x ${commands[dig]} ]]; then
3785                 dig_after_all
3786                 zle -M 'Found `dig'\'' installed. '
3787             else
3788                 zle -M 'Try `drill'\'' instead of `dig'\''.'
3789             fi
3790         }
3791         compdef _dig dig
3792     fi
3793 fi
3794
3795 zrclocal
3796
3797 ## genrefcard.pl settings
3798
3799 ### doc strings for external functions from files
3800 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3801
3802 ### example: split functions-search 8,16,24,32
3803 #@# split functions-search 8
3804
3805 ## END OF FILE #################################################################
3806 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3807 # Local variables:
3808 # mode: sh
3809 # End: