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