zshrc: improve purge() function.
[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 bindkey '^xp'   history-beginning-search-backward
621 bindkey '^xP'   history-beginning-search-forward
622 bindkey "\e[5~" history-beginning-search-backward #PageUp
623 bindkey "\e[6~" history-beginning-search-forward  #PageDown
624 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
625 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
626
627
628 # insert unicode character
629 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an Â§
630 # See for example http://unicode.org/charts/ for unicode characters code
631 zrcautoload insert-unicode-char
632 zle -N insert-unicode-char
633 #k# Insert Unicode character
634 bindkey '^Xi' insert-unicode-char
635
636 #m# k Shift-tab Perform backwards menu completion
637 if [[ -n "$terminfo[kcbt]" ]]; then
638     bindkey "$terminfo[kcbt]" reverse-menu-complete
639 elif [[ -n "$terminfo[cbt]" ]]; then # required for GNU screen
640     bindkey "$terminfo[cbt]"  reverse-menu-complete
641 fi
642
643 ## toggle the ,. abbreviation feature on/off
644 # NOABBREVIATION: default abbreviation-state
645 #                 0 - enabled (default)
646 #                 1 - disabled
647 NOABBREVIATION=${NOABBREVIATION:-0}
648
649 grml_toggle_abbrev() {
650     if (( ${NOABBREVIATION} > 0 )) ; then
651         NOABBREVIATION=0
652     else
653         NOABBREVIATION=1
654     fi
655 }
656
657 zle -N grml_toggle_abbrev
658 bindkey '^xA' grml_toggle_abbrev
659
660 # add a command line to the shells history without executing it
661 commit-to-history() {
662     print -s ${(z)BUFFER}
663     zle send-break
664 }
665 zle -N commit-to-history
666 bindkey "^x^h" commit-to-history
667
668 # only slash should be considered as a word separator:
669 slash-backward-kill-word() {
670     local WORDCHARS="${WORDCHARS:s@/@}"
671     # zle backward-word
672     zle backward-kill-word
673 }
674 zle -N slash-backward-kill-word
675
676 #k# Kill everything in a word up to its last \kbd{/}
677 bindkey '\ev' slash-backward-kill-word
678 #k# Kill everything in a word up to its last \kbd{/}
679 bindkey '\e^h' slash-backward-kill-word
680 #k# Kill everything in a word up to its last \kbd{/}
681 bindkey '\e^?' slash-backward-kill-word
682
683 # use the new *-pattern-* widgets for incremental history search
684 if is439 ; then
685     bindkey '^r' history-incremental-pattern-search-backward
686     bindkey '^s' history-incremental-pattern-search-forward
687 fi
688 # }}}
689
690 # a generic accept-line wrapper {{{
691
692 # This widget can prevent unwanted autocorrections from command-name
693 # to _command-name, rehash automatically on enter and call any number
694 # of builtin and user-defined widgets in different contexts.
695 #
696 # For a broader description, see:
697 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
698 #
699 # The code is imported from the file 'zsh/functions/accept-line' from
700 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
701 # distributed under the same terms as zsh itself.
702
703 # A newly added command will may not be found or will cause false
704 # correction attempts, if you got auto-correction set. By setting the
705 # following style, we force accept-line() to rehash, if it cannot
706 # find the first word on the command line in the $command[] hash.
707 zstyle ':acceptline:*' rehash true
708
709 function Accept-Line() {
710     emulate -L zsh
711     local -a subs
712     local -xi aldone
713     local sub
714
715     zstyle -a ":acceptline:${alcontext}" actions subs
716
717     (( ${#subs} < 1 )) && return 0
718
719     (( aldone = 0 ))
720     for sub in ${subs} ; do
721         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
722         zle ${sub}
723
724         (( aldone > 0 )) && break
725     done
726 }
727
728 function Accept-Line-getdefault() {
729     emulate -L zsh
730     local default_action
731
732     zstyle -s ":acceptline:${alcontext}" default_action default_action
733     case ${default_action} in
734         ((accept-line|))
735             printf ".accept-line"
736             ;;
737         (*)
738             printf ${default_action}
739             ;;
740     esac
741 }
742
743 function accept-line() {
744     emulate -L zsh
745     local -a cmdline
746     local -x alcontext
747     local buf com fname format msg default_action
748
749     alcontext='default'
750     buf="${BUFFER}"
751     cmdline=(${(z)BUFFER})
752     com="${cmdline[1]}"
753     fname="_${com}"
754
755     zstyle -t ":acceptline:${alcontext}" rehash \
756         && [[ -z ${commands[$com]} ]]           \
757         && rehash
758
759     if    [[ -n ${reswords[(r)$com]} ]] \
760        || [[ -n ${aliases[$com]}     ]] \
761        || [[ -n ${functions[$com]}   ]] \
762        || [[ -n ${builtins[$com]}    ]] \
763        || [[ -n ${commands[$com]}    ]] ; then
764
765         # there is something sensible to execute, just do it.
766         alcontext='normal'
767         zle Accept-Line
768
769         default_action=$(Accept-Line-getdefault)
770         zstyle -T ":acceptline:${alcontext}" call_default \
771             && zle ${default_action}
772         return
773     fi
774
775     if    [[ -o correct              ]] \
776        || [[ -o correctall           ]] \
777        && [[ -n ${functions[$fname]} ]] ; then
778
779         # nothing there to execute but there is a function called
780         # _command_name; a completion widget. Makes no sense to
781         # call it on the commandline, but the correct{,all} options
782         # will ask for it nevertheless, so warn the user.
783         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
784             # Okay, we warned the user before, he called us again,
785             # so have it his way.
786             alcontext='force'
787             zle Accept-Line
788
789             default_action=$(Accept-Line-getdefault)
790             zstyle -T ":acceptline:${alcontext}" call_default \
791                 && zle ${default_action}
792             return
793         fi
794
795         # prepare warning message for the user, configurable via zstyle.
796         zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
797
798         if [[ -z ${msg} ]] ; then
799             msg="%c will not execute and completion %f exists."
800         fi
801
802         zformat -f msg "${msg}" "c:${com}" "f:${fname}"
803
804         zle -M -- "${msg}"
805         return
806     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
807         # If we are here, the commandline contains something that is not
808         # executable, which is neither subject to _command_name correction
809         # and is not empty. might be a variable assignment
810         alcontext='misc'
811         zle Accept-Line
812
813         default_action=$(Accept-Line-getdefault)
814         zstyle -T ":acceptline:${alcontext}" call_default \
815             && zle ${default_action}
816         return
817     fi
818
819     # If we got this far, the commandline only contains whitespace, or is empty.
820     alcontext='empty'
821     zle Accept-Line
822
823     default_action=$(Accept-Line-getdefault)
824     zstyle -T ":acceptline:${alcontext}" call_default \
825         && zle ${default_action}
826 }
827
828 zle -N accept-line
829 zle -N Accept-Line
830
831 # }}}
832
833 # power completion - abbreviation expansion {{{
834 # power completion / abbreviation expansion / buffer expansion
835 # see http://zshwiki.org/home/examples/zleiab for details
836 # less risky than the global aliases but powerful as well
837 # just type the abbreviation key and afterwards ',.' to expand it
838 declare -A abk
839 setopt extendedglob
840 setopt interactivecomments
841 abk=(
842 #   key   # value                  (#d additional doc string)
843 #A# start
844     '...'  '../..'
845     '....' '../../..'
846     'BG'   '& exit'
847     'C'    '| wc -l'
848     'G'    '|& grep --color=auto '
849     'H'    '| head'
850     'Hl'   ' --help |& less -r'    #d (Display help in pager)
851     'L'    '| less'
852     'LL'   '|& less -r'
853     'M'    '| most'
854     'N'    '&>/dev/null'           #d (No Output)
855     'R'    '| tr A-z N-za-m'       #d (ROT13)
856     'SL'   '| sort | less'
857     'S'    '| sort -u'
858     'T'    '| tail'
859     'V'    '|& vim -'
860 #A# end
861     'co'   './configure && make && sudo make install'
862 )
863
864 globalias() {
865     emulate -L zsh
866     setopt extendedglob
867     local MATCH
868
869     if (( NOABBREVIATION > 0 )) ; then
870         LBUFFER="${LBUFFER},."
871         return 0
872     fi
873
874     matched_chars='[.-|_a-zA-Z0-9]#'
875     LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
876     LBUFFER+=${abk[$MATCH]:-$MATCH}
877 }
878
879 zle -N globalias
880 bindkey ",." globalias
881 # }}}
882
883 # {{{ autoloading
884 zrcautoload zmv    # who needs mmv or rename?
885 zrcautoload history-search-end
886
887 # we don't want to quote/espace URLs on our own...
888 # if autoload -U url-quote-magic ; then
889 #    zle -N self-insert url-quote-magic
890 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
891 # else
892 #    print 'Notice: no url-quote-magic available :('
893 # fi
894 alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
895
896 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
897 alias run-help >&/dev/null && unalias run-help
898 for rh in run-help{,-git,-svk,-svn}; do
899     zrcautoload $rh
900 done; unset rh
901
902 # completion system
903 if zrcautoload compinit ; then
904     compinit || print 'Notice: no compinit available :('
905 else
906     print 'Notice: no compinit available :('
907     function zstyle { }
908     function compdef { }
909 fi
910
911 is4 && zrcautoload zed # use ZLE editor to edit a file or function
912
913 is4 && \
914 for mod in complist deltochar mathfunc ; do
915     zmodload -i zsh/${mod} 2>/dev/null || print "Notice: no ${mod} available :("
916 done
917
918 # autoload zsh modules when they are referenced
919 if is4 ; then
920     zmodload -a  zsh/stat    zstat
921     zmodload -a  zsh/zpty    zpty
922     zmodload -ap zsh/mapfile mapfile
923 fi
924
925 if is4 && zrcautoload insert-files && zle -N insert-files ; then
926     #k# Insert files
927     bindkey "^Xf" insert-files # C-x-f
928 fi
929
930 bindkey ' '   magic-space    # also do history expansion on space
931 #k# Trigger menu-complete
932 bindkey '\ei' menu-complete  # menu completion via esc-i
933
934 # press esc-e for editing command line in $EDITOR or $VISUAL
935 if is4 && zrcautoload edit-command-line && zle -N edit-command-line ; then
936     #k# Edit the current line in \kbd{\$EDITOR}
937     bindkey '\ee' edit-command-line
938 fi
939
940 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
941     #k# menu selection: pick item but stay in the menu
942     bindkey -M menuselect '\e^M' accept-and-menu-complete
943     # also use + and INSERT since it's easier to press repeatedly
944     bindkey -M menuselect "+" accept-and-menu-complete
945     bindkey -M menuselect "^[[2~" accept-and-menu-complete
946
947     # accept a completion and try to complete again by using menu
948     # completion; very useful with completing directories
949     # by using 'undo' one's got a simple file browser
950     bindkey -M menuselect '^o' accept-and-infer-next-history
951 fi
952
953 # press "ctrl-e d" to insert the actual date in the form yyyy-mm-dd
954 insert-datestamp() { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
955 zle -N insert-datestamp
956
957 #k# Insert a timestamp on the command line (yyyy-mm-dd)
958 bindkey '^Ed' insert-datestamp
959
960 # press esc-m for inserting last typed word again (thanks to caphuso!)
961 insert-last-typed-word() { zle insert-last-word -- 0 -1 };
962 zle -N insert-last-typed-word;
963
964 #k# Insert last typed word
965 bindkey "\em" insert-last-typed-word
966
967 function grml-zsh-fg() {
968   if (( ${#jobstates} )); then
969     zle .push-input
970     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
971     BUFFER="${BUFFER}fg"
972     zle .accept-line
973   else
974     zle -M 'No background jobs. Doing nothing.'
975   fi
976 }
977 zle -N grml-zsh-fg
978 #k# A smart shortcut for \kbd{fg<enter>}
979 bindkey '^z' grml-zsh-fg
980
981 # run command line as user root via sudo:
982 sudo-command-line() {
983     [[ -z $BUFFER ]] && zle up-history
984     if [[ $BUFFER != sudo\ * ]]; then
985         BUFFER="sudo $BUFFER"
986         CURSOR=$(( CURSOR+5 ))
987     fi
988 }
989 zle -N sudo-command-line
990
991 #k# Put the current command line into a \kbd{sudo} call
992 bindkey "^Os" sudo-command-line
993
994 ### jump behind the first word on the cmdline.
995 ### useful to add options.
996 function jump_after_first_word() {
997     local words
998     words=(${(z)BUFFER})
999
1000     if (( ${#words} <= 1 )) ; then
1001         CURSOR=${#BUFFER}
1002     else
1003         CURSOR=${#${words[1]}}
1004     fi
1005 }
1006 zle -N jump_after_first_word
1007
1008 bindkey '^x1' jump_after_first_word
1009
1010 # complete word from history with menu (from Book: ZSH, OpenSource-Press)
1011 zle -C hist-complete complete-word _generic
1012 zstyle ':completion:hist-complete:*' completer _history
1013 #k# complete word from history with menu
1014 bindkey "^X^X" hist-complete
1015
1016 # }}}
1017
1018 # {{{ history
1019
1020 ZSHDIR=$HOME/.zsh
1021
1022 #v#
1023 HISTFILE=$HOME/.zsh_history
1024 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
1025 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
1026
1027 # }}}
1028
1029 # dirstack handling {{{
1030
1031 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
1032 DIRSTACKFILE=${DIRSTACKFILE:-${HOME}/.zdirs}
1033
1034 if [[ -f ${DIRSTACKFILE} ]] && [[ ${#dirstack[*]} -eq 0 ]] ; then
1035     dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
1036     # "cd -" won't work after login by just setting $OLDPWD, so
1037     [[ -d $dirstack[0] ]] && cd $dirstack[0] && cd $OLDPWD
1038 fi
1039
1040 chpwd() {
1041     local -ax my_stack
1042     my_stack=( ${PWD} ${dirstack} )
1043     if is42 ; then
1044         builtin print -l ${(u)my_stack} >! ${DIRSTACKFILE}
1045     else
1046         uprint my_stack >! ${DIRSTACKFILE}
1047     fi
1048 }
1049
1050 # }}}
1051
1052 # directory based profiles {{{
1053
1054 if is433 ; then
1055
1056 CHPWD_PROFILE='default'
1057 function chpwd_profiles() {
1058     # Say you want certain settings to be active in certain directories.
1059     # This is what you want.
1060     #
1061     # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
1062     # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
1063     #
1064     # When that's done and you enter a directory that matches the pattern
1065     # in the third part of the context, a function called chpwd_profile_grml,
1066     # for example, is called (if it exists).
1067     #
1068     # If no pattern matches (read: no profile is detected) the profile is
1069     # set to 'default', which means chpwd_profile_default is attempted to
1070     # be called.
1071     #
1072     # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
1073     # command) which is used: The third part in the context is matched against
1074     # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
1075     # Because that way the profile is detected for all these values of ${PWD}:
1076     #   /foo/bar
1077     #   /foo/bar/
1078     #   /foo/bar/baz
1079     # So, if you want to make double damn sure a profile works in /foo/bar
1080     # and everywhere deeper in that tree, just use (|/|/*) and be happy.
1081     #
1082     # The name of the detected profile will be available in a variable called
1083     # 'profile' in your functions. You don't need to do anything, it'll just
1084     # be there.
1085     #
1086     # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
1087     # was is currently active. That way you can avoid running code for a
1088     # profile that is already active, by running code such as the following
1089     # at the start of your function:
1090     #
1091     # function chpwd_profile_grml() {
1092     #     [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1093     #   ...
1094     # }
1095     #
1096     # The initial value for $CHPWD_PROFILE is 'default'.
1097     #
1098     # Version requirement:
1099     #   This feature requires zsh 4.3.3 or newer.
1100     #   If you use this feature and need to know whether it is active in your
1101     #   current shell, there are several ways to do that. Here are two simple
1102     #   ways:
1103     #
1104     #   a) If knowing if the profiles feature is active when zsh starts is
1105     #      good enough for you, you can put the following snippet into your
1106     #      .zshrc.local:
1107     #
1108     #   (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
1109     #
1110     #   b) If that is not good enough, and you would prefer to be notified
1111     #      whenever a profile changes, you can solve that by making sure you
1112     #      start *every* profile function you create like this:
1113     #
1114     #   function chpwd_profile_myprofilename() {
1115     #       [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
1116     #       print "chpwd(): Switching to profile: $profile"
1117     #     ...
1118     #   }
1119     #
1120     #      That makes sure you only get notified if a profile is *changed*,
1121     #      not everytime you change directory, which would probably piss
1122     #      you off fairly quickly. :-)
1123     #
1124     # There you go. Now have fun with that.
1125     local -x profile
1126
1127     zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
1128     if (( ${+functions[chpwd_profile_$profile]} )) ; then
1129         chpwd_profile_${profile}
1130     fi
1131
1132     CHPWD_PROFILE="${profile}"
1133     return 0
1134 }
1135 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
1136
1137 fi # is433
1138
1139 # }}}
1140
1141 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
1142 if [[ $BATTERY -gt 0 ]] ; then
1143     if ! check_com -c acpi ; then
1144         BATTERY=0
1145     fi
1146 fi
1147
1148 battery() {
1149 if [[ $BATTERY -gt 0 ]] ; then
1150     PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
1151     if [[ -z "$PERCENT" ]] ; then
1152         PERCENT='acpi not present'
1153     else
1154         if [[ "$PERCENT" -lt 20 ]] ; then
1155             PERCENT="warning: ${PERCENT}%%"
1156         else
1157             PERCENT="${PERCENT}%%"
1158         fi
1159     fi
1160 fi
1161 }
1162 # }}}
1163
1164 # set colors for use in prompts {{{
1165 if zrcautoload colors && colors 2>/dev/null ; then
1166     BLUE="%{${fg[blue]}%}"
1167     RED="%{${fg_bold[red]}%}"
1168     GREEN="%{${fg[green]}%}"
1169     CYAN="%{${fg[cyan]}%}"
1170     MAGENTA="%{${fg[magenta]}%}"
1171     YELLOW="%{${fg[yellow]}%}"
1172     WHITE="%{${fg[white]}%}"
1173     NO_COLOUR="%{${reset_color}%}"
1174 else
1175     BLUE=$'%{\e[1;34m%}'
1176     RED=$'%{\e[1;31m%}'
1177     GREEN=$'%{\e[1;32m%}'
1178     CYAN=$'%{\e[1;36m%}'
1179     WHITE=$'%{\e[1;37m%}'
1180     MAGENTA=$'%{\e[1;35m%}'
1181     YELLOW=$'%{\e[1;33m%}'
1182     NO_COLOUR=$'%{\e[0m%}'
1183 fi
1184
1185 # }}}
1186
1187 # gather version control information for inclusion in a prompt {{{
1188
1189 if ! is41 ; then
1190     # Be quiet about version problems in grml's zshrc as the user cannot disable
1191     # loading vcs_info() as it is *in* the zshrc - as you can see. :-)
1192     # Just unset most probable variables and disable vcs_info altogether.
1193     local -i i
1194     for i in {0..9} ; do
1195         unset VCS_INFO_message_${i}_
1196     done
1197     zstyle ':vcs_info:*' enable false
1198 fi
1199
1200 if zrcautoload vcs_info; then
1201     GRML_VCS_INFO=0
1202     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
1203     # function, which can cause a lot of trouble with our directory-based
1204     # profiles. So:
1205     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
1206         function VCS_INFO_realpath () {
1207             setopt localoptions NO_shwordsplit chaselinks
1208             ( builtin cd -q $1 2> /dev/null && pwd; )
1209         }
1210     fi
1211 else
1212 # I'm not reindenting the whole code below.
1213 GRML_VCS_INFO=1
1214
1215 # The following code is imported from the file 'zsh/functions/vcs_info'
1216 # from <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>,
1217 # which distributed under the same terms as zsh itself.
1218
1219 # we will be using two variables, so let the code know now.
1220 zstyle ':vcs_info:*' max-exports 2
1221
1222 # vcs_info() documentation:
1223 #{{{
1224 # REQUIREMENTS:
1225 #{{{
1226 #     This functionality requires zsh version >= 4.1.*.
1227 #}}}
1228 #
1229 # LOADING:
1230 #{{{
1231 # To load vcs_info(), copy this file to your $fpath[] and do:
1232 #   % autoload -Uz vcs_info && vcs_info
1233 #
1234 # To work, vcs_info() needs 'setopt prompt_subst' in your setup.
1235 #}}}
1236 #
1237 # QUICKSTART:
1238 #{{{
1239 # To get vcs_info() working quickly (including colors), you can do the
1240 # following (assuming, you loaded vcs_info() properly - see above):
1241 #
1242 # % RED=$'%{\e[31m%}'
1243 # % GR=$'%{\e[32m%}'
1244 # % MA=$'%{\e[35m%}'
1245 # % YE=$'%{\e[33m%}'
1246 # % NC=$'%{\e[0m%}'
1247 #
1248 # % zstyle ':vcs_info:*' actionformats \
1249 #       "${MA}(${NC}%s${MA})${YE}-${MA}[${GR}%b${YE}|${RED}%a${MA}]${NC} "
1250 #
1251 # % zstyle ':vcs_info:*' formats       \
1252 #       "${MA}(${NC}%s${MA})${Y}-${MA}[${GR}%b${MA}]${NC}%} "
1253 #
1254 # % zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YE}%r"
1255 #
1256 # % precmd () { vcs_info }
1257 # % PS1='${MA}[${GR}%n${MA}] ${MA}(${RED}%!${MA}) ${YE}%3~ ${VCS_INFO_message_0_}${NC}%# '
1258 #
1259 # Obviously, the las two lines are there for demonstration: You need to
1260 # call vcs_info() from your precmd() function (see 'SPECIAL FUNCTIONS' in
1261 # 'man zshmisc'). Once that is done you need a *single* quoted
1262 # '${VCS_INFO_message_0_}' in your prompt.
1263 #
1264 # Now call the 'vcs_info_printsys' utility from the command line:
1265 #
1266 # % vcs_info_printsys
1267 # # list of supported version control backends:
1268 # # disabled systems are prefixed by a hash sign (#)
1269 # git
1270 # hg
1271 # bzr
1272 # darcs
1273 # svk
1274 # mtn
1275 # svn
1276 # cvs
1277 # cdv
1278 # tla
1279 # # flavours (cannot be used in the disable style; they
1280 # # are disabled with their master [git-svn -> git]):
1281 # git-p4
1282 # git-svn
1283 #
1284 # Ten version control backends as you can see. You may not want all
1285 # of these. Because there is no point in running the code to detect
1286 # systems you do not use. ever. So, there is a way to disable some
1287 # backends altogether:
1288 #
1289 # % zstyle ':vcs_info:*' disable bzr cdv darcs mtn svk tla
1290 #
1291 # If you rerun 'vcs_info_printsys' now, you will see the backends listed
1292 # in the 'disable' style marked as diabled by a hash sign. That means the
1293 # detection of these systems is skipped *completely*. No wasted time there.
1294 #
1295 # For more control, read the reference below.
1296 #}}}
1297 #
1298 # CONFIGURATION:
1299 #{{{
1300 # The vcs_info() feature can be configured via zstyle.
1301 #
1302 # First, the context in which we are working:
1303 #       :vcs_info:<vcs-string>:<user-context>
1304 #
1305 # ...where <vcs-string> is one of:
1306 #   - git, git-svn, git-p4, hg, darcs, bzr, cdv, mtn, svn, cvs, svk or tla.
1307 #
1308 # ...and <user-context> is a freely configurable string, assignable by the
1309 # user as the first argument to vcs_info() (see its description below).
1310 #
1311 # There is are three special values for <vcs-string>: The first is named
1312 # 'init', that is in effect as long as there was no decision what vcs
1313 # backend to use. The second is 'preinit; it is used *before* vcs_info()
1314 # is run, when initializing the data exporting variables. The third
1315 # special value is 'formats' and is used by the 'vcs_info_lastmsg' for
1316 # looking up its styles.
1317 #
1318 # There are two pre-defined values for <user-context>:
1319 #   default  - the one used if none is specified
1320 #   command  - used by vcs_info_lastmsg to lookup its styles.
1321 #
1322 # You may *not* use 'print_systems_' as a user-context string, because it
1323 # is used internally.
1324 #
1325 # You can of course use ':vcs_info:*' to match all VCSs in all
1326 # user-contexts at once.
1327 #
1328 # Another special context is 'formats', which is used by the
1329 # vcs_info_lastmsg() utility function (see below).
1330 #
1331 #
1332 # This is a description of all styles, that are looked up:
1333 #   formats             - A list of formats, used when actionformats is not
1334 #                         used (which is most of the time).
1335 #   actionformats       - A list of formats, used if a there is a special
1336 #                         action going on in your current repository;
1337 #                         (like an interactive rebase or a merge conflict)
1338 #   branchformat        - Some backends replace %b in the formats and
1339 #                         actionformats styles above, not only by a branch
1340 #                         name but also by a revision number. This style
1341 #                         let's you modify how that string should look like.
1342 #   nvcsformats         - These "formats" are exported, when we didn't detect
1343 #                         a version control system for the current directory.
1344 #                         This is useful, if you want vcs_info() to completely
1345 #                         take over the generation of your prompt.
1346 #                         You would do something like
1347 #                           PS1='${VCS_INFO_message_0_}'
1348 #                         to accomplish that.
1349 #   max-exports         - Defines the maximum number if VCS_INFO_message_*_
1350 #                         variables vcs_info() will export.
1351 #   enable              - Checked in the 'init' context. If set to false,
1352 #                         vcs_info() will do nothing.
1353 #   disable             - Provide a list of systems, you don't want
1354 #                         the vcs_info() to check for repositories
1355 #                         (checked in the 'init' context, too).
1356 #   disable-patterns    - A list of patterns that are checked against $PWD.
1357 #                         If the pattern matches, vcs_info will be disabled.
1358 #                         Say, ~/.zsh is a directory under version control,
1359 #                         in which you do not want vcs_info to be active, do:
1360 #                         zstyle ':vcs_info:*' disable-patterns "$HOME/.zsh+(|/*)"
1361 #   use-simple          - If there are two different ways of gathering
1362 #                         information, you can select the simpler one
1363 #                         by setting this style to true; the default
1364 #                         is to use the not-that-simple code, which is
1365 #                         potentially a lot slower but might be more
1366 #                         accurate in all possible cases.
1367 #   use-prompt-escapes  - determines if we assume that the assembled
1368 #                         string from vcs_info() includes prompt escapes.
1369 #                         (Used by vcs_info_lastmsg().
1370 #
1371 # The use-simple style is only available for the bzr backend.
1372 #
1373 # The default values for these in all contexts are:
1374 #   formats             " (%s)-[%b|%a]-"
1375 #   actionformats       " (%s)-[%b]-"
1376 #   branchformat        "%b:%r" (for bzr, svn and svk)
1377 #   nvcsformats         ""
1378 #   max-exports         2
1379 #   enable              true
1380 #   disable             (empty list)
1381 #   disable-patterns    (empty list)
1382 #   use-simple          false
1383 #   use-prompt-escapes  true
1384 #
1385 #
1386 # In normal formats and actionformats, the following replacements
1387 # are done:
1388 #   %s  - The vcs in use (git, hg, svn etc.)
1389 #   %b  - Information about the current branch.
1390 #   %a  - An identifier, that describes the action.
1391 #         Only makes sense in actionformats.
1392 #   %R  - base directory of the repository.
1393 #   %r  - repository name
1394 #         If %R is '/foo/bar/repoXY', %r is 'repoXY'.
1395 #   %S  - subdirectory within a repository. if $PWD is
1396 #         '/foo/bar/reposXY/beer/tasty', %S is 'beer/tasty'.
1397 #
1398 #
1399 # In branchformat these replacements are done:
1400 #   %b  - the branch name
1401 #   %r  - the current revision number
1402 #
1403 # Not all vcs backends have to support all replacements.
1404 # nvcsformat does not perform *any* replacements. It is just a string.
1405 #}}}
1406 #
1407 # ODDITIES:
1408 #{{{
1409 # If you want to use the %b (bold off) prompt expansion in 'formats', which
1410 # expands %b itself, use %%b. That will cause the vcs_info() expansion to
1411 # replace %%b with %b. So zsh's prompt expansion mechanism can handle it.
1412 # Similarly, to hand down %b from branchformat, use %%%%b. Sorry for this
1413 # inconvenience, but it cannot be easily avoided. Luckily we do not clash
1414 # with a lot of prompt expansions and this only needs to be done for those.
1415 # See 'man zshmisc' for details about EXPANSION OF PROMPT SEQUENCES.
1416 #}}}
1417 #
1418 # FUNCTION DESCRIPTIONS (public API):
1419 #{{{
1420 #   vcs_info()
1421 #       The main function, that runs all backends and assembles
1422 #       all data into ${VCS_INFO_message_*_}. This is the function
1423 #       you want to call from precmd() if you want to include
1424 #       up-to-date information in your prompt (see VARIABLE
1425 #       DESCRIPTION below).
1426 #
1427 #   vcs_info_printsys()
1428 #       Prints a list of all supported version control systems.
1429 #       Useful to find out possible contexts (and which of them are enabled)
1430 #       or values for the 'disable' style.
1431 #
1432 #   vcs_info_lastmsg()
1433 #       Outputs the last ${VCS_INFO_message_*_} value. Takes into account
1434 #       the value of the use-prompt-escapes style in ':vcs_info:formats'.
1435 #       It also only prints max-exports values.
1436 #
1437 # All functions named VCS_INFO_* are for internal use only.
1438 #}}}
1439 #
1440 # VARIABLE DESCRIPTION:
1441 #{{{
1442 #   ${VCS_INFO_message_N_}    (Note the trailing underscore)
1443 #       Where 'N' is an integer, eg: VCS_INFO_message_0_
1444 #       These variables are the storage for the informational message the
1445 #       last vcs_info() call has assembled. These are strongly connected
1446 #       to the formats, actionformats and nvcsformats styles described
1447 #       above. Those styles are lists. the first member of that list gets
1448 #       expanded into ${VCS_INFO_message_0_}, the second into
1449 #       ${VCS_INFO_message_1_} and the Nth into ${VCS_INFO_message_N-1_}.
1450 #       These parameters are exported into the environment.
1451 #       (See the max-exports style above.)
1452 #}}}
1453 #
1454 # EXAMPLES:
1455 #{{{
1456 #   Don't use vcs_info at all (even though it's in your prompt):
1457 #   % zstyle ':vcs_info:*' enable false
1458 #
1459 #   Disable the backends for bzr and svk:
1460 #   % zstyle ':vcs_info:*' disable bzr svk
1461 #
1462 #   Provide a special formats for git:
1463 #   % zstyle ':vcs_info:git:*' formats       ' GIT, BABY! [%b]'
1464 #   % zstyle ':vcs_info:git:*' actionformats ' GIT ACTION! [%b|%a]'
1465 #
1466 #   Use the quicker bzr backend (if you do, please report if it does
1467 #   the-right-thing[tm] - thanks):
1468 #   % zstyle ':vcs_info:bzr:*' use-simple true
1469 #
1470 #   Display the revision number in yellow for bzr and svn:
1471 #   % zstyle ':vcs_info:(svn|bzr):*' branchformat '%b%{'${fg[yellow]}'%}:%r'
1472 #
1473 # If you want colors, make sure you enclose the color codes in %{...%},
1474 # if you want to use the string provided by vcs_info() in prompts.
1475 #
1476 # Here is how to print the vcs infomation as a command:
1477 #   % alias vcsi='vcs_info command; vcs_info_lastmsg'
1478 #
1479 #   This way, you can even define different formats for output via
1480 #   vcs_info_lastmsg() in the ':vcs_info:command:*' namespace.
1481 #}}}
1482 #}}}
1483 # utilities
1484 VCS_INFO_adjust () { #{{{
1485     [[ -n ${vcs_comm[overwrite_name]} ]] && vcs=${vcs_comm[overwrite_name]}
1486     return 0
1487 }
1488 # }}}
1489 VCS_INFO_check_com () { #{{{
1490     (( ${+commands[$1]} )) && [[ -x ${commands[$1]} ]] && return 0
1491     return 1
1492 }
1493 # }}}
1494 VCS_INFO_formats () { # {{{
1495     setopt localoptions noksharrays
1496     local action=$1 branch=$2 base=$3
1497     local msg
1498     local -i i
1499
1500     if [[ -n ${action} ]] ; then
1501         zstyle -a ":vcs_info:${vcs}:${usercontext}" actionformats msgs
1502         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b|%a]-'
1503     else
1504         zstyle -a ":vcs_info:${vcs}:${usercontext}" formats msgs
1505         (( ${#msgs} < 1 )) && msgs[1]=' (%s)-[%b]-'
1506     fi
1507
1508     (( ${#msgs} > maxexports )) && msgs[$(( maxexports + 1 )),-1]=()
1509     for i in {1..${#msgs}} ; do
1510         zformat -f msg ${msgs[$i]}                      \
1511                         a:${action}                     \
1512                         b:${branch}                     \
1513                         r:${base:t}                     \
1514                         s:${vcs}                        \
1515                         R:${base}                       \
1516                         S:"$(VCS_INFO_reposub ${base})"
1517         msgs[$i]=${msg}
1518     done
1519     return 0
1520 }
1521 # }}}
1522 VCS_INFO_maxexports () { #{{{
1523     zstyle -s ":vcs_info:${vcs}:${usercontext}" "max-exports" maxexports || maxexports=2
1524     if [[ ${maxexports} != <-> ]] || (( maxexports < 1 )); then
1525         printf 'vcs_info(): expecting numeric arg >= 1 for max-exports (got %s).\n' ${maxexports}
1526         printf 'Defaulting to 2.\n'
1527         maxexports=2
1528     fi
1529 }
1530 # }}}
1531 VCS_INFO_nvcsformats () { #{{{
1532     setopt localoptions noksharrays
1533     local c v
1534
1535     if [[ $1 == 'preinit' ]] ; then
1536         c=default
1537         v=preinit
1538     fi
1539     zstyle -a ":vcs_info:${v:-$vcs}:${c:-$usercontext}" nvcsformats msgs
1540     (( ${#msgs} > maxexports )) && msgs[${maxexports},-1]=()
1541 }
1542 # }}}
1543 VCS_INFO_realpath () { #{{{
1544     # a portable 'readlink -f'
1545     # forcing a subshell, to ensure chpwd() is not removed
1546     # from the calling shell (if VCS_INFO_realpath() is called
1547     # manually).
1548     (
1549         (( ${+functions[chpwd]} )) && unfunction chpwd
1550         setopt chaselinks
1551         cd $1 2>/dev/null && pwd
1552     )
1553 }
1554 # }}}
1555 VCS_INFO_reposub () { #{{{
1556     setopt localoptions extendedglob
1557     local base=${1%%/##}
1558
1559     [[ ${PWD} == ${base}/* ]] || {
1560         printf '.'
1561         return 1
1562     }
1563     printf '%s' ${PWD#$base/}
1564     return 0
1565 }
1566 # }}}
1567 VCS_INFO_set () { #{{{
1568     setopt localoptions noksharrays
1569     local -i i j
1570
1571     if [[ $1 == '--clear' ]] ; then
1572         for i in {0..9} ; do
1573             unset VCS_INFO_message_${i}_
1574         done
1575     fi
1576     if [[ $1 == '--nvcs' ]] ; then
1577         [[ $2 == 'preinit' ]] && (( maxexports == 0 )) && (( maxexports = 1 ))
1578         for i in {0..$((maxexports - 1))} ; do
1579             typeset -gx VCS_INFO_message_${i}_=
1580         done
1581         VCS_INFO_nvcsformats $2
1582     fi
1583
1584     (( ${#msgs} - 1 < 0 )) && return 0
1585     for i in {0..$(( ${#msgs} - 1 ))} ; do
1586         (( j = i + 1 ))
1587         typeset -gx VCS_INFO_message_${i}_=${msgs[$j]}
1588     done
1589     return 0
1590 }
1591 # }}}
1592 # information gathering
1593 VCS_INFO_bzr_get_data () { # {{{
1594     setopt localoptions noksharrays
1595     local bzrbase bzrbr
1596     local -a bzrinfo
1597
1598     if zstyle -t ":vcs_info:${vcs}:${usercontext}" "use-simple" ; then
1599         bzrbase=${vcs_comm[basedir]}
1600         bzrinfo[2]=${bzrbase:t}
1601         if [[ -f ${bzrbase}/.bzr/branch/last-revision ]] ; then
1602             bzrinfo[1]=$(< ${bzrbase}/.bzr/branch/last-revision)
1603             bzrinfo[1]=${${bzrinfo[1]}%% *}
1604         fi
1605     else
1606         bzrbase=${${(M)${(f)"$( bzr info )"}:# ##branch\ root:*}/*: ##/}
1607         bzrinfo=( ${${${(M)${(f)"$( bzr version-info )"}:#(#s)(revno|branch-nick)*}/*: /}/*\//} )
1608         bzrbase="$(VCS_INFO_realpath ${bzrbase})"
1609     fi
1610
1611     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat bzrbr || bzrbr="%b:%r"
1612     zformat -f bzrbr "${bzrbr}" "b:${bzrinfo[2]}" "r:${bzrinfo[1]}"
1613     VCS_INFO_formats '' "${bzrbr}" "${bzrbase}"
1614     return 0
1615 }
1616 # }}}
1617 VCS_INFO_cdv_get_data () { # {{{
1618     local cdvbase
1619
1620     cdvbase=${vcs_comm[basedir]}
1621     VCS_INFO_formats '' "${cdvbase:t}" "${cdvbase}"
1622     return 0
1623 }
1624 # }}}
1625 VCS_INFO_cvs_get_data () { # {{{
1626     local cvsbranch cvsbase basename
1627
1628     cvsbase="."
1629     while [[ -d "${cvsbase}/../CVS" ]]; do
1630         cvsbase="${cvsbase}/.."
1631     done
1632     cvsbase="$(VCS_INFO_realpath ${cvsbase})"
1633     cvsbranch=$(< ./CVS/Repository)
1634     basename=${cvsbase:t}
1635     cvsbranch=${cvsbranch##${basename}/}
1636     [[ -z ${cvsbranch} ]] && cvsbranch=${basename}
1637     VCS_INFO_formats '' "${cvsbranch}" "${cvsbase}"
1638     return 0
1639 }
1640 # }}}
1641 VCS_INFO_darcs_get_data () { # {{{
1642     local darcsbase
1643
1644     darcsbase=${vcs_comm[basedir]}
1645     VCS_INFO_formats '' "${darcsbase:t}" "${darcsbase}"
1646     return 0
1647 }
1648 # }}}
1649 VCS_INFO_git_getaction () { #{{{
1650     local gitaction='' gitdir=$1
1651     local tmp
1652
1653     for tmp in "${gitdir}/rebase-apply" \
1654                "${gitdir}/rebase"       \
1655                "${gitdir}/../.dotest" ; do
1656         if [[ -d ${tmp} ]] ; then
1657             if   [[ -f "${tmp}/rebasing" ]] ; then
1658                 gitaction="rebase"
1659             elif [[ -f "${tmp}/applying" ]] ; then
1660                 gitaction="am"
1661             else
1662                 gitaction="am/rebase"
1663             fi
1664             printf '%s' ${gitaction}
1665             return 0
1666         fi
1667     done
1668
1669     for tmp in "${gitdir}/rebase-merge/interactive" \
1670                "${gitdir}/.dotest-merge/interactive" ; do
1671         if [[ -f "${tmp}" ]] ; then
1672             printf '%s' "rebase-i"
1673             return 0
1674         fi
1675     done
1676
1677     for tmp in "${gitdir}/rebase-merge" \
1678                "${gitdir}/.dotest-merge" ; do
1679         if [[ -d "${tmp}" ]] ; then
1680             printf '%s' "rebase-m"
1681             return 0
1682         fi
1683     done
1684
1685     if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1686         printf '%s' "merge"
1687         return 0
1688     fi
1689
1690     if [[ -f "${gitdir}/BISECT_LOG" ]] ; then
1691         printf '%s' "bisect"
1692         return 0
1693     fi
1694     return 1
1695 }
1696 # }}}
1697 VCS_INFO_git_getbranch () { #{{{
1698     local gitbranch gitdir=$1 tmp actiondir
1699     local gitsymref='git symbolic-ref HEAD'
1700
1701     actiondir=''
1702     for tmp in "${gitdir}/rebase-apply" \
1703                "${gitdir}/rebase"       \
1704                "${gitdir}/../.dotest"; do
1705         if [[ -d ${tmp} ]]; then
1706             actiondir=${tmp}
1707             break
1708         fi
1709     done
1710     if [[ -n ${actiondir} ]]; then
1711         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1712         [[ -z ${gitbranch} ]] && [[ -r ${actiondir}/head-name ]] \
1713             && gitbranch="$(< ${actiondir}/head-name)"
1714
1715     elif [[ -f "${gitdir}/MERGE_HEAD" ]] ; then
1716         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1717         [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/MERGE_HEAD)"
1718
1719     elif [[ -d "${gitdir}/rebase-merge" ]] ; then
1720         gitbranch="$(< ${gitdir}/rebase-merge/head-name)"
1721
1722     elif [[ -d "${gitdir}/.dotest-merge" ]] ; then
1723         gitbranch="$(< ${gitdir}/.dotest-merge/head-name)"
1724
1725     else
1726         gitbranch="$(${(z)gitsymref} 2> /dev/null)"
1727
1728         if [[ $? -ne 0 ]] ; then
1729             gitbranch="refs/tags/$(git describe --exact-match HEAD 2>/dev/null)"
1730
1731             if [[ $? -ne 0 ]] ; then
1732                 gitbranch="${${"$(< $gitdir/HEAD)"}[1,7]}..."
1733             fi
1734         fi
1735     fi
1736
1737     printf '%s' "${gitbranch##refs/[^/]##/}"
1738     return 0
1739 }
1740 # }}}
1741 VCS_INFO_git_get_data () { # {{{
1742     setopt localoptions extendedglob
1743     local gitdir gitbase gitbranch gitaction
1744
1745     gitdir=${vcs_comm[gitdir]}
1746     gitbranch="$(VCS_INFO_git_getbranch ${gitdir})"
1747
1748     if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then
1749         return 1
1750     fi
1751
1752     VCS_INFO_adjust
1753     gitaction="$(VCS_INFO_git_getaction ${gitdir})"
1754     gitbase=${PWD%/${$( git rev-parse --show-prefix )%/##}}
1755     VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}"
1756     return 0
1757 }
1758 # }}}
1759 VCS_INFO_hg_get_data () { # {{{
1760     local hgbranch hgbase file
1761
1762     hgbase=${vcs_comm[basedir]}
1763
1764     file="${hgbase}/.hg/branch"
1765     if [[ -r ${file} ]] ; then
1766         hgbranch=$(< ${file})
1767     else
1768         hgbranch='default'
1769     fi
1770
1771     VCS_INFO_formats '' "${hgbranch}" "${hgbase}"
1772     return 0
1773 }
1774 # }}}
1775 VCS_INFO_mtn_get_data () { # {{{
1776     local mtnbranch mtnbase
1777
1778     mtnbase=${vcs_comm[basedir]}
1779     mtnbranch=${${(M)${(f)"$( mtn status )"}:#(#s)Current branch:*}/*: /}
1780     VCS_INFO_formats '' "${mtnbranch}" "${mtnbase}"
1781     return 0
1782 }
1783 # }}}
1784 VCS_INFO_svk_get_data () { # {{{
1785     local svkbranch svkbase
1786
1787     svkbase=${vcs_comm[basedir]}
1788     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svkbranch || svkbranch="%b:%r"
1789     zformat -f svkbranch "${svkbranch}" "b:${vcs_comm[branch]}" "r:${vcs_comm[revision]}"
1790     VCS_INFO_formats '' "${svkbranch}" "${svkbase}"
1791     return 0
1792 }
1793 # }}}
1794 VCS_INFO_svn_get_data () { # {{{
1795     setopt localoptions noksharrays
1796     local svnbase svnbranch
1797     local -a svninfo
1798
1799     svnbase="."
1800     while [[ -d "${svnbase}/../.svn" ]]; do
1801         svnbase="${svnbase}/.."
1802     done
1803     svnbase="$(VCS_INFO_realpath ${svnbase})"
1804     svninfo=( ${${${(M)${(f)"$( svn info )"}:#(#s)(URL|Revision)*}/*: /}/*\//} )
1805
1806     zstyle -s ":vcs_info:${vcs}:${usercontext}" branchformat svnbranch || svnbranch="%b:%r"
1807     zformat -f svnbranch "${svnbranch}" "b:${svninfo[1]}" "r:${svninfo[2]}"
1808     VCS_INFO_formats '' "${svnbranch}" "${svnbase}"
1809     return 0
1810 }
1811 # }}}
1812 VCS_INFO_tla_get_data () { # {{{
1813     local tlabase tlabranch
1814
1815     tlabase="$(VCS_INFO_realpath ${vcs_comm[basedir]})"
1816     # tree-id gives us something like 'foo@example.com/demo--1.0--patch-4', so:
1817     tlabranch=${${"$( tla tree-id )"}/*\//}
1818     VCS_INFO_formats '' "${tlabranch}" "${tlabase}"
1819     return 0
1820 }
1821 # }}}
1822 # detection
1823 VCS_INFO_detect_by_dir() { #{{{
1824     local dirname=$1
1825     local basedir="." realbasedir
1826
1827     realbasedir="$(VCS_INFO_realpath ${basedir})"
1828     while [[ ${realbasedir} != '/' ]]; do
1829         [[ -r ${realbasedir} ]] || return 1
1830         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
1831             [[ -d ${basedir}/${dirname} ]] && \
1832             [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
1833                 break
1834         else
1835             [[ -d ${basedir}/${dirname} ]] && break
1836         fi
1837
1838         basedir=${basedir}/..
1839         realbasedir="$(VCS_INFO_realpath ${basedir})"
1840     done
1841
1842     [[ ${realbasedir} == "/" ]] && return 1
1843     vcs_comm[basedir]=${realbasedir}
1844     return 0
1845 }
1846 # }}}
1847 VCS_INFO_bzr_detect() { #{{{
1848     VCS_INFO_check_com bzr || return 1
1849     vcs_comm[detect_need_file]=branch/format
1850     VCS_INFO_detect_by_dir '.bzr'
1851     return $?
1852 }
1853 # }}}
1854 VCS_INFO_cdv_detect() { #{{{
1855     VCS_INFO_check_com cdv || return 1
1856     vcs_comm[detect_need_file]=format
1857     VCS_INFO_detect_by_dir '.cdv'
1858     return $?
1859 }
1860 # }}}
1861 VCS_INFO_cvs_detect() { #{{{
1862     VCS_INFO_check_com cvs || return 1
1863     [[ -d "./CVS" ]] && [[ -r "./CVS/Repository" ]] && return 0
1864     return 1
1865 }
1866 # }}}
1867 VCS_INFO_darcs_detect() { #{{{
1868     VCS_INFO_check_com darcs || return 1
1869     vcs_comm[detect_need_file]=format
1870     VCS_INFO_detect_by_dir '_darcs'
1871     return $?
1872 }
1873 # }}}
1874 VCS_INFO_git_detect() { #{{{
1875     if VCS_INFO_check_com git && git rev-parse --is-inside-work-tree &> /dev/null ; then
1876         vcs_comm[gitdir]="$(git rev-parse --git-dir 2> /dev/null)" || return 1
1877         if   [[ -d ${vcs_comm[gitdir]}/svn ]]             ; then vcs_comm[overwrite_name]='git-svn'
1878         elif [[ -d ${vcs_comm[gitdir]}/refs/remotes/p4 ]] ; then vcs_comm[overwrite_name]='git-p4' ; fi
1879         return 0
1880     fi
1881     return 1
1882 }
1883 # }}}
1884 VCS_INFO_hg_detect() { #{{{
1885     VCS_INFO_check_com hg || return 1
1886     vcs_comm[detect_need_file]=store
1887     VCS_INFO_detect_by_dir '.hg'
1888     return $?
1889 }
1890 # }}}
1891 VCS_INFO_mtn_detect() { #{{{
1892     VCS_INFO_check_com mtn || return 1
1893     vcs_comm[detect_need_file]=revision
1894     VCS_INFO_detect_by_dir '_MTN'
1895     return $?
1896 }
1897 # }}}
1898 VCS_INFO_svk_detect() { #{{{
1899     setopt localoptions noksharrays extendedglob
1900     local -a info
1901     local -i fhash
1902     fhash=0
1903
1904     VCS_INFO_check_com svk || return 1
1905     [[ -f ~/.svk/config ]] || return 1
1906
1907     # This detection function is a bit different from the others.
1908     # We need to read svk's config file to detect a svk repository
1909     # in the first place. Therefore, we'll just proceed and read
1910     # the other information, too. This is more then any of the
1911     # other detections do but this takes only one file open for
1912     # svk at most. VCS_INFO_svk_get_data() get simpler, too. :-)
1913     while IFS= read -r line ; do
1914         if [[ -n ${vcs_comm[basedir]} ]] ; then
1915             line=${line## ##}
1916             [[ ${line} == depotpath:* ]] && vcs_comm[branch]=${line##*/}
1917             [[ ${line} == revision:* ]] && vcs_comm[revision]=${line##*[[:space:]]##}
1918             [[ -n ${vcs_comm[branch]} ]] && [[ -n ${vcs_comm[revision]} ]] && break
1919             continue
1920         fi
1921         (( fhash > 0 )) && [[ ${line} == '  '[^[:space:]]*:* ]] && break
1922         [[ ${line} == '  hash:'* ]] && fhash=1 && continue
1923         (( fhash == 0 )) && continue
1924         [[ ${PWD}/ == ${${line## ##}%:*}/* ]] && vcs_comm[basedir]=${${line## ##}%:*}
1925     done < ~/.svk/config
1926
1927     [[ -n ${vcs_comm[basedir]} ]]  && \
1928     [[ -n ${vcs_comm[branch]} ]]   && \
1929     [[ -n ${vcs_comm[revision]} ]] && return 0
1930     return 1
1931 }
1932 # }}}
1933 VCS_INFO_svn_detect() { #{{{
1934     VCS_INFO_check_com svn || return 1
1935     [[ -d ".svn" ]] && return 0
1936     return 1
1937 }
1938 # }}}
1939 VCS_INFO_tla_detect() { #{{{
1940     VCS_INFO_check_com tla || return 1
1941     vcs_comm[basedir]="$(tla tree-root 2> /dev/null)" && return 0
1942     return 1
1943 }
1944 # }}}
1945 # public API
1946 vcs_info_printsys () { # {{{
1947     vcs_info print_systems_
1948 }
1949 # }}}
1950 vcs_info_lastmsg () { # {{{
1951     emulate -L zsh
1952     local -i i
1953
1954     VCS_INFO_maxexports
1955     for i in {0..$((maxexports - 1))} ; do
1956         printf '$VCS_INFO_message_%d_: "' $i
1957         if zstyle -T ':vcs_info:formats:command' use-prompt-escapes ; then
1958             print -nP ${(P)${:-VCS_INFO_message_${i}_}}
1959         else
1960             print -n ${(P)${:-VCS_INFO_message_${i}_}}
1961         fi
1962         printf '"\n'
1963     done
1964 }
1965 # }}}
1966 vcs_info () { # {{{
1967     emulate -L zsh
1968     setopt extendedglob
1969
1970     [[ -r . ]] || return 1
1971
1972     local pat
1973     local -i found
1974     local -a VCSs disabled dps
1975     local -x vcs usercontext
1976     local -ix maxexports
1977     local -ax msgs
1978     local -Ax vcs_comm
1979
1980     vcs="init"
1981     VCSs=(git hg bzr darcs svk mtn svn cvs cdv tla)
1982     case $1 in
1983         (print_systems_)
1984             zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
1985             print -l '# list of supported version control backends:' \
1986                      '# disabled systems are prefixed by a hash sign (#)'
1987             for vcs in ${VCSs} ; do
1988                 [[ -n ${(M)disabled:#${vcs}} ]] && printf '#'
1989                 printf '%s\n' ${vcs}
1990             done
1991             print -l '# flavours (cannot be used in the disable style; they' \
1992                      '# are disabled with their master [git-svn -> git]):'   \
1993                      git-{p4,svn}
1994             return 0
1995             ;;
1996         ('')
1997             [[ -z ${usercontext} ]] && usercontext=default
1998             ;;
1999         (*) [[ -z ${usercontext} ]] && usercontext=$1
2000             ;;
2001     esac
2002
2003     zstyle -T ":vcs_info:${vcs}:${usercontext}" "enable" || {
2004         [[ -n ${VCS_INFO_message_0_} ]] && VCS_INFO_set --clear
2005         return 0
2006     }
2007     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable" disabled
2008
2009     zstyle -a ":vcs_info:${vcs}:${usercontext}" "disable-patterns" dps
2010     for pat in ${dps} ; do
2011         if [[ ${PWD} == ${~pat} ]] ; then
2012             [[ -n ${vcs_info_msg_0_} ]] && VCS_INFO_set --clear
2013             return 0
2014         fi
2015     done
2016
2017     VCS_INFO_maxexports
2018
2019     (( found = 0 ))
2020     for vcs in ${VCSs} ; do
2021         [[ -n ${(M)disabled:#${vcs}} ]] && continue
2022         vcs_comm=()
2023         VCS_INFO_${vcs}_detect && (( found = 1 )) && break
2024     done
2025
2026     (( found == 0 )) && {
2027         VCS_INFO_set --nvcs
2028         return 0
2029     }
2030
2031     VCS_INFO_${vcs}_get_data || {
2032         VCS_INFO_set --nvcs
2033         return 1
2034     }
2035
2036     VCS_INFO_set
2037     return 0
2038 }
2039
2040 VCS_INFO_set --nvcs preinit
2041 # }}}
2042
2043 fi
2044
2045 # Change vcs_info formats for the grml prompt. The 2nd format sets up
2046 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
2047 # TODO: The included vcs_info() version still uses $VCS_INFO_message_N_.
2048 #       That needs to be the use of $VCS_INFO_message_N_ needs to be changed
2049 #       to $vcs_info_msg_N_ as soon as we use the included version.
2050 if [[ "$TERM" == dumb ]] ; then
2051     zstyle ':vcs_info:*' actionformats "(%s%)-[%b|%a] " "zsh: %r"
2052     zstyle ':vcs_info:*' formats       "(%s%)-[%b] "    "zsh: %r"
2053 else
2054     # these are the same, just with a lot of colours:
2055     zstyle ':vcs_info:*' actionformats "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOUR} " \
2056                                        "zsh: %r"
2057     zstyle ':vcs_info:*' formats       "${MAGENTA}(${NO_COLOUR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOUR}%} " \
2058                                        "zsh: %r"
2059     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
2060 fi
2061
2062 if [[ -o restricted ]]; then
2063     zstyle ':vcs_info:*' enable false
2064 fi
2065
2066 # }}}
2067
2068 # command not found handling {{{
2069
2070 (( ${COMMAND_NOT_FOUND} == 1 )) &&
2071 function command_not_found_handler() {
2072     emulate -L zsh
2073     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
2074         ${GRML_ZSH_CNF_HANDLER} $1
2075     fi
2076     return 1
2077 }
2078
2079 # }}}
2080
2081 # {{{ set prompt
2082 if zrcautoload promptinit && promptinit 2>/dev/null ; then
2083     promptinit # people should be able to use their favourite prompt
2084 else
2085     print 'Notice: no promptinit available :('
2086 fi
2087
2088 setopt prompt_subst
2089
2090 # make sure to use right prompt only when not running a command
2091 is41 && setopt transient_rprompt
2092
2093
2094 function ESC_print () {
2095     info_print $'\ek' $'\e\\' "$@"
2096 }
2097 function set_title () {
2098     info_print  $'\e]0;' $'\a' "$@"
2099 }
2100
2101 function info_print () {
2102     local esc_begin esc_end
2103     esc_begin="$1"
2104     esc_end="$2"
2105     shift 2
2106     printf '%s' ${esc_begin}
2107     printf '%s' "$*"
2108     printf '%s' "${esc_end}"
2109 }
2110
2111 # TODO: revise all these NO* variables and especially their documentation
2112 #       in zsh-help() below.
2113 is4 && [[ $NOPRECMD -eq 0 ]] && precmd () {
2114     [[ $NOPRECMD -gt 0 ]] && return 0
2115     # update VCS information
2116     vcs_info
2117
2118     if [[ $TERM == screen* ]] ; then
2119         if [[ -n ${VCS_INFO_message_1_} ]] ; then
2120             ESC_print ${VCS_INFO_message_1_}
2121         elif [[ -n ${vcs_info_msg_1_} ]] ; then
2122             ESC_print ${vcs_info_msg_1_}
2123         else
2124             ESC_print "zsh"
2125         fi
2126     fi
2127     # just use DONTSETRPROMPT=1 to be able to overwrite RPROMPT
2128     if [[ $DONTSETRPROMPT -eq 0 ]] ; then
2129         if [[ $BATTERY -gt 0 ]] ; then
2130             # update battery (dropped into $PERCENT) information
2131             battery
2132             RPROMPT="%(?..:() ${PERCENT}"
2133         else
2134             RPROMPT="%(?..:() "
2135         fi
2136     fi
2137     # adjust title of xterm
2138     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
2139     [[ ${NOTITLE} -gt 0 ]] && return 0
2140     case $TERM in
2141         (xterm*|rxvt*)
2142             set_title ${(%):-"%n@%m: %~"}
2143             ;;
2144     esac
2145 }
2146
2147 # preexec() => a function running before every command
2148 is4 && [[ $NOPRECMD -eq 0 ]] && \
2149 preexec () {
2150     [[ $NOPRECMD -gt 0 ]] && return 0
2151 # set hostname if not running on host with name 'grml'
2152     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != $(hostname) ]] ; then
2153        NAME="@$HOSTNAME"
2154     fi
2155 # get the name of the program currently running and hostname of local machine
2156 # set screen window title if running in a screen
2157     if [[ "$TERM" == screen* ]] ; then
2158         # local CMD=${1[(wr)^(*=*|sudo|ssh|-*)]}       # don't use hostname
2159         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME" # use hostname
2160         ESC_print ${CMD}
2161     fi
2162 # adjust title of xterm
2163     [[ ${NOTITLE} -gt 0 ]] && return 0
2164     case $TERM in
2165         (xterm*|rxvt*)
2166             set_title "${(%):-"%n@%m:"}" "$1"
2167             ;;
2168     esac
2169 }
2170
2171 EXITCODE="%(?..%?%1v )"
2172 PS2='\`%_> '      # secondary prompt, printed when the shell needs more information to complete a command.
2173 PS3='?# '         # selection prompt used within a select loop.
2174 PS4='+%N:%i:%_> ' # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
2175
2176 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
2177 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
2178     debian_chroot=$(cat /etc/debian_chroot)
2179 fi
2180
2181 # don't use colors on dumb terminals (like emacs):
2182 if [[ "$TERM" == dumb ]] ; then
2183     PROMPT="${EXITCODE}${debian_chroot:+($debian_chroot)}%n@%m %40<...<%B%~%b%<< "
2184 else
2185     # only if $GRMLPROMPT is set (e.g. via 'GRMLPROMPT=1 zsh') use the extended prompt
2186     # set variable identifying the chroot you work in (used in the prompt below)
2187     if [[ $GRMLPROMPT -gt 0 ]] ; then
2188         PROMPT="${RED}${EXITCODE}${CYAN}[%j running job(s)] ${GREEN}{history#%!} ${RED}%(3L.+.) ${BLUE}%* %D
2189 ${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
2190     else
2191         # This assembles the primary prompt string
2192         if (( EUID != 0 )); then
2193             PROMPT="${RED}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${BLUE}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
2194         else
2195             PROMPT="${BLUE}${EXITCODE}${WHITE}${debian_chroot:+($debian_chroot)}${RED}%n${NO_COLOUR}@%m %40<...<%B%~%b%<< "
2196         fi
2197     fi
2198 fi
2199
2200 if (( GRML_VCS_INFO )); then
2201     PROMPT="${PROMPT}"'${VCS_INFO_message_0_}'"%# "
2202 else
2203     PROMPT="${PROMPT}"'${vcs_info_msg_0_}'"%# "
2204 fi
2205
2206 # if we are inside a grml-chroot set a specific prompt theme
2207 if [[ -n "$GRML_CHROOT" ]] ; then
2208     PROMPT="%{$fg[red]%}(CHROOT) %{$fg_bold[red]%}%n%{$fg_no_bold[white]%}@%m %40<...<%B%~%b%<< %\# "
2209 fi
2210 # }}}
2211
2212 # {{{ 'hash' some often used directories
2213 #d# start
2214 hash -d deb=/var/cache/apt/archives
2215 hash -d doc=/usr/share/doc
2216 hash -d linux=/lib/modules/$(command uname -r)/build/
2217 hash -d log=/var/log
2218 hash -d slog=/var/log/syslog
2219 hash -d src=/usr/src
2220 hash -d templ=/usr/share/doc/grml-templates
2221 hash -d tt=/usr/share/doc/texttools-doc
2222 hash -d www=/var/www
2223 #d# end
2224 # }}}
2225
2226 # {{{ some aliases
2227 if check_com -c screen ; then
2228     if [[ $UID -eq 0 ]] ; then
2229         [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
2230     elif [[ -r $HOME/.screenrc ]] ; then
2231         alias screen="${commands[screen]} -c $HOME/.screenrc"
2232     else
2233         if [[ -r /etc/grml/screenrc_grml ]]; then
2234             alias screen="${commands[screen]} -c /etc/grml/screenrc_grml"
2235         else
2236             [[ -r /etc/grml/screenrc ]] && alias screen="${commands[screen]} -c /etc/grml/screenrc"
2237         fi
2238     fi
2239 fi
2240
2241 # do we have GNU ls with color-support?
2242 if ls --help 2>/dev/null | grep -- --color= >/dev/null && [[ "$TERM" != dumb ]] ; then
2243     #a1# execute \kbd{@a@}:\quad ls with colors
2244     alias ls='ls -b -CF --color=auto'
2245     #a1# execute \kbd{@a@}:\quad list all files, with colors
2246     alias la='ls -la --color=auto'
2247     #a1# long colored list, without dotfiles (@a@)
2248     alias ll='ls -l --color=auto'
2249     #a1# long colored list, human readable sizes (@a@)
2250     alias lh='ls -hAl --color=auto'
2251     #a1# List files, append qualifier to filenames \\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
2252     alias l='ls -lF --color=auto'
2253 else
2254     alias ls='ls -b -CF'
2255     alias la='ls -la'
2256     alias ll='ls -l'
2257     alias lh='ls -hAl'
2258     alias l='ls -lF'
2259 fi
2260
2261 alias mdstat='cat /proc/mdstat'
2262 alias ...='cd ../../'
2263
2264 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
2265 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
2266     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
2267 fi
2268
2269 alias cp='nocorrect cp'         # no spelling correction on cp
2270 alias mkdir='nocorrect mkdir'   # no spelling correction on mkdir
2271 alias mv='nocorrect mv'         # no spelling correction on mv
2272 alias rm='nocorrect rm'         # no spelling correction on rm
2273
2274 #a1# Execute \kbd{rmdir}
2275 alias rd='rmdir'
2276 #a1# Execute \kbd{mkdir}
2277 alias md='mkdir'
2278
2279 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
2280 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
2281 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
2282
2283 # make sure it is not assigned yet
2284 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
2285 utf2iso() {
2286     if isutfenv ; then
2287         for ENV in $(env | command grep -i '.utf') ; do
2288             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
2289         done
2290     fi
2291 }
2292
2293 # make sure it is not assigned yet
2294 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
2295 iso2utf() {
2296     if ! isutfenv ; then
2297         for ENV in $(env | command grep -i '\.iso') ; do
2298             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
2299         done
2300     fi
2301 }
2302
2303 # set up software synthesizer via speakup
2304 swspeak() {
2305     if [ -x /usr/sbin/swspeak-setup ] ; then
2306        setopt singlelinezle
2307        unsetopt prompt_cr
2308        export PS1="%m%# "
2309        /usr/sbin/swspeak-setup $@
2310      else # old version:
2311         if ! [[ -r /dev/softsynth ]] ; then
2312             flite -o play -t "Sorry, software synthesizer not available. Did you boot with swspeak bootoption?"
2313             return 1
2314         else
2315            setopt singlelinezle
2316            unsetopt prompt_cr
2317            export PS1="%m%# "
2318             nice -n -20 speechd-up
2319             sleep 2
2320             flite -o play -t "Finished setting up software synthesizer"
2321         fi
2322      fi
2323 }
2324
2325 # I like clean prompt, so provide simple way to get that
2326 check_com 0 || alias 0='return 0'
2327
2328 # for really lazy people like mika:
2329 check_com S &>/dev/null || alias S='screen'
2330 check_com s &>/dev/null || alias s='ssh'
2331
2332 # especially for roadwarriors using GNU screen and ssh:
2333 if ! check_com asc &>/dev/null ; then
2334   asc() { autossh -t "$@" 'screen -RdU' }
2335   compdef asc=ssh
2336 fi
2337
2338 # get top 10 shell commands:
2339 alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
2340
2341 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
2342 if check_com -c truecrypt ; then
2343     if isutfenv ; then
2344         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077,utf8" '
2345     else
2346         alias truec='truecrypt --mount-options "rw,sync,dirsync,users,uid=1000,gid=users,umask=077" '
2347     fi
2348 fi
2349
2350 #f1# Hints for the use of zsh on grml
2351 zsh-help() {
2352     print "$bg[white]$fg[black]
2353 zsh-help - hints for use of zsh on grml
2354 =======================================$reset_color"
2355
2356     print '
2357 Main configuration of zsh happens in /etc/zsh/zshrc.
2358 That file is part of the package grml-etc-core, if you want to
2359 use them on a non-grml-system just get the tar.gz from
2360 http://deb.grml.org/ or (preferably) get it from the git repository:
2361
2362   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
2363
2364 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
2365 The file is still there, but it is empty for backwards compatibility.
2366
2367 For your own changes use these two files:
2368     $HOME/.zshrc.pre
2369     $HOME/.zshrc.local
2370
2371 The former is sourced very early in our zshrc, the latter is sourced
2372 very lately.
2373
2374 System wide configuration without touching configuration files of grml
2375 can take place in /etc/zsh/zshrc.local.
2376
2377 Normally, the root user (EUID == 0) does not get the whole grml setup.
2378 If you want to force the whole setup for that user, too, set
2379 GRML_ALWAYS_LOAD_ALL=1 in .zshrc.pre in root'\''s home directory.
2380
2381 For information regarding zsh start at http://grml.org/zsh/
2382
2383 Take a look at grml'\''s zsh refcard:
2384 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
2385
2386 Check out the main zsh refcard:
2387 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
2388
2389 And of course visit the zsh-lovers:
2390 % man zsh-lovers
2391
2392 You can adjust some options through environment variables when
2393 invoking zsh without having to edit configuration files.
2394 Basically meant for bash users who are not used to the power of
2395 the zsh yet. :)
2396
2397   "NOCOR=1    zsh" => deactivate automatic correction
2398   "NOMENU=1   zsh" => do not use auto menu completion (note: use ctrl-d for completion instead!)
2399   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
2400   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
2401                       preexec() and precmd() completely
2402   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
2403   "COMMAND_NOT_FOUND=1 zsh"
2404                    => Enable a handler if an external command was not found
2405                       The command called in the handler can be altered by setting
2406                       the GRML_ZSH_CNF_HANDLER variable, the default is:
2407                       "/usr/share/command-not-found/command-not-found"
2408
2409 A value greater than 0 is enables a feature; a value equal to zero
2410 disables it. If you like one or the other of these settings, you can
2411 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
2412 zshrc.'
2413
2414     print "
2415 $bg[white]$fg[black]
2416 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
2417 Enjoy your grml system with the zsh!$reset_color"
2418 }
2419
2420 # debian stuff
2421 if [[ -r /etc/debian_version ]] ; then
2422     #a3# Execute \kbd{apt-cache search}
2423     alias acs='apt-cache search'
2424     #a3# Execute \kbd{apt-cache show}
2425     alias acsh='apt-cache show'
2426     #a3# Execute \kbd{apt-cache policy}
2427     alias acp='apt-cache policy'
2428     #a3# Execute \kbd{apt-get dist-upgrade}
2429     salias adg="apt-get dist-upgrade"
2430     #a3# Execute \kbd{apt-get install}
2431     salias agi="apt-get install"
2432     #a3# Execute \kbd{aptitude install}
2433     salias ati="aptitude install"
2434     #a3# Execute \kbd{apt-get upgrade}
2435     salias ag="apt-get upgrade"
2436     #a3# Execute \kbd{apt-get update}
2437     salias au="apt-get update"
2438     #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
2439     salias -a up="aptitude update ; aptitude safe-upgrade"
2440     #a3# Execute \kbd{dpkg-buildpackage}
2441     alias dbp='dpkg-buildpackage'
2442     #a3# Execute \kbd{grep-excuses}
2443     alias ge='grep-excuses'
2444
2445     # debian upgrade
2446     #f3# Execute \kbd{apt-get update \&\& }\\&\quad \kbd{apt-get dist-upgrade}
2447     upgrade() {
2448         emulate -L zsh
2449         if [[ -z $1 ]] ; then
2450             $SUDO apt-get update
2451             $SUDO apt-get -u upgrade
2452         else
2453             ssh $1 $SUDO apt-get update
2454             # ask before the upgrade
2455             local dummy
2456             ssh $1 $SUDO apt-get --no-act upgrade
2457             echo -n 'Process the upgrade?'
2458             read -q dummy
2459             if [[ $dummy == "y" ]] ; then
2460                 ssh $1 $SUDO apt-get -u upgrade --yes
2461             fi
2462         fi
2463     }
2464
2465     # get a root shell as normal user in live-cd mode:
2466     if isgrmlcd && [[ $UID -ne 0 ]] ; then
2467        alias su="sudo su"
2468      fi
2469
2470     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
2471     salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
2472     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
2473     salias tlog="tail -f /var/log/syslog"    # follow the syslog
2474 fi
2475
2476 # sort installed Debian-packages by size
2477 if check_com -c grep-status ; then
2478     #a3# List installed Debian-packages sorted by size
2479     alias debs-by-size='grep-status -FStatus -sInstalled-Size,Package -n "install ok installed" | paste -sd "  \n" | sort -rn'
2480 fi
2481
2482 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
2483 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
2484     if check_com -c wodim; then
2485         cdrecord() {
2486             cat <<EOMESS
2487 cdrecord is not provided under its original name by Debian anymore.
2488 See #377109 in the BTS of Debian for more details.
2489
2490 Please use the wodim binary instead
2491 EOMESS
2492             return 1
2493         }
2494     fi
2495 fi
2496
2497 # get_tw_cli has been renamed into get_3ware
2498 if check_com -c get_3ware ; then
2499     get_tw_cli() {
2500         echo 'Warning: get_tw_cli has been renamed into get_3ware. Invoking get_3ware for you.'>&2
2501         get_3ware
2502     }
2503 fi
2504
2505 # I hate lacking backward compatibility, so provide an alternative therefore
2506 if ! check_com -c apache2-ssl-certificate ; then
2507
2508     apache2-ssl-certificate() {
2509
2510     print 'Debian does not ship apache2-ssl-certificate anymore (see #398520). :('
2511     print 'You might want to take a look at Debian the package ssl-cert as well.'
2512     print 'To generate a certificate for use with apache2 follow the instructions:'
2513
2514     echo '
2515
2516 export RANDFILE=/dev/random
2517 mkdir /etc/apache2/ssl/
2518 openssl req $@ -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem
2519 chmod 600 /etc/apache2/ssl/apache.pem
2520
2521 Run "grml-tips ssl-certificate" if you need further instructions.
2522 '
2523     }
2524 fi
2525 # }}}
2526
2527 # {{{ Use hard limits, except for a smaller stack and no core dumps
2528 unlimit
2529 is425 && limit stack 8192
2530 isgrmlcd && limit core 0 # important for a live-cd-system
2531 limit -s
2532 # }}}
2533
2534 # {{{ completion system
2535
2536 # called later (via is4 && grmlcomp)
2537 # note: use 'zstyle' for getting current settings
2538 #         press ^Xh (control-x h) for getting tags in context; ^X? (control-x ?) to run complete_debug with trace output
2539 grmlcomp() {
2540     # TODO: This could use some additional information
2541
2542     # allow one error for every three characters typed in approximate completer
2543     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
2544
2545     # don't complete backup files as executables
2546     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
2547
2548     # start menu completion only if it could find no unambiguous initial string
2549     zstyle ':completion:*:correct:*'       insert-unambiguous true
2550     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
2551     zstyle ':completion:*:correct:*'       original true
2552
2553     # activate color-completion
2554     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
2555
2556     # format on completion
2557     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
2558
2559     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
2560     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
2561
2562     # insert all expansions for expand completer
2563     zstyle ':completion:*:expand:*'        tag-order all-expansions
2564     zstyle ':completion:*:history-words'   list false
2565
2566     # activate menu
2567     zstyle ':completion:*:history-words'   menu yes
2568
2569     # ignore duplicate entries
2570     zstyle ':completion:*:history-words'   remove-all-dups yes
2571     zstyle ':completion:*:history-words'   stop yes
2572
2573     # match uppercase from lowercase
2574     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
2575
2576     # separate matches into groups
2577     zstyle ':completion:*:matches'         group 'yes'
2578     zstyle ':completion:*'                 group-name ''
2579
2580     if [[ "$NOMENU" -eq 0 ]] ; then
2581         # if there are more than 5 options allow selecting from a menu
2582         zstyle ':completion:*'               menu select=5
2583     else
2584         # don't use any menus at all
2585         setopt no_auto_menu
2586     fi
2587
2588     zstyle ':completion:*:messages'        format '%d'
2589     zstyle ':completion:*:options'         auto-description '%d'
2590
2591     # describe options in full
2592     zstyle ':completion:*:options'         description 'yes'
2593
2594     # on processes completion complete all user processes
2595     zstyle ':completion:*:processes'       command 'ps -au$USER'
2596
2597     # offer indexes before parameters in subscripts
2598     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
2599
2600     # provide verbose completion information
2601     zstyle ':completion:*'                 verbose true
2602
2603     # recent (as of Dec 2007) zsh versions are able to provide descriptions
2604     # for commands (read: 1st word in the line) that it will list for the user
2605     # to choose from. The following disables that, because it's not exactly fast.
2606     zstyle ':completion:*:-command-:*:'    verbose false
2607
2608     # set format for warnings
2609     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
2610
2611     # define files to ignore for zcompile
2612     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
2613     zstyle ':completion:correct:'          prompt 'correct to: %e'
2614
2615     # Ignore completion functions for commands you don't have:
2616     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
2617
2618     # Provide more processes in completion of programs like killall:
2619     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
2620
2621     # complete manual by their section
2622     zstyle ':completion:*:manuals'    separate-sections true
2623     zstyle ':completion:*:manuals.*'  insert-sections   true
2624     zstyle ':completion:*:man:*'      menu yes select
2625
2626     # provide .. as a completion
2627     zstyle ':completion:*' special-dirs ..
2628
2629     # run rehash on completion so new installed program are found automatically:
2630     _force_rehash() {
2631         (( CURRENT == 1 )) && rehash
2632         return 1
2633     }
2634
2635     ## correction
2636     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
2637     if [[ "$NOCOR" -gt 0 ]] ; then
2638         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
2639         setopt nocorrect
2640     else
2641         # try to be smart about when to use what completer...
2642         setopt correct
2643         zstyle -e ':completion:*' completer '
2644             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
2645                 _last_try="$HISTNO$BUFFER$CURSOR"
2646                 reply=(_complete _match _ignored _prefix _files)
2647             else
2648                 if [[ $words[1] == (rm|mv) ]] ; then
2649                     reply=(_complete _files)
2650                 else
2651                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
2652                 fi
2653             fi'
2654     fi
2655
2656     # command for process lists, the local web server details and host completion
2657     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
2658
2659     # caching
2660     [[ -d $ZSHDIR/cache ]] && zstyle ':completion:*' use-cache yes && \
2661                             zstyle ':completion::complete:*' cache-path $ZSHDIR/cache/
2662
2663     # host completion /* add brackets as vim can't parse zsh's complex cmdlines 8-) {{{ */
2664     if is42 ; then
2665         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
2666         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
2667     else
2668         _ssh_hosts=()
2669         _etc_hosts=()
2670     fi
2671     hosts=(
2672         $(hostname)
2673         "$_ssh_hosts[@]"
2674         "$_etc_hosts[@]"
2675         grml.org
2676         localhost
2677     )
2678     zstyle ':completion:*:hosts' hosts $hosts
2679     # TODO: so, why is this here?
2680     #  zstyle '*' hosts $hosts
2681
2682     # use generic completion system for programs not yet defined; (_gnu_generic works
2683     # with commands that provide a --help option with "standard" gnu-like output.)
2684     for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
2685                    pal stow tail uname ; do
2686         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
2687     done; unset compcom
2688
2689     # see upgrade function in this file
2690     compdef _hosts upgrade
2691 }
2692 # }}}
2693
2694 # {{{ grmlstuff
2695 grmlstuff() {
2696 # people should use 'grml-x'!
2697     if check_com -c 915resolution; then
2698         855resolution() {
2699             echo "Please use 915resolution as resolution modifying tool for Intel \
2700 graphic chipset."
2701             return -1
2702         }
2703     fi
2704
2705     #a1# Output version of running grml
2706     alias grml-version='cat /etc/grml_version'
2707
2708     if check_com -c rebuildfstab ; then
2709         #a1# Rebuild /etc/fstab
2710         alias grml-rebuildfstab='rebuildfstab -v -r -config'
2711     fi
2712
2713     if check_com -c grml-debootstrap ; then
2714         debian2hd() {
2715             echo "Installing debian to harddisk is possible by using grml-debootstrap."
2716             return 1
2717         }
2718     fi
2719 }
2720 # }}}
2721
2722 # {{{ now run the functions
2723 isgrml && checkhome
2724 is4    && isgrml    && grmlstuff
2725 is4    && grmlcomp
2726 # }}}
2727
2728 # {{{ keephack
2729 is4 && xsource "/etc/zsh/keephack"
2730 # }}}
2731
2732 # {{{ wonderful idea of using "e" glob qualifier by Peter Stephenson
2733 # You use it as follows:
2734 # $ NTREF=/reference/file
2735 # $ ls -l *(e:nt:)
2736 # This lists all the files in the current directory newer than the reference file.
2737 # You can also specify the reference file inline; note quotes:
2738 # $ ls -l *(e:'nt ~/.zshenv':)
2739 is4 && nt() {
2740     if [[ -n $1 ]] ; then
2741         local NTREF=${~1}
2742     fi
2743     [[ $REPLY -nt $NTREF ]]
2744 }
2745 # }}}
2746
2747 # shell functions {{{
2748
2749 #f1# Provide csh compatibility
2750 setenv()  { typeset -x "${1}${1:+=}${(@)argv[2,$#]}" }  # csh compatibility
2751
2752 #f1# Reload an autoloadable function
2753 freload() { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
2754 compdef _functions freload
2755
2756 #f1# List symlinks in detail (more detailed version of 'readlink -f' and 'whence -s')
2757 sll() {
2758     [[ -z "$1" ]] && printf 'Usage: %s <file(s)>\n' "$0" && return 1
2759     for file in "$@" ; do
2760         while [[ -h "$file" ]] ; do
2761             ls -l $file
2762             file=$(readlink "$file")
2763         done
2764     done
2765 }
2766
2767 # fast manual access
2768 if check_com qma ; then
2769     #f1# View the zsh manual
2770     manzsh()  { qma zshall "$1" }
2771     compdef _man qma
2772 else
2773     manzsh()  { /usr/bin/man zshall |  vim -c "se ft=man| se hlsearch" +/"$1" - ; }
2774 fi
2775
2776 # TODO: Is it supported to use pager settings like this?
2777 #   PAGER='less -Mr' - If so, the use of $PAGER here needs fixing
2778 # with respect to wordsplitting. (ie. ${=PAGER})
2779 if check_com -c $PAGER ; then
2780     #f1# View Debian's changelog of a given package
2781     dchange() {
2782         emulate -L zsh
2783         if [[ -r /usr/share/doc/$1/changelog.Debian.gz ]] ; then
2784             $PAGER /usr/share/doc/$1/changelog.Debian.gz
2785         elif [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2786             $PAGER /usr/share/doc/$1/changelog.gz
2787         else
2788             if check_com -c aptitude ; then
2789                 echo "No changelog for package $1 found, using aptitude to retrieve it."
2790                 if isgrml ; then
2791                     aptitude -t unstable changelog $1
2792                 else
2793                     aptitude changelog $1
2794                 fi
2795             else
2796                 echo "No changelog for package $1 found, sorry."
2797                 return 1
2798             fi
2799         fi
2800     }
2801     _dchange() { _files -W /usr/share/doc -/ }
2802     compdef _dchange dchange
2803
2804     #f1# View Debian's NEWS of a given package
2805     dnews() {
2806         emulate -L zsh
2807         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
2808             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
2809         else
2810             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
2811                 $PAGER /usr/share/doc/$1/NEWS.gz
2812             else
2813                 echo "No NEWS file for package $1 found, sorry."
2814                 return 1
2815             fi
2816         fi
2817     }
2818     _dnews() { _files -W /usr/share/doc -/ }
2819     compdef _dnews dnews
2820
2821     #f1# View upstream's changelog of a given package
2822     uchange() {
2823         emulate -L zsh
2824         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
2825             $PAGER /usr/share/doc/$1/changelog.gz
2826         else
2827             echo "No changelog for package $1 found, sorry."
2828             return 1
2829         fi
2830     }
2831     _uchange() { _files -W /usr/share/doc -/ }
2832     compdef _uchange uchange
2833 fi
2834
2835 # zsh profiling
2836 profile() {
2837     ZSH_PROFILE_RC=1 $SHELL "$@"
2838 }
2839
2840 #f1# Edit an alias via zle
2841 edalias() {
2842     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
2843 }
2844 compdef _aliases edalias
2845
2846 #f1# Edit a function via zle
2847 edfunc() {
2848     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
2849 }
2850 compdef _functions edfunc
2851
2852 # use it e.g. via 'Restart apache2'
2853 #m# f6 Start() \kbd{/etc/init.d/\em{process}}\quad\kbd{start}
2854 #m# f6 Restart() \kbd{/etc/init.d/\em{process}}\quad\kbd{restart}
2855 #m# f6 Stop() \kbd{/etc/init.d/\em{process}}\quad\kbd{stop}
2856 #m# f6 Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{reload}
2857 #m# f6 Force-Reload() \kbd{/etc/init.d/\em{process}}\quad\kbd{force-reload}
2858 if [[ -d /etc/init.d || -d /etc/service ]] ; then
2859     __start_stop() {
2860         local action_="${1:l}"  # e.g Start/Stop/Restart
2861         local service_="$2"
2862         local param_="$3"
2863
2864         local service_target_="$(readlink /etc/init.d/$service_)"
2865         if [[ $service_target_ == "/usr/bin/sv" ]]; then
2866             # runit
2867             case "${action_}" in
2868                 start) if [[ ! -e /etc/service/$service_ ]]; then
2869                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
2870                        else
2871                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2872                        fi ;;
2873                 # there is no reload in runits sysv emulation
2874                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
2875                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
2876             esac
2877         else
2878             # sysvinit
2879             $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
2880         fi
2881     }
2882
2883     for i in Start Restart Stop Force-Reload Reload ; do
2884         eval "$i() { __start_stop $i \"\$1\" \"\$2\" ; }"
2885     done
2886 fi
2887
2888 #f1# Provides useful information on globbing
2889 H-Glob() {
2890     echo -e "
2891     /      directories
2892     .      plain files
2893     @      symbolic links
2894     =      sockets
2895     p      named pipes (FIFOs)
2896     *      executable plain files (0100)
2897     %      device files (character or block special)
2898     %b     block special files
2899     %c     character special files
2900     r      owner-readable files (0400)
2901     w      owner-writable files (0200)
2902     x      owner-executable files (0100)
2903     A      group-readable files (0040)
2904     I      group-writable files (0020)
2905     E      group-executable files (0010)
2906     R      world-readable files (0004)
2907     W      world-writable files (0002)
2908     X      world-executable files (0001)
2909     s      setuid files (04000)
2910     S      setgid files (02000)
2911     t      files with the sticky bit (01000)
2912
2913   print *(m-1)          # Files modified up to a day ago
2914   print *(a1)           # Files accessed a day ago
2915   print *(@)            # Just symlinks
2916   print *(Lk+50)        # Files bigger than 50 kilobytes
2917   print *(Lk-50)        # Files smaller than 50 kilobytes
2918   print **/*.c          # All *.c files recursively starting in \$PWD
2919   print **/*.c~file.c   # Same as above, but excluding 'file.c'
2920   print (foo|bar).*     # Files starting with 'foo' or 'bar'
2921   print *~*.*           # All Files that do not contain a dot
2922   chmod 644 *(.^x)      # make all plain non-executable files publically readable
2923   print -l *(.c|.h)     # Lists *.c and *.h
2924   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
2925   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
2926 }
2927 alias help-zshglob=H-Glob
2928
2929 check_com -c qma && alias ?='qma zshall'
2930
2931 # grep for running process, like: 'any vim'
2932 any() {
2933     emulate -L zsh
2934     unsetopt KSH_ARRAYS
2935     if [[ -z "$1" ]] ; then
2936         echo "any - grep for process(es) by keyword" >&2
2937         echo "Usage: any <keyword>" >&2 ; return 1
2938     else
2939         ps xauwww | grep --color=auto "[${1[1]}]${1[2,-1]}"
2940     fi
2941 }
2942
2943
2944 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
2945 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
2946 [[ -r /proc/1/maps ]] && \
2947 deswap() {
2948     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
2949     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
2950     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
2951 }
2952
2953 # print hex value of a number
2954 hex() {
2955     emulate -L zsh
2956     [[ -n "$1" ]] && printf "%x\n" $1 || { print 'Usage: hex <number-to-convert>' ; return 1 }
2957 }
2958
2959 # calculate (or eval at all ;-)) with perl => p[erl-]eval
2960 # hint: also take a look at zcalc -> 'autoload zcalc' -> 'man zshmodules | less -p MATHFUNC'
2961 peval() {
2962     [[ -n "$1" ]] && CALC="$*" || print "Usage: calc [expression]"
2963     perl -e "print eval($CALC),\"\n\";"
2964 }
2965 functions peval &>/dev/null && alias calc=peval
2966
2967 # brltty seems to have problems with utf8 environment and/or font Uni3-Terminus16 under
2968 # certain circumstances, so work around it, no matter which environment we have
2969 brltty() {
2970     if [[ -z "$DISPLAY" ]] ; then
2971         consolechars -f /usr/share/consolefonts/default8x16.psf.gz
2972         command brltty "$@"
2973     else
2974         command brltty "$@"
2975     fi
2976 }
2977
2978 # just press 'asdf' keys to toggle between dvorak and us keyboard layout
2979 aoeu() {
2980     echo -n 'Switching to us keyboard layout: '
2981     [[ -z "$DISPLAY" ]] && $SUDO loadkeys us &>/dev/null || setxkbmap us &>/dev/null
2982     echo 'Done'
2983 }
2984 asdf() {
2985     echo -n 'Switching to dvorak keyboard layout: '
2986     [[ -z "$DISPLAY" ]] && $SUDO loadkeys dvorak &>/dev/null || setxkbmap dvorak &>/dev/null
2987     echo 'Done'
2988 }
2989 # just press 'asdf' key to toggle from neon layout to us keyboard layout
2990 uiae() {
2991     echo -n 'Switching to us keyboard layout: '
2992     setxkbmap us && echo 'Done' || echo 'Failed'
2993 }
2994
2995 # set up an ipv6 tunnel
2996 ipv6-tunnel() {
2997     emulate -L zsh
2998     case $1 in
2999         start)
3000             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
3001                 print 'ipv6 tunnel already set up, nothing to be done.'
3002                 print 'execute: "ifconfig sit1 down ; ifconfig sit0 down" to remove ipv6-tunnel.' ; return 1
3003             else
3004                 [[ -n "$PUBLIC_IP" ]] || \
3005                     local PUBLIC_IP=$(ifconfig $(route -n | awk '/^0\.0\.0\.0/{print $8; exit}') | \
3006                                       awk '/inet addr:/ {print $2}' | tr -d 'addr:')
3007
3008                 [[ -n "$PUBLIC_IP" ]] || { print 'No $PUBLIC_IP set and could not determine default one.' ; return 1 }
3009                 local IPV6ADDR=$(printf "2002:%02x%02x:%02x%02x:1::1" $(print ${PUBLIC_IP//./ }))
3010                 print -n "Setting up ipv6 tunnel $IPV6ADDR via ${PUBLIC_IP}: "
3011                 ifconfig sit0 tunnel ::192.88.99.1 up
3012                 ifconfig sit1 add "$IPV6ADDR" && print done || print failed
3013             fi
3014             ;;
3015         status)
3016             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
3017                 print 'ipv6 tunnel available' ; return 0
3018             else
3019                 print 'ipv6 tunnel not available' ; return 1
3020             fi
3021             ;;
3022         stop)
3023             if ifconfig sit1 2>/dev/null | grep -q 'inet6 addr: 2002:.*:1::1' ; then
3024                 print -n 'Stopping ipv6 tunnel (sit0 + sit1): '
3025                 ifconfig sit1 down ; ifconfig sit0 down && print done || print failed
3026             else
3027                 print 'No ipv6 tunnel found, nothing to be done.' ; return 1
3028             fi
3029             ;;
3030         *)
3031             print "Usage: ipv6-tunnel [start|stop|status]">&2 ; return 1
3032             ;;
3033     esac
3034 }
3035
3036 # run dhclient for wireless device
3037 iwclient() {
3038     sudo dhclient "$(wavemon -d | awk '/device/{print $3}')"
3039 }
3040
3041 # spawn a minimally set up mksh - useful if you want to umount /usr/.
3042 minimal-shell() {
3043     emulate -L zsh
3044     local shell="/bin/mksh"
3045
3046     if [[ ! -x ${shell} ]]; then
3047         printf '`%s'\'' not available, giving up.\n' ${shell} >&2
3048         return 1
3049     fi
3050
3051     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ${shell}
3052 }
3053
3054 # a wrapper for vim, that deals with title setting
3055 #   VIM_OPTIONS
3056 #       set this array to a set of options to vim you always want
3057 #       to have set when calling vim (in .zshrc.local), like:
3058 #           VIM_OPTIONS=( -p )
3059 #       This will cause vim to send every file given on the
3060 #       commandline to be send to it's own tab (needs vim7).
3061 vim() {
3062     VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
3063 }
3064
3065 # make a backup of a file
3066 bk() {
3067     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
3068 }
3069
3070 #f1# grep for patterns in grml's zsh setup
3071 zg() {
3072 #{{{
3073     LANG=C perl -e '
3074
3075 sub usage {
3076     print "usage: zg -[anr] <pattern>\n";
3077     print " Search for patterns in grml'\''s zshrc.\n";
3078     print " zg takes no or exactly one option plus a non empty pattern.\n\n";
3079     print "   options:\n";
3080     print "     --  no options (use if your pattern starts in with a dash.\n";
3081     print "     -a  search for the pattern in all code regions\n";
3082     print "     -n  search for the pattern in non-root code only\n";
3083     print "     -r  search in code for everyone (also root) only\n\n";
3084     print "   The default is -a for non-root users and -r for root.\n\n";
3085     print " If you installed the zshrc to a non-default locations (ie *NOT*\n";
3086     print " in /etc/zsh/zshrc) do: export GRML_ZSHRC=\$HOME/.zshrc\n";
3087     print " ...in case you copied the file to that location.\n\n";
3088     exit 1;
3089 }
3090
3091 if ($ENV{GRML_ZSHRC} ne "") {
3092     $RC = $ENV{GRML_ZSHRC};
3093 } else {
3094     $RC = "/etc/zsh/zshrc";
3095 }
3096
3097 usage if ($#ARGV < 0 || $#ARGV > 1);
3098 if ($> == 0) { $mode = "allonly"; }
3099 else { $mode = "all"; }
3100
3101 $opt = $ARGV[0];
3102 if ($opt eq "--")     { shift; }
3103 elsif ($opt eq "-a")  { $mode = "all"; shift; }
3104 elsif ($opt eq "-n")  { $mode = "nonroot"; shift; }
3105 elsif ($opt eq "-r" ) { $mode = "allonly"; shift; }
3106 elsif ($opt =~ m/^-/ || $#ARGV > 0) { usage(); }
3107
3108 $pattern = $ARGV[0];
3109 usage() if ($pattern eq "");
3110
3111 open FH, "<$RC" or die "zg: Could not open $RC: $!\n";
3112 while ($line = <FH>) {
3113     chomp $line;
3114     if ($line =~ m/^#:grep:marker:for:mika:/) { $markerfound = 1; next; }
3115     next if ($mode eq "nonroot" && markerfound == 0);
3116     break if ($mode eq "allonly" && markerfound == 1);
3117     print $line, "\n" if ($line =~ /$pattern/);
3118 }
3119 close FH;
3120 exit 0;
3121
3122     ' -- "$@"
3123 #}}}
3124     return $?
3125 }
3126
3127 ssl_hashes=( sha512 sha256 sha1 md5 )
3128
3129 for sh in ${ssl_hashes}; do
3130     eval 'ssl-cert-'${sh}'() {
3131         emulate -L zsh
3132         if [[ -z $1 ]] ; then
3133             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
3134             return 1
3135         fi
3136         openssl x509 -noout -fingerprint -'${sh}' -in $1
3137     }'
3138 done; unset sh
3139
3140 ssl-cert-fingerprints() {
3141     emulate -L zsh
3142     local i
3143     if [[ -z $1 ]] ; then
3144         printf 'usage: ssl-cert-fingerprints <file>\n'
3145         return 1
3146     fi
3147     for i in ${ssl_hashes}
3148         do ssl-cert-$i $1;
3149     done
3150 }
3151
3152 ssl-cert-info() {
3153     emulate -L zsh
3154     if [[ -z $1 ]] ; then
3155         printf 'usage: ssl-cert-info <file>\n'
3156         return 1
3157     fi
3158     openssl x509 -noout -text -in $1
3159     ssl-cert-fingerprints $1
3160 }
3161
3162 # }}}
3163
3164 # {{{ make sure our environment is clean regarding colors
3165 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
3166 # }}}
3167
3168 # "persistent history" {{{
3169 # just write important commands you always need to ~/.important_commands
3170 if [[ -r ~/.important_commands ]] ; then
3171     fc -R ~/.important_commands
3172 fi
3173 # }}}
3174
3175 # load the lookup subsystem if it's available on the system
3176 zrcautoload lookupinit && lookupinit
3177
3178 #:grep:marker:for:mika: :-)
3179 ### non-root (EUID != 0) code below
3180 ###
3181
3182 if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
3183     zrclocal
3184     return 0
3185 fi
3186
3187 # variables {{{
3188
3189 # set terminal property (used e.g. by msgid-chooser)
3190 export COLORTERM="yes"
3191
3192 # set default browser
3193 if [[ -z "$BROWSER" ]] ; then
3194     if [[ -n "$DISPLAY" ]] ; then
3195         #v# If X11 is running
3196         check_com -c firefox && export BROWSER=firefox
3197     else
3198         #v# If no X11 is running
3199         check_com -c w3m && export BROWSER=w3m
3200     fi
3201 fi
3202
3203 #m# v QTDIR \kbd{/usr/share/qt[34]}\quad [for non-root only]
3204 [[ -d /usr/share/qt3 ]] && export QTDIR=/usr/share/qt3
3205 [[ -d /usr/share/qt4 ]] && export QTDIR=/usr/share/qt4
3206
3207 # support running 'jikes *.java && jamvm HelloWorld' OOTB:
3208 #v# [for non-root only]
3209 [[ -f /usr/share/classpath/glibj.zip ]] && export JIKESPATH=/usr/share/classpath/glibj.zip
3210 # }}}
3211
3212 # aliases {{{
3213
3214 # Xterm resizing-fu.
3215 # Based on http://svn.kitenet.net/trunk/home-full/.zshrc?rev=11710&view=log (by Joey Hess)
3216 alias hide='echo -en "\033]50;nil2\007"'
3217 alias tiny='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-80-*-*-c-*-iso8859-15\007"'
3218 alias small='echo -en "\033]50;6x10\007"'
3219 alias medium='echo -en "\033]50;-misc-fixed-medium-r-normal--13-120-75-75-c-80-iso8859-15\007"'
3220 alias default='echo -e "\033]50;-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-15\007"'
3221 alias large='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-150-*-*-c-*-iso8859-15\007"'
3222 alias huge='echo -en "\033]50;-misc-fixed-medium-r-normal-*-*-210-*-*-c-*-iso8859-15\007"'
3223 alias smartfont='echo -en "\033]50;-artwiz-smoothansi-*-*-*-*-*-*-*-*-*-*-*-*\007"'
3224 alias semifont='echo -en "\033]50;-misc-fixed-medium-r-semicondensed-*-*-120-*-*-*-*-iso8859-15\007"'
3225
3226 # general
3227 #a2# Execute \kbd{du -sch}
3228 alias da='du -sch'
3229 #a2# Execute \kbd{jobs -l}
3230 alias j='jobs -l'
3231
3232 # compile stuff
3233 #a2# Execute \kbd{./configure}
3234 alias CO="./configure"
3235 #a2# Execute \kbd{./configure --help}
3236 alias CH="./configure --help"
3237
3238 # listing stuff
3239 #a2# Execute \kbd{ls -lSrah}
3240 alias dir="ls -lSrah"
3241 #a2# Only show dot-directories
3242 alias lad='ls -d .*(/)'                # only show dot-directories
3243 #a2# Only show dot-files
3244 alias lsa='ls -a .*(.)'                # only show dot-files
3245 #a2# Only files with setgid/setuid/sticky flag
3246 alias lss='ls -l *(s,S,t)'             # only files with setgid/setuid/sticky flag
3247 #a2# Only show 1st ten symlinks
3248 alias lsl='ls -l *(@)'                 # only symlinks
3249 #a2# Display only executables
3250 alias lsx='ls -l *(*)'                 # only executables
3251 #a2# Display world-{readable,writable,executable} files
3252 alias lsw='ls -ld *(R,W,X.^ND/)'       # world-{readable,writable,executable} files
3253 #a2# Display the ten biggest files
3254 alias lsbig="ls -flh *(.OL[1,10])"     # display the biggest files
3255 #a2# Only show directories
3256 alias lsd='ls -d *(/)'                 # only show directories
3257 #a2# Only show empty directories
3258 alias lse='ls -d *(/^F)'               # only show empty directories
3259 #a2# Display the ten newest files
3260 alias lsnew="ls -rtlh *(D.om[1,10])"   # display the newest files
3261 #a2# Display the ten oldest files
3262 alias lsold="ls -rtlh *(D.Om[1,10])"   # display the oldest files
3263 #a2# Display the ten smallest files
3264 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
3265
3266 # chmod
3267 #a2# Execute \kbd{chmod 600}
3268 alias rw-='chmod 600'
3269 #a2# Execute \kbd{chmod 700}
3270 alias rwx='chmod 700'
3271 #m# a2 r-{}- Execute \kbd{chmod 644}
3272 alias r--='chmod 644'
3273 #a2# Execute \kbd{chmod 755}
3274 alias r-x='chmod 755'
3275
3276 # some useful aliases
3277 #a2# Execute \kbd{mkdir -o}
3278 alias md='mkdir -p'
3279
3280 # console stuff
3281 #a2# Execute \kbd{mplayer -vo fbdev}
3282 alias cmplayer='mplayer -vo fbdev'
3283 #a2# Execute \kbd{mplayer -vo fbdev -fs -zoom}
3284 alias fbmplayer='mplayer -vo fbdev -fs -zoom'
3285 #a2# Execute \kbd{links2 -driver fb}
3286 alias fblinks='links2 -driver fb'
3287
3288 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
3289 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3290 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
3291
3292 # simple webserver
3293 check_com -c python && alias http="python -m SimpleHTTPServer"
3294
3295 # Use 'g' instead of 'git':
3296 check_com g || alias g='git'
3297
3298 # work around non utf8 capable software in utf environment via $LANG and luit
3299 if check_com isutfenv && check_com luit ; then
3300     if check_com -c mrxvt ; then
3301         isutfenv && [[ -n "$LANG" ]] && \
3302             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
3303     fi
3304
3305     if check_com -c aterm ; then
3306         isutfenv && [[ -n "$LANG" ]] && \
3307             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
3308     fi
3309
3310     if check_com -c centericq ; then
3311         isutfenv && [[ -n "$LANG" ]] && \
3312             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
3313     fi
3314 fi
3315 # }}}
3316
3317 # useful functions {{{
3318
3319 # searching
3320 #f4# Search for newspostings from authors
3321 agoogle() { ${=BROWSER} "http://groups.google.com/groups?as_uauthors=$*" ; }
3322 #f4# Search Debian Bug Tracking System
3323 debbug()  {
3324     emulate -L zsh
3325     setopt extendedglob
3326     if [[ $# -eq 1 ]]; then
3327         case "$1" in
3328             ([0-9]##)
3329             ${=BROWSER} "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=$1"
3330             ;;
3331             (*@*)
3332             ${=BROWSER} "http://bugs.debian.org/cgi-bin/pkgreport.cgi?submitter=$1"
3333             ;;
3334             (*)
3335             ${=BROWSER} "http://bugs.debian.org/$*"
3336             ;;
3337         esac
3338     else
3339         print "$0 needs one argument"
3340         return 1
3341     fi
3342 }
3343 #f4# Search Debian Bug Tracking System in mbox format
3344 debbugm() {
3345     emulate -L zsh
3346     bts show --mbox $1
3347 }
3348 #f4# Search DMOZ
3349 dmoz()    {
3350     emulate -L zsh
3351     ${=BROWSER} http://search.dmoz.org/cgi-bin/search\?search=${1// /_}
3352 }
3353 #f4# Search German   Wiktionary
3354 dwicti()  {
3355     emulate -L zsh
3356     ${=BROWSER} http://de.wiktionary.org/wiki/${(C)1// /_}
3357 }
3358 #f4# Search English  Wiktionary
3359 ewicti()  {
3360     emulate -L zsh
3361     ${=BROWSER} http://en.wiktionary.org/wiki/${(C)1// /_}
3362 }
3363 #f4# Search Google Groups
3364 ggogle()  {
3365     emulate -L zsh
3366     ${=BROWSER} "http://groups.google.com/groups?q=$*"
3367 }
3368 #f4# Search Google
3369 google()  {
3370     emulate -L zsh
3371     ${=BROWSER} "http://www.google.com/search?&num=100&q=$*"
3372 }
3373 #f4# Search Google Groups for MsgID
3374 mggogle() {
3375     emulate -L zsh
3376     ${=BROWSER} "http://groups.google.com/groups?selm=$*"
3377 }
3378 #f4# Search Netcraft
3379 netcraft(){
3380     emulate -L zsh
3381     ${=BROWSER} "http://toolbar.netcraft.com/site_report?url=$1"
3382 }
3383 #f4# Use German Wikipedia's full text search
3384 swiki()   {
3385     emulate -L zsh
3386     ${=BROWSER} http://de.wikipedia.org/wiki/Spezial:Search/${(C)1}
3387 }
3388 #f4# search \kbd{dict.leo.org}
3389 oleo()    {
3390     emulate -L zsh
3391     ${=BROWSER} "http://dict.leo.org/?search=$*"
3392 }
3393 #f4# Search German   Wikipedia
3394 wikide()  {
3395     emulate -L zsh
3396     ${=BROWSER} http://de.wikipedia.org/wiki/"${(C)*}"
3397 }
3398 #f4# Search English  Wikipedia
3399 wikien()  {
3400     emulate -L zsh
3401     ${=BROWSER} http://en.wikipedia.org/wiki/"${(C)*}"
3402 }
3403 #f4# Search official debs
3404 wodeb()   {
3405     emulate -L zsh
3406     ${=BROWSER} "http://packages.debian.org/search?keywords=$1&searchon=contents&suite=${2:=unstable}&section=all"
3407 }
3408
3409 #m# f4 gex() Exact search via Google
3410 check_com google && gex () {
3411     google "\"[ $1]\" $*"
3412 }
3413
3414 # misc
3415 #f5# Backup \kbd{file {\rm to} file\_timestamp}
3416 bk() {
3417     emulate -L zsh
3418     cp -b $1 $1_`date --iso-8601=m`
3419 }
3420 #f5# Copied diff
3421 cdiff() {
3422     emulate -L zsh
3423     diff -crd "$@" | egrep -v "^Only in |^Binary files "
3424 }
3425 #f5# cd to directoy and list files
3426 cl() {
3427     emulate -L zsh
3428     cd $1 && ls -a
3429 }
3430 #f5# Cvs add
3431 cvsa() {
3432     emulate -L zsh
3433     cvs add $* && cvs com -m 'initial checkin' $*
3434 }
3435 #f5# Cvs diff
3436 cvsd() {
3437     emulate -L zsh
3438     cvs diff -N $* |& $PAGER
3439 }
3440 #f5# Cvs log
3441 cvsl() {
3442     emulate -L zsh
3443     cvs log $* |& $PAGER
3444 }
3445 #f5# Cvs update
3446 cvsq() {
3447     emulate -L zsh
3448     cvs -nq update
3449 }
3450 #f5# Rcs2log
3451 cvsr() {
3452     emulate -L zsh
3453     rcs2log $* | $PAGER
3454 }
3455 #f5# Cvs status
3456 cvss() {
3457     emulate -L zsh
3458     cvs status -v $*
3459 }
3460 #f5# Disassemble source files using gcc and as
3461 disassemble(){
3462     emulate -L zsh
3463     gcc -pipe -S -o - -O -g $* | as -aldh -o /dev/null
3464 }
3465 #f5# Firefox remote control - open given URL
3466 fir() {
3467     if [ -e /etc/debian_version ]; then
3468         firefox -a iceweasel -remote "openURL($1)" || firefox ${1}&
3469     else
3470         firefox -a firefox -remote "openURL($1)" || firefox ${1}&
3471     fi
3472 }
3473 #f5# Create Directoy and \kbd{cd} to it
3474 mcd() {
3475     mkdir -p "$@" && cd "$@"
3476 }
3477 #f5# Unified diff to timestamped outputfile
3478 mdiff() {
3479     diff -udrP "$1" "$2" > diff.`date "+%Y-%m-%d"`."$1"
3480 }
3481 #f5# Memory overview
3482 memusage() {
3483     ps aux | awk '{if (NR > 1) print $5; if (NR > 2) print "+"} END { print "p" }' | dc
3484 }
3485 #f5# Show contents of gzipped tar file
3486 shtar() {
3487     emulate -L zsh
3488     gunzip -c $1 | tar -tf - -- | $PAGER
3489 }
3490 #f5# Show contents of zip file
3491 shzip() {
3492     emulate -L zsh
3493     unzip -l $1 | $PAGER
3494 }
3495 #f5# Unified diff
3496 udiff() {
3497     emulate -L zsh
3498     diff -urd $* | egrep -v "^Only in |^Binary files "
3499 }
3500 #f5# (Mis)use \kbd{vim} as \kbd{less}
3501 viless() {
3502     emulate -L zsh
3503     vim --cmd 'let no_plugin_maps = 1' -c "so \$VIMRUNTIME/macros/less.vim" "${@:--}"
3504 }
3505
3506 # Function Usage: uopen $URL/$file
3507 #f5# Download a file and display it locally
3508 uopen() {
3509     emulate -L zsh
3510     if ! [[ -n "$1" ]] ; then
3511         print "Usage: uopen \$URL/\$file">&2
3512         return 1
3513     else
3514         FILE=$1
3515         MIME=$(curl --head $FILE | grep Content-Type | cut -d ' ' -f 2 | cut -d\; -f 1)
3516         MIME=${MIME%$'\r'}
3517         curl $FILE | see ${MIME}:-
3518     fi
3519 }
3520
3521 # Function Usage: doc packagename
3522 #f5# \kbd{cd} to /usr/share/doc/\textit{package}
3523 doc() {
3524     emulate -L zsh
3525     cd /usr/share/doc/$1 && ls
3526 }
3527 _doc() { _files -W /usr/share/doc -/ }
3528 check_com compdef && compdef _doc doc
3529
3530 #f5# Make screenshot
3531 sshot() {
3532     [[ ! -d ~/shots  ]] && mkdir ~/shots
3533     #cd ~/shots ; sleep 5 ; import -window root -depth 8 -quality 80 `date "+%Y-%m-%d--%H:%M:%S"`.png
3534     cd ~/shots ; sleep 5; import -window root shot_`date --iso-8601=m`.jpg
3535 }
3536
3537 # list images only
3538 limg() {
3539     local -a images
3540     images=( *.{jpg,gif,png}(.N) )
3541
3542     if [[ $#images -eq 0 ]] ; then
3543         print "No image files found"
3544     else
3545         ls "$images[@]"
3546     fi
3547 }
3548
3549 #f5# Create PDF file from source code
3550 makereadable() {
3551     emulate -L zsh
3552     output=$1
3553     shift
3554     a2ps --medium A4dj -E -o $output $*
3555     ps2pdf $output
3556 }
3557
3558 # zsh with perl-regex - use it e.g. via:
3559 # regcheck '\s\d\.\d{3}\.\d{3} Euro' ' 1.000.000 Euro'
3560 #f5# Checks whether a regex matches or not.\\&\quad Example: \kbd{regcheck '.\{3\} EUR' '500 EUR'}
3561 regcheck() {
3562     emulate -L zsh
3563     zmodload -i zsh/pcre
3564     pcre_compile $1 && \
3565     pcre_match $2 && echo "regex matches" || echo "regex does not match"
3566 }
3567
3568 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
3569 accessed() {
3570     emulate -L zsh
3571     print -l -- *(a-${1:-1})
3572 }
3573
3574 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
3575 changed() {
3576     emulate -L zsh
3577     print -l -- *(c-${1:-1})
3578 }
3579
3580 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
3581 modified() {
3582     emulate -L zsh
3583     print -l -- *(m-${1:-1})
3584 }
3585 # modified() was named new() in earlier versions, add an alias for backwards compatibility
3586 check_com new || alias new=modified
3587
3588 #f5# Grep in history
3589 greph() {
3590     emulate -L zsh
3591     history 0 | grep $1
3592 }
3593 # use colors when GNU grep with color-support
3594 #a2# Execute \kbd{grep -{}-color=auto}
3595 (grep --help 2>/dev/null |grep -- --color) >/dev/null && alias grep='grep --color=auto'
3596 #a2# Execute \kbd{grep -i -{}-color=auto}
3597 alias GREP='grep -i --color=auto'
3598
3599 #f5# Watch manpages in a stretched style
3600 man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
3601
3602 # usage example: 'lcheck strcpy'
3603 #f5# Find out which libs define a symbol
3604 lcheck() {
3605     if [[ -n "$1" ]] ; then
3606         nm -go /usr/lib/lib*.a 2>/dev/null | grep ":[[:xdigit:]]\{8\} . .*$1"
3607     else
3608         echo "Usage: lcheck <function>" >&2
3609     fi
3610 }
3611
3612 #f5# Clean up directory - remove well known tempfiles
3613 purge() {
3614     emulate -L zsh
3615     setopt HIST_SUBST_PATTERN
3616     local -a TEXTEMPFILES GHCTEMPFILES PYTEMPFILES FILES
3617     TEXTEMPFILES=(*.tex(N:s/%tex/'(log|toc|aux|nav|snm|out|tex.backup|bbl|blg|bib.backup|vrb|lof|lot|hd|idx)(N)'/))
3618     GHCTEMPFILES=(*.(hs|lhs)(N:r:s/%/'.(hi|hc|(p|u|s)_(o|hi))(N)'/))
3619     PYTEMPFILES=(*.py(N:s/%py/'(pyc|pyo)(N)'/))
3620     LONELY_MOOD_FILES=((*.mood)(NDe:'local -a AF;AF=( ${${REPLY#.}%mood}(mp3|flac|ogg|asf|wmv|aac)(N) ); [[ -z "$AF" ]]':))
3621     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})
3622     local NBFILES=${#FILES}
3623     local CURDIRSUDO=""
3624     [[ ! -w ./ ]] && CURDIRSUDO=$SUDO
3625     if [[ $NBFILES > 0 ]] ; then
3626         print -l $FILES
3627         local ans
3628         echo -n "Remove these files? [y/n] "
3629         read -q ans
3630         if [[ $ans == "y" ]] ; then
3631             $CURDIRSUDO rm ${FILES}
3632             echo ">> $PWD purged, $NBFILES files removed"
3633         else
3634             echo "Ok. .. then not.."
3635         fi
3636     fi
3637 }
3638
3639 #f5# show labels and uuids of disk devices
3640 if is439 && [[ -d /dev/disk/by-id/ ]]; then
3641     lsdisk() {
3642         emulate -L zsh
3643         setopt extendedglob
3644         local -a -U disks
3645         disks=( /dev/disk/by-id/*(@:A) )
3646         for dev in "$disks[@]"; do
3647             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)
3648             print -f "  %s\n" /dev/disk/by-id/*(@e/'[[ ${REPLY:A} == $dev ]]'/N:t)
3649         done
3650     }
3651 fi
3652
3653 # Translate DE<=>EN
3654 # 'translate' looks up fot a word in a file with language-to-language
3655 # translations (field separator should be " : "). A typical wordlist looks
3656 # like at follows:
3657 #  | english-word : german-transmission
3658 # It's also only possible to translate english to german but not reciprocal.
3659 # Use the following oneliner to turn back the sort order:
3660 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
3661 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
3662 #f5# Translates a word
3663 trans() {
3664     emulate -L zsh
3665     case "$1" in
3666         -[dD]*)
3667             translate -l de-en $2
3668             ;;
3669         -[eE]*)
3670             translate -l en-de $2
3671             ;;
3672         *)
3673             echo "Usage: $0 { -D | -E }"
3674             echo "         -D == German to English"
3675             echo "         -E == English to German"
3676     esac
3677 }
3678
3679 #f5# List all occurrences of programm in current PATH
3680 plap() {
3681     emulate -L zsh
3682     if [[ $# = 0 ]] ; then
3683         echo "Usage:    $0 program"
3684         echo "Example:  $0 zsh"
3685         echo "Lists all occurrences of program in the current PATH."
3686     else
3687         ls -l ${^path}/*$1*(*N)
3688     fi
3689 }
3690
3691 # Found in the mailinglistarchive from Zsh (IIRC ~1996)
3692 #f5# Select items for specific command(s) from history
3693 selhist() {
3694     emulate -L zsh
3695     local TAB=$'\t';
3696     (( $# < 1 )) && {
3697         echo "Usage: $0 command"
3698         return 1
3699     };
3700     cmd=(${(f)"$(grep -w $1 $HISTFILE | sort | uniq | pr -tn)"})
3701     print -l $cmd | less -F
3702     echo -n "enter number of desired command [1 - $(( ${#cmd[@]} - 1 ))]: "
3703     local answer
3704     read answer
3705     print -z "${cmd[$answer]#*$TAB}"
3706 }
3707
3708 # Use vim to convert plaintext to HTML
3709 #f5# Transform files to html with highlighting
3710 2html() {
3711     emulate -L zsh
3712     vim -u NONE -n -c ':syntax on' -c ':so $VIMRUNTIME/syntax/2html.vim' -c ':wqa' $1 &>/dev/null
3713 }
3714
3715 # Usage: simple-extract <file>
3716 #f5# Smart archive extractor
3717 simple-extract () {
3718     emulate -L zsh
3719     if [[ -f $1 ]] ; then
3720         case $1 in
3721             *.tar.bz2)  bzip2 -v -d $1      ;;
3722             *.tar.gz)   tar -xvzf $1        ;;
3723             *.rar)      unrar $1            ;;
3724             *.deb)      ar -x $1            ;;
3725             *.bz2)      bzip2 -d $1         ;;
3726             *.lzh)      lha x $1            ;;
3727             *.gz)       gunzip -d $1        ;;
3728             *.tar)      tar -xvf $1         ;;
3729             *.tgz)      gunzip -d $1        ;;
3730             *.tbz2)     tar -jxvf $1        ;;
3731             *.zip)      unzip $1            ;;
3732             *.Z)        uncompress $1       ;;
3733             *)          echo "'$1' Error. Please go away" ;;
3734         esac
3735     else
3736         echo "'$1' is not a valid file"
3737     fi
3738 }
3739
3740 # Usage: smartcompress <file> (<type>)
3741 #f5# Smart archive creator
3742 smartcompress() {
3743     emulate -L zsh
3744     if [[ -n $2 ]] ; then
3745         case $2 in
3746             tgz | tar.gz)   tar -zcvf$1.$2 $1 ;;
3747             tbz2 | tar.bz2) tar -jcvf$1.$2 $1 ;;
3748             tar.Z)          tar -Zcvf$1.$2 $1 ;;
3749             tar)            tar -cvf$1.$2  $1 ;;
3750             gz | gzip)      gzip           $1 ;;
3751             bz2 | bzip2)    bzip2          $1 ;;
3752             *)
3753                 echo "Error: $2 is not a valid compression type"
3754                 ;;
3755         esac
3756     else
3757         smartcompress $1 tar.gz
3758     fi
3759 }
3760
3761 # Usage: show-archive <archive>
3762 #f5# List an archive's content
3763 show-archive() {
3764     emulate -L zsh
3765     if [[ -f $1 ]] ; then
3766         case $1 in
3767             *.tar.gz)      gunzip -c $1 | tar -tf - -- ;;
3768             *.tar)         tar -tf $1 ;;
3769             *.tgz)         tar -ztf $1 ;;
3770             *.zip)         unzip -l $1 ;;
3771             *.bz2)         bzless $1 ;;
3772             *.deb)         dpkg-deb --fsys-tarfile $1 | tar -tf - -- ;;
3773             *)             echo "'$1' Error. Please go away" ;;
3774         esac
3775     else
3776         echo "'$1' is not a valid archive"
3777     fi
3778 }
3779
3780 # It's shameless stolen from <http://www.vim.org/tips/tip.php?tip_id=167>
3781 #f5# Use \kbd{vim} as your manpage reader
3782 vman() {
3783     emulate -L zsh
3784     if (( ${#argv} == 0 )); then
3785         printf 'usage: vman <topic>\n'
3786         return 1
3787     fi
3788     man "$@" | col -b | view -c 'set ft=man nomod nolist' -
3789 }
3790
3791 # function readme() { $PAGER -- (#ia3)readme* }
3792 #f5# View all README-like files in current directory in pager
3793 readme() {
3794     emulate -L zsh
3795     local files
3796     files=(./(#i)*(read*me|lue*m(in|)ut)*(ND))
3797     if (($#files)) ; then
3798         $PAGER $files
3799     else
3800         print 'No README files.'
3801     fi
3802 }
3803
3804 # function ansi-colors()
3805 #f5# Display ANSI colors
3806 ansi-colors() {
3807     typeset esc="\033[" line1 line2
3808     echo " _ _ _40 _ _ _41_ _ _ _42 _ _ 43_ _ _ 44_ _ _45 _ _ _ 46_ _ _ 47_ _ _ 49_ _"
3809     for fore in 30 31 32 33 34 35 36 37; do
3810         line1="$fore "
3811         line2="   "
3812         for back in 40 41 42 43 44 45 46 47 49; do
3813             line1="${line1}${esc}${back};${fore}m Normal ${esc}0m"
3814             line2="${line2}${esc}${back};${fore};1m Bold   ${esc}0m"
3815         done
3816         echo -e "$line1\n$line2"
3817     done
3818 }
3819
3820 #f5# Find all files in \$PATH with setuid bit set
3821 suidfind() { ls -latg $path | grep '^...s' }
3822
3823 # TODO: So, this is the third incarnation of this function!?
3824 #f5# Reload given functions
3825 refunc() {
3826     for func in $argv ; do
3827         unfunction $func
3828         autoload $func
3829     done
3830 }
3831 compdef _functions refunc
3832
3833 # a small check to see which DIR is located on which server/partition.
3834 # stolen and modified from Sven's zshrc.forall
3835 #f5# Report diskusage of a directory
3836 dirspace() {
3837     emulate -L zsh
3838     if [[ -n "$1" ]] ; then
3839         for dir in "$@" ; do
3840             if [[ -d "$dir" ]] ; then
3841                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3842             else
3843                 echo "warning: $dir does not exist" >&2
3844             fi
3845         done
3846     else
3847         for dir in $path; do
3848             if [[ -d "$dir" ]] ; then
3849                 ( cd $dir; echo "-<$dir>"; du -shx .; echo);
3850             else
3851                 echo "warning: $dir does not exist" >&2
3852             fi
3853         done
3854     fi
3855 }
3856
3857 # % slow_print `cat /etc/passwd`
3858 #f5# Slowly print out parameters
3859 slow_print() {
3860     for argument in "$@" ; do
3861         for ((i = 1; i <= ${#1} ;i++)) ; do
3862             print -n "${argument[i]}"
3863             sleep 0.08
3864         done
3865         print -n " "
3866     done
3867     print ""
3868 }
3869
3870 #f5# Show some status info
3871 status() {
3872     print
3873     print "Date..: "$(date "+%Y-%m-%d %H:%M:%S")
3874     print "Shell.: Zsh $ZSH_VERSION (PID = $$, $SHLVL nests)"
3875     print "Term..: $TTY ($TERM), ${BAUD:+$BAUD bauds, }$COLUMNS x $LINES chars"
3876     print "Login.: $LOGNAME (UID = $EUID) on $HOST"
3877     print "System: $(cat /etc/[A-Za-z]*[_-][rv]e[lr]*)"
3878     print "Uptime:$(uptime)"
3879     print
3880 }
3881
3882 # Rip an audio CD
3883 #f5# Rip an audio CD
3884 audiorip() {
3885     mkdir -p ~/ripps
3886     cd ~/ripps
3887     cdrdao read-cd --device $DEVICE --driver generic-mmc audiocd.toc
3888     cdrdao read-cddb --device $DEVICE --driver generic-mmc audiocd.toc
3889     echo " * Would you like to burn the cd now? (yes/no)"
3890     read input
3891     if [[ "$input" = "yes" ]] ; then
3892         echo " ! Burning Audio CD"
3893         audioburn
3894         echo " * done."
3895     else
3896         echo " ! Invalid response."
3897     fi
3898 }
3899
3900 # and burn it
3901 #f5# Burn an audio CD (in combination with audiorip)
3902 audioburn() {
3903     cd ~/ripps
3904     cdrdao write --device $DEVICE --driver generic-mmc audiocd.toc
3905     echo " * Should I remove the temporary files? (yes/no)"
3906     read input
3907     if [[ "$input" = "yes" ]] ; then
3908         echo " ! Removing Temporary Files."
3909         cd ~
3910         rm -rf ~/ripps
3911         echo " * done."
3912     else
3913         echo " ! Invalid response."
3914     fi
3915 }
3916
3917 #f5# Make an audio CD from all mp3 files
3918 mkaudiocd() {
3919     # TODO: do the renaming more zshish, possibly with zmv()
3920     emulate -L zsh
3921     cd ~/ripps
3922     for i in *.[Mm][Pp]3; do mv "$i" `echo $i | tr '[A-Z]' '[a-z]'`; done
3923     for i in *.mp3; do mv "$i" `echo $i | tr ' ' '_'`; done
3924     for i in *.mp3; do mpg123 -w `basename $i .mp3`.wav $i; done
3925     normalize -m *.wav
3926     for i in *.wav; do sox $i.wav -r 44100 $i.wav resample; done
3927 }
3928
3929 #f5# Create an ISO image. You are prompted for\\&\quad volume name, filename and directory
3930 mkiso() {
3931     emulate -L zsh
3932     echo " * Volume name "
3933     read volume
3934     echo " * ISO Name (ie. tmp.iso)"
3935     read iso
3936     echo " * Directory or File"
3937     read files
3938     mkisofs -o ~/$iso -A $volume -allow-multidot -J -R -iso-level 3 -V $volume -R $files
3939 }
3940
3941 #f5# Simple thumbnails generator
3942 genthumbs() {
3943     rm -rf thumb-* index.html
3944     echo "
3945 <html>
3946   <head>
3947     <title>Images</title>
3948   </head>
3949   <body>" > index.html
3950     for f in *.(gif|jpeg|jpg|png) ; do
3951         convert -size 100x200 "$f" -resize 100x200 thumb-"$f"
3952         echo "    <a href=\"$f\"><img src=\"thumb-$f\"></a>" >> index.html
3953     done
3954     echo "
3955   </body>
3956 </html>" >> index.html
3957 }
3958
3959 #f5# Set all ulimit parameters to \kbd{unlimited}
3960 allulimit() {
3961     ulimit -c unlimited
3962     ulimit -d unlimited
3963     ulimit -f unlimited
3964     ulimit -l unlimited
3965     ulimit -n unlimited
3966     ulimit -s unlimited
3967     ulimit -t unlimited
3968 }
3969
3970 # 2mp3 transcodes flac and ogg to mp3 with bitrate of 192 while preserving basic tags
3971 if check_com lame; then
3972     2mp3_192() {
3973         emulate -L zsh
3974         setopt extendedglob
3975         unsetopt ksharrays
3976
3977         local -a DECODE id3tags
3978         local -A tagmap
3979         local tagdata
3980         local RC=0
3981         tagmap=("(#l)title" --tt "(#l)artist" --ta "(#l)tracknumber" --tn "(#l)genre" --tg "(#l)album" --tl)
3982
3983         if [[ ${@[(i)*.ogg]} -le ${#@} ]] && ! check_com oggdec; then
3984             echo "ERROR: please install oggdec" >&2
3985             return 1
3986         fi
3987         if [[ ${@[(i)*.flac]} -le ${#@} ]] && ! check_com flac; then
3988             echo "ERROR: please install flac" >&2
3989             return 1
3990         fi
3991
3992         for af in "$@"; do
3993             id3tags=()
3994             case "$af" in
3995                 (*.flac)
3996                     DECODE=(flac -d -c "$af")
3997                     tagdata="$(metaflac --export-tags-to=- "$af")"
3998                     ;;
3999                 (*.ogg)
4000                     DECODE=(oggdec -Q -o - "$af")
4001                     tagdata="$(ogginfo "$af")"
4002                     ;;
4003                 (*) continue ;;
4004             esac
4005             for line (${(f)tagdata}) \
4006                 [[ "$line" == (#s)[[:space:]]#(#b)([^=]##)=(*)(#e) && -n $tagmap[(k)$match[1]] ]] && \
4007                 id3tags+=($tagmap[(k)$match[1]] "$match[2]")
4008             [[ ${#id3tags} -gt 0 ]] && id3tags=(--add-id3v2 --ignore-tag-errors $id3tags)
4009             $DECODE[*] | lame -b 192 -v -h --replaygain-fast  "${id3tags[@]}" - "${af:r}.mp3" || {RC=$?; print "Error transcoding" "${af}"; }
4010         done
4011         # return 0 if no error or exit code if at least one error happened
4012         return $RC
4013     }
4014     alias ogg2mp3_192 2mp3_192
4015 fi
4016
4017 #f5# RFC 2396 URL encoding in Z-Shell
4018 urlencode() {
4019     emulate -L zsh
4020     setopt extendedglob
4021     input=( ${(s::)1} )
4022     print ${(j::)input/(#b)([^A-Za-z0-9_.!~*\'\(\)-])/%${(l:2::0:)$(([##16]#match))}}
4023 }
4024
4025 # http://strcat.de/blog/index.php?/archives/335-Software-sauber-deinstallieren...html
4026 #f5# Log 'make install' output
4027 mmake() {
4028     emulate -L zsh
4029     [[ ! -d ~/.errorlogs ]] && mkdir ~/.errorlogs
4030     make -n install > ~/.errorlogs/${PWD##*/}-makelog
4031 }
4032
4033 #f5# Indent source code
4034 smart-indent() {
4035     indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
4036 }
4037
4038 # highlight important stuff in diff output, usage example: hg diff | hidiff
4039 #m# a2 hidiff \kbd{histring} oneliner for diffs
4040 check_com -c histring && \
4041     alias hidiff="histring -fE '^Comparing files .*|^diff .*' | histring -c yellow -fE '^\-.*' | histring -c green -fE '^\+.*'"
4042
4043 # rename pictures based on information found in exif headers
4044 #f5# Rename pictures based on information found in exif headers
4045 exirename() {
4046     emulate -L zsh
4047     if [[ $# -lt 1 ]] ; then
4048         echo 'Usage: jpgrename $FILES' >& 2
4049         return 1
4050     else
4051         echo -n 'Checking for jhead with version newer than 1.9: '
4052         jhead_version=`jhead -h | grep 'used by most Digital Cameras.  v.*' | awk '{print $6}' | tr -d v`
4053         if [[ $jhead_version > '1.9' ]]; then
4054             echo 'success - now running jhead.'
4055             jhead -n%Y-%m-%d_%Hh%M_%f $*
4056         else
4057             echo 'failed - exiting.'
4058         fi
4059     fi
4060 }
4061
4062 # get_ic() - queries imap servers for capabilities; real simple. no imaps
4063 ic_get() {
4064     emulate -L zsh
4065     local port
4066     if [[ ! -z $1 ]] ; then
4067         port=${2:-143}
4068         print "querying imap server on $1:${port}...\n";
4069         print "a1 capability\na2 logout\n" | nc $1 ${port}
4070     else
4071         print "usage:\n  $0 <imap-server> [port]"
4072     fi
4073 }
4074
4075 # creates a Maildir/ with its {new,cur,tmp} subdirs
4076 mkmaildir() {
4077     emulate -L zsh
4078     local root subdir
4079     root=${MAILDIR_ROOT:-${HOME}/Mail}
4080     if [[ -z ${1} ]] ; then print "Usage:\n $0 <dirname>" ; return 1 ; fi
4081     subdir=${1}
4082     mkdir -p ${root}/${subdir}/{cur,new,tmp}
4083 }
4084
4085 #f5# Change the xterm title from within GNU-screen
4086 xtrename() {
4087     emulate -L zsh
4088     if [[ $1 != "-f" ]] ; then
4089         if [[ -z ${DISPLAY} ]] ; then
4090             printf 'xtrename only makes sense in X11.\n'
4091             return 1
4092         fi
4093     else
4094         shift
4095     fi
4096     if [[ -z $1 ]] ; then
4097         printf 'usage: xtrename [-f] "title for xterm"\n'
4098         printf '  renames the title of xterm from _within_ screen.\n'
4099         printf '  also works without screen.\n'
4100         printf '  will not work if DISPLAY is unset, use -f to override.\n'
4101         return 0
4102     fi
4103     print -n "\eP\e]0;${1}\C-G\e\\"
4104     return 0
4105 }
4106
4107 # hl() highlighted less
4108 # http://ft.bewatermyfriend.org/comp/data/zsh/zfunct.html
4109 if check_com -c highlight ; then
4110     function hl() {
4111     emulate -L zsh
4112         local theme lang
4113         theme=${HL_THEME:-""}
4114         case ${1} in
4115             (-l|--list)
4116                 ( printf 'available languages (syntax parameter):\n\n' ;
4117                     highlight --list-langs ; ) | less -SMr
4118                 ;;
4119             (-t|--themes)
4120                 ( printf 'available themes (style parameter):\n\n' ;
4121                     highlight --list-themes ; ) | less -SMr
4122                 ;;
4123             (-h|--help)
4124                 printf 'usage: hl <syntax[:theme]> <file>\n'
4125                 printf '    available options: --list (-l), --themes (-t), --help (-h)\n\n'
4126                 printf '  Example: hl c main.c\n'
4127                 ;;
4128             (*)
4129                 if [[ -z ${2} ]] || (( ${#argv} > 2 )) ; then
4130                     printf 'usage: hl <syntax[:theme]> <file>\n'
4131                     printf '    available options: --list (-l), --themes (-t), --help (-h)\n'
4132                     (( ${#argv} > 2 )) && printf '  Too many arguments.\n'
4133                     return 1
4134                 fi
4135                 lang=${1%:*}
4136                 [[ ${1} == *:* ]] && [[ -n ${1#*:} ]] && theme=${1#*:}
4137                 if [[ -n ${theme} ]] ; then
4138                     highlight --xterm256 --syntax ${lang} --style ${theme} ${2} | less -SMr
4139                 else
4140                     highlight --ansi --syntax ${lang} ${2} | less -SMr
4141                 fi
4142                 ;;
4143         esac
4144         return 0
4145     }
4146     # ... and a proper completion for hl()
4147     # needs 'highlight' as well, so it fits fine in here.
4148     function _hl_genarg()  {
4149         local expl
4150         if [[ -prefix 1 *: ]] ; then
4151             local themes
4152             themes=(${${${(f)"$(LC_ALL=C highlight --list-themes)"}/ #/}:#*(Installed|Use name)*})
4153             compset -P 1 '*:'
4154             _wanted -C list themes expl theme compadd ${themes}
4155         else
4156             local langs
4157             langs=(${${${(f)"$(LC_ALL=C highlight --list-langs)"}/ #/}:#*(Installed|Use name)*})
4158             _wanted -C list languages expl languages compadd -S ':' -q ${langs}
4159         fi
4160     }
4161     function _hl_complete() {
4162         _arguments -s '1: :_hl_genarg' '2:files:_path_files'
4163     }
4164     compdef _hl_complete hl
4165 fi
4166
4167 # TODO:
4168 # Rewrite this by either using tinyurl.com's API
4169 # or using another shortening service to comply with
4170 # tinyurl.com's policy.
4171 #
4172 # Create small urls via http://tinyurl.com using wget(1).
4173 #function zurl() {
4174 #    emulate -L zsh
4175 #    [[ -z $1 ]] && { print "USAGE: zurl <URL>" ; return 1 }
4176 #
4177 #    local PN url tiny grabber search result preview
4178 #    PN=$0
4179 #    url=$1
4180 ##   Check existence of given URL with the help of ping(1).
4181 ##   N.B. ping(1) only works without an eventual given protocol.
4182 #    ping -c 1 ${${url#(ftp|http)://}%%/*} >& /dev/null || \
4183 #        read -q "?Given host ${${url#http://*/}%/*} is not reachable by pinging. Proceed anyway? [y|n] "
4184 #
4185 #    if (( $? == 0 )) ; then
4186 ##           Prepend 'http://' to given URL where necessary for later output.
4187 #            [[ ${url} != http(s|)://* ]] && url='http://'${url}
4188 #            tiny='http://tinyurl.com/create.php?url='
4189 #            if check_com -c wget ; then
4190 #                grabber='wget -O- -o/dev/null'
4191 #            else
4192 #                print "wget is not available, but mandatory for ${PN}. Aborting."
4193 #            fi
4194 ##           Looking for i.e.`copy('http://tinyurl.com/7efkze')' in TinyURL's HTML code.
4195 #            search='copy\(?http://tinyurl.com/[[:alnum:]]##*'
4196 #            result=${(M)${${${(f)"$(${=grabber} ${tiny}${url})"}[(fr)${search}*]}//[()\';]/}%%http:*}
4197 ##           TinyURL provides the rather new feature preview for more confidence. <http://tinyurl.com/preview.php>
4198 #            preview='http://preview.'${result#http://}
4199 #
4200 #            printf '%s\n\n' "${PN} - Shrinking long URLs via webservice TinyURL <http://tinyurl.com>."
4201 #            printf '%s\t%s\n\n' 'Given URL:' ${url}
4202 #            printf '%s\t%s\n\t\t%s\n' 'TinyURL:' ${result} ${preview}
4203 #    else
4204 #        return 1
4205 #    fi
4206 #}
4207
4208 #f2# Print a specific line of file(s).
4209 linenr () {
4210 # {{{
4211     emulate -L zsh
4212     if [ $# -lt 2 ] ; then
4213        print "Usage: linenr <number>[,<number>] <file>" ; return 1
4214     elif [ $# -eq 2 ] ; then
4215          local number=$1
4216          local file=$2
4217          command ed -s $file <<< "${number}n"
4218     else
4219          local number=$1
4220          shift
4221          for file in "$@" ; do
4222              if [ ! -d $file ] ; then
4223                 echo "${file}:"
4224                 command ed -s $file <<< "${number}n" 2> /dev/null
4225              else
4226                 continue
4227              fi
4228          done | less
4229     fi
4230 # }}}
4231 }
4232
4233 #f2# Find history events by search pattern and list them by date.
4234 whatwhen()  {
4235 # {{{
4236     emulate -L zsh
4237     local usage help ident format_l format_s first_char remain first last
4238     usage='USAGE: whatwhen [options] <searchstring> <search range>'
4239     help='Use `whatwhen -h'\'' for further explanations.'
4240     ident=${(l,${#${:-Usage: }},, ,)}
4241     format_l="${ident}%s\t\t\t%s\n"
4242     format_s="${format_l//(\\t)##/\\t}"
4243     # Make the first char of the word to search for case
4244     # insensitive; e.g. [aA]
4245     first_char=[${(L)1[1]}${(U)1[1]}]
4246     remain=${1[2,-1]}
4247     # Default search range is `-100'.
4248     first=${2:-\-100}
4249     # Optional, just used for `<first> <last>' given.
4250     last=$3
4251     case $1 in
4252         ("")
4253             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
4254             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4255         ;;
4256         (-h)
4257             printf '%s\n\n' ${usage}
4258             print 'OPTIONS:'
4259             printf $format_l '-h' 'show help text'
4260             print '\f'
4261             print 'SEARCH RANGE:'
4262             printf $format_l "'0'" 'the whole history,'
4263             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
4264             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
4265             printf '\n%s\n' 'EXAMPLES:'
4266             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
4267             printf $format_l 'whatwhen zsh -250'
4268             printf $format_l 'whatwhen foo 1 99'
4269         ;;
4270         (\?)
4271             printf '%s\n%s\n\n' ${usage} ${help} && return 1
4272         ;;
4273         (*)
4274             # -l list results on stout rather than invoking $EDITOR.
4275             # -i Print dates as in YYYY-MM-DD.
4276             # -m Search for a - quoted - pattern within the history.
4277             fc -li -m "*${first_char}${remain}*" $first $last
4278         ;;
4279     esac
4280 # }}}
4281 }
4282
4283 # change fluxbox keys from 'Alt-#' to 'Alt-F#' and vice versa
4284 fluxkey-change() {
4285     emulate -L zsh
4286     [[ -n "$FLUXKEYS" ]] || local FLUXKEYS="$HOME/.fluxbox/keys"
4287     if ! [[ -r "$FLUXKEYS" ]] ; then
4288         echo "Sorry, \$FLUXKEYS file $FLUXKEYS could not be read - nothing to be done."
4289         return 1
4290     else
4291         if grep -q 'Mod1 F[0-9] :Workspace [0-9]' $FLUXKEYS ; then
4292             echo -n 'Switching to Alt-# mode in ~/.fluxbox/keys: '
4293             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)F\([0-9]\+[: space :]\+:Workspace.*\)|\1\2|' $FLUXKEYS && echo done || echo failed
4294         elif grep -q 'Mod1 [0-9] :Workspace [0-9]' $FLUXKEYS ; then
4295             echo -n 'Switching to Alt-F# mode in ~/.fluxbox/keys: '
4296             sed -i -e 's|^\(Mod[0-9]\+[: space :]\+\)\([0-9]\+[: space :]\+:Workspace.*\)|\1F\2|' $FLUXKEYS && echo done || echo failed
4297         else
4298             echo 'Sorry, do not know what to do.'
4299             return 1
4300         fi
4301     fi
4302 }
4303
4304 # retrieve weather information on the console
4305 # Usage example: 'weather LOWG'
4306 weather() {
4307     emulate -L zsh
4308     [[ -n "$1" ]] || {
4309         print 'Usage: weather <station_id>' >&2
4310         print 'List of stations: http://en.wikipedia.org/wiki/List_of_airports_by_ICAO_code'>&2
4311         return 1
4312     }
4313
4314     local VERBOSE="yes"    # TODO: Make this a command line switch
4315
4316     local ODIR=`pwd`
4317     local PLACE="${1:u}"
4318     local DIR="${HOME}/.weather"
4319     local LOG="${DIR}/log"
4320
4321     [[ -d ${DIR} ]] || {
4322         print -n "Creating ${DIR}: "
4323         mkdir ${DIR}
4324         print 'done'
4325     }
4326
4327     print "Retrieving information for ${PLACE}:"
4328     print
4329     cd ${DIR} && wget -T 10 --no-verbose --output-file=$LOG --timestamping http://weather.noaa.gov/pub/data/observations/metar/decoded/$PLACE.TXT
4330
4331     if [[ $? -eq 0 ]] ; then
4332         if [[ -n "$VERBOSE" ]] ; then
4333             cat ${PLACE}.TXT
4334         else
4335             DATE=$(grep 'UTC' ${PLACE}.TXT | sed 's#.* /##')
4336             TEMPERATURE=$(awk '/Temperature/ { print $4" degree Celcius / " $2" degree Fahrenheit" }' ${PLACE}.TXT | tr -d '(')
4337             echo "date: $DATE"
4338             echo "temp:  $TEMPERATURE"
4339         fi
4340     else
4341         print "There was an error retrieving the weather information for $PLACE" >&2
4342         cat $LOG
4343         cd $ODIR
4344         return 1
4345     fi
4346     cd $ODIR
4347 }
4348 # }}}
4349
4350 # mercurial related stuff {{{
4351 if check_com -c hg ; then
4352     # gnu like diff for mercurial
4353     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
4354     #f5# GNU like diff for mercurial
4355     hgdi() {
4356         emulate -L zsh
4357         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
4358     }
4359
4360     # build debian package
4361     #a2# Alias for \kbd{hg-buildpackage}
4362     alias hbp='hg-buildpackage'
4363
4364     # execute commands on the versioned patch-queue from the current repos
4365     alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
4366
4367     # diffstat for specific version of a mercurial repository
4368     #   hgstat      => display diffstat between last revision and tip
4369     #   hgstat 1234 => display diffstat between revision 1234 and tip
4370     #f5# Diffstat for specific version of a mercurial repos
4371     hgstat() {
4372         emulate -L zsh
4373         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
4374     }
4375
4376 fi # end of check whether we have the 'hg'-executable
4377
4378 # }}}
4379
4380 # some useful commands often hard to remember - let's grep for them {{{
4381 # actually use our zg() function now. :)
4382
4383 # Work around ion/xterm resize bug.
4384 #if [[ "$SHLVL" -eq 1 ]]; then
4385 #       if check_com -c resize ; then
4386 #               eval `resize </dev/null`
4387 #       fi
4388 #fi
4389
4390 # enable jackd:
4391 #  /usr/bin/jackd -dalsa -dhw:0 -r48000 -p1024 -n2
4392 # now play audio file:
4393 #  alsaplayer -o jack foobar.mp3
4394
4395 # send files via netcat
4396 # on sending side:
4397 #  send() {j=$*; tar cpz ${j/%${!#}/}|nc -w 1 ${!#} 51330;}
4398 #  send dir* $HOST
4399 #  alias receive='nc -vlp 51330 | tar xzvp'
4400
4401 # debian stuff:
4402 # dh_make -e foo@localhost -f $1
4403 # dpkg-buildpackage -rfakeroot
4404 # lintian *.deb
4405 # dpkg-scanpackages ./ /dev/null | gzip > Packages.gz
4406 # dpkg-scansources . | gzip > Sources.gz
4407 # grep-dctrl --field Maintainer $* /var/lib/apt/lists/*
4408
4409 # other stuff:
4410 # convert -geometry 200x200 -interlace LINE -verbose
4411 # ldapsearch -x -b "OU=Bedienstete,O=tug" -h ldap.tugraz.at sn=$1
4412 # ps -ao user,pcpu,start,command
4413 # gpg --keyserver blackhole.pca.dfn.de --recv-keys
4414 # xterm -bg black -fg yellow -fn -misc-fixed-medium-r-normal--14-140-75-75-c-90-iso8859-15 -ah
4415 # nc -vz $1 1-1024   # portscan via netcat
4416 # wget --mirror --no-parent --convert-links
4417 # pal -d `date +%d`
4418 # autoload -U tetris; zle -N tetris; bindkey '...' ; echo "press ... for playing tennis"
4419 #
4420 # modify console cursor
4421 # see http://www.tldp.org/HOWTO/Framebuffer-HOWTO-5.html
4422 # print $'\e[?96;0;64c'
4423 # }}}
4424
4425 # grml-small cleanups {{{
4426
4427 # The following is used to remove zsh-config-items that do not work
4428 # in grml-small by default.
4429 # If you do not want these adjustments (for whatever reason), set
4430 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
4431 # sources if it is there).
4432
4433 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
4434
4435     unset abk[V]
4436     unalias    'V'      &> /dev/null
4437     unfunction vman     &> /dev/null
4438     unfunction viless   &> /dev/null
4439     unfunction 2html    &> /dev/null
4440
4441     # manpages are not in grmlsmall
4442     unfunction manzsh   &> /dev/null
4443     unfunction man2     &> /dev/null
4444
4445 fi
4446
4447 #}}}
4448
4449 zrclocal
4450
4451 ## genrefcard.pl settings {{{
4452
4453 ### doc strings for external functions from files
4454 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
4455
4456 ### example: split functions-search 8,16,24,32
4457 #@# split functions-search 8
4458
4459 ## }}}
4460
4461 ## END OF FILE #################################################################
4462 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
4463 # Local variables:
4464 # mode: sh
4465 # End: