### vim:ft=sh:foldmethod=marker
###
### split zsh configration
###   (for interactive shells)
###
### Frank Terbeck <ft@bewatermyfriend.org>
### Last-Modified: Sat May 24 22:30:48 2008
###
### URI: <http://ft.bewatermyfriend.org/comp/zsh.html>
###
### DESCRIPTION
#{{{
###   This file serves two purposes:
###     a) check if an ancient zsh version called us
###     b) load the appropriate _real_ startup file
###
###   Why is this needed?
###     Because pre-3 versions of zsh do not support large parts
###     of my version checking code in 'zshrc.real'.
###     Sourcing of 'zshrc.real' will break with syntax errors
###     and nothing will be set up at all.
###     I will not rewrite that system as these old versions are
###     DEPRECATED and their use is DISCOURAGED.
###
###     I guess noone really uses these versions, except for
###     the fun of checking out what these versions felt like.
###     So, a minimal setup should be okay. }}}
###

### INSTALLATION
#{{{
###   This setup is pretty easily usable.
###   The basic idea is, to keep all setup files in a seperate directory
###   and add a few symlinks in the user's home directory.
###
###   All setup files are bundled into a bzip2'ed tar archive, available at:
###   <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>
###
###   This archive creates a subdir called 'zsh' that contains the whole setup.
###   The default (being the setup I am using myself) is, to create a subdir
###   named 'etc' in the user's homedir and unpack the tar archive into this
###   directory. That means the zsh setup files would be in '~/etc/zsh'.
###   Many people do not like having a directory structure like '~/etc/zsh'
###   in their home directories. So, another common setup would be to put all
###   setup files into '~/.zsh'.
###
###   To get a working setup you now got two options:
###       a) automated installation
###       b) manual installation
###
### -- The "new" way: let the zshrc do the work -- {{{
###
###   You may call this files (zshrc) as if it is a zsh skript.
###   In that case, the file detects that a non-interactive shell called it
###   and starts an installation routine. You just need to make sure, that
###   $ZRC_SOURCE_DIR (in the zshrc file) is set to the path, where you copied
###   the configfile-set.
###
###     Examples:
###       % zsh ~/etc/zsh/zshrc     # prints an usage message
###       % zsh ~/etc/zsh/zshrc -   # starts the installation routine
###                                 # in normal mode
###       % zsh ~/etc/zsh/zshrc +   # starts the installation routine
###                                 # in force mode.
###
###   The 'force' method is *not* needed generally. Only use it, if the normal
###   method fails and you _know_ what the 'force' way does.
###
###   To demonstrate, how to use this feature, let's demonstrate two possible
###   installations:
###
###     a) The default way in '~/etc/zsh':
###           % cd ~
###           % [[ ! -e ~/etc ]] && mkdir etc
###           % cd etc
###           % wget http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2
###           % bunzip2 -c zsh-dotfiles.tar.bz2 | tar xvvf -
###           % zsh zsh/zshrc -
###
###         That's it. Simple enough, I'd say.
###
###     b) Installation in custom location (lets say: '~/.zsh'):
###           % cd ~
###           % wget http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2
###           % bunzip2 -c zsh-dotfiles.tar.bz2 | tar xvvf -
###           % [[ -e ~/.zsh ]] && mv .zsh .zsh.old
###           % mv zsh .zsh
###           % zsh .zsh/zshrc - ~/.zsh
###
###         Done.
###           If you prefer, you can leave the 2nd argument (~/.zsh) to the last
###           call to zsh out, if you prefer to adjust the $ZRC_SOURCE_DIR
###           setting manually in your favourite editor (if you do not trust my
###           ed-onliner). :-)
###           You will even be forced to use your editor, if your system does
###           not provide 'ed'. But normally, on a POSIX-like system, 'ed' will
###           be there and ready to take action.
###
###   Restart zsh and be happy. :-)
###   for those of you, who understand a bit of german, I blogged about this:
###   <http://www.bewatermyfriend.org/posts/2006/12-08.17-29-44-computer.html>
#}}}
### -- The "old" way: manually create the needed symlinks -- {{{
###
###   For the default installation path, these symlinks are needed:
###
###       Link      |   Target
###   ----------------------------
###     ~/.zshrc    | ~/etc/zsh/zshrc
###     ~/.zkbd     | ~/etc/zsh/kbd
###     ~/.zlogout  | ~/etc/zsh/zlogout
###
###   To install the setup files to '~/.zsh':
###   Download the tar archive unpack it into your homedir and rename
###   the resulting 'zsh' dir to '.zsh'.
###
###   Now, create the following symlinks:
###
###       Link      |   Target
###   ----------------------------
###     ~/.zshrc    | ~/.zsh/zshrc
###     ~/.zkbd     | ~/.zsh/kbd
###     ~/.zlogout  | ~/.zsh/zlogout
###
###   A last step is needed:
###   You have to tell the setup files where they are. To achieve this, there
###   is a variable defined below: $ZRC_SOURCE_DIR;
###   Set it to the appropriate directory (in this case: '~/.zsh'). }}}
#}}}
###
### CONFIGURATION
#{{{
###   Beside the $ZRC_SOURCE_DIR variable described in the 'INSTALLATION' part,
###   there is a variable that tells the zshrc to be more verbose when being
###   loaded. This variable is called $ZSHRC_VERBOSE and must be set to a
###   numeric value.
###
###   By default it is defined like this: ZSHRC_VERBOSE=${ZSHRC_VERBOSE:-0}
###   This means that, if you start zsh and $ZSHRC_VERBOSE is not set
###   (which is the default) it gets set to 0.
###   You are now able to start zsh like this:
###
###       % ZSHRC_VERBOSE=3 zsh
###
###   which starts zsh and sets ZSHRC_VERBOSE to 3. Thus the default value will
###   not be applied. To change this default value, you can change the initial
###   setting to: ZSHRC_VERBOSE=${ZSHRC_VERBOSE:-2}, which changes the default
###   value to '2'.
###
###   Most people do have things they need in their shell configuration
###   additionaly. To serve these needs, there is a file that gets sourced
###   if it exists (it is ignored, if it is absent): 'zshrc.local'
###
###   So, if you'd like to get a fortune cookie everytime you start an
###   interactive shell, do: echo "fortune" >> ~/.zsh/zshrc.local
###   (given you set $ZRC_SOURCE_DIR to '~/.zsh' below.)
###
###   Zsh is able to pre-parse config files, so that when you source a file
###   no parsing has to be done. This speeds up loading large config files
###   on slow machines.
###
###   This config file set supports this compilation.
###   To enable this feature set ZSHRC_COMPILE accordingly.
###   Note, that 'zshrc.pre3' will never be compiled. That is not a bug.
###   pre3 versions of zsh do not support this.
###   Note, that 'compctl' and 'compsys' are only compiled if they will be
###   sourced afterwards. }}}
###
### CONTACT
#{{{
###   If you do use this configuration and something breaks on your system, feel
###   free to tell me about it. Personally I use these files on Linux as well
###   as on OpenBSD systems. I think it should not break on any UNIX system, so
###   please tell me, if you got problems. I will try to improve the parts
###   that break. Note that I do not care about Cygwin, so don't expect to
###   get any changes for that, but the simplest.
###   Everyone else on UNIX(-like) systems, report problems.
###
###   Ways to get in touch with me:
###     + Email: Frank Terbeck <ft@bewatermyfriend.org>
###     + IRC: 'ft' on freenode; channel: #zsh
###     + Jabber: efftee@jabber.ccc.de
###
###   Generally,  Email is the safest way to reach me. If you try to contact me
###   via jabber, make sure to tell me, that you'd like to discuss the zshrc.
###   If you like IRC, consider joining #zsh in irc.freenode.org and help
###   users new to zsh to resolve their problems. }}}
###

### ZSHRC_VERBOSE:
###    0:   no verbosity (only errors)
###   >0:   print files that are loaded by zrcsource
###         warns when a file needs to be (re)compiled
###   >1:   print functions zrcautoload cannot find
###   >2:   print functions zrcautoload loads
###         makes zrcneedcomp verbose
###   >3:   make version checking verbose
ZSHRC_VERBOSE=${ZSHRC_VERBOSE:-0}

### ZSHRC_COMPILE:
###    0:   don't try to compile parts of the config
###   >0:   _do_ use zcompile
ZSHRC_COMPILE=1

### I am storing the files '~/.zshrc' sources in ~/etc/zsh.
### If you moved these to another dir, set this to that dir.
ZRC_SOURCE_DIR="~/etc/zsh"

############ DO NOT CHANGE ANYTHING BELOW ############
### new installation procedure {{{
if [[ ! -o interactive ]] ; then
    PATH="/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin"
    ZRC_SOURCE_DIR=${ZRC_SOURCE_DIR%/}
    if [[ ${1} = '+' ]] ; then force=1 ; else force=0 ; fi
    setopt extendedglob

    function zdie() { #{{{
        printf "  |\n"
        printf "  |  %s\n" ${1}
        printf "  |\n\n"
        exit 1
    } #}}}
    function zrc_installed() { #{{{
        local dot_rc dot_kbd dot_lo
        [[ ${force} -gt 0 ]] && return 0
        [[ -h ${HOME}/.zshrc    ]] && dot_rc=$(  readlink ${HOME}/.zshrc   )
        [[ -h ${HOME}/.zkbd     ]] && dot_kbd=$( readlink ${HOME}/.zkbd    )
        [[ -h ${HOME}/.zlogout  ]] && dot_lo=$(  readlink ${HOME}/.zlogout )
        if    [[ ${dot_rc}  = ${~ZRC_SOURCE_DIR}/zshrc   ]] \
           && [[ ${dot_kbd} = ${~ZRC_SOURCE_DIR}/kbd     ]] \
           && [[ ${dot_lo}  = ${~ZRC_SOURCE_DIR}/zlogout ]] ; then
            printf "  |   Installation seems to be intact already.\n"
            printf "  |   Use forced installation, if that is not the case.\n"
            printf "  |\n\n"
        exit 0
        fi
    } #}}}
    function zinst_link() { #{{{
        printf "  |  + linking %s -> %s\n" "${(r:${3}:: :::)2:t}" "${1}"
        ln -s ${1} ${2}
    } #}}}
    function zinst_linkok() { #{{{
        ### return 1, if link is okay; 0 otherwise
        local file dest
        file=${1##*/}
        ### calling readlink here untested is okay,
        ### because this function won't be called in forced mode
        dest=$(readlink ${1})
        case ${file} in
            .zshrc)   [[ ${dest} = ${~ZRC_SOURCE_DIR}/zshrc   ]] && return 1       ;;
            .zkbd)    [[ ${dest} = ${~ZRC_SOURCE_DIR}/kbd     ]] && return 1       ;;
            .zlogout) [[ ${dest} = ${~ZRC_SOURCE_DIR}/zlogout ]] && return 1       ;;
            *)        zdie "zinst_linkok() called with unknown parameter ${1}" ;;
        esac
        return 0
    } #}}}
    function zinst() { #{{{
        local file dest backup linkok
        backup=$(date +"%Y-%m-%d_%H-%M-%S")
        for file in '.zshrc' '.zkbd' '.zlogout' ; do
            case ${file} in
                .zshrc)   dest=${~ZRC_SOURCE_DIR}/zshrc   ;;
                .zkbd)    dest=${~ZRC_SOURCE_DIR}/kbd     ;;
                .zlogout) dest=${~ZRC_SOURCE_DIR}/zlogout ;;
                *) zdie "zinst_prepare broken." ;;
            esac

            linkok=0
            if [[ -e ${HOME}/${file} ]] ; then
                if [[ -h ${HOME}/${file} ]] ; then
                    zinst_linkok "${HOME}/${file}"
                    linkok=$?
                    if [[ ${linkok} -eq 0 ]] ; then
                        printf "  |  - savely removing link: %s (%s)\n" ${HOME}/${file} "$(readlink ${HOME}/${file})"
                        rm -f ${HOME}/${file}
                    fi
                else
                    if [[ -e ${file}.${backup} ]] ; then
                        zdie "${HOME}/${file}.${backup} exists! weird. GIVING UP."
                    fi
                    printf "  |  - renaming existing %s to %s\n" ${file} "${file}.${backup}"
                    mv "${HOME}/${file}" "${HOME}/${file}.${backup}"
                fi
            fi
            [[ ${linkok} -eq 0 ]] && zinst_link "${dest}" "${HOME}/${file}" 8
        done
        if [[ ${ARGV2} = ${ZRC_SOURCE_DIR} ]] ; then
            printf "  |  + editing %s with ed.\n" "${HOME}/.zshrc"
            printf "  |    - setting \${ZRC_SOURCE_DIR} to: %s\n" "${ZRC_SOURCE_DIR}"
            printf '/^[         ]*ZRC_SOURCE_DIR=/\ns!=.*$!="%s"!\nw\n' "${ZRC_SOURCE_DIR}" | ed "${HOME}/.zshrc" >/dev/null 2>&1
        fi
    } #}}}
    function verify_zrcdir() { #{{{
        local dir
        dir=${~1}
        if [[ ! -e ${dir}/zshrc.real || ! -e ${dir}/zshrc.pre3 ]] ; then
            printf "  |   Important Files *not* found!\n"
            printf "  |   Check where you put the config file and set \$ZRC_SOURCE_DIR.\n"
            return 1
        fi
        return 0
    } #}}}

    printf "\n"
    printf "  +----------------------------------------------------------------------\n"
    printf "  |\n"
    printf "  |  Automatic installation procedure\n"
    printf "  | ------------------------------------\n"
    printf "  |\n"

    ### if '-', we _need_ readlink.
    if [[ ${force} -eq 0 ]] && [[ ! -x $(which readlink) ]] ; then
        printf "  |   readlink not found in standard-\$PATH\n"
        printf "  |   You may want to try the forced installation.\n"
        printf "  |   If you do not want that, read the old INSTALLATION instructions.\n"
        printf "  |     -- ABORT! --\n"
        printf "  |\n\n"
        exit 1
    fi
    ### NEW: support automatic setting of ${ZRC_SOURCE_DIR} via 2nd argument.
    ARGV2=${2}
    if [[ -n ${ARGV2} ]] ; then
        if [[ ! -x $(which ed) ]] ; then
            zdie "Sorry, I need 'ed' to edit myself. But I cannot find it. ABORT."
        fi
        ZRC_SOURCE_DIR=${ARGV2}
    fi
    ### if 'zshrc.real' and 'zsh.pre3' are not in ZRC_SOURCE_DIR,
    ### something is seriously broken or ZRC_SOURCE_DIR set incorrectly.
    if ! verify_zrcdir ${ZRC_SOURCE_DIR} ; then
        zdie "-- ABORT! --"
    fi
    case ${1} in
        -)
            zrc_installed
            zinst
            printf "  |\n\n"
            ;;
        +)
            printf "  |  -!- Forced Installation!\n"
            printf "  |\n"
            printf "  |      - ~/{.zshrc,.zkbd,.zlogout} will be removed!\n"
            printf "  |\n"
            printf "  |    Continuing in 5 seconds; HIT CTRL-C to abort!\n"
            printf "  |\n"
            sleep 5
            rm -Rf ${HOME}/.zshrc ${HOME}/.zkbd ${HOME}/.zlogout
            zinst
            printf "  |\n\n"
            ;;
        *)
            printf "  |   Usage:\n"
            printf "  |  --------\n"
            printf "  |\n"
            printf "  |   %% zsh /path/to/zshrc <FLAG> [ZRC_SOURCE_DIR]\n"
            printf "  |\n"
            printf "  |       edit this file and setup \$ZRC_SOURCE_DIR correctly.\n"
            printf "  |       NEW: you may define your \$ZRC_SOURCE_DIR as 2nd arg\n"
            printf "  |            to this installation procedure (needs 'ed').\n"
            printf "  |\n"
            printf "  |         use '-' as <FLAG> to create the needed symlinks.\n"
            printf "  |             '+' as <FLAG> forcibly remove files in ~/,\n"
            printf "  |                           that prevent installation\n"
            printf "  |\n"
            printf "  |  Beware! Forced installation will remove these files:\n"
            printf "  |    ~/.zshrc, ~/.zkbd and ~/.zlogout\n"
            printf "  |\n\n"
            ;;
    esac
    exit 0
fi #}}}

### check for pre-3.0 versions
if [[ -z ${ZSH_VERSION} ]] && [[ ${VERSION} = zsh* ]] ; then
    #{{{
    printf "\n"
    printf "  +----------------------------------------------------------------------\n"
    printf "  |\n"
    printf "  |  +-+-+-+-+-+-+-+-+-+-+-+-+   !WARNING!   +-+-+-+-+-+-+-+-+-+-+-+-+\n"
    printf "  |\n"
    printf "  |    You are running a pre-3.0 version of zsh (%s)!\n" ${VERSION##zsh }
    printf "  |\n"
    printf "  |    Some of these versions are still available online,\n"
    printf "  |    _BUT_ they are *deprecated* and the continued use of\n"
    printf "  |    these is *STRONGLY* *DISCOURAGED*!\n"
    printf "  |\n"
    printf "  |    This zsh setup does not actively support pre-3.0 versions.\n"
    printf "  |    I will try to load a minimal working setup, but basically,\n"
    printf "  |    you are completely on your own now, young soldier.\n"
    printf "  |\n"
    printf "  |    Please, please, PLEASE(!) consider updating to at least v3.0.2.\n"
    printf "  |    These versions are way more feature-rich and STABLE than this.\n"
    printf "  |    In fact, you are probably best off, to go for v4.2+ anyway.\n"
    printf "  |    The improvements are uncountable.\n"
    printf "  |    Please do so, for your own good.\n"
    printf "  |\n"
    printf "  |    Ye been warned!\n"
    printf "  |\n\n"
    setopt extendedglob
    if [[ -e ${~ZRC_SOURCE_DIR}/zshrc.pre3 ]] ; then
        source ${~ZRC_SOURCE_DIR}/zshrc.pre3
    else
        printf "  -!- Sorry dude. I could not find 'zshrc.pre3'.\n"
        printf "  -!- Please check your installation. Adjust \$ZRC_SOURCE_DIR as needed.\n"
    fi
    #}}}
else
    #{{{
    setopt extendedglob
    if [[ -e ${~ZRC_SOURCE_DIR}/zshrc.real ]] ; then
        ZRC_SOURCE_DIR=${~ZRC_SOURCE_DIR}
        setopt noextendedglob
        source ${ZRC_SOURCE_DIR}/zshrc.real
    else
        printf "  -!- Sorry dude. I could not find 'zshrc.real'.\n"
        printf "  -!- Please check your installation. Adjust \$ZRC_SOURCE_DIR as needed.\n"
    fi
    #}}}
fi