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