zshrc: Put _grmlinitd completion directly into zshrc.
[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
106 # Only load once
107 [[ ${(t)GRML} != *association* ]] && typeset -gA GRML
108 if (( ${GRML[ZSHRC_LOADED]} )); then
109     return 0
110 else
111     GRML[ZSHRC_LOADED]=1
112 fi
113
114 # zsh profiling {{{
115 # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
116 if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
117     zmodload zsh/zprof
118 fi
119 # }}}
120
121 # load .zshrc.pre to give the user the chance to overwrite the defaults
122 [[ -r ${HOME}/.zshrc.pre ]] && source ${HOME}/.zshrc.pre
123
124 # {{{ check for version/system
125 # check for versions (compatibility reasons)
126 is4(){
127     [[ $ZSH_VERSION == <4->* ]] && return 0
128     return 1
129 }
130
131 is41(){
132     [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
133     return 1
134 }
135
136 is42(){
137     [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
138     return 1
139 }
140
141 is425(){
142     [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
143     return 1
144 }
145
146 is43(){
147     [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
148     return 1
149 }
150
151 is433(){
152     [[ $ZSH_VERSION == 4.3.<3->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
153     return 1
154 }
155
156 is439(){
157     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* || $ZSH_VERSION == <5->* ]] && return 0
158     return 1
159 }
160
161 #f1# Checks whether or not you're running grml
162 isgrml(){
163     [[ -f /etc/grml_version ]] && return 0
164     return 1
165 }
166
167 #f1# Checks whether or not you're running a grml cd
168 isgrmlcd(){
169     [[ -f /etc/grml_cd ]] && return 0
170     return 1
171 }
172
173 if isgrml ; then
174 #f1# Checks whether or not you're running grml-small
175     isgrmlsmall() {
176         [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]] && return 0 ; return 1
177     }
178 else
179     isgrmlsmall() { return 1 }
180 fi
181
182 isdarwin(){
183     [[ $OSTYPE == darwin* ]] && return 0
184     return 1
185 }
186
187 #f1# are we running within an utf environment?
188 isutfenv() {
189     case "$LANG $CHARSET $LANGUAGE" in
190         *utf*) return 0 ;;
191         *UTF*) return 0 ;;
192         *)     return 1 ;;
193     esac
194 }
195
196 # check for user, if not running as root set $SUDO to sudo
197 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
198
199 # change directory to home on first invocation of zsh
200 # important for rungetty -> autologin
201 # Thanks go to Bart Schaefer!
202 isgrml && checkhome() {
203     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
204         export ALREADY_DID_CD_HOME=$HOME
205         cd
206     fi
207 }
208
209 # check for zsh v3.1.7+
210
211 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
212      || ${ZSH_VERSION} == 3.<2->.<->*    \
213      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
214
215     printf '-!-\n'
216     printf '-!- In this configuration we try to make use of features, that only\n'
217     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
218     printf '-!- used with a wide range of zsh versions, while using fairly\n'
219     printf '-!- advanced features in all supported versions.\n'
220     printf '-!-\n'
221     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
222     printf '-!-\n'
223     printf '-!- While this *may* work, it might as well fail.\n'
224     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
225     printf '-!-\n'
226     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
227     printf '-!- If it does today, you'\''ve been lucky.\n'
228     printf '-!-\n'
229     printf '-!- Ye been warned!\n'
230     printf '-!-\n'
231
232     function zstyle() { : }
233 fi
234
235 # autoload wrapper - use this one instead of autoload directly
236 # We need to define this function as early as this, because autoloading
237 # 'is-at-least()' needs it.
238 function zrcautoload() {
239     emulate -L zsh
240     setopt extended_glob
241     local fdir ffile
242     local -i ffound
243
244     ffile=$1
245     (( found = 0 ))
246     for fdir in ${fpath} ; do
247         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
248     done
249
250     (( ffound == 0 )) && return 1
251     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
252         autoload -U ${ffile} || return 1
253     else
254         autoload ${ffile} || return 1
255     fi
256     return 0
257 }
258
259 # Load is-at-least() for more precise version checks
260 # Note that this test will *always* fail, if the is-at-least
261 # function could not be marked for autoloading.
262 zrcautoload is-at-least || is-at-least() { return 1 }
263
264 # }}}
265
266 # {{{ set some important options (as early as possible)
267 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
268 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
269 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
270 is4 && setopt histignorealldups # If  a  new  command  line being added to the history
271                             # list duplicates an older one, the older command is removed from the list
272 setopt histignorespace      # remove command lines from the history list when
273                             # the first character on the line is a space
274 setopt auto_cd              # if a command is issued that can't be executed as a normal command,
275                             # and the command is the name of a directory, perform the cd command to that directory
276 setopt extended_glob        # in order to use #, ~ and ^ for filename generation
277                             # grep word *~(*.gz|*.bz|*.bz2|*.zip|*.Z) ->
278                             # -> searches for word not in compressed files
279                             # don't forget to quote '^', '~' and '#'!
280 setopt longlistjobs         # display PID when suspending processes as well
281 setopt notify               # report the status of backgrounds jobs immediately
282 setopt hash_list_all        # Whenever a command completion is attempted, make sure \
283                             # the entire command path is hashed first.
284 setopt completeinword       # not just at the end
285 setopt nohup                # and don't kill them, either
286 setopt auto_pushd           # make cd push the old directory onto the directory stack.
287 setopt nonomatch            # try to avoid the 'zsh: no matches found...'
288 setopt nobeep               # avoid "beep"ing
289 setopt pushd_ignore_dups    # don't push the same dir twice.
290 setopt noglobdots           # * shouldn't match dotfiles. ever.
291 setopt noshwordsplit        # use zsh style word splitting
292 setopt unset                # don't error out when unset parameters are used
293
294 # }}}
295
296 # setting some default values {{{
297
298 NOCOR=${NOCOR:-0}
299 NOMENU=${NOMENU:-0}
300 NOPRECMD=${NOPRECMD:-0}
301 COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
302 GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
303 BATTERY=${BATTERY:-0}
304 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
305 GRML_ALWAYS_LOAD_ALL=${GRML_ALWAYS_LOAD_ALL:-0}
306 ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
307
308 # }}}
309
310 # utility functions {{{
311 # this function checks if a command exists and returns either true
312 # or false. This avoids using 'which' and 'whence', which will
313 # avoid problems with aliases for which on certain weird systems. :-)
314 # Usage: check_com [-c|-g] word
315 #   -c  only checks for external commands
316 #   -g  does the usual tests and also checks for global aliases
317 check_com() {
318     emulate -L zsh
319     local -i comonly gatoo
320
321     if [[ $1 == '-c' ]] ; then
322         (( comonly = 1 ))
323         shift
324     elif [[ $1 == '-g' ]] ; then
325         (( gatoo = 1 ))
326     else
327         (( comonly = 0 ))
328         (( gatoo = 0 ))
329     fi
330
331     if (( ${#argv} != 1 )) ; then
332         printf 'usage: check_com [-c] <command>\n' >&2
333         return 1
334     fi
335
336     if (( comonly > 0 )) ; then
337         [[ -n ${commands[$1]}  ]] && return 0
338         return 1
339     fi
340
341     if   [[ -n ${commands[$1]}    ]] \
342       || [[ -n ${functions[$1]}   ]] \
343       || [[ -n ${aliases[$1]}     ]] \
344       || [[ -n ${reswords[(r)$1]} ]] ; then
345
346         return 0
347     fi
348
349     if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
350         return 0
351     fi
352
353     return 1
354 }
355
356 # creates an alias and precedes the command with
357 # sudo if $EUID is not zero.
358 salias() {
359     emulate -L zsh
360     local only=0 ; local multi=0
361     while [[ $1 == -* ]] ; do
362         case $1 in
363             (-o) only=1 ;;
364             (-a) multi=1 ;;
365             (--) shift ; break ;;
366             (-h)
367                 printf 'usage: salias [-h|-o|-a] <alias-expression>\n'
368                 printf '  -h      shows this help text.\n'
369                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
370                 printf '          be careful using this option.\n'
371                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
372                 return 0
373                 ;;
374             (*) printf "unkown option: '%s'\n" "$1" ; return 1 ;;
375         esac
376         shift
377     done
378
379     if (( ${#argv} > 1 )) ; then
380         printf 'Too many arguments %s\n' "${#argv}"
381         return 1
382     fi
383
384     key="${1%%\=*}" ;  val="${1#*\=}"
385     if (( EUID == 0 )) && (( only == 0 )); then
386         alias -- "${key}=${val}"
387     elif (( EUID > 0 )) ; then
388         (( multi > 0 )) && val="${val// ; / ; sudo }"
389         alias -- "${key}=sudo ${val}"
390     fi
391
392     return 0
393 }
394
395 # a "print -l ${(u)foo}"-workaround for pre-4.2.0 shells
396 # usage: uprint foo
397 #   Where foo is the *name* of the parameter you want printed.
398 #   Note that foo is no typo; $foo would be wrong here!
399 if ! is42 ; then
400     uprint () {
401         emulate -L zsh
402         local -a u
403         local w
404         local parameter=$1
405
406         if [[ -z ${parameter} ]] ; then
407             printf 'usage: uprint <parameter>\n'
408             return 1
409         fi
410
411         for w in ${(P)parameter} ; do
412             [[ -z ${(M)u:#$w} ]] && u=( $u $w )
413         done
414
415         builtin print -l $u
416     }
417 fi
418
419 # Check if we can read given files and source those we can.
420 xsource() {
421     if (( ${#argv} < 1 )) ; then
422         printf 'usage: xsource FILE(s)...\n' >&2
423         return 1
424     fi
425
426     while (( ${#argv} > 0 )) ; do
427         [[ -r "$1" ]] && source "$1"
428         shift
429     done
430     return 0
431 }
432
433 # Check if we can read a given file and 'cat(1)' it.
434 xcat() {
435     emulate -L zsh
436     if (( ${#argv} != 1 )) ; then
437         printf 'usage: xcat FILE\n' >&2
438         return 1
439     fi
440
441     [[ -r $1 ]] && cat $1
442     return 0
443 }
444
445 # Remove these functions again, they are of use only in these
446 # setup files. This should be called at the end of .zshrc.
447 xunfunction() {
448     emulate -L zsh
449     local -a funcs
450     funcs=(salias xcat xsource xunfunction zrcautoload)
451
452     for func in $funcs ; do
453         [[ -n ${functions[$func]} ]] \
454             && unfunction $func
455     done
456     return 0
457 }
458
459 # this allows us to stay in sync with grml's zshrc and put own
460 # modifications in ~/.zshrc.local
461 zrclocal() {
462     xsource "/etc/zsh/zshrc.local"
463     xsource "${HOME}/.zshrc.local"
464     return 0
465 }
466
467 #}}}
468
469 # locale setup {{{
470 if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
471     xsource "/etc/default/locale"
472 fi
473
474 for var in LANG LC_ALL LC_MESSAGES ; do
475     [[ -n ${(P)var} ]] && export $var
476 done
477
478 xsource "/etc/sysconfig/keyboard"
479
480 TZ=$(xcat /etc/timezone)
481 # }}}
482
483 # {{{ set some variables
484 if check_com -c vim ; then
485 #v#
486     export EDITOR=${EDITOR:-vim}
487 else
488     export EDITOR=${EDITOR:-vi}
489 fi
490
491 #v#
492 export PAGER=${PAGER:-less}
493
494 #v#
495 export MAIL=${MAIL:-/var/mail/$USER}
496
497 # if we don't set $SHELL then aterm, rxvt,.. will use /bin/sh or /bin/bash :-/
498 export SHELL='/bin/zsh'
499
500 # color setup for ls:
501 check_com -c dircolors && eval $(dircolors -b)
502 # color setup for ls on OS X:
503 isdarwin && export CLICOLOR=1
504
505 # do MacPorts setup on darwin
506 if isdarwin && [[ -d /opt/local ]]; then
507     # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
508     # zshenv.
509     PATH="/opt/local/bin:/opt/local/sbin:$PATH"
510     MANPATH="/opt/local/share/man:$MANPATH"
511 fi
512 # do Fink setup on darwin
513 isdarwin && xsource /sw/bin/init.sh
514
515 # load our function and completion directories
516 for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
517     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
518     if [[ ${fpath} == '/usr/share/grml/zsh/functions' ]] ; then
519         for func in ${fdir}/**/[^_]*[^~](N.) ; do
520             zrcautoload ${func:t}
521         done
522     fi
523 done
524 unset fdir func
525
526 # support colors in less
527 export LESS_TERMCAP_mb=$'\E[01;31m'
528 export LESS_TERMCAP_md=$'\E[01;31m'
529 export LESS_TERMCAP_me=$'\E[0m'
530 export LESS_TERMCAP_se=$'\E[0m'
531 export LESS_TERMCAP_so=$'\E[01;44;33m'
532 export LESS_TERMCAP_ue=$'\E[0m'
533 export LESS_TERMCAP_us=$'\E[01;32m'
534
535 MAILCHECK=30       # mailchecks
536 REPORTTIME=5       # report about cpu-/system-/user-time of command if running longer than 5 seconds
537 watch=(notme root) # watch for everyone but me and root
538
539 # automatically remove duplicates from these arrays
540 typeset -U path cdpath fpath manpath
541 # }}}
542
543 # {{{ keybindings
544 if [[ "$TERM" != emacs ]] ; then
545     [[ -z "$terminfo[kdch1]" ]] || bindkey -M emacs "$terminfo[kdch1]" delete-char
546     [[ -z "$terminfo[khome]" ]] || bindkey -M emacs "$terminfo[khome]" beginning-of-line
547     [[ -z "$terminfo[kend]"  ]] || bindkey -M emacs "$terminfo[kend]"  end-of-line
548     [[ -z "$terminfo[kdch1]" ]] || bindkey -M vicmd "$terminfo[kdch1]" vi-delete-char
549     [[ -z "$terminfo[khome]" ]] || bindkey -M vicmd "$terminfo[khome]" vi-beginning-of-line
550     [[ -z "$terminfo[kend]"  ]] || bindkey -M vicmd "$terminfo[kend]"  vi-end-of-line
551     [[ -z "$terminfo[cuu1]"  ]] || bindkey -M viins "$terminfo[cuu1]"  vi-up-line-or-history
552     [[ -z "$terminfo[cuf1]"  ]] || bindkey -M viins "$terminfo[cuf1]"  vi-forward-char
553     [[ -z "$terminfo[kcuu1]" ]] || bindkey -M viins "$terminfo[kcuu1]" vi-up-line-or-history
554     [[ -z "$terminfo[kcud1]" ]] || bindkey -M viins "$terminfo[kcud1]" vi-down-line-or-history
555     [[ -z "$terminfo[kcuf1]" ]] || bindkey -M viins "$terminfo[kcuf1]" vi-forward-char
556     [[ -z "$terminfo[kcub1]" ]] || bindkey -M viins "$terminfo[kcub1]" vi-backward-char
557     # ncurses stuff:
558     [[ "$terminfo[kcuu1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuu1]/O/[}" vi-up-line-or-history
559     [[ "$terminfo[kcud1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcud1]/O/[}" vi-down-line-or-history
560     [[ "$terminfo[kcuf1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcuf1]/O/[}" vi-forward-char
561     [[ "$terminfo[kcub1]" == $'\eO'* ]] && bindkey -M viins "${terminfo[kcub1]/O/[}" vi-backward-char
562     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M viins "${terminfo[khome]/O/[}" beginning-of-line
563     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M viins "${terminfo[kend]/O/[}"  end-of-line
564     [[ "$terminfo[khome]" == $'\eO'* ]] && bindkey -M emacs "${terminfo[khome]/O/[}" beginning-of-line
565     [[ "$terminfo[kend]"  == $'\eO'* ]] && bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line
566 fi
567
568 ## keybindings (run 'bindkeys' for details, more details via man zshzle)
569 # use emacs style per default:
570 bindkey -e
571 # use vi style:
572 # bindkey -v
573
574 ## beginning-of-line OR beginning-of-buffer OR beginning of history
575 ## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
576 beginning-or-end-of-somewhere() {
577     local hno=$HISTNO
578     if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
579       ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
580         zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
581     else
582         zle .${WIDGET:s/somewhere/line-hist/} "$@"
583         if (( HISTNO != hno )); then
584             zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
585         fi
586     fi
587 }
588 zle -N beginning-of-somewhere beginning-or-end-of-somewhere
589 zle -N end-of-somewhere beginning-or-end-of-somewhere
590
591
592 #if [[ "$TERM" == screen ]] ; then
593
594 ## with HOME/END, move to beginning/end of line (on multiline) on first keypress
595 ## to beginning/end of buffer on second keypress
596 ## and to beginning/end of history on (at most) the third keypress
597 # terminator & non-debian xterm
598 bindkey '\eOH' beginning-of-somewhere  # home
599 bindkey '\eOF' end-of-somewhere        # end
600 # freebsd console
601 bindkey '\e[H' beginning-of-somewhere   # home
602 bindkey '\e[F' end-of-somewhere         # end
603 # xterm,gnome-terminal,quake,etc
604 bindkey '^[[1~' beginning-of-somewhere  # home
605 bindkey '^[[4~' end-of-somewhere        # end
606 # if terminal type is set to 'rxvt':
607 bindkey '\e[7~' beginning-of-somewhere  # home
608 bindkey '\e[8~' end-of-somewhere        # end
609 #fi
610
611 bindkey '\e[A'  up-line-or-search       # cursor up
612 bindkey '\e[B'  down-line-or-search     # <ESC>-
613
614 ## alt-backspace is already the default for backwards-delete-word
615 ## let's also set alt-delete for deleting current word (right of cursor)
616 #k# Delete current word
617 bindkey "3~" delete-word
618
619 ## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on the CL
620 bindkey "\e[5C" forward-word
621 bindkey "\e[5D" backward-word
622 bindkey "\e[1;5C" forward-word
623 bindkey "\e[1;5D" backward-word
624 ## the same for alt-left-arrow and alt-right-arrow
625 bindkey '^[[1;3C' forward-word
626 bindkey '^[[1;3D' backward-word
627
628 # Search backward in the history for a line beginning with the current
629 # line up to the cursor and move the cursor to the end of the line then
630 zle -N history-beginning-search-backward-end history-search-end
631 zle -N history-beginning-search-forward-end  history-search-end
632 bindkey '^xp'   history-beginning-search-backward-end
633 bindkey '^xP'   history-beginning-search-forward-end
634 bindkey "\e[5~" history-beginning-search-backward-end # PageUp
635 bindkey "\e[6~" history-beginning-search-forward-end  # PageDown
636
637 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
638 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
639
640 # insert unicode character
641 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
642 # See for example http://unicode.org/charts/ for unicode characters code
643 zrcautoload insert-unicode-char
644 zle -N insert-unicode-char
645 #k# Insert Unicode character
646 bindkey '^Xi' insert-unicode-char
647
648 #m# k Shift-tab Perform backwards menu completion
649 if [[ -n "$terminfo[kcbt]" ]]; then
650     bindkey "$terminfo[kcbt]" reverse-menu-complete
651 elif [[ -n "$terminfo[cbt]" ]]; then # required for GNU screen
652     bindkey "$terminfo[cbt]"  reverse-menu-complete
653 fi
654
655 ## toggle the ,. abbreviation feature on/off
656 # NOABBREVIATION: default abbreviation-state
657 #                 0 - enabled (default)
658 #                 1 - disabled
659 NOABBREVIATION=${NOABBREVIATION:-0}
660
661 grml_toggle_abbrev() {
662     if (( ${NOABBREVIATION} > 0 )) ; then
663         NOABBREVIATION=0
664     else
665         NOABBREVIATION=1
666     fi
667 }
668
669 zle -N grml_toggle_abbrev
670 bindkey '^xA' grml_toggle_abbrev
671
672 # add a command line to the shells history without executing it
673 commit-to-history() {
674     print -s ${(z)BUFFER}
675     zle send-break
676 }
677 zle -N commit-to-history
678 bindkey "^x^h" commit-to-history
679
680 # only slash should be considered as a word separator:
681 slash-backward-kill-word() {
682     local WORDCHARS="${WORDCHARS:s@/@}"
683     # zle backward-word
684     zle backward-kill-word
685 }
686 zle -N slash-backward-kill-word
687
688 #k# Kill everything in a word up to its last \kbd{/}
689 bindkey '\ev' slash-backward-kill-word
690 #k# Kill everything in a word up to its last \kbd{/}
691 bindkey '\e^h' slash-backward-kill-word
692 #k# Kill everything in a word up to its last \kbd{/}
693 bindkey '\e^?' slash-backward-kill-word
694
695 # use the new *-pattern-* widgets for incremental history search
696 if is439 ; then
697     bindkey '^r' history-incremental-pattern-search-backward
698     bindkey '^s' history-incremental-pattern-search-forward
699 fi
700 # }}}
701
702 # a generic accept-line wrapper {{{
703
704 # This widget can prevent unwanted autocorrections from command-name
705 # to _command-name, rehash automatically on enter and call any number
706 # of builtin and user-defined widgets in different contexts.
707 #
708 # For a broader description, see:
709 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
710 #
711 # The code is imported from the file 'zsh/functions/accept-line' from
712 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
713 # distributed under the same terms as zsh itself.
714
715 # A newly added command will may not be found or will cause false
716 # correction attempts, if you got auto-correction set. By setting the
717 # following style, we force accept-line() to rehash, if it cannot
718 # find the first word on the command line in the $command[] hash.
719 zstyle ':acceptline:*' rehash true
720
721 function Accept-Line() {
722     emulate -L zsh
723     local -a subs
724     local -xi aldone
725     local sub
726
727     zstyle -a ":acceptline:${alcontext}" actions subs
728
729     (( ${#subs} < 1 )) && return 0
730
731     (( aldone = 0 ))
732     for sub in ${subs} ; do
733         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
734         zle ${sub}
735
736         (( aldone > 0 )) && break
737     done
738 }
739
740 function Accept-Line-getdefault() {
741     emulate -L zsh
742     local default_action
743
744     zstyle -s ":acceptline:${alcontext}" default_action default_action
745     case ${default_action} in
746         ((accept-line|))
747             printf ".accept-line"
748             ;;
749         (*)
750             printf ${default_action}
751             ;;
752     esac
753 }
754
755 function accept-line() {
756     emulate -L zsh
757     local -a cmdline
758     local -x alcontext
759     local buf com fname format msg default_action
760
761     alcontext='default'
762     buf="${BUFFER}"
763     cmdline=(${(z)BUFFER})
764     com="${cmdline[1]}"
765     fname="_${com}"
766
767     zstyle -t ":acceptline:${alcontext}" rehash \
768         && [[ -z ${commands[$com]} ]]           \
769         && rehash
770
771     if    [[ -n ${reswords[(r)$com]} ]] \
772        || [[ -n ${aliases[$com]}     ]] \
773        || [[ -n ${functions[$com]}   ]] \
774        || [[ -n ${builtins[$com]}    ]] \
775        || [[ -n ${commands[$com]}    ]] ; then
776
777         # there is something sensible to execute, just do it.
778         alcontext='normal'
779         zle Accept-Line
780
781         default_action=$(Accept-Line-getdefault)
782         zstyle -T ":acceptline:${alcontext}" call_default \
783             && zle ${default_action}
784         return
785     fi
786
787     if    [[ -o correct              ]] \
788        || [[ -o correctall           ]] \
789        && [[ -n ${functions[$fname]} ]] ; then
790
791         # nothing there to execute but there is a function called
792         # _command_name; a completion widget. Makes no sense to
793         # call it on the commandline, but the correct{,all} options
794         # will ask for it nevertheless, so warn the user.
795         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
796             # Okay, we warned the user before, he called us again,
797             # so have it his way.
798             alcontext='force'
799             zle Accept-Line
800
801             default_action=$(Accept-Line-getdefault)
802             zstyle -T ":acceptline:${alcontext}" call_default \
803                 && zle ${default_action}
804             return
805         fi
806
807         # prepare warning message for the user, configurable via zstyle.
808         zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
809
810         if [[ -z ${msg} ]] ; then
811             msg="%c will not execute and completion %f exists."
812         fi
813
814         zformat -f msg "${msg}" "c:${com}" "f:${fname}"
815
816         zle -M -- "${msg}"
817         return
818     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
819         # If we are here, the commandline contains something that is not
820         # executable, which is neither subject to _command_name correction
821         # and is not empty. might be a variable assignment
822         alcontext='misc'
823         zle Accept-Line
824
825         default_action=$(Accept-Line-getdefault)
826         zstyle -T ":acceptline:${alcontext}" call_default \
827             && zle ${default_action}
828         return
829     fi
830
831     # If we got this far, the commandline only contains whitespace, or is empty.
832     alcontext='empty'
833     zle Accept-Line
834
835     default_action=$(Accept-Line-getdefault)
836     zstyle -T ":acceptline:${alcontext}" call_default \
837         && zle ${default_action}
838 }
839
840 zle -N accept-line
841 zle -N Accept-Line
842
843 # }}}
844
845 # power completion - abbreviation expansion {{{
846 # power completion / abbreviation expansion / buffer expansion
847 # see http://zshwiki.org/home/examples/zleiab for details
848 # less risky than the global aliases but powerful as well
849 # just type the abbreviation key and afterwards ',.' to expand it
850 declare -A abk
851 setopt extendedglob
852 setopt interactivecomments
853 abk=(
854 #   key   # value                  (#d additional doc string)
855 #A# start
856     '...'  '../..'
857     '....' '../../..'
858     'BG'   '& exit'
859     'C'    '| wc -l'
860     'G'    '|& grep --color=auto '
861     'H'    '| head'
862     'Hl'   ' --help |& less -r'    #d (Display help in pager)
863     'L'    '| less'
864     'LL'   '|& less -r'
865     'M'    '| most'
866     'N'    '&>/dev/null'           #d (No Output)
867     'R'    '| tr A-z N-za-m'       #d (ROT13)
868     'SL'   '| sort | less'
869     'S'    '| sort -u'
870     'T'    '| tail'
871     'V'    '|& vim -'
872 #A# end
873     'co'   './configure && make && sudo make install'
874 )
875
876 globalias() {
877     emulate -L zsh
878     setopt extendedglob
879     local MATCH
880
881     if (( NOABBREVIATION > 0 )) ; then
882         LBUFFER="${LBUFFER},."
883         return 0
884     fi
885
886     matched_chars='[.-|_a-zA-Z0-9]#'
887     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
888     LBUFFER+=${abk[$MATCH]:-$MATCH}
889 }
890
891 zle -N globalias
892 bindkey ",." globalias
893 # }}}
894
895 # {{{ autoloading
896 zrcautoload zmv    # who needs mmv or rename?
897 zrcautoload history-search-end
898
899 # we don't want to quote/espace URLs on our own...
900 # if autoload -U url-quote-magic ; then
901 #    zle -N self-insert url-quote-magic
902 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
903 # else
904 #    print 'Notice: no url-quote-magic available :('
905 # fi
906 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
907
908 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
909 alias run-help >&/dev/null && unalias run-help
910 for rh in run-help{,-git,-svk,-svn}; do
911     zrcautoload $rh
912 done; unset rh
913
914 # completion system
915 if zrcautoload compinit ; then
916     compinit || print 'Notice: no compinit available :('
917 else
918     print 'Notice: no compinit available :('
919     function zstyle { }
920     function compdef { }
921 fi
922
923 is4 && zrcautoload zed # use ZLE editor to edit a file or function
924
925 is4 && \
926 for mod in complist deltochar mathfunc ; do
927     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
928 done
929
930 # autoload zsh modules when they are referenced
931 if is4 ; then
932     zmodload -a  zsh/stat    zstat
933     zmodload -a  zsh/zpty    zpty
934     zmodload -ap zsh/mapfile mapfile
935 fi
936
937 if is4 && zrcautoload insert-files && zle -N insert-files ; then
938     #k# Insert files
939     bindkey "^Xf" insert-files # C-x-f
940 fi
941
942 bindkey ' '   magic-space    # also do history expansion on space
943 #k# Trigger menu-complete
944 bindkey '\ei' menu-complete  # menu completion via esc-i
945
946 # press esc-e for editing command line in $EDITOR or $VISUAL
947 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
948     #k# Edit the current line in \kbd{\$EDITOR}
949     bindkey '\ee' edit-command-line
950 fi
951
952 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
953     #k# menu selection: pick item but stay in the menu
954     bindkey -M menuselect '\e^M' accept-and-menu-complete
955     # also use + and INSERT since it's easier to press repeatedly
956     bindkey -M menuselect "+" accept-and-menu-complete
957     bindkey -M menuselect "^[[2~" accept-and-menu-complete
958
959     # accept a completion and try to complete again by using menu
960     # completion; very useful with completing directories
961     # by using 'undo' one's got a simple file browser
962     bindkey -M menuselect '^o' accept-and-infer-next-history
963 fi
964
965 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
966 insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
967 zle -N insert-datestamp
968
969 #k# Insert a timestamp on the command line (yyyy-mm-dd)
970 bindkey '^Ed' insert-datestamp
971
972 # press esc-m for inserting last typed word again (thanks to caphuso!)
973 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
974 zle -N insert-last-typed-word;
975
976 #k# Insert last typed word
977 bindkey "\em" insert-last-typed-word
978
979 function grml-zsh-fg() {
980   if (( ${#jobstates} )); then
981     zle .push-input
982     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
983     BUFFER="${BUFFER}fg"
984     zle .accept-line
985   else
986     zle -M 'No background jobs. Doing nothing.'
987   fi
988 }
989 zle -N grml-zsh-fg
990 #k# A smart shortcut for \kbd{fg<enter>}
991 bindkey '^z' grml-zsh-fg
992
993 # run command line as user root via sudo:
994 sudo-command-line() {
995     [[ -z $BUFFER ]] && zle up-history
996     if [[ $BUFFER != sudo\ * ]]; then
997         BUFFER="sudo $BUFFER"
998         CURSOR=$(( CURSOR+5 ))
999     fi
1000 }
1001 zle -N sudo-command-line
1002
1003 #k# Put the current command line into a \kbd{sudo} call
1004 bindkey "^Os" sudo-command-line
1005
1006 ### jump behind the first word on the cmdline.
1007 ### useful to add options.
1008 function jump_after_first_word() {
1009     local words
1010     words=(${(z)BUFFER})
1011
1012     if (( ${#words} <= 1 )) ; then
1013         CURSOR=${#BUFFER}
1014     else
1015         CURSOR=${#${words[1]}}
1016     fi
1017 }
1018 zle -N jump_after_first_word
1019
1020 bindkey '^x1' jump_after_first_word
1021
1022 # complete word from history with menu (from Book: ZSH, OpenSource-Press)
1023 zle -C hist-complete complete-word _generic
1024 zstyle ':completion:hist-complete:*' completer _history
1025 #k# complete word from history with menu
1026 bindkey "^X^X" hist-complete
1027
1028 ## complete word from currently visible SCREEN buffer.
1029 if check_com -c screen ; then
1030     _complete_screen_display() {
1031         [[ "$TERM" != "screen" ]] && return 1
1032
1033         local TMPFILE=$(mktemp)
1034         local -U -a _screen_display_wordlist
1035         trap "rm -f $TMPFILE" EXIT
1036
1037         screen -X hardcopy $TMPFILE
1038         # fill array with contents from screen hardcopy
1039         _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
1040         # remove PREFIX to be completed from that array
1041         _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
1042         compadd -a _screen_display_wordlist
1043     }
1044     #k# complete word from currently visible GNU screen buffer
1045     bindkey -r "^XS"
1046     compdef -k _complete_screen_display complete-word '^XS'
1047 fi
1048
1049 # }}}
1050
1051 # {{{ history
1052
1053 ZSHDIR=$HOME/.zsh
1054
1055 #v#
1056 HISTFILE=$HOME/.zsh_history
1057 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
1058 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
1059
1060 # }}}
1061
1062 # dirstack handling {{{
1063
1064 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1065 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
1066
1067 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1068     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1069     # "cd -" won't work after login by just setting $OLDPWD, so
1070     [[ -d $dirstack[0] ]] && cd $dirstack[0] && cd $OLDPWD
1071 fi
1072
1073 chpwd() {
1074     local -ax my_stack
1075     my_stack=( ${PWD} ${dirstack} )
1076     if is42 ; then
1077         builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
1078     else
1079         uprint my_stack >! ${DIRSTACKFILE}
1080     fi
1081 }
1082
1083 # }}}
1084
1085 # directory based profiles {{{
1086
1087 if is433 ; then
1088
1089 CHPWD_PROFILE='default'
1090 function chpwd_profiles() {
1091     # Say you want certain settings to be active in certain directories.
1092     # This is what you want.
1093     #
1094     # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
1095     # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1096     #
1097     # When that's done and you enter a directory that matches the pattern
1098     # in the third part of the context, a function called chpwd_profile_grml,
1099     # for example, is called (if it exists).
1100     #
1101     # If no pattern matches (read: no profile is detected) the profile is
1102     # set to 'default', which means chpwd_profile_default is attempted to
1103     # be called.
1104     #
1105     # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
1106     # command) which is used: The third part in the context is matched against
1107     # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
1108     # Because that way the profile is detected for all these values of ${PWD}:
1109     #   /foo/bar
1110     #   /foo/bar/
1111     #   /foo/bar/baz
1112     # So, if you want to make double damn sure a profile works in /foo/bar
1113     # and everywhere deeper in that tree, just use (|/|/*) and be happy.
1114     #
1115     # The name of the detected profile will be available in a variable called
1116     # 'profile' in your functions. You don't need to do anything, it'll just
1117     # be there.
1118     #
1119     # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
1120     # was is currently active. That way you can avoid running code for a
1121     # profile that is already active, by running code such as the following
1122     # at the start of your function:
1123     #
1124     # function chpwd_profile_grml() {
1125     #     [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1126     #   ...
1127     # }
1128     #
1129     # The initial value for $CHPWD_PROFILE is 'default'.
1130     #
1131     # Version requirement:
1132     #   This feature requires zsh 4.3.3 or newer.
1133     #   If you use this feature and need to know whether it is active in your
1134     #   current shell, there are several ways to do that. Here are two simple
1135     #   ways:
1136     #
1137     #   a) If knowing if the profiles feature is active when zsh starts is
1138     #      good enough for you, you can put the following snippet into your
1139     #      .zshrc.local:
1140     #
1141     #   (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
1142     #
1143     #   b) If that is not good enough, and you would prefer to be notified
1144     #      whenever a profile changes, you can solve that by making sure you
1145     #      start *every* profile function you create like this:
1146     #
1147     #   function chpwd_profile_myprofilename() {
1148     #       [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1149     #       print "chpwd(): Switching to profile: $profile"
1150     #     ...
1151     #   }
1152     #
1153     #      That makes sure you only get notified if a profile is *changed*,
1154     #      not everytime you change directory, which would probably piss
1155     #      you off fairly quickly. :-)
1156     #
1157     # There you go. Now have fun with that.
1158     local -x profile
1159
1160     zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
1161     if (( ${+functions[chpwd_profile_$profile]} )) ; then
1162         chpwd_profile_${profile}
1163     fi
1164
1165     CHPWD_PROFILE="${profile}"
1166     return 0
1167 }
1168 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1169
1170 fi # is433
1171
1172 # }}}
1173
1174 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
1175 if [[ $BATTERY -gt 0 ]] ; then
1176     if ! check_com -c acpi ; then
1177         BATTERY=0
1178     fi
1179 fi
1180
1181 battery() {
1182 if [[ $BATTERY -gt 0 ]] ; then
1183     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1184     if [[ -z "$PERCENT" ]] ; then
1185         PERCENT='acpi not present'
1186     else
1187         if [[ "$PERCENT" -lt 20 ]] ; then
1188             PERCENT="warning: ${PERCENT}%%"
1189         else
1190             PERCENT="${PERCENT}%%"
1191         fi
1192     fi
1193 fi
1194 }
1195 # }}}
1196
1197 # set colors for use in prompts {{{
1198 if zrcautoload colors && colors 2>/dev/null ; then
1199     BLUE="%{${fg[blue]}%}"
1200     RED="%{${fg_bold[red]}%}"
1201     GREEN="%{${fg[green]}%}"
1202     CYAN="%{${fg[cyan]}%}"
1203     MAGENTA="%{${fg[magenta]}%}"
1204     YELLOW="%{${fg[yellow]}%}"
1205     WHITE="%{${fg[white]}%}"
1206     NO_COLOUR="%{${reset_color}%}"
1207 else
1208     BLUE=$'%{\e[1;34m%}'
1209     RED=$'%{\e[1;31m%}'
1210     GREEN=$'%{\e[1;32m%}'
1211     CYAN=$'%{\e[1;36m%}'
1212     WHITE=$'%{\e[1;37m%}'
1213     MAGENTA=$'%{\e[1;35m%}'
1214     YELLOW=$'%{\e[1;33m%}'
1215     NO_COLOUR=$'%{\e[0m%}'
1216 fi
1217
1218 # }}}
1219
1220 # gather version control information for inclusion in a prompt {{{
1221
1222 if zrcautoload vcs_info; then
1223     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
1224     # function, which can cause a lot of trouble with our directory-based
1225     # profiles. So:
1226     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
1227         function VCS_INFO_realpath () {
1228             setopt localoptions NO_shwordsplit chaselinks
1229             ( builtin cd -q $1 2> /dev/null && pwd; )
1230         }
1231     fi
1232
1233     zstyle ':vcs_info:*' max-exports 2
1234
1235     if [[ -o restricted ]]; then
1236         zstyle ':vcs_info:*' enable NONE
1237     fi
1238 fi
1239
1240 # Change vcs_info formats for the grml prompt. The 2nd format sets up
1241 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
1242 # TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
1243 #       That needs to be the use of $VCS_INFO_message_N_ needs to be changed
1244 #       to $vcs_info_msg_N_ as soon as we use the included version.
1245 if [[ "$TERM" == dumb ]] ; then
1246     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
1247     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "    "zsh: %r"
1248 else
1249     # these are the same, just with a lot of colours:
1250     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
1251                                        "zsh: %r"
1252     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
1253                                        "zsh: %r"
1254     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
1255 fi
1256
1257
1258 # }}}
1259
1260 # command not found handling {{{
1261
1262 (( ${COMMAND_NOT_FOUND} == 1 )) &&
1263 function command_not_found_handler() {
1264     emulate -L zsh
1265     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
1266         ${GRML_ZSH_CNF_HANDLER} $1
1267     fi
1268     return 1
1269 }
1270
1271 # }}}
1272
1273 # {{{ set prompt
1274 if zrcautoload promptinit && promptinit 2>/dev/null ; then
1275     promptinit # people should be able to use their favourite prompt
1276 else
1277     print 'Notice: no promptinit available :('
1278 fi
1279
1280 setopt prompt_subst
1281
1282 # make sure to use right prompt only when not running a command
1283 is41 && setopt transient_rprompt
1284
1285
1286 function ESC_print () {
1287     info_print $'\ek' $'\e\\' "$@"
1288 }
1289 function set_title () {
1290     info_print  $'\e]0;' $'\a' "$@"
1291 }
1292
1293 function info_print () {
1294     local esc_begin esc_end
1295     esc_begin="$1"
1296     esc_end="$2"
1297     shift 2
1298     printf '%s' ${esc_begin}
1299     printf '%s' "$*"
1300     printf '%s' "${esc_end}"
1301 }
1302
1303 # TODO: revise all these NO* variables and especially their documentation
1304 #       in zsh-help() below.
1305 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
1306     [[ $NOPRECMD -gt 0 ]] && return 0
1307     # update VCS information
1308     vcs_info
1309
1310     if [[ $TERM == screen* ]] ; then
1311         if [[ -n ${vcs_info_msg_1_} ]] ; then
1312             ESC_print ${vcs_info_msg_1_}
1313         else
1314             ESC_print "zsh"
1315         fi
1316     fi
1317     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
1318     if [[ $DONTSETRPROMPT -eq 0 ]] ; then
1319         if [[ $BATTERY -gt 0 ]] ; then
1320             # update battery (dropped into $PERCENT) information
1321             battery
1322             RPROMPT="%(?..:() ${PERCENT}"
1323         else
1324             RPROMPT="%(?..:() "
1325         fi
1326     fi
1327     # adjust title of xterm
1328     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
1329     [[ ${NOTITLE} -gt 0 ]] && return 0
1330     case $TERM in
1331         (xterm*|rxvt*)
1332             set_title ${(%):-"%n@%m: %~"}
1333             ;;
1334     esac
1335 }
1336
1337 # preexec() => a function running before every command
1338 is4 && [[ $NOPRECMD -eq 0 ]] && \
1339 preexec () {
1340     [[ $NOPRECMD -gt 0 ]] && return 0
1341 # set hostname if not running on host with name 'grml'
1342     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
1343        NAME="@$HOSTNAME"
1344     fi
1345 # get the name of the program currently running and hostname of local machine
1346 # set screen window title if running in a screen
1347     if [[ "$TERM" == screen* ]] ; then
1348         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
1349         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
1350         ESC_print ${CMD}
1351     fi
1352 # adjust title of xterm
1353     [[ ${NOTITLE} -gt 0 ]] && return 0
1354     case $TERM in
1355         (xterm*|rxvt*)
1356             set_title "${(%):-"%n@%m:"}" "$1"
1357             ;;
1358     esac
1359 }
1360
1361 EXITCODE="%(?..%?%1v )"
1362 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
1363 PS3='?# '         # selection prompt used within a select loop.
1364 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
1365
1366 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
1367 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
1368     debian_chroot=$(cat /etc/debian_chroot)
1369 fi
1370
1371 # don't use colors on dumb terminals (like emacs):
1372 if [[ "$TERM" == dumb ]] ; then
1373     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "
1374 else
1375     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
1376     # set variable identifying the chroot you work in (used in the prompt below)
1377     if [[ $GRMLPROMPT -gt 0 ]] ; then
1378         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
1379 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1380     else
1381         # This assembles the primary prompt string
1382         if (( EUID != 0 )); then
1383             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1384         else
1385             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
1386         fi
1387     fi
1388 fi
1389
1390 PROMPT="${PROMPT}"'${vcs_info_msg_0_}'"%# "
1391
1392 # if we are inside a grml-chroot set a specific prompt theme
1393 if [[ -n "$GRML_CHROOT" ]] ; then
1394     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
1395 fi
1396 # }}}
1397
1398 # {{{ 'hash' some often used directories
1399 #d# start
1400 hash -d deb=/var/cache/apt/archives
1401 hash -d doc=/usr/share/doc
1402 hash -d linux=/lib/modules/$(command uname -r)/build/
1403 hash -d log=/var/log
1404 hash -d slog=/var/log/syslog
1405 hash -d src=/usr/src
1406 hash -d templ=/usr/share/doc/grml-templates
1407 hash -d tt=/usr/share/doc/texttools-doc
1408 hash -d www=/var/www
1409 #d# end
1410 # }}}
1411
1412 # {{{ some aliases
1413 if check_com -c screen ; then
1414     if [[ $UID -eq 0 ]] ; then
1415         [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
1416     elif [[ -r $HOME/.screenrc ]] ; then
1417         alias screen="${commands[screen]} -c $HOME/.screenrc"
1418     else
1419         if [[ -r /etc/grml/screenrc_grml ]]; then
1420             alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
1421         else
1422             [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
1423         fi
1424     fi
1425 fi
1426
1427 # do we have GNU ls with color-support?
1428 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
1429     #a1# execute \kbd{@a@}:\quad ls with colors
1430     alias ls='ls -b -CF --color=auto'
1431     #a1# execute \kbd{@a@}:\quad list all files, with colors
1432     alias la='ls -la --color=auto'
1433     #a1# long colored list, without dotfiles (@a@)
1434     alias ll='ls -l --color=auto'
1435     #a1# long colored list, human readable sizes (@a@)
1436     alias lh='ls -hAl --color=auto'
1437     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
1438     alias l='ls -lF --color=auto'
1439 else
1440     alias ls='ls -b -CF'
1441     alias la='ls -la'
1442     alias ll='ls -l'
1443     alias lh='ls -hAl'
1444     alias l='ls -lF'
1445 fi
1446
1447 alias mdstat='cat /proc/mdstat'
1448 alias ...='cd ../../'
1449
1450 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
1451 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
1452     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
1453 fi
1454
1455 alias cp='nocorrect cp'         # no spelling correction on cp
1456 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
1457 alias mv='nocorrect mv'         # no spelling correction on mv
1458 alias rm='nocorrect rm'         # no spelling correction on rm
1459
1460 #a1# Execute \kbd{rmdir}
1461 alias rd='rmdir'
1462 #a1# Execute \kbd{mkdir}
1463 alias md='mkdir'
1464
1465 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
1466 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
1467 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
1468
1469 # make sure it is not assigned yet
1470 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
1471 utf2iso() {
1472     if isutfenv ; then
1473         for ENV in $(env | command grep -i '.utf') ; do
1474             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
1475         done
1476     fi
1477 }
1478
1479 # make sure it is not assigned yet
1480 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
1481 iso2utf() {
1482     if ! isutfenv ; then
1483         for ENV in $(env | command grep -i '\.iso') ; do
1484             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
1485         done
1486     fi
1487 }
1488
1489 # set up software synthesizer via speakup
1490 swspeak() {
1491     if [ -x /usr/sbin/swspeak-setup ] ; then
1492        setopt singlelinezle
1493        unsetopt prompt_cr
1494        export PS1="%m%# "
1495        /usr/sbin/swspeak-setup $@
1496      else # old version:
1497         if ! [[ -r /dev/softsynth ]] ; then
1498             flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
1499             return 1
1500         else
1501            setopt singlelinezle
1502            unsetopt prompt_cr
1503            export PS1="%m%# "
1504             nice -n -20 speechd-up
1505             sleep 2
1506             flite -o play -t "Finished setting up software synthesizer"
1507         fi
1508      fi
1509 }
1510
1511 # I like clean prompt, so provide simple way to get that
1512 check_com 0 || alias 0='return 0'
1513
1514 # for really lazy people like mika:
1515 check_com S &>/dev/null || alias S='screen'
1516 check_com s &>/dev/null || alias s='ssh'
1517
1518 # especially for roadwarriors using GNU screen and ssh:
1519 if ! check_com asc &>/dev/null ; then
1520   asc() { autossh -t "$@" 'screen -RdU' }
1521   compdef asc=ssh
1522 fi
1523
1524 # get top 10 shell commands:
1525 alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
1526
1527 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
1528 if check_com -c truecrypt ; then
1529     if isutfenv ; then
1530         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
1531     else
1532         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
1533     fi
1534 fi
1535
1536 #f1# Hints for the use of zsh on grml
1537 zsh-help() {
1538     print "$bg[white]$fg[black]
1539 zsh-help - hints for use of zsh on grml
1540 =======================================$reset_color"
1541
1542     print '
1543 Main configuration of zsh happens in /etc/zsh/zshrc.
1544 That file is part of the package grml-etc-core, if you want to
1545 use them on a non-grml-system just get the tar.gz from
1546 http://deb.grml.org/ or (preferably) get it from the git repository:
1547
1548   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
1549
1550 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
1551 The file is still there, but it is empty for backwards compatibility.
1552
1553 For your own changes use these two files:
1554     $HOME/.zshrc.pre
1555     $HOME/.zshrc.local
1556
1557 The former is sourced very early in our zshrc, the latter is sourced
1558 very lately.
1559
1560 System wide configuration without touching configuration files of grml
1561 can take place in /etc/zsh/zshrc.local.
1562
1563 Normally, the root user (EUID == 0) does not get the whole grml setup.
1564 If you want to force the whole setup for that user, too, set
1565 GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
1566
1567 For information regarding zsh start at http://grml.org/zsh/
1568
1569 Take a look at grml'\''s zsh refcard:
1570 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
1571
1572 Check out the main zsh refcard:
1573 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
1574
1575 And of course visit the zsh-lovers:
1576 % man zsh-lovers
1577
1578 You can adjust some options through environment variables when
1579 invoking zsh without having to edit configuration files.
1580 Basically meant for bash users who are not used to the power of
1581 the zsh yet. :)
1582
1583   "NOCOR=1    zsh" => deactivate automatic correction
1584   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
1585   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
1586   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
1587                       preexec() and precmd() completely
1588   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
1589   "COMMAND_NOT_FOUND=1 zsh"
1590                    => Enable a handler if an external command was not found
1591                       The command called in the handler can be altered by setting
1592                       the GRML_ZSH_CNF_HANDLER variable, the default is:
1593                       "/usr/share/command-not-found/command-not-found"
1594
1595 A value greater than 0 is enables a feature; a value equal to zero
1596 disables it. If you like one or the other of these settings, you can
1597 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
1598 zshrc.'
1599
1600     print "
1601 $bg[white]$fg[black]
1602 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
1603 Enjoy your grml system with the zsh!$reset_color"
1604 }
1605
1606 # debian stuff
1607 if [[ -r /etc/debian_version ]] ; then
1608     #a3# Execute \kbd{apt-cache search}
1609     alias acs='apt-cache search'
1610     #a3# Execute \kbd{apt-cache show}
1611     alias acsh='apt-cache show'
1612     #a3# Execute \kbd{apt-cache policy}
1613     alias acp='apt-cache policy'
1614     #a3# Execute \kbd{apt-get dist-upgrade}
1615     salias adg="apt-get dist-upgrade"
1616     #a3# Execute \kbd{apt-get install}
1617     salias agi="apt-get install"
1618     #a3# Execute \kbd{aptitude install}
1619     salias ati="aptitude install"
1620     #a3# Execute \kbd{apt-get upgrade}
1621     salias ag="apt-get upgrade"
1622     #a3# Execute \kbd{apt-get update}
1623     salias au="apt-get update"
1624     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
1625     salias -a up="aptitude update ; aptitude safe-upgrade"
1626     #a3# Execute \kbd{dpkg-buildpackage}
1627     alias dbp='dpkg-buildpackage'
1628     #a3# Execute \kbd{grep-excuses}
1629     alias ge='grep-excuses'
1630
1631     # debian upgrade
1632     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
1633     upgrade() {
1634         emulate -L zsh
1635         if [[ -z $1 ]] ; then
1636             $SUDO apt-get update
1637             $SUDO apt-get -u upgrade
1638         else
1639             ssh $1 $SUDO apt-get update
1640             # ask before the upgrade
1641             local dummy
1642             ssh $1 $SUDO apt-get --no-act upgrade
1643             echo -n 'Process the upgrade?'
1644             read -q dummy
1645             if [[ $dummy == "y" ]] ; then
1646                 ssh $1 $SUDO apt-get -u upgrade --yes
1647             fi
1648         fi
1649     }
1650
1651     # get a root shell as normal user in live-cd mode:
1652     if isgrmlcd && [[ $UID -ne 0 ]] ; then
1653        alias su="sudo su"
1654      fi
1655
1656     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
1657     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
1658     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
1659     salias tlog="tail -f /var/log/syslog"    # follow the syslog
1660 fi
1661
1662 # sort installed Debian-packages by size
1663 if check_com -c grep-status ; then
1664     #a3# List installed Debian-packages sorted by size
1665     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
1666 fi
1667
1668 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
1669 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
1670     if check_com -c wodim; then
1671         cdrecord() {
1672             cat <<EOMESS
1673 cdrecord is not provided under its original name by Debian anymore.
1674 See #377109 in the BTS of Debian for more details.
1675
1676 Please use the wodim binary instead
1677 EOMESS
1678             return 1
1679         }
1680     fi
1681 fi
1682
1683 # get_tw_cli has been renamed into get_3ware
1684 if check_com -c get_3ware ; then
1685     get_tw_cli() {
1686         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
1687         get_3ware
1688     }
1689 fi
1690
1691 # I hate lacking backward compatibility, so provide an alternative therefore
1692 if ! check_com -c apache2-ssl-certificate ; then
1693
1694     apache2-ssl-certificate() {
1695
1696     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
1697     print 'You might want to take a look at Debian the package ssl-cert as well.'
1698     print 'To generate a certificate for use with apache2 follow the instructions:'
1699
1700     echo '
1701
1702 export RANDFILE=/dev/random
1703 mkdir /etc/apache2/ssl/
1704 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
1705 chmod 600 /etc/apache2/ssl/apache.pem
1706
1707 Run "grml-tips ssl-certificate" if you need further instructions.
1708 '
1709     }
1710 fi
1711 # }}}
1712
1713 # {{{ Use hard limits, except for a smaller stack and no core dumps
1714 unlimit
1715 is425 && limit stack 8192
1716 isgrmlcd && limit core 0 # important for a live-cd-system
1717 limit -s
1718 # }}}
1719
1720 # {{{ completion system
1721
1722 # called later (via is4 && grmlcomp)
1723 # note: use 'zstyle' for getting current settings
1724 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
1725 grmlcomp() {
1726     # TODO: This could use some additional information
1727
1728     # allow one error for every three characters typed in approximate completer
1729     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
1730
1731     # don't complete backup files as executables
1732     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
1733
1734     # start menu completion only if it could find no unambiguous initial string
1735     zstyle ':completion:*:correct:*'       insert-unambiguous true
1736     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
1737     zstyle ':completion:*:correct:*'       original true
1738
1739     # activate color-completion
1740     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
1741
1742     # format on completion
1743     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
1744
1745     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
1746     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
1747
1748     # insert all expansions for expand completer
1749     zstyle ':completion:*:expand:*'        tag-order all-expansions
1750     zstyle ':completion:*:history-words'   list false
1751
1752     # activate menu
1753     zstyle ':completion:*:history-words'   menu yes
1754
1755     # ignore duplicate entries
1756     zstyle ':completion:*:history-words'   remove-all-dups yes
1757     zstyle ':completion:*:history-words'   stop yes
1758
1759     # match uppercase from lowercase
1760     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
1761
1762     # separate matches into groups
1763     zstyle ':completion:*:matches'         group 'yes'
1764     zstyle ':completion:*'                 group-name ''
1765
1766     if [[ "$NOMENU" -eq 0 ]] ; then
1767         # if there are more than 5 options allow selecting from a menu
1768         zstyle ':completion:*'               menu select=5
1769     else
1770         # don't use any menus at all
1771         setopt no_auto_menu
1772     fi
1773
1774     zstyle ':completion:*:messages'        format '%d'
1775     zstyle ':completion:*:options'         auto-description '%d'
1776
1777     # describe options in full
1778     zstyle ':completion:*:options'         description 'yes'
1779
1780     # on processes completion complete all user processes
1781     zstyle ':completion:*:processes'       command 'ps -au$USER'
1782
1783     # offer indexes before parameters in subscripts
1784     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
1785
1786     # provide verbose completion information
1787     zstyle ':completion:*'                 verbose true
1788
1789     # recent (as of Dec 2007) zsh versions are able to provide descriptions
1790     # for commands (read: 1st word in the line) that it will list for the user
1791     # to choose from. The following disables that, because it's not exactly fast.
1792     zstyle ':completion:*:-command-:*:'    verbose false
1793
1794     # set format for warnings
1795     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
1796
1797     # define files to ignore for zcompile
1798     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
1799     zstyle ':completion:correct:'          prompt 'correct to: %e'
1800
1801     # Ignore completion functions for commands you don't have:
1802     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
1803
1804     # Provide more processes in completion of programs like killall:
1805     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
1806
1807     # complete manual by their section
1808     zstyle ':completion:*:manuals'    separate-sections true
1809     zstyle ':completion:*:manuals.*'  insert-sections   true
1810     zstyle ':completion:*:man:*'      menu yes select
1811
1812     # provide .. as a completion
1813     zstyle ':completion:*' special-dirs ..
1814
1815     # run rehash on completion so new installed program are found automatically:
1816     _force_rehash() {
1817         (( CURRENT == 1 )) && rehash
1818         return 1
1819     }
1820
1821     ## correction
1822     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
1823     if [[ "$NOCOR" -gt 0 ]] ; then
1824         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
1825         setopt nocorrect
1826     else
1827         # try to be smart about when to use what completer...
1828         setopt correct
1829         zstyle -e ':completion:*' completer '
1830             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
1831                 _last_try="$HISTNO$BUFFER$CURSOR"
1832                 reply=(_complete _match _ignored _prefix _files)
1833             else
1834                 if [[ $words[1] == (rm|mv) ]] ; then
1835                     reply=(_complete _files)
1836                 else
1837                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
1838                 fi
1839             fi'
1840     fi
1841
1842     # command for process lists, the local web server details and host completion
1843     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
1844
1845     # caching
1846     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
1847                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
1848
1849     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
1850     if is42 ; then
1851         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
1852         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
1853     else
1854         _ssh_hosts=()
1855         _etc_hosts=()
1856     fi
1857     hosts=(
1858         $(hostname)
1859         "$_ssh_hosts[@]"
1860         "$_etc_hosts[@]"
1861         grml.org
1862         localhost
1863     )
1864     zstyle ':completion:*:hosts' hosts $hosts
1865     # TODO: so, why is this here?
1866     #  zstyle '*' hosts $hosts
1867
1868     # use generic completion system for programs not yet defined; (_gnu_generic works
1869     # with commands that provide a --help option with "standard" gnu-like output.)
1870     for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
1871                    pal stow tail uname ; do
1872         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
1873     done; unset compcom
1874
1875     # see upgrade function in this file
1876     compdef _hosts upgrade
1877 }
1878 # }}}
1879
1880 # {{{ grmlstuff
1881 grmlstuff() {
1882 # people should use 'grml-x'!
1883     if check_com -c 915resolution; then
1884         855resolution() {
1885             echo "Please use 915resolution as resolution modifying tool for Intel \
1886 graphic chipset."
1887             return -1
1888         }
1889     fi
1890
1891     #a1# Output version of running grml
1892     alias grml-version='cat /etc/grml_version'
1893
1894     if check_com -c rebuildfstab ; then
1895         #a1# Rebuild /etc/fstab
1896         alias grml-rebuildfstab='rebuildfstab -v -r -config'
1897     fi
1898
1899     if check_com -c grml-debootstrap ; then
1900         debian2hd() {
1901             echo "Installing debian to harddisk is possible by using grml-debootstrap."
1902             return 1
1903         }
1904     fi
1905 }
1906 # }}}
1907
1908 # {{{ now run the functions
1909 isgrml && checkhome
1910 is4    && isgrml    && grmlstuff
1911 is4    && grmlcomp
1912 # }}}
1913
1914 # {{{ keephack
1915 is4 && xsource "/etc/zsh/keephack"
1916 # }}}
1917
1918 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
1919 # You use it as follows:
1920 # $ NTREF=/reference/file
1921 # $ ls -l *(e:nt:)
1922 # This lists all the files in the current directory newer than the reference file.
1923 # You can also specify the reference file inline; note quotes:
1924 # $ ls -l *(e:'nt ~/.zshenv':)
1925 is4 && nt() {
1926     if [[ -n $1 ]] ; then
1927         local NTREF=${~1}
1928     fi
1929     [[ $REPLY -nt $NTREF ]]
1930 }
1931 # }}}
1932
1933 # shell functions {{{
1934
1935 #f1# Provide csh compatibility
1936 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
1937
1938 #f1# Reload an autoloadable function
1939 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
1940 compdef _functions freload
1941
1942 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
1943 sll() {
1944     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
1945     for file in "$@" ; do
1946         while [[ -h "$file" ]] ; do
1947             ls -l $file
1948             file=$(readlink "$file")
1949         done
1950     done
1951 }
1952
1953 # fast manual access
1954 if check_com qma ; then
1955     #f1# View the zsh manual
1956     manzsh()  { qma zshall "$1" }
1957     compdef _man qma
1958 else
1959     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
1960 fi
1961
1962 # TODO: Is it supported to use pager settings like this?
1963 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
1964 # with respect to wordsplitting. (ie. ${=PAGER})
1965 if check_com -c $PAGER ; then
1966     #f1# View Debian's changelog of a given package
1967     dchange() {
1968         emulate -L zsh
1969         if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
1970             $PAGER /usr/share/doc/$1/changelog.Debian.gz
1971         elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
1972             $PAGER /usr/share/doc/$1/changelog.gz
1973         else
1974             if check_com -c aptitude ; then
1975                 echo "No changelog for package $1 found, using aptitude to retrieve it."
1976                 if isgrml ; then
1977                     aptitude -t unstable changelog $1
1978                 else
1979                     aptitude changelog $1
1980                 fi
1981             else
1982                 echo "No changelog for package $1 found, sorry."
1983                 return 1
1984             fi
1985         fi
1986     }
1987     _dchange() { _files -W /usr/share/doc -/ }
1988     compdef _dchange dchange
1989
1990     #f1# View Debian's NEWS of a given package
1991     dnews() {
1992         emulate -L zsh
1993         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
1994             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
1995         else
1996             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
1997                 $PAGER /usr/share/doc/$1/NEWS.gz
1998             else
1999                 echo "No NEWS file for package $1 found, sorry."
2000                 return 1
2001             fi
2002         fi
2003     }
2004     _dnews() { _files -W /usr/share/doc -/ }
2005     compdef _dnews dnews
2006
2007     #f1# View upstream's changelog of a given package
2008     uchange() {
2009         emulate -L zsh
2010         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2011             $PAGER /usr/share/doc/$1/changelog.gz
2012         else
2013             echo "No changelog for package $1 found, sorry."
2014             return 1
2015         fi
2016     }
2017     _uchange() { _files -W /usr/share/doc -/ }
2018     compdef _uchange uchange
2019 fi
2020
2021 # zsh profiling
2022 profile() {
2023     ZSH_PROFILE_RC=1 $SHELL "$@"
2024 }
2025
2026 #f1# Edit an alias via zle
2027 edalias() {
2028     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2029 }
2030 compdef _aliases edalias
2031
2032 #f1# Edit a function via zle
2033 edfunc() {
2034     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2035 }
2036 compdef _functions edfunc
2037
2038 # use it e.g. via 'Restart apache2'
2039 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2040 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2041 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2042 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2043 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2044 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2045     __start_stop() {
2046         local action_="${1:l}"  # e.g Start/Stop/Restart
2047         local service_="$2"
2048         local param_="$3"
2049
2050         local service_target_="$(readlink /etc/init.d/$service_)"
2051         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2052             # runit
2053             case "${action_}" in
2054                 start) if [[ ! -e /etc/service/$service_ ]]; then
2055                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2056                        else
2057                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2058                        fi ;;
2059                 # there is no reload in runits sysv emulation
2060                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2061                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2062             esac
2063         else
2064             # sysvinit
2065             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2066         fi
2067     }
2068
2069     _grmlinitd() {
2070         local -a scripts
2071         scripts=( /etc/init.d/*(x:t) )
2072         _describe "service startup script" scripts
2073     }
2074
2075     for i in Start Restart Stop Force-Reload Reload ; do
2076         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2077         compdef _grmlinitd $i
2078     done
2079 fi
2080
2081 #f1# Provides useful information on globbing
2082 H-Glob() {
2083     echo -e "
2084     /      directories
2085     .      plain files
2086     @      symbolic links
2087     =      sockets
2088     p      named pipes (FIFOs)
2089     *      executable plain files (0100)
2090     %      device files (character or block special)
2091     %b     block special files
2092     %c     character special files
2093     r      owner-readable files (0400)
2094     w      owner-writable files (0200)
2095     x      owner-executable files (0100)
2096     A      group-readable files (0040)
2097     I      group-writable files (0020)
2098     E      group-executable files (0010)
2099     R      world-readable files (0004)
2100     W      world-writable files (0002)
2101     X      world-executable files (0001)
2102     s      setuid files (04000)
2103     S      setgid files (02000)
2104     t      files with the sticky bit (01000)
2105
2106   print *(m-1)          # Files modified up to a day ago
2107   print *(a1)           # Files accessed a day ago
2108   print *(@)            # Just symlinks
2109   print *(Lk+50)        # Files bigger than 50 kilobytes
2110   print *(Lk-50)        # Files smaller than 50 kilobytes
2111   print **/*.c          # All *.c files recursively starting in \$PWD
2112   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2113   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2114   print *~*.*           # All Files that do not contain a dot
2115   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2116   print -l *(.c|.h)     # Lists *.c and *.h
2117   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2118   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2119 }
2120 alias help-zshglob=H-Glob
2121
2122 check_com -c qma && alias ?='qma zshall'
2123
2124 # grep for running process, like: 'any vim'
2125 any() {
2126     emulate -L zsh
2127     unsetopt KSH_ARRAYS
2128     if [[ -z "$1" ]] ; then
2129         echo "any - grep for process(es) by keyword" >&2
2130         echo "Usage: any <keyword>" >&2 ; return 1
2131     else
2132         ps xauwww | grep --color=auto "[${1[1]}]${1[2,-1]}"
2133     fi
2134 }
2135
2136
2137 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2138 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2139 [[ -r /proc/1/maps ]] && \
2140 deswap() {
2141     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2142     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2143     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2144 }
2145
2146 # print hex value of a number
2147 hex() {
2148     emulate -L zsh
2149     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2150 }
2151
2152 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2153 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2154 peval() {
2155     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2156     perl -e "print eval($CALC),\"\n\";"
2157 }
2158 functions peval &>/dev/null && alias calc=peval
2159
2160 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2161 # certain circumstances, so work around it, no matter which environment we have
2162 brltty() {
2163     if [[ -z "$DISPLAY" ]] ; then
2164         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2165         command brltty "$@"
2166     else
2167         command brltty "$@"
2168     fi
2169 }
2170
2171 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2172 aoeu() {
2173     echo -n 'Switching to us keyboard layout: '
2174     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2175     echo 'Done'
2176 }
2177 asdf() {
2178     echo -n 'Switching to dvorak keyboard layout: '
2179     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2180     echo 'Done'
2181 }
2182 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2183 uiae() {
2184     echo -n 'Switching to us keyboard layout: '
2185     setxkbmap us && echo 'Done' || echo 'Failed'
2186 }
2187
2188 # set up an ipv6 tunnel
2189 ipv6-tunnel() {
2190     emulate -L zsh
2191     case $1 in
2192         start)
2193             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2194                 print 'ipv6 tunnel already set up, nothing to be done.'
2195                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
2196             else
2197                 [[ -n "$PUBLIC_IP" ]] || \
2198                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
2199                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
2200
2201                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
2202                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
2203                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
2204                 ifconfig sit0 tunnel ::192.88.99.1 up
2205                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
2206             fi
2207             ;;
2208         status)
2209             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2210                 print 'ipv6 tunnel available' ; return 0
2211             else
2212                 print 'ipv6 tunnel not available' ; return 1
2213             fi
2214             ;;
2215         stop)
2216             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
2217                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
2218                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
2219             else
2220                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
2221             fi
2222             ;;
2223         *)
2224             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
2225             ;;
2226     esac
2227 }
2228
2229 # run dhclient for wireless device
2230 iwclient() {
2231     sudo dhclient "$(wavemon -d | awk '/device/{print $3}')"
2232 }
2233
2234 # spawn a minimally set up mksh - useful if you want to umount /usr/.
2235 minimal-shell() {
2236     emulate -L zsh
2237     local shell="/bin/mksh"
2238
2239     if [[ ! -x ${shell} ]]; then
2240         printf '`%s'\'' not available, giving up.\n' ${shell} >&2
2241         return 1
2242     fi
2243
2244     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ${shell}
2245 }
2246
2247 # a wrapper for vim, that deals with title setting
2248 #   VIM_OPTIONS
2249 #       set this array to a set of options to vim you always want
2250 #       to have set when calling vim (in .zshrc.local), like:
2251 #           VIM_OPTIONS=( -p )
2252 #       This will cause vim to send every file given on the
2253 #       commandline to be send to it's own tab (needs vim7).
2254 vim() {
2255     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
2256 }
2257
2258 # make a backup of a file
2259 bk() {
2260     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
2261 }
2262
2263 #f1# grep for patterns in grml's zsh setup
2264 zg() {
2265 #{{{
2266     LANG=C perl -e '
2267
2268 sub usage {
2269     print "usage: zg -[anr] <pattern>\n";
2270     print " Search for patterns in grml'\''s zshrc.\n";
2271     print " zg takes no or exactly one option plus a non empty pattern.\n\n";
2272     print "   options:\n";
2273     print "     --  no options (use if your pattern starts in with a dash.\n";
2274     print "     -a  search for the pattern in all code regions\n";
2275     print "     -n  search for the pattern in non-root code only\n";
2276     print "     -r  search in code for everyone (also root) only\n\n";
2277     print "   The default is -a for non-root users and -r for root.\n\n";
2278     print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
2279     print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
2280     print " ...in case you copied the file to that location.\n\n";
2281     exit 1;
2282 }
2283
2284 if ($ENV{GRML_ZSHRC} ne "") {
2285     $RC = $ENV{GRML_ZSHRC};
2286 } else {
2287     $RC = "/etc/zsh/zshrc";
2288 }
2289
2290 usage if ($#ARGV < 0 || $#ARGV > 1);
2291 if ($> == 0) { $mode = "allonly"; }
2292 else { $mode = "all"; }
2293
2294 $opt = $ARGV[0];
2295 if ($opt eq "--")     { shift; }
2296 elsif ($opt eq "-a")  { $mode = "all"; shift; }
2297 elsif ($opt eq "-n")  { $mode = "nonroot"; shift; }
2298 elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
2299 elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
2300
2301 $pattern = $ARGV[0];
2302 usage() if ($pattern eq "");
2303
2304 open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
2305 while ($line = <FH>) {
2306     chomp $line;
2307     if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
2308     next if ($mode eq "nonroot" && markerfound == 0);
2309     break if ($mode eq "allonly" && markerfound == 1);
2310     print $line, "\n" if ($line =~ /$pattern/);
2311 }
2312 close FH;
2313 exit 0;
2314
2315     ' -- "$@"
2316 #}}}
2317     return $?
2318 }
2319
2320 ssl_hashes=( sha512 sha256 sha1 md5 )
2321
2322 for sh in ${ssl_hashes}; do
2323     eval 'ssl-cert-'${sh}'() {
2324         emulate -L zsh
2325         if [[ -z $1 ]] ; then
2326             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
2327             return 1
2328         fi
2329         openssl x509 -noout -fingerprint -'${sh}' -in $1
2330     }'
2331 done; unset sh
2332
2333 ssl-cert-fingerprints() {
2334     emulate -L zsh
2335     local i
2336     if [[ -z $1 ]] ; then
2337         printf 'usage: ssl-cert-fingerprints <file>\n'
2338         return 1
2339     fi
2340     for i in ${ssl_hashes}
2341         do ssl-cert-$i $1;
2342     done
2343 }
2344
2345 ssl-cert-info() {
2346     emulate -L zsh
2347     if [[ -z $1 ]] ; then
2348         printf 'usage: ssl-cert-info <file>\n'
2349         return 1
2350     fi
2351     openssl x509 -noout -text -in $1
2352     ssl-cert-fingerprints $1
2353 }
2354
2355 # }}}
2356
2357 # {{{ make sure our environment is clean regarding colors
2358 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
2359 # }}}
2360
2361 # "persistent history" {{{
2362 # just write important commands you always need to ~/.important_commands
2363 if [[ -r ~/.important_commands ]] ; then
2364     fc -R ~/.important_commands
2365 fi
2366 # }}}
2367
2368 # load the lookup subsystem if it's available on the system
2369 zrcautoload lookupinit && lookupinit
2370
2371 #:grep:marker:for:mika: :-)
2372 ### non-root (EUID != 0) code below
2373 ###
2374
2375 if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
2376     zrclocal
2377     return 0
2378 fi
2379
2380 # variables {{{
2381
2382 # set terminal property (used e.g. by msgid-chooser)
2383 export COLORTERM="yes"
2384
2385 # set default browser
2386 if [[ -z "$BROWSER" ]] ; then
2387     if [[ -n "$DISPLAY" ]] ; then
2388         #v# If X11 is running
2389         check_com -c firefox && export BROWSER=firefox
2390     else
2391         #v# If no X11 is running
2392         check_com -c w3m && export BROWSER=w3m
2393     fi
2394 fi
2395
2396 #m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
2397 [[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
2398 [[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
2399
2400 # support running 'jikes *.java && jamvm HelloWorld' OOTB:
2401 #v# [for non-root only]
2402 [[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
2403 # }}}
2404
2405 # aliases {{{
2406
2407 # Xterm resizing-fu.
2408 # Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
2409 alias hide='echo -en "\033]50;nil2\007"'
2410 alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
2411 alias small='echo -en "\033]50;6x10\007"'
2412 alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
2413 alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
2414 alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
2415 alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
2416 alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
2417 alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
2418
2419 # general
2420 #a2# Execute \kbd{du -sch}
2421 alias da='du -sch'
2422 #a2# Execute \kbd{jobs -l}
2423 alias j='jobs -l'
2424
2425 # compile stuff
2426 #a2# Execute \kbd{./configure}
2427 alias CO="./configure"
2428 #a2# Execute \kbd{./configure --help}
2429 alias CH="./configure --help"
2430
2431 # listing stuff
2432 #a2# Execute \kbd{ls -lSrah}
2433 alias dir="ls -lSrah"
2434 #a2# Only show dot-directories
2435 alias lad='ls -d .*(/)'                # only show dot-directories
2436 #a2# Only show dot-files
2437 alias lsa='ls -a .*(.)'                # only show dot-files
2438 #a2# Only files with setgid/setuid/sticky flag
2439 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
2440 #a2# Only show 1st ten symlinks
2441 alias lsl='ls -l *(@)'                 # only symlinks
2442 #a2# Display only executables
2443 alias lsx='ls -l *(*)'                 # only executables
2444 #a2# Display world-{readable,writable,executable} files
2445 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
2446 #a2# Display the ten biggest files
2447 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
2448 #a2# Only show directories
2449 alias lsd='ls -d *(/)'                 # only show directories
2450 #a2# Only show empty directories
2451 alias lse='ls -d *(/^F)'               # only show empty directories
2452 #a2# Display the ten newest files
2453 alias lsnew="ls -rtlh *(D.om[1,10])"   # display the newest files
2454 #a2# Display the ten oldest files
2455 alias lsold="ls -rtlh *(D.Om[1,10])"   # display the oldest files
2456 #a2# Display the ten smallest files
2457 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
2458
2459 # chmod
2460 #a2# Execute \kbd{chmod 600}
2461 alias rw-='chmod 600'
2462 #a2# Execute \kbd{chmod 700}
2463 alias rwx='chmod 700'
2464 #m# a2 r-{}- Execute \kbd{chmod 644}
2465 alias r--='chmod 644'
2466 #a2# Execute \kbd{chmod 755}
2467 alias r-x='chmod 755'
2468
2469 # some useful aliases
2470 #a2# Execute \kbd{mkdir -o}
2471 alias md='mkdir -p'
2472
2473 # console stuff
2474 #a2# Execute \kbd{mplayer -vo fbdev}
2475 alias cmplayer='mplayer -vo fbdev'
2476 #a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
2477 alias fbmplayer='mplayer -vo fbdev -fs -zoom'
2478 #a2# Execute \kbd{links2 -driver fb}
2479 alias fblinks='links2 -driver fb'
2480
2481 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
2482 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2483 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
2484
2485 # simple webserver
2486 check_com -c python && alias http="python -m SimpleHTTPServer"
2487
2488 # Use 'g' instead of 'git':
2489 check_com g || alias g='git'
2490
2491 # work around non utf8 capable software in utf environment via $LANG and luit
2492 if check_com isutfenv && check_com luit ; then
2493     if check_com -c mrxvt ; then
2494         isutfenv && [[ -n "$LANG" ]] && \
2495             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
2496     fi
2497
2498     if check_com -c aterm ; then
2499         isutfenv && [[ -n "$LANG" ]] && \
2500             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
2501     fi
2502
2503     if check_com -c centericq ; then
2504         isutfenv && [[ -n "$LANG" ]] && \
2505             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
2506     fi
2507 fi
2508 # }}}
2509
2510 # useful functions {{{
2511
2512 # searching
2513 #f4# Search for newspostings from authors
2514 agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
2515 #f4# Search Debian Bug Tracking System
2516 debbug()  {
2517     emulate -L zsh
2518     setopt extendedglob
2519     if [[ $# -eq 1 ]]; then
2520         case "$1" in
2521             ([0-9]##)
2522             ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
2523             ;;
2524             (*@*)
2525             ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
2526             ;;
2527             (*)
2528             ${=BROWSER} "http://bugs.debian.org/$*"
2529             ;;
2530         esac
2531     else
2532         print "$0 needs one argument"
2533         return 1
2534     fi
2535 }
2536 #f4# Search Debian Bug Tracking System in mbox format
2537 debbugm() {
2538     emulate -L zsh
2539     bts show --mbox $1
2540 }
2541 #f4# Search DMOZ
2542 dmoz()    {
2543     emulate -L zsh
2544     ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_}
2545 }
2546 #f4# Search German   Wiktionary
2547 dwicti()  {
2548     emulate -L zsh
2549     ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_}
2550 }
2551 #f4# Search English  Wiktionary
2552 ewicti()  {
2553     emulate -L zsh
2554     ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_}
2555 }
2556 #f4# Search Google Groups
2557 ggogle()  {
2558     emulate -L zsh
2559     ${=BROWSER} "http://groups.google.com/groups?q=$*"
2560 }
2561 #f4# Search Google
2562 google()  {
2563     emulate -L zsh
2564     ${=BROWSER} "http://www.google.com/search?&num=100&q=$*"
2565 }
2566 #f4# Search Google Groups for MsgID
2567 mggogle() {
2568     emulate -L zsh
2569     ${=BROWSER} "http://groups.google.com/groups?selm=$*"
2570 }
2571 #f4# Search Netcraft
2572 netcraft(){
2573     emulate -L zsh
2574     ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1"
2575 }
2576 #f4# Use German Wikipedia's full text search
2577 swiki()   {
2578     emulate -L zsh
2579     ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1}
2580 }
2581 #f4# search \kbd{dict.leo.org}
2582 oleo()    {
2583     emulate -L zsh
2584     ${=BROWSER} "http://dict.leo.org/?search=$*"
2585 }
2586 #f4# Search German   Wikipedia
2587 wikide()  {
2588     emulate -L zsh
2589     ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}"
2590 }
2591 #f4# Search English  Wikipedia
2592 wikien()  {
2593     emulate -L zsh
2594     ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}"
2595 }
2596 #f4# Search official debs
2597 wodeb()   {
2598     emulate -L zsh
2599     ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all"
2600 }
2601
2602 #m# f4 gex() Exact search via Google
2603 check_com google && gex () {
2604     google "\"[ $1]\" $*"
2605 }
2606
2607 # misc
2608 #f5# Backup \kbd{file {\rm to} file\_timestamp}
2609 bk() {
2610     emulate -L zsh
2611     cp -b $1 $1_`date --iso-8601=m`
2612 }
2613 #f5# Copied diff
2614 cdiff() {
2615     emulate -L zsh
2616     diff -crd "$@" | egrep -v "^Only in |^Binary files "
2617 }
2618 #f5# cd to directoy and list files
2619 cl() {
2620     emulate -L zsh
2621     cd $1 && ls -a
2622 }
2623 #f5# Cvs add
2624 cvsa() {
2625     emulate -L zsh
2626     cvs add $* && cvs com -m 'initial checkin' $*
2627 }
2628 #f5# Cvs diff
2629 cvsd() {
2630     emulate -L zsh
2631     cvs diff -N $* |& $PAGER
2632 }
2633 #f5# Cvs log
2634 cvsl() {
2635     emulate -L zsh
2636     cvs log $* |& $PAGER
2637 }
2638 #f5# Cvs update
2639 cvsq() {
2640     emulate -L zsh
2641     cvs -nq update
2642 }
2643 #f5# Rcs2log
2644 cvsr() {
2645     emulate -L zsh
2646     rcs2log $* | $PAGER
2647 }
2648 #f5# Cvs status
2649 cvss() {
2650     emulate -L zsh
2651     cvs status -v $*
2652 }
2653 #f5# Disassemble source files using gcc and as
2654 disassemble(){
2655     emulate -L zsh
2656     gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null
2657 }
2658 #f5# Firefox remote control - open given URL
2659 fir() {
2660     if [ -e /etc/debian_version ]; then
2661         firefox -a iceweasel -remote "openURL($1)" || firefox ${1}&
2662     else
2663         firefox -a firefox -remote "openURL($1)" || firefox ${1}&
2664     fi
2665 }
2666 #f5# Create Directoy and \kbd{cd} to it
2667 mcd() {
2668     mkdir -p "$@" && cd "$@"
2669 }
2670 #f5# Create temporary directory and \kbd{cd} to it
2671 cdt() {
2672     local t
2673     t=$(mktemp -d)
2674     echo "$t"
2675     builtin cd "$t"
2676 }
2677 #f5# Unified diff to timestamped outputfile
2678 mdiff() {
2679     diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1"
2680 }
2681
2682 #f5# Create directory under cursor or the selected area
2683 # Press ctrl-xM to create the directory under the cursor or the selected area.
2684 # To select an area press ctrl-@ or ctrl-space and use the cursor.
2685 # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
2686 # directory does not exist yet -> press ctrl-XM and problem solved
2687 inplaceMkDirs() {
2688     local PATHTOMKDIR
2689     if ((REGION_ACTIVE==1)); then
2690         local F=$MARK T=$CURSOR
2691         if [[ $F -gt $T ]]; then
2692             F=${CURSOR}
2693             T=${MARK}
2694         fi
2695         # get marked area from buffer and eliminate whitespace
2696         PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
2697         PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
2698     else
2699         local bufwords iword
2700         bufwords=(${(z)LBUFFER})
2701         iword=${#bufwords}
2702         bufwords=(${(z)BUFFER})
2703         PATHTOMKDIR="$bufwords[iword]"
2704     fi
2705     [[ -z "${PATHTOMKDIR}" ]] && return 1
2706     if [[ -e "${PATHTOMKDIR}" ]]; then
2707         zle -M " path already exists, doing nothing"
2708     else
2709         zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
2710         zle end-of-line
2711     fi
2712 }
2713 zle -N inplaceMkDirs && bindkey '^XM' inplaceMkDirs
2714
2715 #f5# Memory overview
2716 memusage() {
2717     ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc
2718 }
2719 #f5# Show contents of gzipped tar file
2720 shtar() {
2721     emulate -L zsh
2722     gunzip -c $1 | tar -tf - -- | $PAGER
2723 }
2724 #f5# Show contents of zip file
2725 shzip() {
2726     emulate -L zsh
2727     unzip -l $1 | $PAGER
2728 }
2729 #f5# Unified diff
2730 udiff() {
2731     emulate -L zsh
2732     diff -urd $* | egrep -v "^Only in |^Binary files "
2733 }
2734 #f5# (Mis)use \kbd{vim} as \kbd{less}
2735 viless() {
2736     emulate -L zsh
2737     vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}"
2738 }
2739
2740 # Function Usage: uopen $URL/$file
2741 #f5# Download a file and display it locally
2742 uopen() {
2743     emulate -L zsh
2744     if ! [[ -n "$1" ]] ; then
2745         print "Usage: uopen \$URL/\$file">&2
2746         return 1
2747     else
2748         FILE=$1
2749         MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
2750         MIME=${MIME%$'\r'}
2751         curl $FILE | see ${MIME}:-
2752     fi
2753 }
2754
2755 # Function Usage: doc packagename
2756 #f5# \kbd{cd} to /usr/share/doc/\textit{package}
2757 doc() {
2758     emulate -L zsh
2759     cd /usr/share/doc/$1 && ls
2760 }
2761 _doc() { _files -W /usr/share/doc -/ }
2762 check_com compdef && compdef _doc doc
2763
2764 #f5# Make screenshot
2765 sshot() {
2766     [[ ! -d ~/shots  ]] && mkdir ~/shots
2767     #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
2768     cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
2769 }
2770
2771 # list images only
2772 limg() {
2773     local -a images
2774     images=( *.{jpg,gif,png}(.N) )
2775
2776     if [[ $#images -eq 0 ]] ; then
2777         print "No image files found"
2778     else
2779         ls "$images[@]"
2780     fi
2781 }
2782
2783 #f5# Create PDF file from source code
2784 makereadable() {
2785     emulate -L zsh
2786     output=$1
2787     shift
2788     a2ps --medium A4dj -E -o $output $*
2789     ps2pdf $output
2790 }
2791
2792 # zsh with perl-regex - use it e.g. via:
2793 # regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
2794 #f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
2795 regcheck() {
2796     emulate -L zsh
2797     zmodload -i zsh/pcre
2798     pcre_compile $1 && \
2799     pcre_match $2 && echo "regex matches" || echo "regex does not match"
2800 }
2801
2802 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
2803 accessed() {
2804     emulate -L zsh
2805     print -l -- *(a-${1:-1})
2806 }
2807
2808 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
2809 changed() {
2810     emulate -L zsh
2811     print -l -- *(c-${1:-1})
2812 }
2813
2814 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
2815 modified() {
2816     emulate -L zsh
2817     print -l -- *(m-${1:-1})
2818 }
2819 # modified() was named new() in earlier versions, add an alias for backwards compatibility
2820 check_com new || alias new=modified
2821
2822 #f5# Grep in history
2823 greph() {
2824     emulate -L zsh
2825     history 0 | grep $1
2826 }
2827 # use colors when GNU grep with color-support
2828 #a2# Execute \kbd{grep -{}-color=auto}
2829 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
2830 #a2# Execute \kbd{grep -i -{}-color=auto}
2831 alias GREP='grep -i --color=auto'
2832
2833 #f5# Watch manpages in a stretched style
2834 man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
2835
2836 # usage example: 'lcheck strcpy'
2837 #f5# Find out which libs define a symbol
2838 lcheck() {
2839     if [[ -n "$1" ]] ; then
2840         nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
2841     else
2842         echo "Usage: lcheck <function>" >&2
2843     fi
2844 }
2845
2846 #f5# Clean up directory - remove well known tempfiles
2847 purge() {
2848     emulate -L zsh
2849     setopt HIST_SUBST_PATTERN
2850     local -a TEXTEMPFILES GHCTEMPFILES PYTEMPFILES FILES
2851     TEXTEMPFILES=(*.tex(N:s/%tex/'(log|toc|aux|nav|snm|out|tex.backup|bbl|blg|bib.backup|vrb|lof|lot|hd|idx)(N)'/))
2852     GHCTEMPFILES=(*.(hs|lhs)(N:r:s/%/'.(hi|hc|(p|u|s)_(o|hi))(N)'/))
2853     PYTEMPFILES=(*.py(N:s/%py/'(pyc|pyo)(N)'/))
2854     LONELY_MOOD_FILES=((*.mood)(NDe:'local -a AF;AF=( ${${REPLY#.}%mood}(mp3|flac|ogg|asf|wmv|aac)(N) ); [[ -z "$AF" ]]':))
2855     FILES=(*~(.N) \#*\#(.N) *.o(.N) a.out(.N) (*.|)core(.N) *.cmo(.N) *.cmi(.N) .*.swp(.N) *.(orig|rej)(.DN) *.dpkg-(old|dist|new)(DN) ._(cfg|mrg)[0-9][0-9][0-9][0-9]_*(N) ${~TEXTEMPFILES} ${~GHCTEMPFILES} ${~PYTEMPFILES} ${LONELY_MOOD_FILES})
2856     local NBFILES=${#FILES}
2857     local CURDIRSUDO=""
2858     [[ ! -w ./ ]] && CURDIRSUDO=$SUDO
2859     if [[ $NBFILES > 0 ]] ; then
2860         print -l $FILES
2861         local ans
2862         echo -n "Remove these files? [y/n] "
2863         read -q ans
2864         if [[ $ans == "y" ]] ; then
2865             $CURDIRSUDO rm ${FILES}
2866             echo ">> $PWD purged, $NBFILES files removed"
2867         else
2868             echo "Ok. .. then not.."
2869         fi
2870     fi
2871 }
2872
2873 #f5# show labels and uuids of disk devices
2874 if is439 && [[ -d /dev/disk/by-id/ ]]; then
2875     lsdisk() {
2876         emulate -L zsh
2877         setopt extendedglob
2878         local -a -U disks
2879         disks=( /dev/disk/by-id/*(@:A) )
2880         for dev in "$disks[@]"; do
2881             print ${fg_bold[red]}${dev}${reset_color} /dev/disk/by-label/*(@e/'[[ ${REPLY:A} == $dev ]] && REPLY=${fg[blue]}LABEL=${REPLY:t}${reset_color}'/N) /dev/disk/by-uuid/*(@e/'[[ ${REPLY:A} == $dev ]] && REPLY=${fg[green]}UUID=${REPLY:t}${reset_color}'/N)
2882             print -f "  %s\n" /dev/disk/by-id/*(@e/'[[ ${REPLY:A} == $dev ]]'/N:t)
2883         done
2884     }
2885 fi
2886
2887 #f5# run command or function in a list of directories
2888 rundirs() {
2889   local d CMD STARTDIR=$PWD
2890   CMD=$1; shift
2891   ( for d ($@) {cd -q $d && { print cd $d; ${(z)CMD} ; cd -q $STARTDIR }} )
2892 }
2893
2894 # Translate DE<=>EN
2895 # 'translate' looks up fot a word in a file with language-to-language
2896 # translations (field separator should be " : "). A typical wordlist looks
2897 # like at follows:
2898 #  | english-word : german-transmission
2899 # It's also only possible to translate english to german but not reciprocal.
2900 # Use the following oneliner to turn back the sort order:
2901 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
2902 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
2903 #f5# Translates a word
2904 trans() {
2905     emulate -L zsh
2906     case "$1" in
2907         -[dD]*)
2908             translate -l de-en $2
2909             ;;
2910         -[eE]*)
2911             translate -l en-de $2
2912             ;;
2913         *)
2914             echo "Usage: $0 { -D | -E }"
2915             echo "         -D == German to English"
2916             echo "         -E == English to German"
2917     esac
2918 }
2919
2920 #f5# List all occurrences of programm in current PATH
2921 plap() {
2922     emulate -L zsh
2923     if [[ $# = 0 ]] ; then
2924         echo "Usage:    $0 program"
2925         echo "Example:  $0 zsh"
2926         echo "Lists all occurrences of program in the current PATH."
2927     else
2928         ls -l ${^path}/*$1*(*N)
2929     fi
2930 }
2931
2932 # Found in the mailinglistarchive from Zsh (IIRC ~1996)
2933 #f5# Select items for specific command(s) from history
2934 selhist() {
2935     emulate -L zsh
2936     local TAB=$'\t';
2937     (( $# < 1 )) && {
2938         echo "Usage: $0 command"
2939         return 1
2940     };
2941     cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
2942     print -l $cmd | less -F
2943     echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
2944     local answer
2945     read answer
2946     print -z "${cmd[$answer]#*$TAB}"
2947 }
2948
2949 # Use vim to convert plaintext to HTML
2950 #f5# Transform files to html with highlighting
2951 2html() {
2952     emulate -L zsh
2953     vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null
2954 }
2955
2956 # Usage: simple-extract <file>
2957 # Using option -d deletes the original archive file.
2958 #f5# Smart archive extractor
2959 simple-extract() {
2960     emulate -L zsh
2961     setopt extended_glob noclobber
2962     local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
2963     local RC=0
2964     zparseopts -D -E "d=DELETE_ORIGINAL"
2965     for ARCHIVE in "${@}"; do
2966         case $ARCHIVE in
2967             *.(tar.bz2|tbz2|tbz))
2968                 DECOMP_CMD="tar -xvjf -"
2969                 USES_STDIN=true
2970                 USES_STDOUT=false
2971                 ;;
2972             *.(tar.gz|tgz))
2973                 DECOMP_CMD="tar -xvzf -"
2974                 USES_STDIN=true
2975                 USES_STDOUT=false
2976                 ;;
2977             *.(tar.xz|txz|tar.lzma))
2978                 DECOMP_CMD="tar -xvJf -"
2979                 USES_STDIN=true
2980                 USES_STDOUT=false
2981                 ;;
2982             *.tar)
2983                 DECOMP_CMD="tar -xvf -"
2984                 USES_STDIN=true
2985                 USES_STDOUT=false
2986                 ;;
2987             *.rar)
2988                 DECOMP_CMD="unrar x"
2989                 USES_STDIN=false
2990                 USES_STDOUT=false
2991                 ;;
2992             *.lzh)
2993                 DECOMP_CMD="lha x"
2994                 USES_STDIN=false
2995                 USES_STDOUT=false
2996                 ;;
2997             *.7z)
2998                 DECOMP_CMD="7z x"
2999                 USES_STDIN=false
3000                 USES_STDOUT=false
3001                 ;;
3002             *.(zip|jar))
3003                 DECOMP_CMD="unzip"
3004                 USES_STDIN=false
3005                 USES_STDOUT=false
3006                 ;;
3007             *.deb)
3008                 DECOMP_CMD="ar -x"
3009                 USES_STDIN=false
3010                 USES_STDOUT=false
3011                 ;;
3012             *.bz2)
3013                 DECOMP_CMD="bzip2 -d -c -"
3014                 USES_STDIN=true
3015                 USES_STDOUT=true
3016                 ;;
3017             *.(gz|Z))
3018                 DECOMP_CMD="gzip -d -c -"
3019                 USES_STDIN=true
3020                 USES_STDOUT=true
3021                 ;;
3022             *.(xz|lzma))
3023                 DECOMP_CMD="xz -d -c -"
3024                 USES_STDIN=true
3025                 USES_STDOUT=true
3026                 ;;
3027             *)
3028                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
3029                 RC=$((RC+1))
3030                 continue
3031                 ;;
3032         esac
3033
3034         if ! check_com ${DECOMP_CMD[(w)1]}; then
3035             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
3036             RC=$((RC+2))
3037             continue
3038         fi
3039
3040         GZTARGET="${ARCHIVE:t:r}"
3041         if [[ -f $ARCHIVE ]] ; then
3042
3043             print "Extracting '$ARCHIVE' ..."
3044             if $USES_STDIN; then
3045                 if $USES_STDOUT; then
3046                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
3047                 else
3048                     ${=DECOMP_CMD} < "$ARCHIVE"
3049                 fi
3050             else
3051                 if $USES_STDOUT; then
3052                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
3053                 else
3054                     ${=DECOMP_CMD} "$ARCHIVE"
3055                 fi
3056             fi
3057             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
3058
3059         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
3060             if check_com curl; then
3061                 WGET_CMD="curl -k -s -o -"
3062             elif check_com wget; then
3063                 WGET_CMD="wget -q -O - --no-check-certificate"
3064             else
3065                 print "ERROR: neither wget nor curl is installed" >&2
3066                 RC=$((RC+4))
3067                 continue
3068             fi
3069             print "Downloading and Extracting '$ARCHIVE' ..."
3070             if $USES_STDIN; then
3071                 if $USES_STDOUT; then
3072                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
3073                     RC=$((RC+$?))
3074                 else
3075                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
3076                     RC=$((RC+$?))
3077                 fi
3078             else
3079                 if $USES_STDOUT; then
3080                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
3081                 else
3082                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
3083                 fi
3084             fi
3085
3086         else
3087             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
3088             RC=$((RC+8))
3089         fi
3090     done
3091     return $RC
3092 }
3093
3094 __archive_or_uri()
3095 {
3096     _alternative \
3097         '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)"' \
3098         '_urls:Remote Archives:_urls'
3099 }
3100
3101 _simple_extract()
3102 {
3103     _arguments \
3104         '-d[delete original archivefile after extraction]' \
3105         '*:Archive Or Uri:__archive_or_uri'
3106 }
3107 compdef _simple_extract simple-extract
3108 alias se=simple-extract
3109
3110 # Usage: smartcompress <file> (<type>)
3111 #f5# Smart archive creator
3112 smartcompress() {
3113     emulate -L zsh
3114     if [[ -n $2 ]] ; then
3115         case $2 in
3116             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
3117             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
3118             tar.Z)          tar -Zcvf$1.$2 $1 ;;
3119             tar)            tar -cvf$1.$2  $1 ;;
3120             gz | gzip)      gzip           $1 ;;
3121             bz2 | bzip2)    bzip2          $1 ;;
3122             *)
3123                 echo "Error: $2 is not a valid compression type"
3124                 ;;
3125         esac
3126     else
3127         smartcompress $1 tar.gz
3128     fi
3129 }
3130
3131 # Usage: show-archive <archive>
3132 #f5# List an archive's content
3133 show-archive() {
3134     emulate -L zsh
3135     if [[ -f $1 ]] ; then
3136         case $1 in
3137             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
3138             *.tar)         tar -tf $1 ;;
3139             *.tgz)         tar -ztf $1 ;;
3140             *.zip)         unzip -l $1 ;;
3141             *.bz2)         bzless $1 ;;
3142             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
3143             *)             echo "'$1' Error. Please go away" ;;
3144         esac
3145     else
3146         echo "'$1' is not a valid archive"
3147     fi
3148 }
3149
3150 # It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
3151 #f5# Use \kbd{vim} as your manpage reader
3152 vman() {
3153     emulate -L zsh
3154     if (( ${#argv} == 0 )); then
3155         printf 'usage: vman <topic>\n'
3156         return 1
3157     fi
3158     man "$@" | col -b | view -c 'set ft=man nomod nolist' -
3159 }
3160
3161 # function readme() { $PAGER -- (#ia3)readme* }
3162 #f5# View all README-like files in current directory in pager
3163 readme() {
3164     emulate -L zsh
3165     local files
3166     files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
3167     if (($#files)) ; then
3168         $PAGER $files
3169     else
3170         print 'No README files.'
3171     fi
3172 }
3173
3174 # function ansi-colors()
3175 #f5# Display ANSI colors
3176 ansi-colors() {
3177     typeset esc="\033[" line1 line2
3178     echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
3179     for fore in 30 31 32 33 34 35 36 37; do
3180         line1="$fore "
3181         line2="   "
3182         for back in 40 41 42 43 44 45 46 47 49; do
3183             line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
3184             line2="${line2}${esc}${back};${fore};1m Bold   ${esc}0m"
3185         done
3186         echo -e "$line1\n$line2"
3187     done
3188 }
3189
3190 #f5# Find all files in \$PATH with setuid bit set
3191 suidfind() { ls -latg $path | grep '^...s' }
3192
3193 # TODO: So, this is the third incarnation of this function!?
3194 #f5# Reload given functions
3195 refunc() {
3196     for func in $argv ; do
3197         unfunction $func
3198         autoload $func
3199     done
3200 }
3201 compdef _functions refunc
3202
3203 # a small check to see which DIR is located on which server/partition.
3204 # stolen and modified from Sven's zshrc.forall
3205 #f5# Report diskusage of a directory
3206 dirspace() {
3207     emulate -L zsh
3208     if [[ -n "$1" ]] ; then
3209         for dir in "$@" ; do
3210             if [[ -d "$dir" ]] ; then
3211                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3212             else
3213                 echo "warning: $dir does not exist" >&2
3214             fi
3215         done
3216     else
3217         for dir in $path; do
3218             if [[ -d "$dir" ]] ; then
3219                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3220             else
3221                 echo "warning: $dir does not exist" >&2
3222             fi
3223         done
3224     fi
3225 }
3226
3227 # % slow_print `cat /etc/passwd`
3228 #f5# Slowly print out parameters
3229 slow_print() {
3230     for argument in "$@" ; do
3231         for ((i = 1; i <= ${#1} ;i++)) ; do
3232             print -n "${argument[i]}"
3233             sleep 0.08
3234         done
3235         print -n " "
3236     done
3237     print ""
3238 }
3239
3240 #f5# Show some status info
3241 status() {
3242     print
3243     print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")
3244     print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
3245     print "Term..: $TTY ($TERM), ${BAUD:+$BAUD bauds, }$COLUMNS x $LINES chars"
3246     print "Login.: $LOGNAME (UID = $EUID) on $HOST"
3247     print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
3248     print "Uptime:$(uptime)"
3249     print
3250 }
3251
3252 # Rip an audio CD
3253 #f5# Rip an audio CD
3254 audiorip() {
3255     mkdir -p ~/ripps
3256     cd ~/ripps
3257     cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
3258     cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
3259     echo " * Would you like to burn the cd now? (yes/no)"
3260     read input
3261     if [[ "$input" = "yes" ]] ; then
3262         echo " ! Burning Audio CD"
3263         audioburn
3264         echo " * done."
3265     else
3266         echo " ! Invalid response."
3267     fi
3268 }
3269
3270 # and burn it
3271 #f5# Burn an audio CD (in combination with audiorip)
3272 audioburn() {
3273     cd ~/ripps
3274     cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
3275     echo " * Should I remove the temporary files? (yes/no)"
3276     read input
3277     if [[ "$input" = "yes" ]] ; then
3278         echo " ! Removing Temporary Files."
3279         cd ~
3280         rm -rf ~/ripps
3281         echo " * done."
3282     else
3283         echo " ! Invalid response."
3284     fi
3285 }
3286
3287 #f5# Make an audio CD from all mp3 files
3288 mkaudiocd() {
3289     # TODO: do the renaming more zshish, possibly with zmv()
3290     emulate -L zsh
3291     cd ~/ripps
3292     for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
3293     for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
3294     for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
3295     normalize -m *.wav
3296     for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
3297 }
3298
3299 #f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
3300 mkiso() {
3301     emulate -L zsh
3302     echo " * Volume name "
3303     read volume
3304     echo " * ISO Name (ie. tmp.iso)"
3305     read iso
3306     echo " * Directory or File"
3307     read files
3308     mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
3309 }
3310
3311 #f5# Simple thumbnails generator
3312 genthumbs() {
3313     rm -rf thumb-* index.html
3314     echo "
3315 <html>
3316   <head>
3317     <title>Images</title>
3318   </head>
3319   <body>" > index.html
3320     for f in *.(gif|jpeg|jpg|png) ; do
3321         convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
3322         echo "    <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
3323     done
3324     echo "
3325   </body>
3326 </html>" >> index.html
3327 }
3328
3329 #f5# Set all ulimit parameters to \kbd{unlimited}
3330 allulimit() {
3331     ulimit -c unlimited
3332     ulimit -d unlimited
3333     ulimit -f unlimited
3334     ulimit -l unlimited
3335     ulimit -n unlimited
3336     ulimit -s unlimited
3337     ulimit -t unlimited
3338 }
3339
3340 # 2mp3 transcodes flac and ogg to mp3 with bitrate of 192 while preserving basic tags
3341 if check_com lame; then
3342     2mp3_192() {
3343         emulate -L zsh
3344         setopt extendedglob
3345         unsetopt ksharrays
3346
3347         local -a DECODE id3tags
3348         local -A tagmap
3349         local tagdata
3350         local RC=0
3351         tagmap=("(#l)title" --tt "(#l)artist" --ta "(#l)tracknumber" --tn "(#l)genre" --tg "(#l)album" --tl)
3352
3353         if [[ ${@[(i)*.ogg]} -le ${#@} ]] && ! check_com oggdec; then
3354             echo "ERROR: please install oggdec" >&2
3355             return 1
3356         fi
3357         if [[ ${@[(i)*.flac]} -le ${#@} ]] && ! check_com flac; then
3358             echo "ERROR: please install flac" >&2
3359             return 1
3360         fi
3361
3362         for af in "$@"; do
3363             id3tags=()
3364             case "$af" in
3365                 (*.flac)
3366                     DECODE=(flac -d -c "$af")
3367                     tagdata="$(metaflac --export-tags-to=- "$af")"
3368                     ;;
3369                 (*.ogg)
3370                     DECODE=(oggdec -Q -o - "$af")
3371                     tagdata="$(ogginfo "$af")"
3372                     ;;
3373                 (*) continue ;;
3374             esac
3375             for line (${(f)tagdata}) \
3376                 [[ "$line" == (#s)[[:space:]]#(#b)([^=]##)=(*)(#e) && -n $tagmap[(k)$match[1]] ]] && \
3377                 id3tags+=($tagmap[(k)$match[1]] "$match[2]")
3378             [[ ${#id3tags} -gt 0 ]] && id3tags=(--add-id3v2 --ignore-tag-errors $id3tags)
3379             $DECODE[*] | lame -b 192 -v -h --replaygain-fast  "${id3tags[@]}" - "${af:r}.mp3" || {RC=$?; print "Error transcoding" "${af}"; }
3380         done
3381         # return 0 if no error or exit code if at least one error happened
3382         return $RC
3383     }
3384     alias ogg2mp3_192 2mp3_192
3385 fi
3386
3387 #f5# RFC 2396 URL encoding in Z-Shell
3388 urlencode() {
3389     emulate -L zsh
3390     setopt extendedglob
3391     input=( ${(s::)1} )
3392     print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
3393 }
3394
3395 # http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
3396 #f5# Log 'make install' output
3397 mmake() {
3398     emulate -L zsh
3399     [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
3400     make -n install > ~/.errorlogs/${PWD##*/}-makelog
3401 }
3402
3403 #f5# Indent source code
3404 smart-indent() {
3405     indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
3406 }
3407
3408 # highlight important stuff in diff output, usage example: hg diff | hidiff
3409 #m# a2 hidiff \kbd{histring} oneliner for diffs
3410 check_com -c histring && \
3411     alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
3412
3413 # rename pictures based on information found in exif headers
3414 #f5# Rename pictures based on information found in exif headers
3415 exirename() {
3416     emulate -L zsh
3417     if [[ $# -lt 1 ]] ; then
3418         echo 'Usage: jpgrename $FILES' >& 2
3419         return 1
3420     else
3421         echo -n 'Checking for jhead with version newer than 1.9: '
3422         jhead_version=`jhead -h | grep 'used by most Digital Cameras.  v.*' | awk '{print $6}' | tr -d v`
3423         if [[ $jhead_version > '1.9' ]]; then
3424             echo 'success - now running jhead.'
3425             jhead -n%Y-%m-%d_%Hh%M_%f $*
3426         else
3427             echo 'failed - exiting.'
3428         fi
3429     fi
3430 }
3431
3432 # get_ic() - queries imap servers for capabilities; real simple. no imaps
3433 ic_get() {
3434     emulate -L zsh
3435     local port
3436     if [[ ! -z $1 ]] ; then
3437         port=${2:-143}
3438         print "querying imap server on $1:${port}...\n";
3439         print "a1 capability\na2 logout\n" | nc $1 ${port}
3440     else
3441         print "usage:\n  $0 <imap-server> [port]"
3442     fi
3443 }
3444
3445 # creates a Maildir/ with its {new,cur,tmp} subdirs
3446 mkmaildir() {
3447     emulate -L zsh
3448     local root subdir
3449     root=${MAILDIR_ROOT:-${HOME}/Mail}
3450     if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
3451     subdir=${1}
3452     mkdir -p ${root}/${subdir}/{cur,new,tmp}
3453 }
3454
3455 #f5# Change the xterm title from within GNU-screen
3456 xtrename() {
3457     emulate -L zsh
3458     if [[ $1 != "-f" ]] ; then
3459         if [[ -z ${DISPLAY} ]] ; then
3460             printf 'xtrename only makes sense in X11.\n'
3461             return 1
3462         fi
3463     else
3464         shift
3465     fi
3466     if [[ -z $1 ]] ; then
3467         printf 'usage: xtrename [-f] "title for xterm"\n'
3468         printf '  renames the title of xterm from _within_ screen.\n'
3469         printf '  also works without screen.\n'
3470         printf '  will not work if DISPLAY is unset, use -f to override.\n'
3471         return 0
3472     fi
3473     print -n "\eP\e]0;${1}\C-G\e\\"
3474     return 0
3475 }
3476
3477 # hl() highlighted less
3478 # http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
3479 if check_com -c highlight ; then
3480     function hl() {
3481     emulate -L zsh
3482         local theme lang
3483         theme=${HL_THEME:-""}
3484         case ${1} in
3485             (-l|--list)
3486                 ( printf 'available languages (syntax parameter):\n\n' ;
3487                     highlight --list-langs ; ) | less -SMr
3488                 ;;
3489             (-t|--themes)
3490                 ( printf 'available themes (style parameter):\n\n' ;
3491                     highlight --list-themes ; ) | less -SMr
3492                 ;;
3493             (-h|--help)
3494                 printf 'usage: hl <syntax[:theme]> <file>\n'
3495                 printf '    available options: --list (-l), --themes (-t), --help (-h)\n\n'
3496                 printf '  Example: hl c main.c\n'
3497                 ;;
3498             (*)
3499                 if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
3500                     printf 'usage: hl <syntax[:theme]> <file>\n'
3501                     printf '    available options: --list (-l), --themes (-t), --help (-h)\n'
3502                     (( ${#argv} > 2 )) && printf '  Too many arguments.\n'
3503                     return 1
3504                 fi
3505                 lang=${1%:*}
3506                 [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
3507                 if [[ -n ${theme} ]] ; then
3508                     highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
3509                 else
3510                     highlight --ansi --syntax ${lang} ${2} | less -SMr
3511                 fi
3512                 ;;
3513         esac
3514         return 0
3515     }
3516     # ... and a proper completion for hl()
3517     # needs 'highlight' as well, so it fits fine in here.
3518     function _hl_genarg()  {
3519         local expl
3520         if [[ -prefix 1 *: ]] ; then
3521             local themes
3522             themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
3523             compset -P 1 '*:'
3524             _wanted -C list themes expl theme compadd ${themes}
3525         else
3526             local langs
3527             langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
3528             _wanted -C list languages expl languages compadd -S ':' -q ${langs}
3529         fi
3530     }
3531     function _hl_complete() {
3532         _arguments -s '1: :_hl_genarg' '2:files:_path_files'
3533     }
3534     compdef _hl_complete hl
3535 fi
3536
3537 # TODO:
3538 # Rewrite this by either using tinyurl.com's API
3539 # or using another shortening service to comply with
3540 # tinyurl.com's policy.
3541 #
3542 # Create small urls via http://tinyurl.com using wget(1).
3543 #function zurl() {
3544 #    emulate -L zsh
3545 #    [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
3546 #
3547 #    local PN url tiny grabber search result preview
3548 #    PN=$0
3549 #    url=$1
3550 ##   Check existence of given URL with the help of ping(1).
3551 ##   N.B. ping(1) only works without an eventual given protocol.
3552 #    ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
3553 #        read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
3554 #
3555 #    if (( $? == 0 )) ; then
3556 ##           Prepend 'http://' to given URL where necessary for later output.
3557 #            [[ ${url} != http(s|)://* ]] && url='http://'${url}
3558 #            tiny='http://tinyurl.com/create.php?url='
3559 #            if check_com -c wget ; then
3560 #                grabber='wget -O- -o/dev/null'
3561 #            else
3562 #                print "wget is not available, but mandatory for ${PN}. Aborting."
3563 #            fi
3564 ##           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
3565 #            search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
3566 #            result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
3567 ##           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
3568 #            preview='http://preview.'${result#http://}
3569 #
3570 #            printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
3571 #            printf '%s\t%s\n\n' 'Given URL:' ${url}
3572 #            printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
3573 #    else
3574 #        return 1
3575 #    fi
3576 #}
3577
3578 #f2# Print a specific line of file(s).
3579 linenr () {
3580 # {{{
3581     emulate -L zsh
3582     if [ $# -lt 2 ] ; then
3583        print "Usage: linenr <number>[,<number>] <file>" ; return 1
3584     elif [ $# -eq 2 ] ; then
3585          local number=$1
3586          local file=$2
3587          command ed -s $file <<< "${number}n"
3588     else
3589          local number=$1
3590          shift
3591          for file in "$@" ; do
3592              if [ ! -d $file ] ; then
3593                 echo "${file}:"
3594                 command ed -s $file <<< "${number}n" 2> /dev/null
3595              else
3596                 continue
3597              fi
3598          done | less
3599     fi
3600 # }}}
3601 }
3602
3603 #f2# Find history events by search pattern and list them by date.
3604 whatwhen()  {
3605 # {{{
3606     emulate -L zsh
3607     local usage help ident format_l format_s first_char remain first last
3608     usage='USAGE: whatwhen [options] <searchstring> <search range>'
3609     help='Use `whatwhen -h'\'' for further explanations.'
3610     ident=${(l,${#${:-Usage: }},, ,)}
3611     format_l="${ident}%s\t\t\t%s\n"
3612     format_s="${format_l//(\\t)##/\\t}"
3613     # Make the first char of the word to search for case
3614     # insensitive; e.g. [aA]
3615     first_char=[${(L)1[1]}${(U)1[1]}]
3616     remain=${1[2,-1]}
3617     # Default search range is `-100'.
3618     first=${2:-\-100}
3619     # Optional, just used for `<first> <last>' given.
3620     last=$3
3621     case $1 in
3622         ("")
3623             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
3624             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3625         ;;
3626         (-h)
3627             printf '%s\n\n' ${usage}
3628             print 'OPTIONS:'
3629             printf $format_l '-h' 'show help text'
3630             print '\f'
3631             print 'SEARCH RANGE:'
3632             printf $format_l "'0'" 'the whole history,'
3633             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
3634             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
3635             printf '\n%s\n' 'EXAMPLES:'
3636             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
3637             printf $format_l 'whatwhen zsh -250'
3638             printf $format_l 'whatwhen foo 1 99'
3639         ;;
3640         (\?)
3641             printf '%s\n%s\n\n' ${usage} ${help} && return 1
3642         ;;
3643         (*)
3644             # -l list results on stout rather than invoking $EDITOR.
3645             # -i Print dates as in YYYY-MM-DD.
3646             # -m Search for a - quoted - pattern within the history.
3647             fc -li -m "*${first_char}${remain}*" $first $last
3648         ;;
3649     esac
3650 # }}}
3651 }
3652
3653 # change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
3654 fluxkey-change() {
3655     emulate -L zsh
3656     [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
3657     if ! [[ -r "$FLUXKEYS" ]] ; then
3658         echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
3659         return 1
3660     else
3661         if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
3662             echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
3663             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
3664         elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
3665             echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
3666             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
3667         else
3668             echo 'Sorry, do not know what to do.'
3669             return 1
3670         fi
3671     fi
3672 }
3673
3674 # retrieve weather information on the console
3675 # Usage example: 'weather LOWG'
3676 weather() {
3677     emulate -L zsh
3678     [[ -n "$1" ]] || {
3679         print 'Usage: weather <station_id>' >&2
3680         print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
3681         return 1
3682     }
3683
3684     local VERBOSE="yes"    # TODO: Make this a command line switch
3685
3686     local ODIR=`pwd`
3687     local PLACE="${1:u}"
3688     local DIR="${HOME}/.weather"
3689     local LOG="${DIR}/log"
3690
3691     [[ -d ${DIR} ]] || {
3692         print -n "Creating ${DIR}: "
3693         mkdir ${DIR}
3694         print 'done'
3695     }
3696
3697     print "Retrieving information for ${PLACE}:"
3698     print
3699     cd ${DIR} && wget -T 10 --no-verbose --output-file=$LOG --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
3700
3701     if [[ $? -eq 0 ]] ; then
3702         if [[ -n "$VERBOSE" ]] ; then
3703             cat ${PLACE}.TXT
3704         else
3705             DATE=$(grep 'UTC' ${PLACE}.TXT | sed 's#.* /##')
3706             TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' ${PLACE}.TXT | tr -d '(')
3707             echo "date: $DATE"
3708             echo "temp:  $TEMPERATURE"
3709         fi
3710     else
3711         print "There was an error retrieving the weather information for $PLACE" >&2
3712         cat $LOG
3713         cd $ODIR
3714         return 1
3715     fi
3716     cd $ODIR
3717 }
3718 # }}}
3719
3720 # mercurial related stuff {{{
3721 if check_com -c hg ; then
3722     # gnu like diff for mercurial
3723     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
3724     #f5# GNU like diff for mercurial
3725     hgdi() {
3726         emulate -L zsh
3727         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
3728     }
3729
3730     # build debian package
3731     #a2# Alias for \kbd{hg-buildpackage}
3732     alias hbp='hg-buildpackage'
3733
3734     # execute commands on the versioned patch-queue from the current repos
3735     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
3736
3737     # diffstat for specific version of a mercurial repository
3738     #   hgstat      => display diffstat between last revision and tip
3739     #   hgstat 1234 => display diffstat between revision 1234 and tip
3740     #f5# Diffstat for specific version of a mercurial repos
3741     hgstat() {
3742         emulate -L zsh
3743         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
3744     }
3745
3746 fi # end of check whether we have the 'hg'-executable
3747
3748 # }}}
3749
3750 # some useful commands often hard to remember - let's grep for them {{{
3751 # actually use our zg() function now. :)
3752
3753 # Work around ion/xterm resize bug.
3754 #if [[ "$SHLVL" -eq 1 ]]; then
3755 #       if check_com -c resize ; then
3756 #               eval `resize </dev/null`
3757 #       fi
3758 #fi
3759
3760 # enable jackd:
3761 #  /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
3762 # now play audio file:
3763 #  alsaplayer -o jack foobar.mp3
3764
3765 # send files via netcat
3766 # on sending side:
3767 #  send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
3768 #  send dir* $HOST
3769 #  alias receive='nc -vlp 51330 | tar xzvp'
3770
3771 # debian stuff:
3772 # dh_make -e foo@localhost -f $1
3773 # dpkg-buildpackage -rfakeroot
3774 # lintian *.deb
3775 # dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
3776 # dpkg-scansources . | gzip > Sources.gz
3777 # grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
3778
3779 # other stuff:
3780 # convert -geometry 200x200 -interlace LINE -verbose
3781 # ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
3782 # ps -ao user,pcpu,start,command
3783 # gpg --keyserver blackhole.pca.dfn.de --recv-keys
3784 # xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
3785 # nc -vz $1 1-1024   # portscan via netcat
3786 # wget --mirror --no-parent --convert-links
3787 # pal -d `date +%d`
3788 # autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
3789 #
3790 # modify console cursor
3791 # see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
3792 # print $'\e[?96;0;64c'
3793 # }}}
3794
3795 # grml-small cleanups {{{
3796
3797 # The following is used to remove zsh-config-items that do not work
3798 # in grml-small by default.
3799 # If you do not want these adjustments (for whatever reason), set
3800 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
3801 # sources if it is there).
3802
3803 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
3804
3805     unset abk[V]
3806     unalias    'V'      &> /dev/null
3807     unfunction vman     &> /dev/null
3808     unfunction viless   &> /dev/null
3809     unfunction 2html    &> /dev/null
3810
3811     # manpages are not in grmlsmall
3812     unfunction manzsh   &> /dev/null
3813     unfunction man2     &> /dev/null
3814
3815 fi
3816
3817 #}}}
3818
3819 zrclocal
3820
3821 ## genrefcard.pl settings {{{
3822
3823 ### doc strings for external functions from files
3824 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
3825
3826 ### example: split functions-search 8,16,24,32
3827 #@# split functions-search 8
3828
3829 ## }}}
3830
3831 ## END OF FILE #################################################################
3832 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
3833 # Local variables:
3834 # mode: sh
3835 # End: