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