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