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