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