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