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