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