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