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