add issolaris()
[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 -F \ldots})
2445     alias ls='command ls -F '${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 -lF \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2453     alias l='command ls -lF '${ls_options:+"${ls_options[*]}"}
2454 else
2455     alias ls='command ls -F'
2456     alias la='command ls -la'
2457     alias ll='command ls -l'
2458     alias lh='command ls -hAl'
2459     alias l='command ls -lF'
2460 fi
2461
2462 alias mdstat='cat /proc/mdstat'
2463 alias ...='cd ../../'
2464
2465 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2466 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2467     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2468 fi
2469
2470 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2471 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2472 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2473
2474 # make sure it is not assigned yet
2475 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
2476 utf2iso() {
2477     if isutfenv ; then
2478         for ENV in $(env | command grep -i '.utf') ; do
2479             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2480         done
2481     fi
2482 }
2483
2484 # make sure it is not assigned yet
2485 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
2486 iso2utf() {
2487     if ! isutfenv ; then
2488         for ENV in $(env | command grep -i '\.iso') ; do
2489             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2490         done
2491     fi
2492 }
2493
2494 # especially for roadwarriors using GNU screen and ssh:
2495 if ! check_com asc &>/dev/null ; then
2496   asc() { autossh -t "$@" 'screen -RdU' }
2497   compdef asc=ssh
2498 fi
2499
2500 #f1# Hints for the use of zsh on grml
2501 zsh-help() {
2502     print "$bg[white]$fg[black]
2503 zsh-help - hints for use of zsh on grml
2504 =======================================$reset_color"
2505
2506     print '
2507 Main configuration of zsh happens in /etc/zsh/zshrc.
2508 That file is part of the package grml-etc-core, if you want to
2509 use them on a non-grml-system just get the tar.gz from
2510 http://deb.grml.org/ or (preferably) get it from the git repository:
2511
2512   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2513
2514 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2515 The file is still there, but it is empty for backwards compatibility.
2516
2517 For your own changes use these two files:
2518     $HOME/.zshrc.pre
2519     $HOME/.zshrc.local
2520
2521 The former is sourced very early in our zshrc, the latter is sourced
2522 very lately.
2523
2524 System wide configuration without touching configuration files of grml
2525 can take place in /etc/zsh/zshrc.local.
2526
2527 For information regarding zsh start at http://grml.org/zsh/
2528
2529 Take a look at grml'\''s zsh refcard:
2530 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2531
2532 Check out the main zsh refcard:
2533 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2534
2535 And of course visit the zsh-lovers:
2536 % man zsh-lovers
2537
2538 You can adjust some options through environment variables when
2539 invoking zsh without having to edit configuration files.
2540 Basically meant for bash users who are not used to the power of
2541 the zsh yet. :)
2542
2543   "NOCOR=1    zsh" => deactivate automatic correction
2544   "NOMENU=1   zsh" => do not use auto menu completion
2545                       (note: use ctrl-d for completion instead!)
2546   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2547   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
2548                       preexec() and precmd() completely
2549   "GRML_DISPLAY_BATTERY=1  zsh"
2550                    => activate battery status on right side of prompt (WIP)
2551   "COMMAND_NOT_FOUND=1 zsh"
2552                    => Enable a handler if an external command was not found
2553                       The command called in the handler can be altered by setting
2554                       the GRML_ZSH_CNF_HANDLER variable, the default is:
2555                       "/usr/share/command-not-found/command-not-found"
2556
2557 A value greater than 0 is enables a feature; a value equal to zero
2558 disables it. If you like one or the other of these settings, you can
2559 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2560 zshrc.'
2561
2562     print "
2563 $bg[white]$fg[black]
2564 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2565 Enjoy your grml system with the zsh!$reset_color"
2566 }
2567
2568 # debian stuff
2569 if [[ -r /etc/debian_version ]] ; then
2570     #a3# Execute \kbd{apt-cache search}
2571     alias acs='apt-cache search'
2572     #a3# Execute \kbd{apt-cache show}
2573     alias acsh='apt-cache show'
2574     #a3# Execute \kbd{apt-cache policy}
2575     alias acp='apt-cache policy'
2576     #a3# Execute \kbd{apt-get dist-upgrade}
2577     salias adg="apt-get dist-upgrade"
2578     #a3# Execute \kbd{apt-get install}
2579     salias agi="apt-get install"
2580     #a3# Execute \kbd{aptitude install}
2581     salias ati="aptitude install"
2582     #a3# Execute \kbd{apt-get upgrade}
2583     salias ag="apt-get upgrade"
2584     #a3# Execute \kbd{apt-get update}
2585     salias au="apt-get update"
2586     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2587     salias -a up="aptitude update ; aptitude safe-upgrade"
2588     #a3# Execute \kbd{dpkg-buildpackage}
2589     alias dbp='dpkg-buildpackage'
2590     #a3# Execute \kbd{grep-excuses}
2591     alias ge='grep-excuses'
2592
2593     # get a root shell as normal user in live-cd mode:
2594     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2595        alias su="sudo su"
2596     fi
2597
2598     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2599     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2600     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2601     salias tlog="tail -f /var/log/syslog"    # follow the syslog
2602 fi
2603
2604 # sort installed Debian-packages by size
2605 if check_com -c dpkg-query ; then
2606     #a3# List installed Debian-packages sorted by size
2607     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"
2608 fi
2609
2610 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2611 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
2612     if check_com -c wodim; then
2613         cdrecord() {
2614             cat <<EOMESS
2615 cdrecord is not provided under its original name by Debian anymore.
2616 See #377109 in the BTS of Debian for more details.
2617
2618 Please use the wodim binary instead
2619 EOMESS
2620             return 1
2621         }
2622     fi
2623 fi
2624
2625 # Use hard limits, except for a smaller stack and no core dumps
2626 unlimit
2627 is425 && limit stack 8192
2628 isgrmlcd && limit core 0 # important for a live-cd-system
2629 limit -s
2630
2631 # grmlstuff
2632 grmlstuff() {
2633 # people should use 'grml-x'!
2634     if check_com -c 915resolution; then
2635         855resolution() {
2636             echo "Please use 915resolution as resolution modifying tool for Intel \
2637 graphic chipset."
2638             return -1
2639         }
2640     fi
2641
2642     #a1# Output version of running grml
2643     alias grml-version='cat /etc/grml_version'
2644
2645     if check_com -c grml-debootstrap ; then
2646         debian2hd() {
2647             echo "Installing debian to harddisk is possible by using grml-debootstrap."
2648             return 1
2649         }
2650     fi
2651 }
2652
2653 # now run the functions
2654 isgrml && checkhome
2655 is4    && isgrml    && grmlstuff
2656 is4    && grmlcomp
2657
2658 # keephack
2659 is4 && xsource "/etc/zsh/keephack"
2660
2661 # wonderful idea of using "e" glob qualifier by Peter Stephenson
2662 # You use it as follows:
2663 # $ NTREF=/reference/file
2664 # $ ls -l *(e:nt:)
2665 # This lists all the files in the current directory newer than the reference file.
2666 # You can also specify the reference file inline; note quotes:
2667 # $ ls -l *(e:'nt ~/.zshenv':)
2668 is4 && nt() {
2669     if [[ -n $1 ]] ; then
2670         local NTREF=${~1}
2671     fi
2672     [[ $REPLY -nt $NTREF ]]
2673 }
2674
2675 # shell functions
2676
2677 #f1# Reload an autoloadable function
2678 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2679 compdef _functions freload
2680
2681 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2682 sll() {
2683     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2684     local file
2685     for file in "$@" ; do
2686         while [[ -h "$file" ]] ; do
2687             ls -l $file
2688             file=$(readlink "$file")
2689         done
2690     done
2691 }
2692
2693 # TODO: Is it supported to use pager settings like this?
2694 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
2695 # with respect to wordsplitting. (ie. ${=PAGER})
2696 if check_com -c $PAGER ; then
2697     #f3# View Debian's changelog of given package(s)
2698     dchange() {
2699         emulate -L zsh
2700         [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
2701
2702         local package
2703         for package in "$@" ; do
2704             if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
2705                 $PAGER /usr/share/doc/${package}/changelog.Debian.gz
2706             elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
2707                 $PAGER /usr/share/doc/${package}/changelog.gz
2708             elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
2709                 $PAGER /usr/share/doc/${package}/changelog
2710             else
2711                 if check_com -c aptitude ; then
2712                     echo "No changelog for package $package found, using aptitude to retrieve it."
2713                     aptitude changelog "$package"
2714                 elif check_com -c apt-get ; then
2715                     echo "No changelog for package $package found, using apt-get to retrieve it."
2716                     apt-get changelog "$package"
2717                 else
2718                     echo "No changelog for package $package found, sorry."
2719                 fi
2720             fi
2721         done
2722     }
2723     _dchange() { _files -W /usr/share/doc -/ }
2724     compdef _dchange dchange
2725
2726     #f3# View Debian's NEWS of a given package
2727     dnews() {
2728         emulate -L zsh
2729         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2730             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2731         else
2732             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2733                 $PAGER /usr/share/doc/$1/NEWS.gz
2734             else
2735                 echo "No NEWS file for package $1 found, sorry."
2736                 return 1
2737             fi
2738         fi
2739     }
2740     _dnews() { _files -W /usr/share/doc -/ }
2741     compdef _dnews dnews
2742
2743     #f3# View Debian's copyright of a given package
2744     dcopyright() {
2745         emulate -L zsh
2746         if [[ -r /usr/share/doc/$1/copyright ]] ; then
2747             $PAGER /usr/share/doc/$1/copyright
2748         else
2749             echo "No copyright file for package $1 found, sorry."
2750             return 1
2751         fi
2752     }
2753     _dcopyright() { _files -W /usr/share/doc -/ }
2754     compdef _dcopyright dcopyright
2755
2756     #f3# View upstream's changelog of a given package
2757     uchange() {
2758         emulate -L zsh
2759         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2760             $PAGER /usr/share/doc/$1/changelog.gz
2761         else
2762             echo "No changelog for package $1 found, sorry."
2763             return 1
2764         fi
2765     }
2766     _uchange() { _files -W /usr/share/doc -/ }
2767     compdef _uchange uchange
2768 fi
2769
2770 # zsh profiling
2771 profile() {
2772     ZSH_PROFILE_RC=1 $SHELL "$@"
2773 }
2774
2775 #f1# Edit an alias via zle
2776 edalias() {
2777     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2778 }
2779 compdef _aliases edalias
2780
2781 #f1# Edit a function via zle
2782 edfunc() {
2783     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2784 }
2785 compdef _functions edfunc
2786
2787 # use it e.g. via 'Restart apache2'
2788 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2789 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2790 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2791 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2792 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2793 #m# f6 Status() \kbd{/etc/init.d/\em{process}}\quad\kbd{status}
2794 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2795     __start_stop() {
2796         local action_="${1:l}"  # e.g Start/Stop/Restart
2797         local service_="$2"
2798         local param_="$3"
2799
2800         local service_target_="$(readlink /etc/init.d/$service_)"
2801         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2802             # runit
2803             case "${action_}" in
2804                 start) if [[ ! -e /etc/service/$service_ ]]; then
2805                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2806                        else
2807                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2808                        fi ;;
2809                 # there is no reload in runits sysv emulation
2810                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2811                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2812             esac
2813         else
2814             # sysvinit
2815             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2816         fi
2817     }
2818
2819     _grmlinitd() {
2820         local -a scripts
2821         scripts=( /etc/init.d/*(x:t) )
2822         _describe "service startup script" scripts
2823     }
2824
2825     for i in Start Restart Stop Force-Reload Reload Status ; do
2826         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2827         compdef _grmlinitd $i
2828     done
2829 fi
2830
2831 #f1# Provides useful information on globbing
2832 H-Glob() {
2833     echo -e "
2834     /      directories
2835     .      plain files
2836     @      symbolic links
2837     =      sockets
2838     p      named pipes (FIFOs)
2839     *      executable plain files (0100)
2840     %      device files (character or block special)
2841     %b     block special files
2842     %c     character special files
2843     r      owner-readable files (0400)
2844     w      owner-writable files (0200)
2845     x      owner-executable files (0100)
2846     A      group-readable files (0040)
2847     I      group-writable files (0020)
2848     E      group-executable files (0010)
2849     R      world-readable files (0004)
2850     W      world-writable files (0002)
2851     X      world-executable files (0001)
2852     s      setuid files (04000)
2853     S      setgid files (02000)
2854     t      files with the sticky bit (01000)
2855
2856   print *(m-1)          # Files modified up to a day ago
2857   print *(a1)           # Files accessed a day ago
2858   print *(@)            # Just symlinks
2859   print *(Lk+50)        # Files bigger than 50 kilobytes
2860   print *(Lk-50)        # Files smaller than 50 kilobytes
2861   print **/*.c          # All *.c files recursively starting in \$PWD
2862   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2863   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2864   print *~*.*           # All Files that do not contain a dot
2865   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2866   print -l *(.c|.h)     # Lists *.c and *.h
2867   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2868   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2869 }
2870 alias help-zshglob=H-Glob
2871
2872 # grep for running process, like: 'any vim'
2873 any() {
2874     emulate -L zsh
2875     unsetopt KSH_ARRAYS
2876     if [[ -z "$1" ]] ; then
2877         echo "any - grep for process(es) by keyword" >&2
2878         echo "Usage: any <keyword>" >&2 ; return 1
2879     else
2880         ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
2881     fi
2882 }
2883
2884
2885 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2886 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2887 [[ -r /proc/1/maps ]] && \
2888 deswap() {
2889     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2890     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2891     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2892 }
2893
2894 # a wrapper for vim, that deals with title setting
2895 #   VIM_OPTIONS
2896 #       set this array to a set of options to vim you always want
2897 #       to have set when calling vim (in .zshrc.local), like:
2898 #           VIM_OPTIONS=( -p )
2899 #       This will cause vim to send every file given on the
2900 #       commandline to be send to it's own tab (needs vim7).
2901 if check_com vim; then
2902     vim() {
2903         VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2904     }
2905 fi
2906
2907 ssl_hashes=( sha512 sha256 sha1 md5 )
2908
2909 for sh in ${ssl_hashes}; do
2910     eval 'ssl-cert-'${sh}'() {
2911         emulate -L zsh
2912         if [[ -z $1 ]] ; then
2913             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2914             return 1
2915         fi
2916         openssl x509 -noout -fingerprint -'${sh}' -in $1
2917     }'
2918 done; unset sh
2919
2920 ssl-cert-fingerprints() {
2921     emulate -L zsh
2922     local i
2923     if [[ -z $1 ]] ; then
2924         printf 'usage: ssl-cert-fingerprints <file>\n'
2925         return 1
2926     fi
2927     for i in ${ssl_hashes}
2928         do ssl-cert-$i $1;
2929     done
2930 }
2931
2932 ssl-cert-info() {
2933     emulate -L zsh
2934     if [[ -z $1 ]] ; then
2935         printf 'usage: ssl-cert-info <file>\n'
2936         return 1
2937     fi
2938     openssl x509 -noout -text -in $1
2939     ssl-cert-fingerprints $1
2940 }
2941
2942 # make sure our environment is clean regarding colors
2943 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2944
2945 # "persistent history"
2946 # just write important commands you always need to ~/.important_commands
2947 if [[ -r ~/.important_commands ]] ; then
2948     fc -R ~/.important_commands
2949 fi
2950
2951 # load the lookup subsystem if it's available on the system
2952 zrcautoload lookupinit && lookupinit
2953
2954 # variables
2955
2956 # set terminal property (used e.g. by msgid-chooser)
2957 export COLORTERM="yes"
2958
2959 # aliases
2960
2961 # general
2962 #a2# Execute \kbd{du -sch}
2963 alias da='du -sch'
2964
2965 # listing stuff
2966 #a2# Execute \kbd{ls -lSrah}
2967 alias dir="command ls -lSrah"
2968 #a2# Only show dot-directories
2969 alias lad='command ls -d .*(/)'
2970 #a2# Only show dot-files
2971 alias lsa='command ls -a .*(.)'
2972 #a2# Only files with setgid/setuid/sticky flag
2973 alias lss='command ls -l *(s,S,t)'
2974 #a2# Only show symlinks
2975 alias lsl='command ls -l *(@)'
2976 #a2# Display only executables
2977 alias lsx='command ls -l *(*)'
2978 #a2# Display world-{readable,writable,executable} files
2979 alias lsw='command ls -ld *(R,W,X.^ND/)'
2980 #a2# Display the ten biggest files
2981 alias lsbig="command ls -flh *(.OL[1,10])"
2982 #a2# Only show directories
2983 alias lsd='command ls -d *(/)'
2984 #a2# Only show empty directories
2985 alias lse='command ls -d *(/^F)'
2986 #a2# Display the ten newest files
2987 alias lsnew="command ls -rtlh *(D.om[1,10])"
2988 #a2# Display the ten oldest files
2989 alias lsold="command ls -rtlh *(D.Om[1,10])"
2990 #a2# Display the ten smallest files
2991 alias lssmall="command ls -Srl *(.oL[1,10])"
2992 #a2# Display the ten newest directories and ten newest .directories
2993 alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
2994 #a2# Display the ten oldest directories and ten oldest .directories
2995 alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
2996
2997 # some useful aliases
2998 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
2999 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
3000
3001 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3002 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3003 #a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3004 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3005
3006 # work around non utf8 capable software in utf environment via $LANG and luit
3007 if check_com isutfenv && check_com luit ; then
3008     if check_com -c mrxvt ; then
3009         isutfenv && [[ -n "$LANG" ]] && \
3010             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3011     fi
3012
3013     if check_com -c aterm ; then
3014         isutfenv && [[ -n "$LANG" ]] && \
3015             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3016     fi
3017
3018     if check_com -c centericq ; then
3019         isutfenv && [[ -n "$LANG" ]] && \
3020             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3021     fi
3022 fi
3023
3024 # useful functions
3025
3026 #f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
3027 bk() {
3028     emulate -L zsh
3029     local current_date=$(date -u "+%Y-%m-%dT%H:%M:%SZ")
3030     local clean keep move verbose result
3031     setopt extended_glob
3032     usage() {
3033         cat << EOT
3034 bk [-hcmv] FILE [FILE ...]
3035 bk -r [-v] [FILE [FILE ...]]
3036 Backup a file or folder in place and append the timestamp
3037 Remove backups of a file or folder, or all backups in the current directory
3038
3039 Usage:
3040 -h    Display this help text
3041 -c    Keep the file/folder as is, create a copy backup using cp(1) (default)
3042 -m    Move the file/folder, using mv(1)
3043 -r    Remove backups of the specified file or directory, using rm(1). If none
3044       is provided, remove all backups in the current directory.
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 ":hcmrv" opt; do
3055         case $opt in
3056             c) unset move clean && (( ++keep ));;
3057             m) unset keep clean && (( ++move ));;
3058             r) unset move keep && (( ++clean ));;
3059             v) verbose="-v";;
3060             h) usage;;
3061             \?) usage >&2; return 1;;
3062         esac
3063     done
3064     shift "$((OPTIND-1))"
3065     if (( keep > 0 )); then
3066         while (( $# > 0 )); do
3067             if islinux || isfreebsd; then
3068                 cp $verbose -a "${1%/}" "${1%/}_$current_date"
3069             else
3070                 cp $verbose -pR "${1%/}" "${1%/}_$current_date"
3071             fi
3072             (( result += $? ))
3073             shift
3074         done
3075     elif (( move > 0 )); then
3076         while (( $# > 0 )); do
3077             mv $verbose "${1%/}" "${1%/}_$current_date"
3078             (( result += $? ))
3079             shift
3080         done
3081     elif (( clean > 0 )); then
3082         if (( $# > 0 )); then
3083             while (( $# > 0 )); do
3084                 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
3085                 (( result += $? ))
3086                 shift
3087             done
3088         else
3089             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
3090             (( result += $? ))
3091         fi
3092     fi
3093     return $result
3094 }
3095
3096 #f5# cd to directoy and list files
3097 cl() {
3098     emulate -L zsh
3099     cd $1 && ls -a
3100 }
3101
3102 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
3103 cd() {
3104     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
3105         [[ ! -e ${1:h} ]] && return 1
3106         print "Correcting ${1} to ${1:h}"
3107         builtin cd ${1:h}
3108     else
3109         builtin cd "$@"
3110     fi
3111 }
3112
3113 #f5# Create Directoy and \kbd{cd} to it
3114 mkcd() {
3115     if (( ARGC != 1 )); then
3116         printf 'usage: mkcd <new-directory>\n'
3117         return 1;
3118     fi
3119     if [[ ! -d "$1" ]]; then
3120         command mkdir -p "$1"
3121     else
3122         printf '`%s'\'' already exists: cd-ing.\n' "$1"
3123     fi
3124     builtin cd "$1"
3125 }
3126
3127 #f5# Create temporary directory and \kbd{cd} to it
3128 cdt() {
3129     local t
3130     t=$(mktemp -d)
3131     echo "$t"
3132     builtin cd "$t"
3133 }
3134
3135 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3136 accessed() {
3137     emulate -L zsh
3138     print -l -- *(a-${1:-1})
3139 }
3140
3141 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3142 changed() {
3143     emulate -L zsh
3144     print -l -- *(c-${1:-1})
3145 }
3146
3147 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3148 modified() {
3149     emulate -L zsh
3150     print -l -- *(m-${1:-1})
3151 }
3152 # modified() was named new() in earlier versions, add an alias for backwards compatibility
3153 check_com new || alias new=modified
3154
3155 # use colors when GNU grep with color-support
3156 if (( $#grep_options > 0 )); then
3157     o=${grep_options:+"${grep_options[*]}"}
3158     #a2# Execute \kbd{grep -{}-color=auto}
3159     alias grep='grep '$o
3160     alias egrep='egrep '$o
3161     unset o
3162 fi
3163
3164 # Translate DE<=>EN
3165 # 'translate' looks up fot a word in a file with language-to-language
3166 # translations (field separator should be " : "). A typical wordlist looks
3167 # like at follows:
3168 #  | english-word : german-transmission
3169 # It's also only possible to translate english to german but not reciprocal.
3170 # Use the following oneliner to turn back the sort order:
3171 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3172 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3173 #f5# Translates a word
3174 trans() {
3175     emulate -L zsh
3176     case "$1" in
3177         -[dD]*)
3178             translate -l de-en $2
3179             ;;
3180         -[eE]*)
3181             translate -l en-de $2
3182             ;;
3183         *)
3184             echo "Usage: $0 { -D | -E }"
3185             echo "         -D == German to English"
3186             echo "         -E == English to German"
3187     esac
3188 }
3189
3190 # Usage: simple-extract <file>
3191 # Using option -d deletes the original archive file.
3192 #f5# Smart archive extractor
3193 simple-extract() {
3194     emulate -L zsh
3195     setopt extended_glob noclobber
3196     local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
3197     local RC=0
3198     zparseopts -D -E "d=DELETE_ORIGINAL"
3199     for ARCHIVE in "${@}"; do
3200         case $ARCHIVE in
3201             *(tar.bz2|tbz2|tbz))
3202                 DECOMP_CMD="tar -xvjf -"
3203                 USES_STDIN=true
3204                 USES_STDOUT=false
3205                 ;;
3206             *(tar.gz|tgz))
3207                 DECOMP_CMD="tar -xvzf -"
3208                 USES_STDIN=true
3209                 USES_STDOUT=false
3210                 ;;
3211             *(tar.xz|txz|tar.lzma))
3212                 DECOMP_CMD="tar -xvJf -"
3213                 USES_STDIN=true
3214                 USES_STDOUT=false
3215                 ;;
3216             *tar)
3217                 DECOMP_CMD="tar -xvf -"
3218                 USES_STDIN=true
3219                 USES_STDOUT=false
3220                 ;;
3221             *rar)
3222                 DECOMP_CMD="unrar x"
3223                 USES_STDIN=false
3224                 USES_STDOUT=false
3225                 ;;
3226             *lzh)
3227                 DECOMP_CMD="lha x"
3228                 USES_STDIN=false
3229                 USES_STDOUT=false
3230                 ;;
3231             *7z)
3232                 DECOMP_CMD="7z x"
3233                 USES_STDIN=false
3234                 USES_STDOUT=false
3235                 ;;
3236             *(zip|jar))
3237                 DECOMP_CMD="unzip"
3238                 USES_STDIN=false
3239                 USES_STDOUT=false
3240                 ;;
3241             *deb)
3242                 DECOMP_CMD="ar -x"
3243                 USES_STDIN=false
3244                 USES_STDOUT=false
3245                 ;;
3246             *bz2)
3247                 DECOMP_CMD="bzip2 -d -c -"
3248                 USES_STDIN=true
3249                 USES_STDOUT=true
3250                 ;;
3251             *(gz|Z))
3252                 DECOMP_CMD="gzip -d -c -"
3253                 USES_STDIN=true
3254                 USES_STDOUT=true
3255                 ;;
3256             *(xz|lzma))
3257                 DECOMP_CMD="xz -d -c -"
3258                 USES_STDIN=true
3259                 USES_STDOUT=true
3260                 ;;
3261             *)
3262                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3263                 RC=$((RC+1))
3264                 continue
3265                 ;;
3266         esac
3267
3268         if ! check_com ${DECOMP_CMD[(w)1]}; then
3269             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3270             RC=$((RC+2))
3271             continue
3272         fi
3273
3274         GZTARGET="${ARCHIVE:t:r}"
3275         if [[ -f $ARCHIVE ]] ; then
3276
3277             print "Extracting '$ARCHIVE' ..."
3278             if $USES_STDIN; then
3279                 if $USES_STDOUT; then
3280                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3281                 else
3282                     ${=DECOMP_CMD} < "$ARCHIVE"
3283                 fi
3284             else
3285                 if $USES_STDOUT; then
3286                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3287                 else
3288                     ${=DECOMP_CMD} "$ARCHIVE"
3289                 fi
3290             fi
3291             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3292
3293         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3294             if check_com curl; then
3295                 WGET_CMD="curl -L -k -s -o -"
3296             elif check_com wget; then
3297                 WGET_CMD="wget -q -O - --no-check-certificate"
3298             else
3299                 print "ERROR: neither wget nor curl is installed" >&2
3300                 RC=$((RC+4))
3301                 continue
3302             fi
3303             print "Downloading and Extracting '$ARCHIVE' ..."
3304             if $USES_STDIN; then
3305                 if $USES_STDOUT; then
3306                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3307                     RC=$((RC+$?))
3308                 else
3309                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3310                     RC=$((RC+$?))
3311                 fi
3312             else
3313                 if $USES_STDOUT; then
3314                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3315                 else
3316                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3317                 fi
3318             fi
3319
3320         else
3321             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3322             RC=$((RC+8))
3323         fi
3324     done
3325     return $RC
3326 }
3327
3328 __archive_or_uri()
3329 {
3330     _alternative \
3331         '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)"' \
3332         '_urls:Remote Archives:_urls'
3333 }
3334
3335 _simple_extract()
3336 {
3337     _arguments \
3338         '-d[delete original archivefile after extraction]' \
3339         '*:Archive Or Uri:__archive_or_uri'
3340 }
3341 compdef _simple_extract simple-extract
3342 alias se=simple-extract
3343
3344 #f5# Set all ulimit parameters to \kbd{unlimited}
3345 allulimit() {
3346     ulimit -c unlimited
3347     ulimit -d unlimited
3348     ulimit -f unlimited
3349     ulimit -l unlimited
3350     ulimit -n unlimited
3351     ulimit -s unlimited
3352     ulimit -t unlimited
3353 }
3354
3355 #f5# Change the xterm title from within GNU-screen
3356 xtrename() {
3357     emulate -L zsh
3358     if [[ $1 != "-f" ]] ; then
3359         if [[ -z ${DISPLAY} ]] ; then
3360             printf 'xtrename only makes sense in X11.\n'
3361             return 1
3362         fi
3363     else
3364         shift
3365     fi
3366     if [[ -z $1 ]] ; then
3367         printf 'usage: xtrename [-f] "title for xterm"\n'
3368         printf '  renames the title of xterm from _within_ screen.\n'
3369         printf '  also works without screen.\n'
3370         printf '  will not work if DISPLAY is unset, use -f to override.\n'
3371         return 0
3372     fi
3373     print -n "\eP\e]0;${1}\C-G\e\\"
3374     return 0
3375 }
3376
3377 # Create small urls via http://goo.gl using curl(1).
3378 # API reference: https://code.google.com/apis/urlshortener/
3379 function zurl() {
3380     emulate -L zsh
3381     setopt extended_glob
3382
3383     if [[ -z $1 ]]; then
3384         print "USAGE: zurl <URL>"
3385         return 1
3386     fi
3387
3388     local PN url prog api json contenttype item
3389     local -a data
3390     PN=$0
3391     url=$1
3392
3393     # Prepend 'http://' to given URL where necessary for later output.
3394     if [[ ${url} != http(s|)://* ]]; then
3395         url='http://'${url}
3396     fi
3397
3398     if check_com -c curl; then
3399         prog=curl
3400     else
3401         print "curl is not available, but mandatory for ${PN}. Aborting."
3402         return 1
3403     fi
3404     api='https://www.googleapis.com/urlshortener/v1/url'
3405     contenttype="Content-Type: application/json"
3406     json="{\"longUrl\": \"${url}\"}"
3407     data=(${(f)"$($prog --silent -H ${contenttype} -d ${json} $api)"})
3408     # Parse the response
3409     for item in "${data[@]}"; do
3410         case "$item" in
3411             ' '#'"id":'*)
3412                 item=${item#*: \"}
3413                 item=${item%\",*}
3414                 printf '%s\n' "$item"
3415                 return 0
3416                 ;;
3417         esac
3418     done
3419     return 1
3420 }
3421
3422 #f2# Find history events by search pattern and list them by date.
3423 whatwhen()  {
3424     emulate -L zsh
3425     local usage help ident format_l format_s first_char remain first last
3426     usage='USAGE: whatwhen [options] <searchstring> <search range>'
3427     help='Use `whatwhen -h'\'' for further explanations.'
3428     ident=${(l,${#${:-Usage: }},, ,)}
3429     format_l="${ident}%s\t\t\t%s\n"
3430     format_s="${format_l//(\\t)##/\\t}"
3431     # Make the first char of the word to search for case
3432     # insensitive; e.g. [aA]
3433     first_char=[${(L)1[1]}${(U)1[1]}]
3434     remain=${1[2,-1]}
3435     # Default search range is `-100'.
3436     first=${2:-\-100}
3437     # Optional, just used for `<first> <last>' given.
3438     last=$3
3439     case $1 in
3440         ("")
3441             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3442             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3443         ;;
3444         (-h)
3445             printf '%s\n\n' ${usage}
3446             print 'OPTIONS:'
3447             printf $format_l '-h' 'show help text'
3448             print '\f'
3449             print 'SEARCH RANGE:'
3450             printf $format_l "'0'" 'the whole history,'
3451             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3452             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3453             printf '\n%s\n' 'EXAMPLES:'
3454             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3455             printf $format_l 'whatwhen zsh -250'
3456             printf $format_l 'whatwhen foo 1 99'
3457         ;;
3458         (\?)
3459             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3460         ;;
3461         (*)
3462             # -l list results on stout rather than invoking $EDITOR.
3463             # -i Print dates as in YYYY-MM-DD.
3464             # -m Search for a - quoted - pattern within the history.
3465             fc -li -m "*${first_char}${remain}*" $first $last
3466         ;;
3467     esac
3468 }
3469
3470 # mercurial related stuff
3471 if check_com -c hg ; then
3472     # gnu like diff for mercurial
3473     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3474     #f5# GNU like diff for mercurial
3475     hgdi() {
3476         emulate -L zsh
3477         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3478     }
3479
3480     # build debian package
3481     #a2# Alias for \kbd{hg-buildpackage}
3482     alias hbp='hg-buildpackage'
3483
3484     # execute commands on the versioned patch-queue from the current repos
3485     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3486
3487     # diffstat for specific version of a mercurial repository
3488     #   hgstat      => display diffstat between last revision and tip
3489     #   hgstat 1234 => display diffstat between revision 1234 and tip
3490     #f5# Diffstat for specific version of a mercurial repos
3491     hgstat() {
3492         emulate -L zsh
3493         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3494     }
3495
3496 fi # end of check whether we have the 'hg'-executable
3497
3498 # grml-small cleanups
3499
3500 # The following is used to remove zsh-config-items that do not work
3501 # in grml-small by default.
3502 # If you do not want these adjustments (for whatever reason), set
3503 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3504 # sources if it is there).
3505
3506 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3507
3508     unset abk[V]
3509     unalias    'V'      &> /dev/null
3510     unfunction vman     &> /dev/null
3511     unfunction viless   &> /dev/null
3512     unfunction 2html    &> /dev/null
3513
3514     # manpages are not in grmlsmall
3515     unfunction manzsh   &> /dev/null
3516     unfunction man2     &> /dev/null
3517
3518 fi
3519
3520 zrclocal
3521
3522 ## genrefcard.pl settings
3523
3524 ### doc strings for external functions from files
3525 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3526
3527 ### example: split functions-search 8,16,24,32
3528 #@# split functions-search 8
3529
3530 ## END OF FILE #################################################################
3531 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3532 # Local variables:
3533 # mode: sh
3534 # End: