zshrc: make sure simple-extract() returns according return code when download of...
[grml-etc-core.git] / etc / zsh / zshrc
index ad5357c..b56cd09 100644 (file)
 # Global Order: zshenv, zprofile, zshrc, zlogin
 ################################################################################
 
+# USAGE
+# If you are using this file as your ~/.zshrc file, please use ~/.zshrc.pre
+# and ~/.zshrc.local for your own customisations. The former file is read
+# before ~/.zshrc, the latter is read after it. Also, consider reading the
+# refcard and the reference manual for this setup, both available from:
+#     <http://grml.org/zsh/>
+
 # Contributing:
 # If you want to help to improve grml's zsh setup, clone the grml-etc-core
 # repository from git.grml.org:
@@ -249,13 +256,6 @@ zrcautoload is-at-least || is-at-least() { return 1 }
 # }}}
 
 # {{{ set some important options (as early as possible)
-# Please update these tags, if you change the umask settings below.
-#o# r_umask     002
-#o# r_umaskstr  rwxrwxr-x
-#o# umask       022
-#o# umaskstr    rwxr-xr-x
-(( EUID != 0 )) && umask 002 || umask 022
-
 setopt append_history       # append history list to the history file (important for multiple parallel zsh sessions!)
 is4 && setopt SHARE_HISTORY # import new commands from the history file also in other zsh-session
 setopt extended_history     # save each command's beginning timestamp and the duration to the history file
@@ -410,14 +410,13 @@ fi
 
 # Check if we can read given files and source those we can.
 xsource() {
-    emulate -L zsh
     if (( ${#argv} < 1 )) ; then
         printf 'usage: xsource FILE(s)...\n' >&2
         return 1
     fi
 
     while (( ${#argv} > 0 )) ; do
-        [[ -r $1 ]] && source $1
+        [[ -r "$1" ]] && source "$1"
         shift
     done
     return 0
@@ -506,7 +505,7 @@ fi
 isdarwin && xsource /sw/bin/init.sh
 
 # load our function and completion directories
-for fdir in /usr/share/grml/zsh/completion /usr/share/grml/functions; do
+for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
     if [[ ${fpath} == '/usr/share/grml/zsh/functions' ]] ; then
         for func in ${fdir}/**/[^_]*[^~](N.) ; do
@@ -564,20 +563,67 @@ bindkey -e
 # use vi style:
 # bindkey -v
 
+## beginning-of-line OR beginning-of-buffer OR beginning of history
+## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
+beginning-or-end-of-somewhere() {
+    local hno=$HISTNO
+    if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
+      ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
+        zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
+    else
+        zle .${WIDGET:s/somewhere/line-hist/} "$@"
+        if (( HISTNO != hno )); then
+            zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
+        fi
+    fi
+}
+zle -N beginning-of-somewhere beginning-or-end-of-somewhere
+zle -N end-of-somewhere beginning-or-end-of-somewhere
+
+
 #if [[ "$TERM" == screen ]] ; then
-bindkey '\e[1~' beginning-of-line       # home
-bindkey '\e[4~' end-of-line             # end
+
+## with HOME/END, move to beginning/end of line (on multiline) on first keypress
+## to beginning/end of buffer on second keypress
+## and to beginning/end of history on (at most) the third keypress
+# terminator & non-debian xterm
+bindkey '\eOH' beginning-of-somewhere  # home
+bindkey '\eOF' end-of-somewhere        # end
+# freebsd console
+bindkey '\e[H' beginning-of-somewhere   # home
+bindkey '\e[F' end-of-somewhere         # end
+# xterm,gnome-terminal,quake,etc
+bindkey '^[[1~' beginning-of-somewhere  # home
+bindkey '^[[4~' end-of-somewhere        # end
+# if terminal type is set to 'rxvt':
+bindkey '\e[7~' beginning-of-somewhere  # home
+bindkey '\e[8~' end-of-somewhere        # end
+#fi
+
 bindkey '\e[A'  up-line-or-search       # cursor up
 bindkey '\e[B'  down-line-or-search     # <ESC>-
 
+## alt-backspace is already the default for backwards-delete-word
+## let's also set alt-delete for deleting current word (right of cursor)
+#k# Delete current word
+bindkey "3~" delete-word
+
+## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on the CL
+bindkey "\e[5C" forward-word
+bindkey "\e[5D" backward-word
+bindkey "\e[1;5C" forward-word
+bindkey "\e[1;5D" backward-word
+## the same for alt-left-arrow and alt-right-arrow
+bindkey '^[[1;3C' forward-word
+bindkey '^[[1;3D' backward-word
+
 bindkey '^xp'   history-beginning-search-backward
 bindkey '^xP'   history-beginning-search-forward
+bindkey "\e[5~" history-beginning-search-backward #PageUp
+bindkey "\e[6~" history-beginning-search-forward  #PageDown
 # bindkey -s '^L' "|less\n"             # ctrl-L pipes to less
 # bindkey -s '^B' " &\n"                # ctrl-B runs it in the background
-# if terminal type is set to 'rxvt':
-bindkey '\e[7~' beginning-of-line       # home
-bindkey '\e[8~' end-of-line             # end
-#fi
+
 
 # insert unicode character
 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an ยง
@@ -629,6 +675,10 @@ zle -N slash-backward-kill-word
 
 #k# Kill everything in a word up to its last \kbd{/}
 bindkey '\ev' slash-backward-kill-word
+#k# Kill everything in a word up to its last \kbd{/}
+bindkey '\e^h' slash-backward-kill-word
+#k# Kill everything in a word up to its last \kbd{/}
+bindkey '\e^?' slash-backward-kill-word
 
 # use the new *-pattern-* widgets for incremental history search
 if is439 ; then
@@ -890,6 +940,9 @@ fi
 if is4 && [[ -n ${(k)modules[zsh/complist]} ]] ; then
     #k# menu selection: pick item but stay in the menu
     bindkey -M menuselect '\e^M' accept-and-menu-complete
+    # also use + and INSERT since it's easier to press repeatedly
+    bindkey -M menuselect "+" accept-and-menu-complete
+    bindkey -M menuselect "^[[2~" accept-and-menu-complete
 
     # accept a completion and try to complete again by using menu
     # completion; very useful with completing directories
@@ -928,7 +981,10 @@ bindkey '^z' grml-zsh-fg
 # run command line as user root via sudo:
 sudo-command-line() {
     [[ -z $BUFFER ]] && zle up-history
-    [[ $BUFFER != sudo\ * ]] && BUFFER="sudo $BUFFER"
+    if [[ $BUFFER != sudo\ * ]]; then
+        BUFFER="sudo $BUFFER"
+        CURSOR=$(( CURSOR+5 ))
+    fi
 }
 zle -N sudo-command-line
 
@@ -951,6 +1007,33 @@ zle -N jump_after_first_word
 
 bindkey '^x1' jump_after_first_word
 
+# complete word from history with menu (from Book: ZSH, OpenSource-Press)
+zle -C hist-complete complete-word _generic
+zstyle ':completion:hist-complete:*' completer _history
+#k# complete word from history with menu
+bindkey "^X^X" hist-complete
+
+## complete word from currently visible SCREEN buffer.
+if check_com -c screen ; then
+    _complete_screen_display() {
+        [[ "$TERM" != "screen" ]] && return 1
+
+        local TMPFILE=$(mktemp)
+        local -U -a _screen_display_wordlist
+        trap "rm -f $TMPFILE" EXIT
+
+        screen -X hardcopy $TMPFILE
+        # fill array with contents from screen hardcopy
+        _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
+        # remove PREFIX to be completed from that array
+        _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
+        compadd -a _screen_display_wordlist
+    }
+    #k# complete word from currently visible GNU screen buffer
+    bindkey -r "^XS"
+    compdef -k _complete_screen_display complete-word '^XS'
+fi
+
 # }}}
 
 # {{{ history
@@ -1137,6 +1220,15 @@ fi
 
 if zrcautoload vcs_info; then
     GRML_VCS_INFO=0
+    # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
+    # function, which can cause a lot of trouble with our directory-based
+    # profiles. So:
+    if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
+        function VCS_INFO_realpath () {
+            setopt localoptions NO_shwordsplit chaselinks
+            ( builtin cd -q $1 2> /dev/null && pwd; )
+        }
+    fi
 else
 # I'm not reindenting the whole code below.
 GRML_VCS_INFO=1
@@ -1988,6 +2080,10 @@ else
     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat "%b${RED}:${YELLOW}%r"
 fi
 
+if [[ -o restricted ]]; then
+    zstyle ':vcs_info:*' enable false
+fi
+
 # }}}
 
 # command not found handling {{{
@@ -2029,9 +2125,7 @@ function info_print () {
     esc_end="$2"
     shift 2
     printf '%s' ${esc_begin}
-    for item in "$@" ; do
-        printf '%s ' "$item"
-    done
+    printf '%s' "$*"
     printf '%s' "${esc_end}"
 }
 
@@ -2263,7 +2357,7 @@ if ! check_com asc &>/dev/null ; then
 fi
 
 # get top 10 shell commands:
-alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
+alias top10='print -l ${(o)history%% *} | uniq -c | sort -nr | head -n 10'
 
 # truecrypt; use e.g. via 'truec /dev/ice /mnt/ice' or 'truec -i'
 if check_com -c truecrypt ; then
@@ -2621,28 +2715,6 @@ grmlcomp() {
 # {{{ grmlstuff
 grmlstuff() {
 # people should use 'grml-x'!
-    startx() {
-        if [[ -e /etc/X11/xorg.conf ]] ; then
-            [[ -x /usr/bin/startx ]] && /usr/bin/startx "$@" || /usr/X11R6/bin/startx "$@"
-        else
-            echo "Please use the script \"grml-x\" for starting the X Window System
-because there does not exist /etc/X11/xorg.conf yet.
-If you want to use startx anyway please call \"/usr/bin/startx\"."
-            return -1
-        fi
-    }
-
-    xinit() {
-        if [[ -e /etc/X11/xorg.conf ]] ; then
-            [[ -x /usr/bin/xinit ]] && /usr/bin/xinit || /usr/X11R6/bin/xinit
-        else
-            echo "Please use the script \"grml-x\" for starting the X Window System.
-because there does not exist /etc/X11/xorg.conf yet.
-If you want to use xinit anyway please call \"/usr/bin/xinit\"."
-            return -1
-        fi
-    }
-
     if check_com -c 915resolution; then
         855resolution() {
             echo "Please use 915resolution as resolution modifying tool for Intel \
@@ -2794,7 +2866,7 @@ compdef _aliases edalias
 
 #f1# Edit a function via zle
 edfunc() {
-    [[ -z "$1" ]] && { echo "Usage: edfun <function_to_edit>" ; return 1 } || zed -f "$1" ;
+    [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
 }
 compdef _functions edfunc
 
@@ -2880,18 +2952,16 @@ check_com -c qma && alias ?='qma zshall'
 # grep for running process, like: 'any vim'
 any() {
     emulate -L zsh
+    unsetopt KSH_ARRAYS
     if [[ -z "$1" ]] ; then
         echo "any - grep for process(es) by keyword" >&2
         echo "Usage: any <keyword>" >&2 ; return 1
     else
-        local STRING=$1
-        local LENGTH=$(expr length $STRING)
-        local FIRSCHAR=$(echo $(expr substr $STRING 1 1))
-        local REST=$(echo $(expr substr $STRING 2 $LENGTH))
-        ps xauwww| grep "[$FIRSCHAR]$REST"
+        ps xauwww | grep --color=auto "[${1[1]}]${1[2,-1]}"
     fi
 }
 
+
 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
 [[ -r /proc/1/maps ]] && \
@@ -3078,14 +3148,14 @@ exit 0;
 ssl_hashes=( sha512 sha256 sha1 md5 )
 
 for sh in ${ssl_hashes}; do
-    ssl-cert-${sh}() {
+    eval 'ssl-cert-'${sh}'() {
         emulate -L zsh
         if [[ -z $1 ]] ; then
-            printf 'usage: %s <file>\n' "ssh-cert-${sh}"
+            printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
             return 1
         fi
-        openssl x509 -noout -fingerprint -${sh} -in $1
-    }
+        openssl x509 -noout -fingerprint -'${sh}' -in $1
+    }'
 done; unset sh
 
 ssl-cert-fingerprints() {
@@ -3123,6 +3193,9 @@ if [[ -r ~/.important_commands ]] ; then
 fi
 # }}}
 
+# load the lookup subsystem if it's available on the system
+zrcautoload lookupinit && lookupinit
+
 #:grep:marker:for:mika: :-)
 ### non-root (EUID != 0) code below
 ###
@@ -3132,7 +3205,6 @@ if (( GRML_ALWAYS_LOAD_ALL == 0 )) && (( $EUID == 0 )) ; then
     return 0
 fi
 
-
 # variables {{{
 
 # set terminal property (used e.g. by msgid-chooser)
@@ -3206,9 +3278,9 @@ alias lsd='ls -d *(/)'                 # only show directories
 #a2# Only show empty directories
 alias lse='ls -d *(/^F)'               # only show empty directories
 #a2# Display the ten newest files
-alias lsnew="ls -rl *(D.om[1,10])"     # display the newest files
+alias lsnew="ls -rtlh *(D.om[1,10])"   # display the newest files
 #a2# Display the ten oldest files
-alias lsold="ls -rtlh *(D.om[1,10])"   # display the oldest files
+alias lsold="ls -rtlh *(D.Om[1,10])"   # display the oldest files
 #a2# Display the ten smallest files
 alias lssmall="ls -Srl *(.oL[1,10])"   # display the smallest files
 
@@ -3369,7 +3441,7 @@ bk() {
 #f5# Copied diff
 cdiff() {
     emulate -L zsh
-    diff -crd "$*" | egrep -v "^Only in |^Binary files "
+    diff -crd "$@" | egrep -v "^Only in |^Binary files "
 }
 #f5# cd to directoy and list files
 cl() {
@@ -3548,29 +3620,6 @@ alias GREP='grep -i --color=auto'
 #f5# Watch manpages in a stretched style
 man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
 
-# d():Copyright 2005 Nikolai Weibull <nikolai@bitwi.se>
-# note: option AUTO_PUSHD has to be set
-#f5# Jump between directories
-d() {
-    emulate -L zsh
-    autoload -U colors
-    local color=$fg_bold[blue]
-    integer i=0
-    dirs -p | while read dir; do
-        local num="${$(printf "%-4d " $i)/ /.}"
-        printf " %s  $color%s$reset_color\n" $num $dir
-        (( i++ ))
-    done
-    integer dir=-1
-    read -r 'dir?Jump to directory: ' || return
-    (( dir == -1 )) && return
-    if (( dir < 0 || dir >= i )); then
-        echo d: no such directory stack entry: $dir
-        return 1
-    fi
-    cd ~$dir
-}
-
 # usage example: 'lcheck strcpy'
 #f5# Find out which libs define a symbol
 lcheck() {
@@ -3583,15 +3632,24 @@ lcheck() {
 
 #f5# Clean up directory - remove well known tempfiles
 purge() {
-    FILES=(*~(N) .*~(N) \#*\#(N) *.o(N) a.out(N) *.core(N) *.cmo(N) *.cmi(N) .*.swp(N))
-    NBFILES=${#FILES}
+    emulate -L zsh
+    setopt HIST_SUBST_PATTERN
+    local -a TEXTEMPFILES GHCTEMPFILES PYTEMPFILES FILES
+    TEXTEMPFILES=(*.tex(N:s/%tex/'(log|toc|aux|nav|snm|out|tex.backup|bbl|blg|bib.backup|vrb|lof|lot|hd|idx)(N)'/))
+    GHCTEMPFILES=(*.(hs|lhs)(N:r:s/%/'.(hi|hc|(p|u|s)_(o|hi))(N)'/))
+    PYTEMPFILES=(*.py(N:s/%py/'(pyc|pyo)(N)'/))
+    LONELY_MOOD_FILES=((*.mood)(NDe:'local -a AF;AF=( ${${REPLY#.}%mood}(mp3|flac|ogg|asf|wmv|aac)(N) ); [[ -z "$AF" ]]':))
+    FILES=(*~(.N) \#*\#(.N) *.o(.N) a.out(.N) (*.|)core(.N) *.cmo(.N) *.cmi(.N) .*.swp(.N) *.(orig|rej)(.DN) *.dpkg-(old|dist|new)(DN) ._(cfg|mrg)[0-9][0-9][0-9][0-9]_*(N) ${~TEXTEMPFILES} ${~GHCTEMPFILES} ${~PYTEMPFILES} ${LONELY_MOOD_FILES})
+    local NBFILES=${#FILES}
+    local CURDIRSUDO=""
+    [[ ! -w ./ ]] && CURDIRSUDO=$SUDO
     if [[ $NBFILES > 0 ]] ; then
-        print $FILES
+        print -l $FILES
         local ans
         echo -n "Remove these files? [y/n] "
         read -q ans
         if [[ $ans == "y" ]] ; then
-            rm ${FILES}
+            $CURDIRSUDO rm ${FILES}
             echo ">> $PWD purged, $NBFILES files removed"
         else
             echo "Ok. .. then not.."
@@ -3599,6 +3657,27 @@ purge() {
     fi
 }
 
+#f5# show labels and uuids of disk devices
+if is439 && [[ -d /dev/disk/by-id/ ]]; then
+    lsdisk() {
+        emulate -L zsh
+        setopt extendedglob
+        local -a -U disks
+        disks=( /dev/disk/by-id/*(@:A) )
+        for dev in "$disks[@]"; do
+            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)
+            print -f "  %s\n" /dev/disk/by-id/*(@e/'[[ ${REPLY:A} == $dev ]]'/N:t)
+        done
+    }
+fi
+
+#f5# run command or function in a list of directories
+rundirs() {
+  local d CMD STARTDIR=$PWD
+  CMD=$1; shift
+  ( for d ($@) {cd -q $d && { print cd $d; ${(z)CMD} ; cd -q $STARTDIR }} )
+}
+
 # Translate DE<=>EN
 # 'translate' looks up fot a word in a file with language-to-language
 # translations (field separator should be " : "). A typical wordlist looks
@@ -3662,29 +3741,158 @@ selhist() {
 }
 
 # Usage: simple-extract <file>
+# Using option -d deletes the original archive file.
 #f5# Smart archive extractor
-simple-extract () {
+simple-extract() {
     emulate -L zsh
-    if [[ -f $1 ]] ; then
-        case $1 in
-            *.tar.bz2)  bzip2 -v -d $1      ;;
-            *.tar.gz)   tar -xvzf $1        ;;
-            *.rar)      unrar $1            ;;
-            *.deb)      ar -x $1            ;;
-            *.bz2)      bzip2 -d $1         ;;
-            *.lzh)      lha x $1            ;;
-            *.gz)       gunzip -d $1        ;;
-            *.tar)      tar -xvf $1         ;;
-            *.tgz)      gunzip -d $1        ;;
-            *.tbz2)     tar -jxvf $1        ;;
-            *.zip)      unzip $1            ;;
-            *.Z)        uncompress $1       ;;
-            *)          echo "'$1' Error. Please go away" ;;
+    setopt extended_glob noclobber
+    local DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
+    local RC=0
+    zparseopts -D -E "d=DELETE_ORIGINAL"
+    for ARCHIVE in "${@}"; do
+        case $ARCHIVE in
+            *.(tar.bz2|tbz2|tbz))
+                DECOMP_CMD="tar -xvjf -"
+                USES_STDIN=true
+                USES_STDOUT=false
+                ;;
+            *.(tar.gz|tgz))
+                DECOMP_CMD="tar -xvzf -"
+                USES_STDIN=true
+                USES_STDOUT=false
+                ;;
+            *.(tar.xz|txz|tar.lzma))
+                DECOMP_CMD="tar -xvJf -"
+                USES_STDIN=true
+                USES_STDOUT=false
+                ;;
+            *.tar)
+                DECOMP_CMD="tar -xvf -"
+                USES_STDIN=true
+                USES_STDOUT=false
+                ;;
+            *.rar)
+                DECOMP_CMD="unrar x"
+                USES_STDIN=false
+                USES_STDOUT=false
+                ;;
+            *.lzh)
+                DECOMP_CMD="lha x"
+                USES_STDIN=false
+                USES_STDOUT=false
+                ;;
+            *.7z)
+                DECOMP_CMD="7z x"
+                USES_STDIN=false
+                USES_STDOUT=false
+                ;;
+            *.(zip|jar))
+                DECOMP_CMD="unzip"
+                USES_STDIN=false
+                USES_STDOUT=false
+                ;;
+            *.deb)
+                DECOMP_CMD="ar -x"
+                USES_STDIN=false
+                USES_STDOUT=false
+                ;;
+            *.bz2)
+                DECOMP_CMD="bzip2 -d -c -"
+                USES_STDIN=true
+                USES_STDOUT=true
+                ;;
+            *.(gz|Z))
+                DECOMP_CMD="gzip -d -c -"
+                USES_STDIN=true
+                USES_STDOUT=true
+                ;;
+            *.(xz|lzma))
+                DECOMP_CMD="xz -d -c -"
+                USES_STDIN=true
+                USES_STDOUT=true
+                ;;
+            *)
+                print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
+                RC=$((RC+1))
+                continue
+                ;;
         esac
-    else
-        echo "'$1' is not a valid file"
-    fi
+
+        if ! check_com ${DECOMP_CMD[(w)1]}; then
+            echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
+            RC=$((RC+2))
+            continue
+        fi
+
+        GZTARGET="${ARCHIVE:t:r}"
+        if [[ -f $ARCHIVE ]] ; then
+
+            print "Extracting '$ARCHIVE' ..."
+            if $USES_STDIN; then
+                if $USES_STDOUT; then
+                    ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
+                else
+                    ${=DECOMP_CMD} < "$ARCHIVE"
+                fi
+            else
+                if $USES_STDOUT; then
+                    ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
+                else
+                    ${=DECOMP_CMD} "$ARCHIVE"
+                fi
+            fi
+            [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
+
+        elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
+            if check_com curl; then
+                WGET_CMD="curl -k -s -o -"
+            elif check_com wget; then
+                WGET_CMD="wget -q -O - --no-check-certificate"
+            else
+                print "ERROR: neither wget nor curl is installed" >&2
+                RC=$((RC+4))
+                continue
+            fi
+            print "Downloading and Extracting '$ARCHIVE' ..."
+            if $USES_STDIN; then
+                if $USES_STDOUT; then
+                    ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
+                    RC=$((RC+$?))
+                else
+                    ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
+                    RC=$((RC+$?))
+                fi
+            else
+                if $USES_STDOUT; then
+                    ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
+                else
+                    ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
+                fi
+            fi
+
+        else
+            print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
+            RC=$((RC+8))
+        fi
+    done
+    return $RC
+}
+
+__archive_or_uri()
+{
+    _alternative \
+        'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
+        '_urls:Remote Archives:_urls'
+}
+
+_simple_extract()
+{
+    _arguments \
+        '-d[delete original archivefile after extraction]' \
+        '*:Archive Or Uri:__archive_or_uri'
 }
+compdef _simple_extract simple-extract
+alias se=simple-extract
 
 # Usage: smartcompress <file> (<type>)
 #f5# Smart archive creator
@@ -3730,7 +3938,11 @@ show-archive() {
 #f5# Use \kbd{vim} as your manpage reader
 vman() {
     emulate -L zsh
-    man $* | col -b | view -c 'set ft=man nomod nolist' -
+    if (( ${#argv} == 0 )); then
+        printf 'usage: vman <topic>\n'
+        return 1
+    fi
+    man "$@" | col -b | view -c 'set ft=man nomod nolist' -
 }
 
 # function readme() { $PAGER -- (#ia3)readme* }
@@ -3773,6 +3985,7 @@ refunc() {
         autoload $func
     done
 }
+compdef _functions refunc
 
 # a small check to see which DIR is located on which server/partition.
 # stolen and modified from Sven's zshrc.forall
@@ -3911,11 +4124,52 @@ allulimit() {
     ulimit -t unlimited
 }
 
-# ogg2mp3 with bitrate of 192
-ogg2mp3_192() {
-    emulate -L zsh
-    oggdec -o - $1 | lame -b 192 - ${1:r}.mp3
-}
+# 2mp3 transcodes flac and ogg to mp3 with bitrate of 192 while preserving basic tags
+if check_com lame; then
+    2mp3_192() {
+        emulate -L zsh
+        setopt extendedglob
+        unsetopt ksharrays
+
+        local -a DECODE id3tags
+        local -A tagmap
+        local tagdata
+        local RC=0
+        tagmap=("(#l)title" --tt "(#l)artist" --ta "(#l)tracknumber" --tn "(#l)genre" --tg "(#l)album" --tl)
+
+        if [[ ${@[(i)*.ogg]} -le ${#@} ]] && ! check_com oggdec; then
+            echo "ERROR: please install oggdec" >&2
+            return 1
+        fi
+        if [[ ${@[(i)*.flac]} -le ${#@} ]] && ! check_com flac; then
+            echo "ERROR: please install flac" >&2
+            return 1
+        fi
+
+        for af in "$@"; do
+            id3tags=()
+            case "$af" in
+                (*.flac)
+                    DECODE=(flac -d -c "$af")
+                    tagdata="$(metaflac --export-tags-to=- "$af")"
+                    ;;
+                (*.ogg)
+                    DECODE=(oggdec -Q -o - "$af")
+                    tagdata="$(ogginfo "$af")"
+                    ;;
+                (*) continue ;;
+            esac
+            for line (${(f)tagdata}) \
+                [[ "$line" == (#s)[[:space:]]#(#b)([^=]##)=(*)(#e) && -n $tagmap[(k)$match[1]] ]] && \
+                id3tags+=($tagmap[(k)$match[1]] "$match[2]")
+            [[ ${#id3tags} -gt 0 ]] && id3tags=(--add-id3v2 --ignore-tag-errors $id3tags)
+            $DECODE[*] | lame -b 192 -v -h --replaygain-fast  "${id3tags[@]}" - "${af:r}.mp3" || {RC=$?; print "Error transcoding" "${af}"; }
+        done
+        # return 0 if no error or exit code if at least one error happened
+        return $RC
+    }
+    alias ogg2mp3_192 2mp3_192
+fi
 
 #f5# RFC 2396 URL encoding in Z-Shell
 urlencode() {