30f15504135ce42eb48bc9b2e02a1f616a035c22
[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 ${HOME}/.zshrc.pre ]] && source ${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 is439(){
148     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
149                                  || $ZSH_VERSION == <5->* ]] && return 0
150     return 1
151 }
152
153 #f1# Checks whether or not you're running grml
154 isgrml(){
155     [[ -f /etc/grml_version ]] && return 0
156     return 1
157 }
158
159 #f1# Checks whether or not you're running a grml cd
160 isgrmlcd(){
161     [[ -f /etc/grml_cd ]] && return 0
162     return 1
163 }
164
165 if isgrml ; then
166 #f1# Checks whether or not you're running grml-small
167     isgrmlsmall() {
168         if [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]]; then
169             return 0
170         fi
171         return 1
172     }
173 else
174     isgrmlsmall() { return 1 }
175 fi
176
177 isdarwin(){
178     [[ $OSTYPE == darwin* ]] && return 0
179     return 1
180 }
181
182 #f1# are we running within an utf environment?
183 isutfenv() {
184     case "$LANG $CHARSET $LANGUAGE" in
185         *utf*) return 0 ;;
186         *UTF*) return 0 ;;
187         *)     return 1 ;;
188     esac
189 }
190
191 # check for user, if not running as root set $SUDO to sudo
192 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
193
194 # change directory to home on first invocation of zsh
195 # important for rungetty -> autologin
196 # Thanks go to Bart Schaefer!
197 isgrml && checkhome() {
198     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
199         export ALREADY_DID_CD_HOME=$HOME
200         cd
201     fi
202 }
203
204 # check for zsh v3.1.7+
205
206 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
207      || ${ZSH_VERSION} == 3.<2->.<->*    \
208      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
209
210     printf '-!-\n'
211     printf '-!- In this configuration we try to make use of features, that only\n'
212     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
213     printf '-!- used with a wide range of zsh versions, while using fairly\n'
214     printf '-!- advanced features in all supported versions.\n'
215     printf '-!-\n'
216     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
217     printf '-!-\n'
218     printf '-!- While this *may* work, it might as well fail.\n'
219     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
220     printf '-!-\n'
221     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
222     printf '-!- If it does today, you'\''ve been lucky.\n'
223     printf '-!-\n'
224     printf '-!- Ye been warned!\n'
225     printf '-!-\n'
226
227     function zstyle() { : }
228 fi
229
230 # autoload wrapper - use this one instead of autoload directly
231 # We need to define this function as early as this, because autoloading
232 # 'is-at-least()' needs it.
233 function zrcautoload() {
234     emulate -L zsh
235     setopt extended_glob
236     local fdir ffile
237     local -i ffound
238
239     ffile=$1
240     (( found = 0 ))
241     for fdir in ${fpath} ; do
242         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
243     done
244
245     (( ffound == 0 )) && return 1
246     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
247         autoload -U ${ffile} || return 1
248     else
249         autoload ${ffile} || return 1
250     fi
251     return 0
252 }
253
254 # Load is-at-least() for more precise version checks Note that this test will
255 # *always* fail, if the is-at-least function could not be marked for
256 # autoloading.
257 zrcautoload is-at-least || is-at-least() { return 1 }
258
259 # set some important options (as early as possible)
260
261 # append history list to the history file; this is the default but we make sure
262 # because it's required for share_history.
263 setopt append_history
264
265 # import new commands from the history file also in other zsh-session
266 is4 && setopt share_history
267
268 # save each command's beginning timestamp and the duration to the history file
269 setopt extended_history
270
271 # If a new command line being added to the history list duplicates an older
272 # one, the older command is removed from the list
273 is4 && setopt histignorealldups
274
275 # remove command lines from the history list when the first character on the
276 # line is a space
277 setopt histignorespace
278
279 # if a command is issued that can't be executed as a normal command, and the
280 # command is the name of a directory, perform the cd command to that directory.
281 setopt auto_cd
282
283 # in order to use #, ~ and ^ for filename generation grep word
284 # *~(*.gz|*.bz|*.bz2|*.zip|*.Z) -> searches for word not in compressed files
285 # don't forget to quote '^', '~' and '#'!
286 setopt extended_glob
287
288 # display PID when suspending processes as well
289 setopt longlistjobs
290
291 # try to avoid the 'zsh: no matches found...'
292 setopt nonomatch
293
294 # report the status of backgrounds jobs immediately
295 setopt notify
296
297 # whenever a command completion is attempted, make sure the entire command path
298 # is hashed first.
299 setopt hash_list_all
300
301 # not just at the end
302 setopt completeinword
303
304 # Don't send SIGHUP to background processes when the shell exits.
305 setopt nohup
306
307 # make cd push the old directory onto the directory stack.
308 setopt auto_pushd
309
310 # avoid "beep"ing
311 setopt nobeep
312
313 # don't push the same dir twice.
314 setopt pushd_ignore_dups
315
316 # * shouldn't match dotfiles. ever.
317 setopt noglobdots
318
319 # use zsh style word splitting
320 setopt noshwordsplit
321
322 # don't error out when unset parameters are used
323 setopt unset
324
325 # setting some default values
326 NOCOR=${NOCOR:-0}
327 NOMENU=${NOMENU:-0}
328 NOPRECMD=${NOPRECMD:-0}
329 COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
330 GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
331 BATTERY=${BATTERY:-0}
332 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
333 ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
334
335 typeset -ga ls_options
336 typeset -ga grep_options
337 if ls --help 2> /dev/null | grep -q GNU; then
338     ls_options=( --color=auto )
339 elif [[ $OSTYPE == freebsd* ]]; then
340     ls_options=( -G )
341 fi
342 if grep --help 2> /dev/null | grep -q GNU; then
343     grep_options=( --color=auto )
344 fi
345
346 # utility functions
347 # this function checks if a command exists and returns either true
348 # or false. This avoids using 'which' and 'whence', which will
349 # avoid problems with aliases for which on certain weird systems. :-)
350 # Usage: check_com [-c|-g] word
351 #   -c  only checks for external commands
352 #   -g  does the usual tests and also checks for global aliases
353 check_com() {
354     emulate -L zsh
355     local -i comonly gatoo
356
357     if [[ $1 == '-c' ]] ; then
358         (( comonly = 1 ))
359         shift
360     elif [[ $1 == '-g' ]] ; then
361         (( gatoo = 1 ))
362     else
363         (( comonly = 0 ))
364         (( gatoo = 0 ))
365     fi
366
367     if (( ${#argv} != 1 )) ; then
368         printf 'usage: check_com [-c] <command>\n' >&2
369         return 1
370     fi
371
372     if (( comonly > 0 )) ; then
373         [[ -n ${commands[$1]}  ]] && return 0
374         return 1
375     fi
376
377     if   [[ -n ${commands[$1]}    ]] \
378       || [[ -n ${functions[$1]}   ]] \
379       || [[ -n ${aliases[$1]}     ]] \
380       || [[ -n ${reswords[(r)$1]} ]] ; then
381
382         return 0
383     fi
384
385     if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
386         return 0
387     fi
388
389     return 1
390 }
391
392 # creates an alias and precedes the command with
393 # sudo if $EUID is not zero.
394 salias() {
395     emulate -L zsh
396     local only=0 ; local multi=0
397     while [[ $1 == -* ]] ; do
398         case $1 in
399             (-o) only=1 ;;
400             (-a) multi=1 ;;
401             (--) shift ; break ;;
402             (-h)
403                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
404                 printf '  -h      shows this help text.\n'
405                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
406                 printf '          be careful using this option.\n'
407                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
408                 return 0
409                 ;;
410             (*) printf "unkown option: '%s'\n" "$1" ; return 1 ;;
411         esac
412         shift
413     done
414
415     if (( ${#argv} > 1 )) ; then
416         printf 'Too many arguments %s\n' "${#argv}"
417         return 1
418     fi
419
420     key="${1%%\=*}" ;  val="${1#*\=}"
421     if (( EUID == 0 )) && (( only == 0 )); then
422         alias -- "${key}=${val}"
423     elif (( EUID > 0 )) ; then
424         (( multi > 0 )) && val="${val// ; / ; sudo }"
425         alias -- "${key}=sudo ${val}"
426     fi
427
428     return 0
429 }
430
431 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
432 # usage: uprint foo
433 #   Where foo is the *name* of the parameter you want printed.
434 #   Note that foo is no typo; $foo would be wrong here!
435 if ! is42 ; then
436     uprint () {
437         emulate -L zsh
438         local -a u
439         local w
440         local parameter=$1
441
442         if [[ -z ${parameter} ]] ; then
443             printf 'usage: uprint <parameter>\n'
444             return 1
445         fi
446
447         for w in ${(P)parameter} ; do
448             [[ -z ${(M)u:#$w} ]] && u=( $u $w )
449         done
450
451         builtin print -l $u
452     }
453 fi
454
455 # Check if we can read given files and source those we can.
456 xsource() {
457     if (( ${#argv} < 1 )) ; then
458         printf 'usage: xsource FILE(s)...\n' >&2
459         return 1
460     fi
461
462     while (( ${#argv} > 0 )) ; do
463         [[ -r "$1" ]] && source "$1"
464         shift
465     done
466     return 0
467 }
468
469 # Check if we can read a given file and 'cat(1)' it.
470 xcat() {
471     emulate -L zsh
472     if (( ${#argv} != 1 )) ; then
473         printf 'usage: xcat FILE\n' >&2
474         return 1
475     fi
476
477     [[ -r $1 ]] && cat $1
478     return 0
479 }
480
481 # Remove these functions again, they are of use only in these
482 # setup files. This should be called at the end of .zshrc.
483 xunfunction() {
484     emulate -L zsh
485     local -a funcs
486     funcs=(salias xcat xsource xunfunction zrcautoload)
487
488     for func in $funcs ; do
489         [[ -n ${functions[$func]} ]] \
490             && unfunction $func
491     done
492     return 0
493 }
494
495 # this allows us to stay in sync with grml's zshrc and put own
496 # modifications in ~/.zshrc.local
497 zrclocal() {
498     xsource "/etc/zsh/zshrc.local"
499     xsource "${HOME}/.zshrc.local"
500     return 0
501 }
502
503 # locale setup
504 if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
505     xsource "/etc/default/locale"
506 fi
507
508 for var in LANG LC_ALL LC_MESSAGES ; do
509     [[ -n ${(P)var} ]] && export $var
510 done
511
512 xsource "/etc/sysconfig/keyboard"
513
514 TZ=$(xcat /etc/timezone)
515
516 # set some variables
517 if check_com -c vim ; then
518 #v#
519     export EDITOR=${EDITOR:-vim}
520 else
521     export EDITOR=${EDITOR:-vi}
522 fi
523
524 #v#
525 export PAGER=${PAGER:-less}
526
527 #v#
528 export MAIL=${MAIL:-/var/mail/$USER}
529
530 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
531 export SHELL='/bin/zsh'
532
533 # color setup for ls:
534 check_com -c dircolors && eval $(dircolors -b)
535 # color setup for ls on OS X:
536 isdarwin && export CLICOLOR=1
537
538 # do MacPorts setup on darwin
539 if isdarwin && [[ -d /opt/local ]]; then
540     # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
541     # zshenv.
542     PATH="/opt/local/bin:/opt/local/sbin:$PATH"
543     MANPATH="/opt/local/share/man:$MANPATH"
544 fi
545 # do Fink setup on darwin
546 isdarwin && xsource /sw/bin/init.sh
547
548 # load our function and completion directories
549 for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
550     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
551     if [[ ${fpath} == '/usr/share/grml/zsh/functions' ]] ; then
552         for func in ${fdir}/**/[^_]*[^~](N.) ; do
553             zrcautoload ${func:t}
554         done
555     fi
556 done
557 unset fdir func
558
559 # support colors in less
560 export LESS_TERMCAP_mb=$'\E[01;31m'
561 export LESS_TERMCAP_md=$'\E[01;31m'
562 export LESS_TERMCAP_me=$'\E[0m'
563 export LESS_TERMCAP_se=$'\E[0m'
564 export LESS_TERMCAP_so=$'\E[01;44;33m'
565 export LESS_TERMCAP_ue=$'\E[0m'
566 export LESS_TERMCAP_us=$'\E[01;32m'
567
568 # mailchecks
569 MAILCHECK=30
570
571 # report about cpu-/system-/user-time of command if running longer than
572 # 5 seconds
573 REPORTTIME=5
574
575 # watch for everyone but me and root
576 watch=(notme root)
577
578 # automatically remove duplicates from these arrays
579 typeset -U path cdpath fpath manpath
580
581 # keybindings
582 if [[ "$TERM" != emacs ]] ; then
583     [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
584     [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
585     [[ -z "$terminfo[kend]"  ]] || bindkey -M emacs "$terminfo[kend]"  end-of-line
586     [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
587     [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
588     [[ -z "$terminfo[kend]"  ]] || bindkey -M vicmd "$terminfo[kend]"  vi-end-of-line
589     [[ -z "$terminfo[cuu1]"  ]] || bindkey -M viins "$terminfo[cuu1]"  vi-up-line-or-history
590     [[ -z "$terminfo[cuf1]"  ]] || bindkey -M viins "$terminfo[cuf1]"  vi-forward-char
591     [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
592     [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
593     [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
594     [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
595     # ncurses stuff:
596     [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
597     [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
598     [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
599     [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
600     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
601     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}"  end-of-line
602     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
603     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line
604 fi
605
606 ## keybindings (run 'bindkeys' for details, more details via man zshzle)
607 # use emacs style per default:
608 bindkey -e
609 # use vi style:
610 # bindkey -v
611
612 ## beginning-of-line OR beginning-of-buffer OR beginning of history
613 ## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
614 beginning-or-end-of-somewhere() {
615     local hno=$HISTNO
616     if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
617       ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
618         zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
619     else
620         zle .${WIDGET:s/somewhere/line-hist/} "$@"
621         if (( HISTNO != hno )); then
622             zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
623         fi
624     fi
625 }
626 zle -N beginning-of-somewhere beginning-or-end-of-somewhere
627 zle -N end-of-somewhere beginning-or-end-of-somewhere
628
629
630 #if [[ "$TERM" == screen ]] ; then
631
632 ## with HOME/END, move to beginning/end of line (on multiline) on first keypress
633 ## to beginning/end of buffer on second keypress
634 ## and to beginning/end of history on (at most) the third keypress
635 # terminator & non-debian xterm
636 bindkey '\eOH' beginning-of-somewhere  # home
637 bindkey '\eOF' end-of-somewhere        # end
638 # freebsd console
639 bindkey '\e[H' beginning-of-somewhere   # home
640 bindkey '\e[F' end-of-somewhere         # end
641 # xterm,gnome-terminal,quake,etc
642 bindkey '^[[1~' beginning-of-somewhere  # home
643 bindkey '^[[4~' end-of-somewhere        # end
644 # if terminal type is set to 'rxvt':
645 bindkey '\e[7~' beginning-of-somewhere  # home
646 bindkey '\e[8~' end-of-somewhere        # end
647 #fi
648
649 bindkey '\e[A'  up-line-or-search       # cursor up
650 bindkey '\e[B'  down-line-or-search     # <ESC>-
651
652 ## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on the CL
653 bindkey "\e[5C" forward-word
654 bindkey "\e[5D" backward-word
655 bindkey "\e[1;5C" forward-word
656 bindkey "\e[1;5D" backward-word
657 ## the same for alt-left-arrow and alt-right-arrow
658 bindkey '^[[1;3C' forward-word
659 bindkey '^[[1;3D' backward-word
660
661 # Search backward in the history for a line beginning with the current
662 # line up to the cursor and move the cursor to the end of the line then
663 zle -N history-beginning-search-backward-end history-search-end
664 zle -N history-beginning-search-forward-end  history-search-end
665 #k# search history backward for entry beginning with typed text
666 bindkey '^xp'   history-beginning-search-backward-end
667 #k# search history forward for entry beginning with typed text
668 bindkey '^xP'   history-beginning-search-forward-end
669 #k# search history backward for entry beginning with typed text
670 bindkey "\e[5~" history-beginning-search-backward-end # PageUp
671 #k# search history forward for entry beginning with typed text
672 bindkey "\e[6~" history-beginning-search-forward-end  # PageDown
673
674 # bindkey -s '^l' "|less\n"             # ctrl-L pipes to less
675 # bindkey -s '^b' " &\n"                # ctrl-B runs it in the background
676
677 # insert unicode character
678 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
679 # See for example http://unicode.org/charts/ for unicode characters code
680 zrcautoload insert-unicode-char
681 zle -N insert-unicode-char
682 #k# Insert Unicode character
683 bindkey '^xi' insert-unicode-char
684
685 #m# k Shift-tab Perform backwards menu completion
686 if [[ -n "$terminfo[kcbt]" ]]; then
687     bindkey "$terminfo[kcbt]" reverse-menu-complete
688 elif [[ -n "$terminfo[cbt]" ]]; then # required for GNU screen
689     bindkey "$terminfo[cbt]"  reverse-menu-complete
690 fi
691
692 ## toggle the ,. abbreviation feature on/off
693 # NOABBREVIATION: default abbreviation-state
694 #                 0 - enabled (default)
695 #                 1 - disabled
696 NOABBREVIATION=${NOABBREVIATION:-0}
697
698 grml_toggle_abbrev() {
699     if (( ${NOABBREVIATION} > 0 )) ; then
700         NOABBREVIATION=0
701     else
702         NOABBREVIATION=1
703     fi
704 }
705
706 #k# Toggle abbreviation expansion on/off
707 zle -N grml_toggle_abbrev
708 bindkey '^xA' grml_toggle_abbrev
709
710 # add a command line to the shells history without executing it
711 commit-to-history() {
712     print -s ${(z)BUFFER}
713     zle send-break
714 }
715 zle -N commit-to-history
716 bindkey "^x^h" commit-to-history
717
718 # only slash should be considered as a word separator:
719 slash-backward-kill-word() {
720     local WORDCHARS="${WORDCHARS:s@/@}"
721     # zle backward-word
722     zle backward-kill-word
723 }
724 zle -N slash-backward-kill-word
725
726 #k# Kill left-side word or everything up to next slash
727 bindkey '\ev' slash-backward-kill-word
728 #k# Kill left-side word or everything up to next slash
729 bindkey '\e^h' slash-backward-kill-word
730 #k# Kill left-side word or everything up to next slash
731 bindkey '\e^?' slash-backward-kill-word
732
733 # use the new *-pattern-* widgets for incremental history search
734 if is439 ; then
735     bindkey '^r' history-incremental-pattern-search-backward
736     bindkey '^s' history-incremental-pattern-search-forward
737 fi
738
739 # a generic accept-line wrapper
740
741 # This widget can prevent unwanted autocorrections from command-name
742 # to _command-name, rehash automatically on enter and call any number
743 # of builtin and user-defined widgets in different contexts.
744 #
745 # For a broader description, see:
746 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
747 #
748 # The code is imported from the file 'zsh/functions/accept-line' from
749 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
750 # distributed under the same terms as zsh itself.
751
752 # A newly added command will may not be found or will cause false
753 # correction attempts, if you got auto-correction set. By setting the
754 # following style, we force accept-line() to rehash, if it cannot
755 # find the first word on the command line in the $command[] hash.
756 zstyle ':acceptline:*' rehash true
757
758 function Accept-Line() {
759     setopt localoptions noksharrays
760     local -a subs
761     local -xi aldone
762     local sub
763     local alcontext=${1:-$alcontext}
764
765     zstyle -a ":acceptline:${alcontext}" actions subs
766
767     (( ${#subs} < 1 )) && return 0
768
769     (( aldone = 0 ))
770     for sub in ${subs} ; do
771         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
772         zle ${sub}
773
774         (( aldone > 0 )) && break
775     done
776 }
777
778 function Accept-Line-getdefault() {
779     emulate -L zsh
780     local default_action
781
782     zstyle -s ":acceptline:${alcontext}" default_action default_action
783     case ${default_action} in
784         ((accept-line|))
785             printf ".accept-line"
786             ;;
787         (*)
788             printf ${default_action}
789             ;;
790     esac
791 }
792
793 function Accept-Line-HandleContext() {
794     zle Accept-Line
795
796     default_action=$(Accept-Line-getdefault)
797     zstyle -T ":acceptline:${alcontext}" call_default \
798         && zle ${default_action}
799 }
800
801 function accept-line() {
802     setopt localoptions noksharrays
803     local -ax cmdline
804     local -x alcontext
805     local buf com fname format msg default_action
806
807     alcontext='default'
808     buf="${BUFFER}"
809     cmdline=(${(z)BUFFER})
810     com="${cmdline[1]}"
811     fname="_${com}"
812
813     Accept-Line 'preprocess'
814
815     zstyle -t ":acceptline:${alcontext}" rehash \
816         && [[ -z ${commands[$com]} ]]           \
817         && rehash
818
819     if    [[ -n ${com}               ]] \
820        && [[ -n ${reswords[(r)$com]} ]] \
821        || [[ -n ${aliases[$com]}     ]] \
822        || [[ -n ${functions[$com]}   ]] \
823        || [[ -n ${builtins[$com]}    ]] \
824        || [[ -n ${commands[$com]}    ]] ; then
825
826         # there is something sensible to execute, just do it.
827         alcontext='normal'
828         Accept-Line-HandleContext
829
830         return
831     fi
832
833     if    [[ -o correct              ]] \
834        || [[ -o correctall           ]] \
835        && [[ -n ${functions[$fname]} ]] ; then
836
837         # nothing there to execute but there is a function called
838         # _command_name; a completion widget. Makes no sense to
839         # call it on the commandline, but the correct{,all} options
840         # will ask for it nevertheless, so warn the user.
841         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
842             # Okay, we warned the user before, he called us again,
843             # so have it his way.
844             alcontext='force'
845             Accept-Line-HandleContext
846
847             return
848         fi
849
850         if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
851             alcontext='normal'
852             Accept-Line-HandleContext
853         else
854             # prepare warning message for the user, configurable via zstyle.
855             zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
856
857             if [[ -z ${msg} ]] ; then
858                 msg="%c will not execute and completion %f exists."
859             fi
860
861             zformat -f msg "${msg}" "c:${com}" "f:${fname}"
862
863             zle -M -- "${msg}"
864         fi
865         return
866     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
867         # If we are here, the commandline contains something that is not
868         # executable, which is neither subject to _command_name correction
869         # and is not empty. might be a variable assignment
870         alcontext='misc'
871         Accept-Line-HandleContext
872
873         return
874     fi
875
876     # If we got this far, the commandline only contains whitespace, or is empty.
877     alcontext='empty'
878     Accept-Line-HandleContext
879 }
880
881 zle -N accept-line
882 zle -N Accept-Line
883 zle -N Accept-Line-HandleContext
884
885 # power completion - abbreviation expansion
886 # power completion / abbreviation expansion / buffer expansion
887 # see http://zshwiki.org/home/examples/zleiab for details
888 # less risky than the global aliases but powerful as well
889 # just type the abbreviation key and afterwards ',.' to expand it
890 declare -A abk
891 setopt extendedglob
892 setopt interactivecomments
893 abk=(
894 #   key   # value                  (#d additional doc string)
895 #A# start
896     '...'  '../..'
897     '....' '../../..'
898     'BG'   '& exit'
899     'C'    '| wc -l'
900     'G'    '|& grep '${grep_options:+"${grep_options[*]} "}
901     'H'    '| head'
902     'Hl'   ' --help |& less -r'    #d (Display help in pager)
903     'L'    '| less'
904     'LL'   '|& less -r'
905     'M'    '| most'
906     'N'    '&>/dev/null'           #d (No Output)
907     'R'    '| tr A-z N-za-m'       #d (ROT13)
908     'SL'   '| sort | less'
909     'S'    '| sort -u'
910     'T'    '| tail'
911     'V'    '|& vim -'
912 #A# end
913     'co'   './configure && make && sudo make install'
914 )
915
916 zleiab() {
917     emulate -L zsh
918     setopt extendedglob
919     local MATCH
920
921     if (( NOABBREVIATION > 0 )) ; then
922         LBUFFER="${LBUFFER},."
923         return 0
924     fi
925
926     matched_chars='[.-|_a-zA-Z0-9]#'
927     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
928     LBUFFER+=${abk[$MATCH]:-$MATCH}
929 }
930
931 zle -N zleiab && bindkey ",." zleiab
932
933 #f# display contents of assoc array $abk
934 help-show-abk()
935 {
936   zle -M "$(print "Type ,. after these abbreviations to expand them:"; print -a -C 2 ${(kv)abk})"
937 }
938 #k# Display list of abbreviations that expand when followed by ,.
939 zle -N help-show-abk && bindkey '^xb' help-show-abk
940
941 # autoloading
942 zrcautoload zmv    # who needs mmv or rename?
943 zrcautoload history-search-end
944
945 # we don't want to quote/espace URLs on our own...
946 # if autoload -U url-quote-magic ; then
947 #    zle -N self-insert url-quote-magic
948 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
949 # else
950 #    print 'Notice: no url-quote-magic available :('
951 # fi
952 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
953
954 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
955 alias run-help >&/dev/null && unalias run-help
956 for rh in run-help{,-git,-svk,-svn}; do
957     zrcautoload $rh
958 done; unset rh
959
960 # completion system
961 if zrcautoload compinit ; then
962     compinit || print 'Notice: no compinit available :('
963 else
964     print 'Notice: no compinit available :('
965     function zstyle { }
966     function compdef { }
967 fi
968
969 is4 && zrcautoload zed # use ZLE editor to edit a file or function
970
971 is4 && \
972 for mod in complist deltochar mathfunc ; do
973     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
974 done
975
976 # autoload zsh modules when they are referenced
977 if is4 ; then
978     zmodload -a  zsh/stat    zstat
979     zmodload -a  zsh/zpty    zpty
980     zmodload -ap zsh/mapfile mapfile
981 fi
982
983 if is4 && zrcautoload insert-files && zle -N insert-files ; then
984     #k# Insert files and test globbing
985     bindkey "^xf" insert-files # C-x-f
986 fi
987
988 bindkey ' '   magic-space    # also do history expansion on space
989 #k# Trigger menu-complete
990 bindkey '\ei' menu-complete  # menu completion via esc-i
991
992 # press esc-e for editing command line in $EDITOR or $VISUAL
993 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
994     #k# Edit the current line in \kbd{\$EDITOR}
995     bindkey '\ee' edit-command-line
996 fi
997
998 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
999     #k# menu selection: pick item but stay in the menu
1000     bindkey -M menuselect '\e^M' accept-and-menu-complete
1001     # also use + and INSERT since it's easier to press repeatedly
1002     bindkey -M menuselect "+" accept-and-menu-complete
1003     bindkey -M menuselect "^[[2~" accept-and-menu-complete
1004
1005     # accept a completion and try to complete again by using menu
1006     # completion; very useful with completing directories
1007     # by using 'undo' one's got a simple file browser
1008     bindkey -M menuselect '^o' accept-and-infer-next-history
1009 fi
1010
1011 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
1012 insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
1013 zle -N insert-datestamp
1014
1015 #k# Insert a timestamp on the command line (yyyy-mm-dd)
1016 bindkey '^ed' insert-datestamp
1017
1018 # press esc-m for inserting last typed word again (thanks to caphuso!)
1019 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
1020 zle -N insert-last-typed-word;
1021
1022 #k# Insert last typed word
1023 bindkey "\em" insert-last-typed-word
1024
1025 function grml-zsh-fg() {
1026   if (( ${#jobstates} )); then
1027     zle .push-input
1028     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
1029     BUFFER="${BUFFER}fg"
1030     zle .accept-line
1031   else
1032     zle -M 'No background jobs. Doing nothing.'
1033   fi
1034 }
1035 zle -N grml-zsh-fg
1036 #k# A smart shortcut for \kbd{fg<enter>}
1037 bindkey '^z' grml-zsh-fg
1038
1039 # run command line as user root via sudo:
1040 sudo-command-line() {
1041     [[ -z $BUFFER ]] && zle up-history
1042     if [[ $BUFFER != sudo\ * ]]; then
1043         BUFFER="sudo $BUFFER"
1044         CURSOR=$(( CURSOR+5 ))
1045     fi
1046 }
1047 zle -N sudo-command-line
1048
1049 #k# prepend the current command with "sudo"
1050 bindkey "^os" sudo-command-line
1051
1052 ### jump behind the first word on the cmdline.
1053 ### useful to add options.
1054 function jump_after_first_word() {
1055     local words
1056     words=(${(z)BUFFER})
1057
1058     if (( ${#words} <= 1 )) ; then
1059         CURSOR=${#BUFFER}
1060     else
1061         CURSOR=${#${words[1]}}
1062     fi
1063 }
1064 zle -N jump_after_first_word
1065 #k# jump to after first word (for adding options)
1066 bindkey '^x1' jump_after_first_word
1067
1068 # complete word from history with menu (from Book: ZSH, OpenSource-Press)
1069 zle -C hist-complete complete-word _generic
1070 zstyle ':completion:hist-complete:*' completer _history
1071 #k# complete word from history with menu
1072 bindkey "^x^x" hist-complete
1073
1074 ## complete word from currently visible Screen or Tmux buffer.
1075 if check_com -c screen || check_com -c tmux; then
1076     _complete_screen_display() {
1077         [[ "$TERM" != "screen" ]] && return 1
1078
1079         local TMPFILE=$(mktemp)
1080         local -U -a _screen_display_wordlist
1081         trap "rm -f $TMPFILE" EXIT
1082
1083         # fill array with contents from screen hardcopy
1084         if ((${+TMUX})); then
1085             #works, but crashes tmux below version 1.4
1086             #luckily tmux -V option to ask for version, was also added in 1.4
1087             tmux -V &>/dev/null || return
1088             tmux -q capture-pane \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
1089         else
1090             screen -X hardcopy $TMPFILE
1091             # screen sucks, it dumps in latin1, apparently always. so recode it
1092             # to system charset
1093             check_com recode && recode latin1 $TMPFILE
1094         fi
1095         _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1096         # remove PREFIX to be completed from that array
1097         _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1098         compadd -a _screen_display_wordlist
1099     }
1100     #k# complete word from currently visible GNU screen buffer
1101     bindkey -r "^xS"
1102     compdef -k _complete_screen_display complete-word '^xS'
1103 fi
1104
1105 # history
1106
1107 ZSHDIR=$HOME/.zsh
1108
1109 #v#
1110 HISTFILE=$HOME/.zsh_history
1111 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
1112 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
1113
1114 # dirstack handling
1115
1116 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1117 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
1118
1119 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1120     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1121     # "cd -" won't work after login by just setting $OLDPWD, so
1122     [[ -d $dirstack[1] ]] && cd $dirstack[1] && cd $OLDPWD
1123 fi
1124
1125 chpwd() {
1126     local -ax my_stack
1127     my_stack=( ${PWD} ${dirstack} )
1128     if is42 ; then
1129         builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
1130     else
1131         uprint my_stack >! ${DIRSTACKFILE}
1132     fi
1133 }
1134
1135 # directory based profiles
1136
1137 if is433 ; then
1138
1139 CHPWD_PROFILE='default'
1140 function chpwd_profiles() {
1141     # Say you want certain settings to be active in certain directories.
1142     # This is what you want.
1143     #
1144     # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
1145     # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1146     #
1147     # When that's done and you enter a directory that matches the pattern
1148     # in the third part of the context, a function called chpwd_profile_grml,
1149     # for example, is called (if it exists).
1150     #
1151     # If no pattern matches (read: no profile is detected) the profile is
1152     # set to 'default', which means chpwd_profile_default is attempted to
1153     # be called.
1154     #
1155     # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
1156     # command) which is used: The third part in the context is matched against
1157     # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
1158     # Because that way the profile is detected for all these values of ${PWD}:
1159     #   /foo/bar
1160     #   /foo/bar/
1161     #   /foo/bar/baz
1162     # So, if you want to make double damn sure a profile works in /foo/bar
1163     # and everywhere deeper in that tree, just use (|/|/*) and be happy.
1164     #
1165     # The name of the detected profile will be available in a variable called
1166     # 'profile' in your functions. You don't need to do anything, it'll just
1167     # be there.
1168     #
1169     # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
1170     # was is currently active. That way you can avoid running code for a
1171     # profile that is already active, by running code such as the following
1172     # at the start of your function:
1173     #
1174     # function chpwd_profile_grml() {
1175     #     [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1176     #   ...
1177     # }
1178     #
1179     # The initial value for $CHPWD_PROFILE is 'default'.
1180     #
1181     # Version requirement:
1182     #   This feature requires zsh 4.3.3 or newer.
1183     #   If you use this feature and need to know whether it is active in your
1184     #   current shell, there are several ways to do that. Here are two simple
1185     #   ways:
1186     #
1187     #   a) If knowing if the profiles feature is active when zsh starts is
1188     #      good enough for you, you can put the following snippet into your
1189     #      .zshrc.local:
1190     #
1191     #   (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
1192     #
1193     #   b) If that is not good enough, and you would prefer to be notified
1194     #      whenever a profile changes, you can solve that by making sure you
1195     #      start *every* profile function you create like this:
1196     #
1197     #   function chpwd_profile_myprofilename() {
1198     #       [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1199     #       print "chpwd(): Switching to profile: $profile"
1200     #     ...
1201     #   }
1202     #
1203     #      That makes sure you only get notified if a profile is *changed*,
1204     #      not everytime you change directory, which would probably piss
1205     #      you off fairly quickly. :-)
1206     #
1207     # There you go. Now have fun with that.
1208     local -x profile
1209
1210     zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
1211     if (( ${+functions[chpwd_profile_$profile]} )) ; then
1212         chpwd_profile_${profile}
1213     fi
1214
1215     CHPWD_PROFILE="${profile}"
1216     return 0
1217 }
1218 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1219
1220 fi # is433
1221
1222 # display battery status on right side of prompt via running 'BATTERY=1 zsh'
1223 if [[ $BATTERY -gt 0 ]] ; then
1224     if ! check_com -c acpi ; then
1225         BATTERY=0
1226     fi
1227 fi
1228
1229 battery() {
1230 if [[ $BATTERY -gt 0 ]] ; then
1231     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1232     if [[ -z "$PERCENT" ]] ; then
1233         PERCENT='acpi not present'
1234     else
1235         if [[ "$PERCENT" -lt 20 ]] ; then
1236             PERCENT="warning: ${PERCENT}%%"
1237         else
1238             PERCENT="${PERCENT}%%"
1239         fi
1240     fi
1241 fi
1242 }
1243 # set colors for use in prompts
1244 if zrcautoload colors && colors 2>/dev/null ; then
1245     BLUE="%{${fg[blue]}%}"
1246     RED="%{${fg_bold[red]}%}"
1247     GREEN="%{${fg[green]}%}"
1248     CYAN="%{${fg[cyan]}%}"
1249     MAGENTA="%{${fg[magenta]}%}"
1250     YELLOW="%{${fg[yellow]}%}"
1251     WHITE="%{${fg[white]}%}"
1252     NO_COLOUR="%{${reset_color}%}"
1253 else
1254     BLUE=$'%{\e[1;34m%}'
1255     RED=$'%{\e[1;31m%}'
1256     GREEN=$'%{\e[1;32m%}'
1257     CYAN=$'%{\e[1;36m%}'
1258     WHITE=$'%{\e[1;37m%}'
1259     MAGENTA=$'%{\e[1;35m%}'
1260     YELLOW=$'%{\e[1;33m%}'
1261     NO_COLOUR=$'%{\e[0m%}'
1262 fi
1263
1264 # gather version control information for inclusion in a prompt
1265
1266 if zrcautoload vcs_info; then
1267     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
1268     # function, which can cause a lot of trouble with our directory-based
1269     # profiles. So:
1270     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
1271         function VCS_INFO_realpath () {
1272             setopt localoptions NO_shwordsplit chaselinks
1273             ( builtin cd -q $1 2> /dev/null && pwd; )
1274         }
1275     fi
1276
1277     zstyle ':vcs_info:*' max-exports 2
1278
1279     if [[ -o restricted ]]; then
1280         zstyle ':vcs_info:*' enable NONE
1281     fi
1282 fi
1283
1284 # Change vcs_info formats for the grml prompt. The 2nd format sets up
1285 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1286 # TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
1287 #       That needs to be the use of $VCS_INFO_message_N_ needs to be changed
1288 #       to $vcs_info_msg_N_ as soon as we use the included version.
1289 if [[ "$TERM" == dumb ]] ; then
1290     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
1291     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "    "zsh: %r"
1292 else
1293     # these are the same, just with a lot of colours:
1294     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
1295                                        "zsh: %r"
1296     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
1297                                        "zsh: %r"
1298     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1299 fi
1300
1301 # command not found handling
1302
1303 (( ${COMMAND_NOT_FOUND} == 1 )) &&
1304 function command_not_found_handler() {
1305     emulate -L zsh
1306     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1307         ${GRML_ZSH_CNF_HANDLER} $1
1308     fi
1309     return 1
1310 }
1311
1312 # set prompt
1313 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1314     promptinit # people should be able to use their favourite prompt
1315 else
1316     print 'Notice: no promptinit available :('
1317 fi
1318
1319 setopt prompt_subst
1320
1321 # make sure to use right prompt only when not running a command
1322 is41 && setopt transient_rprompt
1323
1324
1325 function ESC_print () {
1326     info_print $'\ek' $'\e\\' "$@"
1327 }
1328 function set_title () {
1329     info_print  $'\e]0;' $'\a' "$@"
1330 }
1331
1332 function info_print () {
1333     local esc_begin esc_end
1334     esc_begin="$1"
1335     esc_end="$2"
1336     shift 2
1337     printf '%s' ${esc_begin}
1338     printf '%s' "$*"
1339     printf '%s' "${esc_end}"
1340 }
1341
1342 # TODO: revise all these NO* variables and especially their documentation
1343 #       in zsh-help() below.
1344 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1345     [[ $NOPRECMD -gt 0 ]] && return 0
1346     # update VCS information
1347     (( ${+functions[vcs_info]} )) && vcs_info
1348
1349     if [[ $TERM == screen* ]] ; then
1350         if [[ -n ${vcs_info_msg_1_} ]] ; then
1351             ESC_print ${vcs_info_msg_1_}
1352         else
1353             ESC_print "zsh"
1354         fi
1355     fi
1356     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1357     if [[ ${DONTSETRPROMPT:-} -eq 0 ]] ; then
1358         if [[ $BATTERY -gt 0 ]] ; then
1359             # update battery (dropped into $PERCENT) information
1360             battery
1361             RPROMPT="%(?..:() ${PERCENT}"
1362         else
1363             RPROMPT="%(?..:() "
1364         fi
1365     fi
1366     # adjust title of xterm
1367     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1368     [[ ${NOTITLE:-} -gt 0 ]] && return 0
1369     case $TERM in
1370         (xterm*|rxvt*)
1371             set_title ${(%):-"%n@%m: %~"}
1372             ;;
1373     esac
1374 }
1375
1376 # preexec() => a function running before every command
1377 is4 && [[ $NOPRECMD -eq 0 ]] && \
1378 preexec () {
1379     [[ $NOPRECMD -gt 0 ]] && return 0
1380 # set hostname if not running on host with name 'grml'
1381     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1382        NAME="@$HOSTNAME"
1383     fi
1384 # get the name of the program currently running and hostname of local machine
1385 # set screen window title if running in a screen
1386     if [[ "$TERM" == screen* ]] ; then
1387         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1388         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1389         ESC_print ${CMD}
1390     fi
1391 # adjust title of xterm
1392     [[ ${NOTITLE} -gt 0 ]] && return 0
1393     case $TERM in
1394         (xterm*|rxvt*)
1395             set_title "${(%):-"%n@%m:"}" "$1"
1396             ;;
1397     esac
1398 }
1399
1400 EXITCODE="%(?..%?%1v )"
1401 # secondary prompt, printed when the shell needs more information to complete a
1402 # command.
1403 PS2='\`%_> '
1404 # selection prompt used within a select loop.
1405 PS3='?# '
1406 # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1407 PS4='+%N:%i:%_> '
1408
1409 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1410 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1411     debian_chroot=$(cat /etc/debian_chroot)
1412 fi
1413
1414 # don't use colors on dumb terminals (like emacs):
1415 if [[ "$TERM" == dumb ]] ; then
1416     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "
1417 else
1418     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended
1419     # prompt set variable identifying the chroot you work in (used in the
1420     # prompt below)
1421     if [[ $GRMLPROMPT -gt 0 ]] ; then
1422         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1423 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1424     else
1425         # This assembles the primary prompt string
1426         if (( EUID != 0 )); then
1427             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1428         else
1429             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1430         fi
1431     fi
1432 fi
1433
1434 PROMPT="${PROMPT}"'${vcs_info_msg_0_}'"%# "
1435
1436 # if we are inside a grml-chroot set a specific prompt theme
1437 if [[ -n "$GRML_CHROOT" ]] ; then
1438     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1439 fi
1440
1441 # 'hash' some often used directories
1442 #d# start
1443 hash -d deb=/var/cache/apt/archives
1444 hash -d doc=/usr/share/doc
1445 hash -d linux=/lib/modules/$(command uname -r)/build/
1446 hash -d log=/var/log
1447 hash -d slog=/var/log/syslog
1448 hash -d src=/usr/src
1449 hash -d templ=/usr/share/doc/grml-templates
1450 hash -d tt=/usr/share/doc/texttools-doc
1451 hash -d www=/var/www
1452 #d# end
1453
1454 # some aliases
1455 if check_com -c screen ; then
1456     if [[ $UID -eq 0 ]] ; then
1457         if [[ -r /etc/grml/screenrc ]]; then
1458             alias screen="${commands[screen]} -c /etc/grml/screenrc"
1459         fi
1460     elif [[ -r $HOME/.screenrc ]] ; then
1461         alias screen="${commands[screen]} -c $HOME/.screenrc"
1462     else
1463         if [[ -r /etc/grml/screenrc_grml ]]; then
1464             alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
1465         else
1466             if [[ -r /etc/grml/screenrc ]]; then
1467                 alias screen="${commands[screen]} -c /etc/grml/screenrc"
1468             fi
1469         fi
1470     fi
1471 fi
1472
1473 # do we have GNU ls with color-support?
1474 if [[ "$TERM" != dumb ]]; then
1475     #a1# execute \kbd{@a@}:\quad ls with colors
1476     alias ls='ls -b -CF '${ls_options:+"${ls_options[*]} "}
1477     #a1# execute \kbd{@a@}:\quad list all files, with colors
1478     alias la='ls -la '${ls_options:+"${ls_options[*]} "}
1479     #a1# long colored list, without dotfiles (@a@)
1480     alias ll='ls -l '${ls_options:+"${ls_options[*]} "}
1481     #a1# long colored list, human readable sizes (@a@)
1482     alias lh='ls -hAl '${ls_options:+"${ls_options[*]} "}
1483     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
1484     alias l='ls -lF '${ls_options:+"${ls_options[*]} "}
1485 else
1486     alias ls='ls -b -CF'
1487     alias la='ls -la'
1488     alias ll='ls -l'
1489     alias lh='ls -hAl'
1490     alias l='ls -lF'
1491 fi
1492
1493 alias mdstat='cat /proc/mdstat'
1494 alias ...='cd ../../'
1495
1496 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
1497 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
1498     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
1499 fi
1500
1501 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
1502 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
1503 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
1504
1505 # make sure it is not assigned yet
1506 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
1507 utf2iso() {
1508     if isutfenv ; then
1509         for ENV in $(env | command grep -i '.utf') ; do
1510             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
1511         done
1512     fi
1513 }
1514
1515 # make sure it is not assigned yet
1516 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
1517 iso2utf() {
1518     if ! isutfenv ; then
1519         for ENV in $(env | command grep -i '\.iso') ; do
1520             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
1521         done
1522     fi
1523 }
1524
1525 # especially for roadwarriors using GNU screen and ssh:
1526 if ! check_com asc &>/dev/null ; then
1527   asc() { autossh -t "$@" 'screen -RdU' }
1528   compdef asc=ssh
1529 fi
1530
1531 #f1# Hints for the use of zsh on grml
1532 zsh-help() {
1533     print "$bg[white]$fg[black]
1534 zsh-help - hints for use of zsh on grml
1535 =======================================$reset_color"
1536
1537     print '
1538 Main configuration of zsh happens in /etc/zsh/zshrc.
1539 That file is part of the package grml-etc-core, if you want to
1540 use them on a non-grml-system just get the tar.gz from
1541 http://deb.grml.org/ or (preferably) get it from the git repository:
1542
1543   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
1544
1545 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
1546 The file is still there, but it is empty for backwards compatibility.
1547
1548 For your own changes use these two files:
1549     $HOME/.zshrc.pre
1550     $HOME/.zshrc.local
1551
1552 The former is sourced very early in our zshrc, the latter is sourced
1553 very lately.
1554
1555 System wide configuration without touching configuration files of grml
1556 can take place in /etc/zsh/zshrc.local.
1557
1558 For information regarding zsh start at http://grml.org/zsh/
1559
1560 Take a look at grml'\''s zsh refcard:
1561 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
1562
1563 Check out the main zsh refcard:
1564 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
1565
1566 And of course visit the zsh-lovers:
1567 % man zsh-lovers
1568
1569 You can adjust some options through environment variables when
1570 invoking zsh without having to edit configuration files.
1571 Basically meant for bash users who are not used to the power of
1572 the zsh yet. :)
1573
1574   "NOCOR=1    zsh" => deactivate automatic correction
1575   "NOMENU=1   zsh" => do not use auto menu completion
1576                       (note: use ctrl-d for completion instead!)
1577   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
1578   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
1579                       preexec() and precmd() completely
1580   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
1581   "COMMAND_NOT_FOUND=1 zsh"
1582                    => Enable a handler if an external command was not found
1583                       The command called in the handler can be altered by setting
1584                       the GRML_ZSH_CNF_HANDLER variable, the default is:
1585                       "/usr/share/command-not-found/command-not-found"
1586
1587 A value greater than 0 is enables a feature; a value equal to zero
1588 disables it. If you like one or the other of these settings, you can
1589 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
1590 zshrc.'
1591
1592     print "
1593 $bg[white]$fg[black]
1594 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
1595 Enjoy your grml system with the zsh!$reset_color"
1596 }
1597
1598 # debian stuff
1599 if [[ -r /etc/debian_version ]] ; then
1600     #a3# Execute \kbd{apt-cache search}
1601     alias acs='apt-cache search'
1602     #a3# Execute \kbd{apt-cache show}
1603     alias acsh='apt-cache show'
1604     #a3# Execute \kbd{apt-cache policy}
1605     alias acp='apt-cache policy'
1606     #a3# Execute \kbd{apt-get dist-upgrade}
1607     salias adg="apt-get dist-upgrade"
1608     #a3# Execute \kbd{apt-get install}
1609     salias agi="apt-get install"
1610     #a3# Execute \kbd{aptitude install}
1611     salias ati="aptitude install"
1612     #a3# Execute \kbd{apt-get upgrade}
1613     salias ag="apt-get upgrade"
1614     #a3# Execute \kbd{apt-get update}
1615     salias au="apt-get update"
1616     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
1617     salias -a up="aptitude update ; aptitude safe-upgrade"
1618     #a3# Execute \kbd{dpkg-buildpackage}
1619     alias dbp='dpkg-buildpackage'
1620     #a3# Execute \kbd{grep-excuses}
1621     alias ge='grep-excuses'
1622
1623     # get a root shell as normal user in live-cd mode:
1624     if isgrmlcd && [[ $UID -ne 0 ]] ; then
1625        alias su="sudo su"
1626      fi
1627
1628     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
1629     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
1630     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
1631     salias tlog="tail -f /var/log/syslog"    # follow the syslog
1632 fi
1633
1634 # sort installed Debian-packages by size
1635 if check_com -c dpkg-query ; then
1636     #a3# List installed Debian-packages sorted by size
1637     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"
1638 fi
1639
1640 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
1641 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
1642     if check_com -c wodim; then
1643         cdrecord() {
1644             cat <<EOMESS
1645 cdrecord is not provided under its original name by Debian anymore.
1646 See #377109 in the BTS of Debian for more details.
1647
1648 Please use the wodim binary instead
1649 EOMESS
1650             return 1
1651         }
1652     fi
1653 fi
1654
1655 # Use hard limits, except for a smaller stack and no core dumps
1656 unlimit
1657 is425 && limit stack 8192
1658 isgrmlcd && limit core 0 # important for a live-cd-system
1659 limit -s
1660
1661 # completion system
1662
1663 # called later (via is4 && grmlcomp)
1664 # note: use 'zstyle' for getting current settings
1665 #         press ^xh (control-x h) for getting tags in context; ^x? (control-x ?) to run complete_debug with trace output
1666 grmlcomp() {
1667     # TODO: This could use some additional information
1668
1669     # allow one error for every three characters typed in approximate completer
1670     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
1671
1672     # don't complete backup files as executables
1673     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
1674
1675     # start menu completion only if it could find no unambiguous initial string
1676     zstyle ':completion:*:correct:*'       insert-unambiguous true
1677     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
1678     zstyle ':completion:*:correct:*'       original true
1679
1680     # activate color-completion
1681     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
1682
1683     # format on completion
1684     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
1685
1686     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
1687     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
1688
1689     # insert all expansions for expand completer
1690     zstyle ':completion:*:expand:*'        tag-order all-expansions
1691     zstyle ':completion:*:history-words'   list false
1692
1693     # activate menu
1694     zstyle ':completion:*:history-words'   menu yes
1695
1696     # ignore duplicate entries
1697     zstyle ':completion:*:history-words'   remove-all-dups yes
1698     zstyle ':completion:*:history-words'   stop yes
1699
1700     # match uppercase from lowercase
1701     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
1702
1703     # separate matches into groups
1704     zstyle ':completion:*:matches'         group 'yes'
1705     zstyle ':completion:*'                 group-name ''
1706
1707     if [[ "$NOMENU" -eq 0 ]] ; then
1708         # if there are more than 5 options allow selecting from a menu
1709         zstyle ':completion:*'               menu select=5
1710     else
1711         # don't use any menus at all
1712         setopt no_auto_menu
1713     fi
1714
1715     zstyle ':completion:*:messages'        format '%d'
1716     zstyle ':completion:*:options'         auto-description '%d'
1717
1718     # describe options in full
1719     zstyle ':completion:*:options'         description 'yes'
1720
1721     # on processes completion complete all user processes
1722     zstyle ':completion:*:processes'       command 'ps -au$USER'
1723
1724     # offer indexes before parameters in subscripts
1725     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
1726
1727     # provide verbose completion information
1728     zstyle ':completion:*'                 verbose true
1729
1730     # recent (as of Dec 2007) zsh versions are able to provide descriptions
1731     # for commands (read: 1st word in the line) that it will list for the user
1732     # to choose from. The following disables that, because it's not exactly fast.
1733     zstyle ':completion:*:-command-:*:'    verbose false
1734
1735     # set format for warnings
1736     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
1737
1738     # define files to ignore for zcompile
1739     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
1740     zstyle ':completion:correct:'          prompt 'correct to: %e'
1741
1742     # Ignore completion functions for commands you don't have:
1743     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
1744
1745     # Provide more processes in completion of programs like killall:
1746     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
1747
1748     # complete manual by their section
1749     zstyle ':completion:*:manuals'    separate-sections true
1750     zstyle ':completion:*:manuals.*'  insert-sections   true
1751     zstyle ':completion:*:man:*'      menu yes select
1752
1753     # provide .. as a completion
1754     zstyle ':completion:*' special-dirs ..
1755
1756     # run rehash on completion so new installed program are found automatically:
1757     _force_rehash() {
1758         (( CURRENT == 1 )) && rehash
1759         return 1
1760     }
1761
1762     ## correction
1763     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
1764     if [[ "$NOCOR" -gt 0 ]] ; then
1765         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
1766         setopt nocorrect
1767     else
1768         # try to be smart about when to use what completer...
1769         setopt correct
1770         zstyle -e ':completion:*' completer '
1771             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
1772                 _last_try="$HISTNO$BUFFER$CURSOR"
1773                 reply=(_complete _match _ignored _prefix _files)
1774             else
1775                 if [[ $words[1] == (rm|mv) ]] ; then
1776                     reply=(_complete _files)
1777                 else
1778                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
1779                 fi
1780             fi'
1781     fi
1782
1783     # command for process lists, the local web server details and host completion
1784     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
1785
1786     # caching
1787     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
1788                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
1789
1790     # host completion
1791     if is42 ; then
1792         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
1793         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
1794     else
1795         _ssh_hosts=()
1796         _etc_hosts=()
1797     fi
1798     hosts=(
1799         $(hostname)
1800         "$_ssh_hosts[@]"
1801         "$_etc_hosts[@]"
1802         grml.org
1803         localhost
1804     )
1805     zstyle ':completion:*:hosts' hosts $hosts
1806     # TODO: so, why is this here?
1807     #  zstyle '*' hosts $hosts
1808
1809     # use generic completion system for programs not yet defined; (_gnu_generic works
1810     # with commands that provide a --help option with "standard" gnu-like output.)
1811     for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
1812                    pal stow tail uname ; do
1813         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
1814     done; unset compcom
1815
1816     # see upgrade function in this file
1817     compdef _hosts upgrade
1818 }
1819
1820 # grmlstuff
1821 grmlstuff() {
1822 # people should use 'grml-x'!
1823     if check_com -c 915resolution; then
1824         855resolution() {
1825             echo "Please use 915resolution as resolution modifying tool for Intel \
1826 graphic chipset."
1827             return -1
1828         }
1829     fi
1830
1831     #a1# Output version of running grml
1832     alias grml-version='cat /etc/grml_version'
1833
1834     if check_com -c rebuildfstab ; then
1835         #a1# Rebuild /etc/fstab
1836         alias grml-rebuildfstab='rebuildfstab -v -r -config'
1837     fi
1838
1839     if check_com -c grml-debootstrap ; then
1840         debian2hd() {
1841             echo "Installing debian to harddisk is possible by using grml-debootstrap."
1842             return 1
1843         }
1844     fi
1845 }
1846
1847 # now run the functions
1848 isgrml && checkhome
1849 is4    && isgrml    && grmlstuff
1850 is4    && grmlcomp
1851
1852 # keephack
1853 is4 && xsource "/etc/zsh/keephack"
1854
1855 # wonderful idea of using "e" glob qualifier by Peter Stephenson
1856 # You use it as follows:
1857 # $ NTREF=/reference/file
1858 # $ ls -l *(e:nt:)
1859 # This lists all the files in the current directory newer than the reference file.
1860 # You can also specify the reference file inline; note quotes:
1861 # $ ls -l *(e:'nt ~/.zshenv':)
1862 is4 && nt() {
1863     if [[ -n $1 ]] ; then
1864         local NTREF=${~1}
1865     fi
1866     [[ $REPLY -nt $NTREF ]]
1867 }
1868
1869 # shell functions
1870
1871 #f1# Reload an autoloadable function
1872 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
1873 compdef _functions freload
1874
1875 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
1876 sll() {
1877     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
1878     for file in "$@" ; do
1879         while [[ -h "$file" ]] ; do
1880             ls -l $file
1881             file=$(readlink "$file")
1882         done
1883     done
1884 }
1885
1886 # TODO: Is it supported to use pager settings like this?
1887 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
1888 # with respect to wordsplitting. (ie. ${=PAGER})
1889 if check_com -c $PAGER ; then
1890     #f1# View Debian's changelog of a given package
1891     dchange() {
1892         emulate -L zsh
1893         if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
1894             $PAGER /usr/share/doc/$1/changelog.Debian.gz
1895         elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
1896             $PAGER /usr/share/doc/$1/changelog.gz
1897         else
1898             if check_com -c aptitude ; then
1899                 echo "No changelog for package $1 found, using aptitude to retrieve it."
1900                 if isgrml ; then
1901                     aptitude -t unstable changelog $1
1902                 else
1903                     aptitude changelog $1
1904                 fi
1905             else
1906                 echo "No changelog for package $1 found, sorry."
1907                 return 1
1908             fi
1909         fi
1910     }
1911     _dchange() { _files -W /usr/share/doc -/ }
1912     compdef _dchange dchange
1913
1914     #f1# View Debian's NEWS of a given package
1915     dnews() {
1916         emulate -L zsh
1917         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
1918             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
1919         else
1920             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
1921                 $PAGER /usr/share/doc/$1/NEWS.gz
1922             else
1923                 echo "No NEWS file for package $1 found, sorry."
1924                 return 1
1925             fi
1926         fi
1927     }
1928     _dnews() { _files -W /usr/share/doc -/ }
1929     compdef _dnews dnews
1930
1931     #f1# View upstream's changelog of a given package
1932     uchange() {
1933         emulate -L zsh
1934         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
1935             $PAGER /usr/share/doc/$1/changelog.gz
1936         else
1937             echo "No changelog for package $1 found, sorry."
1938             return 1
1939         fi
1940     }
1941     _uchange() { _files -W /usr/share/doc -/ }
1942     compdef _uchange uchange
1943 fi
1944
1945 # zsh profiling
1946 profile() {
1947     ZSH_PROFILE_RC=1 $SHELL "$@"
1948 }
1949
1950 #f1# Edit an alias via zle
1951 edalias() {
1952     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
1953 }
1954 compdef _aliases edalias
1955
1956 #f1# Edit a function via zle
1957 edfunc() {
1958     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
1959 }
1960 compdef _functions edfunc
1961
1962 # use it e.g. via 'Restart apache2'
1963 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
1964 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
1965 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
1966 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
1967 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
1968 if [[ -d /etc/init.d || -d /etc/service ]] ; then
1969     __start_stop() {
1970         local action_="${1:l}"  # e.g Start/Stop/Restart
1971         local service_="$2"
1972         local param_="$3"
1973
1974         local service_target_="$(readlink /etc/init.d/$service_)"
1975         if [[ $service_target_ == "/usr/bin/sv" ]]; then
1976             # runit
1977             case "${action_}" in
1978                 start) if [[ ! -e /etc/service/$service_ ]]; then
1979                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
1980                        else
1981                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
1982                        fi ;;
1983                 # there is no reload in runits sysv emulation
1984                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
1985                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
1986             esac
1987         else
1988             # sysvinit
1989             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
1990         fi
1991     }
1992
1993     _grmlinitd() {
1994         local -a scripts
1995         scripts=( /etc/init.d/*(x:t) )
1996         _describe "service startup script" scripts
1997     }
1998
1999     for i in Start Restart Stop Force-Reload Reload ; do
2000         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2001         compdef _grmlinitd $i
2002     done
2003 fi
2004
2005 #f1# Provides useful information on globbing
2006 H-Glob() {
2007     echo -e "
2008     /      directories
2009     .      plain files
2010     @      symbolic links
2011     =      sockets
2012     p      named pipes (FIFOs)
2013     *      executable plain files (0100)
2014     %      device files (character or block special)
2015     %b     block special files
2016     %c     character special files
2017     r      owner-readable files (0400)
2018     w      owner-writable files (0200)
2019     x      owner-executable files (0100)
2020     A      group-readable files (0040)
2021     I      group-writable files (0020)
2022     E      group-executable files (0010)
2023     R      world-readable files (0004)
2024     W      world-writable files (0002)
2025     X      world-executable files (0001)
2026     s      setuid files (04000)
2027     S      setgid files (02000)
2028     t      files with the sticky bit (01000)
2029
2030   print *(m-1)          # Files modified up to a day ago
2031   print *(a1)           # Files accessed a day ago
2032   print *(@)            # Just symlinks
2033   print *(Lk+50)        # Files bigger than 50 kilobytes
2034   print *(Lk-50)        # Files smaller than 50 kilobytes
2035   print **/*.c          # All *.c files recursively starting in \$PWD
2036   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2037   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2038   print *~*.*           # All Files that do not contain a dot
2039   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2040   print -l *(.c|.h)     # Lists *.c and *.h
2041   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2042   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2043 }
2044 alias help-zshglob=H-Glob
2045
2046 #v1# set number of lines to display per page
2047 HELP_LINES_PER_PAGE=20
2048 #v1# set location of help-zle cache file
2049 HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
2050 #f1# helper function for help-zle, actually generates the help text
2051 help_zle_parse_keybindings()
2052 {
2053     emulate -L zsh
2054     setopt extendedglob
2055     unsetopt ksharrays  #indexing starts at 1
2056
2057     #v1# choose files that help-zle will parse for keybindings
2058     ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
2059
2060     if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
2061         local load_cache=0
2062         for f ($HELPZLE_KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
2063         [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
2064     fi
2065
2066     #fill with default keybindings, possibly to be overwriten in a file later
2067     #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
2068     local -A help_zle_keybindings
2069     help_zle_keybindings['<Ctrl>@']="set MARK"
2070     help_zle_keybindings['<Ctrl>x<Ctrl>j']="vi-join lines"
2071     help_zle_keybindings['<Ctrl>x<Ctrl>b']="jump to matching brace"
2072     help_zle_keybindings['<Ctrl>x<Ctrl>u']="undo"
2073     help_zle_keybindings['<Ctrl>_']="undo"
2074     help_zle_keybindings['<Ctrl>x<Ctrl>f<c>']="find <c> in cmdline"
2075     help_zle_keybindings['<Ctrl>a']="goto beginning of line"
2076     help_zle_keybindings['<Ctrl>e']="goto end of line"
2077     help_zle_keybindings['<Ctrl>t']="transpose charaters"
2078     help_zle_keybindings['<Alt>t']="transpose words"
2079     help_zle_keybindings['<Alt>s']="spellcheck word"
2080     help_zle_keybindings['<Ctrl>k']="backward kill buffer"
2081     help_zle_keybindings['<Ctrl>u']="forward kill buffer"
2082     help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
2083     help_zle_keybindings["<Alt>'"]="quote line"
2084     help_zle_keybindings['<Alt>"']="quote from mark to cursor"
2085     help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
2086     help_zle_keybindings['<Alt>u']="make next word Uppercase"
2087     help_zle_keybindings['<Alt>l']="make next word lowercase"
2088     help_zle_keybindings['<Ctrl>xd']="preview expansion under cursor"
2089     help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
2090     help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
2091     help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
2092     help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
2093     help_zle_keybindings['<Ctrl>v']="insert next keypress symbol literally (e.g. for bindkey)"
2094     help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
2095     help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
2096     help_zle_keybindings['<Alt>h']="show help/manpage for current command"
2097
2098     #init global variables
2099     unset help_zle_lines help_zle_sln
2100     typeset -g -a help_zle_lines
2101     typeset -g help_zle_sln=1
2102
2103     local k v
2104     local lastkeybind_desc contents     #last description starting with #k# that we found
2105     local num_lines_elapsed=0            #number of lines between last description and keybinding
2106     #search config files in the order they a called (and thus the order in which they overwrite keybindings)
2107     for f in $HELPZLE_KEYBINDING_FILES; do
2108         [[ -r "$f" ]] || continue   #not readable ? skip it
2109         contents="$(<$f)"
2110         for cline in "${(f)contents}"; do
2111             #zsh pattern: matches lines like: #k# ..............
2112             if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
2113                 lastkeybind_desc="$match[*]"
2114                 num_lines_elapsed=0
2115             #zsh pattern: matches lines that set a keybinding using bindkey or compdef -k
2116             #             ignores lines that are commentend out
2117             #             grabs first in '' or "" enclosed string with length between 1 and 6 characters
2118             elif [[ "$cline" == [^#]#(bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*)  ]]; then
2119                 #description prevously found ? description not more than 2 lines away ? keybinding not empty ?
2120                 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
2121                     #substitute keybinding string with something readable
2122                     k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
2123                     #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
2124                     #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
2125                     help_zle_keybindings[${k}]=$lastkeybind_desc
2126                 fi
2127                 lastkeybind_desc=""
2128             else
2129               ((num_lines_elapsed++))
2130             fi
2131         done
2132     done
2133     unset contents
2134     #calculate length of keybinding column
2135     local kstrlen=0
2136     for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
2137     #convert the assoc array into preformated lines, which we are able to sort
2138     for k v in ${(kv)help_zle_keybindings[@]}; do
2139         #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
2140         help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
2141     done
2142     #sort lines alphabetically
2143     help_zle_lines=("${(i)help_zle_lines[@]}")
2144     [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
2145     echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
2146     zcompile $HELP_ZLE_CACHE_FILE
2147 }
2148 typeset -g help_zle_sln
2149 typeset -g -a help_zle_lines
2150
2151 #f1# Provides (partially autogenerated) help on keybindings and the zsh line editor
2152 help-zle()
2153 {
2154     emulate -L zsh
2155     unsetopt ksharrays  #indexing starts at 1
2156     #help lines already generated ? no ? then do it
2157     [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
2158     #already displayed all lines ? go back to the start
2159     [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
2160     local sln=$help_zle_sln
2161     #note that help_zle_sln is a global var, meaning we remember the last page we viewed
2162     help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
2163     zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
2164 }
2165 #k# display help for keybindings and ZLE (cycle pages with consecutive use)
2166 zle -N help-zle && bindkey '^xz' help-zle
2167
2168 # grep for running process, like: 'any vim'
2169 any() {
2170     emulate -L zsh
2171     unsetopt KSH_ARRAYS
2172     if [[ -z "$1" ]] ; then
2173         echo "any - grep for process(es) by keyword" >&2
2174         echo "Usage: any <keyword>" >&2 ; return 1
2175     else
2176         ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
2177     fi
2178 }
2179
2180
2181 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2182 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2183 [[ -r /proc/1/maps ]] && \
2184 deswap() {
2185     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2186     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2187     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2188 }
2189
2190 # a wrapper for vim, that deals with title setting
2191 #   VIM_OPTIONS
2192 #       set this array to a set of options to vim you always want
2193 #       to have set when calling vim (in .zshrc.local), like:
2194 #           VIM_OPTIONS=( -p )
2195 #       This will cause vim to send every file given on the
2196 #       commandline to be send to it's own tab (needs vim7).
2197 vim() {
2198     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2199 }
2200
2201 # make a backup of a file
2202 bk() {
2203     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2204 }
2205
2206 ssl_hashes=( sha512 sha256 sha1 md5 )
2207
2208 for sh in ${ssl_hashes}; do
2209     eval 'ssl-cert-'${sh}'() {
2210         emulate -L zsh
2211         if [[ -z $1 ]] ; then
2212             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2213             return 1
2214         fi
2215         openssl x509 -noout -fingerprint -'${sh}' -in $1
2216     }'
2217 done; unset sh
2218
2219 ssl-cert-fingerprints() {
2220     emulate -L zsh
2221     local i
2222     if [[ -z $1 ]] ; then
2223         printf 'usage: ssl-cert-fingerprints <file>\n'
2224         return 1
2225     fi
2226     for i in ${ssl_hashes}
2227         do ssl-cert-$i $1;
2228     done
2229 }
2230
2231 ssl-cert-info() {
2232     emulate -L zsh
2233     if [[ -z $1 ]] ; then
2234         printf 'usage: ssl-cert-info <file>\n'
2235         return 1
2236     fi
2237     openssl x509 -noout -text -in $1
2238     ssl-cert-fingerprints $1
2239 }
2240
2241 # make sure our environment is clean regarding colors
2242 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2243
2244 # "persistent history"
2245 # just write important commands you always need to ~/.important_commands
2246 if [[ -r ~/.important_commands ]] ; then
2247     fc -R ~/.important_commands
2248 fi
2249
2250 # load the lookup subsystem if it's available on the system
2251 zrcautoload lookupinit && lookupinit
2252
2253 # variables
2254
2255 # set terminal property (used e.g. by msgid-chooser)
2256 export COLORTERM="yes"
2257
2258 # aliases
2259
2260 # general
2261 #a2# Execute \kbd{du -sch}
2262 alias da='du -sch'
2263 #a2# Execute \kbd{jobs -l}
2264 alias j='jobs -l'
2265
2266 # listing stuff
2267 #a2# Execute \kbd{ls -lSrah}
2268 alias dir="ls -lSrah"
2269 #a2# Only show dot-directories
2270 alias lad='ls -d .*(/)'                # only show dot-directories
2271 #a2# Only show dot-files
2272 alias lsa='ls -a .*(.)'                # only show dot-files
2273 #a2# Only files with setgid/setuid/sticky flag
2274 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
2275 #a2# Only show 1st ten symlinks
2276 alias lsl='ls -l *(@)'                 # only symlinks
2277 #a2# Display only executables
2278 alias lsx='ls -l *(*)'                 # only executables
2279 #a2# Display world-{readable,writable,executable} files
2280 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
2281 #a2# Display the ten biggest files
2282 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
2283 #a2# Only show directories
2284 alias lsd='ls -d *(/)'                 # only show directories
2285 #a2# Only show empty directories
2286 alias lse='ls -d *(/^F)'               # only show empty directories
2287 #a2# Display the ten newest files
2288 alias lsnew="ls -rtlh *(D.om[1,10])"   # display the newest files
2289 #a2# Display the ten oldest files
2290 alias lsold="ls -rtlh *(D.Om[1,10])"   # display the oldest files
2291 #a2# Display the ten smallest files
2292 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
2293 #a2# Display the ten newest directories and ten newest .directories
2294 alias lsnewdir="ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
2295 #a2# Display the ten oldest directories and ten oldest .directories
2296 alias lsolddir="ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
2297
2298 # some useful aliases
2299 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir $OLDCWD}
2300 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
2301
2302 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
2303 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2304 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2305
2306 # simple webserver
2307 check_com -c python && alias http="python -m SimpleHTTPServer"
2308
2309 # work around non utf8 capable software in utf environment via $LANG and luit
2310 if check_com isutfenv && check_com luit ; then
2311     if check_com -c mrxvt ; then
2312         isutfenv && [[ -n "$LANG" ]] && \
2313             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
2314     fi
2315
2316     if check_com -c aterm ; then
2317         isutfenv && [[ -n "$LANG" ]] && \
2318             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
2319     fi
2320
2321     if check_com -c centericq ; then
2322         isutfenv && [[ -n "$LANG" ]] && \
2323             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
2324     fi
2325 fi
2326
2327 # useful functions
2328
2329 #f5# Backup \kbd{file {\rm to} file\_timestamp}
2330 bk() {
2331     emulate -L zsh
2332     cp -b $1 $1_`date --iso-8601=m`
2333 }
2334
2335 #f5# cd to directoy and list files
2336 cl() {
2337     emulate -L zsh
2338     cd $1 && ls -a
2339 }
2340
2341 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
2342 cd() {
2343     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
2344         [[ ! -e ${1:h} ]] && return 1
2345         print "Correcting ${1} to ${1:h}"
2346         builtin cd ${1:h}
2347     else
2348         builtin cd "$@"
2349     fi
2350 }
2351
2352 #f5# Create Directoy and \kbd{cd} to it
2353 mkcd() {
2354     mkdir -p "$@" && cd "$@"
2355 }
2356
2357 #f5# Create temporary directory and \kbd{cd} to it
2358 cdt() {
2359     local t
2360     t=$(mktemp -d)
2361     echo "$t"
2362     builtin cd "$t"
2363 }
2364
2365 #f5# Create directory under cursor or the selected area
2366 # Press ctrl-xM to create the directory under the cursor or the selected area.
2367 # To select an area press ctrl-@ or ctrl-space and use the cursor.
2368 # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
2369 # directory does not exist yet -> press ctrl-XM and problem solved
2370 inplaceMkDirs() {
2371     local PATHTOMKDIR
2372     if ((REGION_ACTIVE==1)); then
2373         local F=$MARK T=$CURSOR
2374         if [[ $F -gt $T ]]; then
2375             F=${CURSOR}
2376             T=${MARK}
2377         fi
2378         # get marked area from buffer and eliminate whitespace
2379         PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
2380         PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
2381     else
2382         local bufwords iword
2383         bufwords=(${(z)LBUFFER})
2384         iword=${#bufwords}
2385         bufwords=(${(z)BUFFER})
2386         PATHTOMKDIR="${(Q)bufwords[iword]}"
2387     fi
2388     [[ -z "${PATHTOMKDIR}" ]] && return 1
2389     if [[ -e "${PATHTOMKDIR}" ]]; then
2390         zle -M " path already exists, doing nothing"
2391     else
2392         zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
2393         zle end-of-line
2394     fi
2395 }
2396 #k# mkdir -p <dir> from string under cursor or marked area
2397 zle -N inplaceMkDirs && bindkey '^xM' inplaceMkDirs
2398
2399 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
2400 accessed() {
2401     emulate -L zsh
2402     print -l -- *(a-${1:-1})
2403 }
2404
2405 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
2406 changed() {
2407     emulate -L zsh
2408     print -l -- *(c-${1:-1})
2409 }
2410
2411 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
2412 modified() {
2413     emulate -L zsh
2414     print -l -- *(m-${1:-1})
2415 }
2416 # modified() was named new() in earlier versions, add an alias for backwards compatibility
2417 check_com new || alias new=modified
2418
2419 # use colors when GNU grep with color-support
2420 #a2# Execute \kbd{grep -{}-color=auto}
2421 (( $#grml_options > 0 )) && alias grep='grep '${grml_options:+"${grml_options[*]} "}'
2422
2423 # Translate DE<=>EN
2424 # 'translate' looks up fot a word in a file with language-to-language
2425 # translations (field separator should be " : "). A typical wordlist looks
2426 # like at follows:
2427 #  | english-word : german-transmission
2428 # It's also only possible to translate english to german but not reciprocal.
2429 # Use the following oneliner to turn back the sort order:
2430 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
2431 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
2432 #f5# Translates a word
2433 trans() {
2434     emulate -L zsh
2435     case "$1" in
2436         -[dD]*)
2437             translate -l de-en $2
2438             ;;
2439         -[eE]*)
2440             translate -l en-de $2
2441             ;;
2442         *)
2443             echo "Usage: $0 { -D | -E }"
2444             echo "         -D == German to English"
2445             echo "         -E == English to German"
2446     esac
2447 }
2448
2449 # Usage: simple-extract <file>
2450 # Using option -d deletes the original archive file.
2451 #f5# Smart archive extractor
2452 simple-extract() {
2453     emulate -L zsh
2454     setopt extended_glob noclobber
2455     local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
2456     local RC=0
2457     zparseopts -D -E "d=DELETE_ORIGINAL"
2458     for ARCHIVE in "${@}"; do
2459         case $ARCHIVE in
2460             *.(tar.bz2|tbz2|tbz))
2461                 DECOMP_CMD="tar -xvjf -"
2462                 USES_STDIN=true
2463                 USES_STDOUT=false
2464                 ;;
2465             *.(tar.gz|tgz))
2466                 DECOMP_CMD="tar -xvzf -"
2467                 USES_STDIN=true
2468                 USES_STDOUT=false
2469                 ;;
2470             *.(tar.xz|txz|tar.lzma))
2471                 DECOMP_CMD="tar -xvJf -"
2472                 USES_STDIN=true
2473                 USES_STDOUT=false
2474                 ;;
2475             *.tar)
2476                 DECOMP_CMD="tar -xvf -"
2477                 USES_STDIN=true
2478                 USES_STDOUT=false
2479                 ;;
2480             *.rar)
2481                 DECOMP_CMD="unrar x"
2482                 USES_STDIN=false
2483                 USES_STDOUT=false
2484                 ;;
2485             *.lzh)
2486                 DECOMP_CMD="lha x"
2487                 USES_STDIN=false
2488                 USES_STDOUT=false
2489                 ;;
2490             *.7z)
2491                 DECOMP_CMD="7z x"
2492                 USES_STDIN=false
2493                 USES_STDOUT=false
2494                 ;;
2495             *.(zip|jar))
2496                 DECOMP_CMD="unzip"
2497                 USES_STDIN=false
2498                 USES_STDOUT=false
2499                 ;;
2500             *.deb)
2501                 DECOMP_CMD="ar -x"
2502                 USES_STDIN=false
2503                 USES_STDOUT=false
2504                 ;;
2505             *.bz2)
2506                 DECOMP_CMD="bzip2 -d -c -"
2507                 USES_STDIN=true
2508                 USES_STDOUT=true
2509                 ;;
2510             *.(gz|Z))
2511                 DECOMP_CMD="gzip -d -c -"
2512                 USES_STDIN=true
2513                 USES_STDOUT=true
2514                 ;;
2515             *.(xz|lzma))
2516                 DECOMP_CMD="xz -d -c -"
2517                 USES_STDIN=true
2518                 USES_STDOUT=true
2519                 ;;
2520             *)
2521                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
2522                 RC=$((RC+1))
2523                 continue
2524                 ;;
2525         esac
2526
2527         if ! check_com ${DECOMP_CMD[(w)1]}; then
2528             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
2529             RC=$((RC+2))
2530             continue
2531         fi
2532
2533         GZTARGET="${ARCHIVE:t:r}"
2534         if [[ -f $ARCHIVE ]] ; then
2535
2536             print "Extracting '$ARCHIVE' ..."
2537             if $USES_STDIN; then
2538                 if $USES_STDOUT; then
2539                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
2540                 else
2541                     ${=DECOMP_CMD} < "$ARCHIVE"
2542                 fi
2543             else
2544                 if $USES_STDOUT; then
2545                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
2546                 else
2547                     ${=DECOMP_CMD} "$ARCHIVE"
2548                 fi
2549             fi
2550             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
2551
2552         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
2553             if check_com curl; then
2554                 WGET_CMD="curl -L -k -s -o -"
2555             elif check_com wget; then
2556                 WGET_CMD="wget -q -O - --no-check-certificate"
2557             else
2558                 print "ERROR: neither wget nor curl is installed" >&2
2559                 RC=$((RC+4))
2560                 continue
2561             fi
2562             print "Downloading and Extracting '$ARCHIVE' ..."
2563             if $USES_STDIN; then
2564                 if $USES_STDOUT; then
2565                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
2566                     RC=$((RC+$?))
2567                 else
2568                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
2569                     RC=$((RC+$?))
2570                 fi
2571             else
2572                 if $USES_STDOUT; then
2573                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
2574                 else
2575                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
2576                 fi
2577             fi
2578
2579         else
2580             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
2581             RC=$((RC+8))
2582         fi
2583     done
2584     return $RC
2585 }
2586
2587 __archive_or_uri()
2588 {
2589     _alternative \
2590         '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)"' \
2591         '_urls:Remote Archives:_urls'
2592 }
2593
2594 _simple_extract()
2595 {
2596     _arguments \
2597         '-d[delete original archivefile after extraction]' \
2598         '*:Archive Or Uri:__archive_or_uri'
2599 }
2600 compdef _simple_extract simple-extract
2601 alias se=simple-extract
2602
2603 #f5# Set all ulimit parameters to \kbd{unlimited}
2604 allulimit() {
2605     ulimit -c unlimited
2606     ulimit -d unlimited
2607     ulimit -f unlimited
2608     ulimit -l unlimited
2609     ulimit -n unlimited
2610     ulimit -s unlimited
2611     ulimit -t unlimited
2612 }
2613
2614 #f5# Change the xterm title from within GNU-screen
2615 xtrename() {
2616     emulate -L zsh
2617     if [[ $1 != "-f" ]] ; then
2618         if [[ -z ${DISPLAY} ]] ; then
2619             printf 'xtrename only makes sense in X11.\n'
2620             return 1
2621         fi
2622     else
2623         shift
2624     fi
2625     if [[ -z $1 ]] ; then
2626         printf 'usage: xtrename [-f] "title for xterm"\n'
2627         printf '  renames the title of xterm from _within_ screen.\n'
2628         printf '  also works without screen.\n'
2629         printf '  will not work if DISPLAY is unset, use -f to override.\n'
2630         return 0
2631     fi
2632     print -n "\eP\e]0;${1}\C-G\e\\"
2633     return 0
2634 }
2635
2636 # TODO:
2637 # Rewrite this by either using tinyurl.com's API
2638 # or using another shortening service to comply with
2639 # tinyurl.com's policy.
2640 #
2641 # Create small urls via http://tinyurl.com using wget(1).
2642 #function zurl() {
2643 #    emulate -L zsh
2644 #    [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
2645 #
2646 #    local PN url tiny grabber search result preview
2647 #    PN=$0
2648 #    url=$1
2649 ##   Check existence of given URL with the help of ping(1).
2650 ##   N.B. ping(1) only works without an eventual given protocol.
2651 #    ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
2652 #        read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
2653 #
2654 #    if (( $? == 0 )) ; then
2655 ##           Prepend 'http://' to given URL where necessary for later output.
2656 #            [[ ${url} != http(s|)://* ]] && url='http://'${url}
2657 #            tiny='http://tinyurl.com/create.php?url='
2658 #            if check_com -c wget ; then
2659 #                grabber='wget -O- -o/dev/null'
2660 #            else
2661 #                print "wget is not available, but mandatory for ${PN}. Aborting."
2662 #            fi
2663 ##           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
2664 #            search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
2665 #            result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
2666 ##           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
2667 #            preview='http://preview.'${result#http://}
2668 #
2669 #            printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
2670 #            printf '%s\t%s\n\n' 'Given URL:' ${url}
2671 #            printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
2672 #    else
2673 #        return 1
2674 #    fi
2675 #}
2676
2677 #f2# Find history events by search pattern and list them by date.
2678 whatwhen()  {
2679     emulate -L zsh
2680     local usage help ident format_l format_s first_char remain first last
2681     usage='USAGE: whatwhen [options] <searchstring> <search range>'
2682     help='Use `whatwhen -h'\'' for further explanations.'
2683     ident=${(l,${#${:-Usage: }},, ,)}
2684     format_l="${ident}%s\t\t\t%s\n"
2685     format_s="${format_l//(\\t)##/\\t}"
2686     # Make the first char of the word to search for case
2687     # insensitive; e.g. [aA]
2688     first_char=[${(L)1[1]}${(U)1[1]}]
2689     remain=${1[2,-1]}
2690     # Default search range is `-100'.
2691     first=${2:-\-100}
2692     # Optional, just used for `<first> <last>' given.
2693     last=$3
2694     case $1 in
2695         ("")
2696             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
2697             printf '%s\n%s\n\n' ${usage} ${help} && return 1
2698         ;;
2699         (-h)
2700             printf '%s\n\n' ${usage}
2701             print 'OPTIONS:'
2702             printf $format_l '-h' 'show help text'
2703             print '\f'
2704             print 'SEARCH RANGE:'
2705             printf $format_l "'0'" 'the whole history,'
2706             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
2707             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
2708             printf '\n%s\n' 'EXAMPLES:'
2709             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
2710             printf $format_l 'whatwhen zsh -250'
2711             printf $format_l 'whatwhen foo 1 99'
2712         ;;
2713         (\?)
2714             printf '%s\n%s\n\n' ${usage} ${help} && return 1
2715         ;;
2716         (*)
2717             # -l list results on stout rather than invoking $EDITOR.
2718             # -i Print dates as in YYYY-MM-DD.
2719             # -m Search for a - quoted - pattern within the history.
2720             fc -li -m "*${first_char}${remain}*" $first $last
2721         ;;
2722     esac
2723 }
2724
2725 # mercurial related stuff
2726 if check_com -c hg ; then
2727     # gnu like diff for mercurial
2728     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
2729     #f5# GNU like diff for mercurial
2730     hgdi() {
2731         emulate -L zsh
2732         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
2733     }
2734
2735     # build debian package
2736     #a2# Alias for \kbd{hg-buildpackage}
2737     alias hbp='hg-buildpackage'
2738
2739     # execute commands on the versioned patch-queue from the current repos
2740     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
2741
2742     # diffstat for specific version of a mercurial repository
2743     #   hgstat      => display diffstat between last revision and tip
2744     #   hgstat 1234 => display diffstat between revision 1234 and tip
2745     #f5# Diffstat for specific version of a mercurial repos
2746     hgstat() {
2747         emulate -L zsh
2748         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
2749     }
2750
2751 fi # end of check whether we have the 'hg'-executable
2752
2753 # grml-small cleanups
2754
2755 # The following is used to remove zsh-config-items that do not work
2756 # in grml-small by default.
2757 # If you do not want these adjustments (for whatever reason), set
2758 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
2759 # sources if it is there).
2760
2761 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
2762
2763     unset abk[V]
2764     unalias    'V'      &> /dev/null
2765     unfunction vman     &> /dev/null
2766     unfunction viless   &> /dev/null
2767     unfunction 2html    &> /dev/null
2768
2769     # manpages are not in grmlsmall
2770     unfunction manzsh   &> /dev/null
2771     unfunction man2     &> /dev/null
2772
2773 fi
2774
2775 zrclocal
2776
2777 ## genrefcard.pl settings
2778
2779 ### doc strings for external functions from files
2780 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
2781
2782 ### example: split functions-search 8,16,24,32
2783 #@# split functions-search 8
2784
2785 ## END OF FILE #################################################################
2786 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
2787 # Local variables:
2788 # mode: sh
2789 # End: