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