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