### vim:ft=zsh:foldmethod=marker
###
### This is the real setup file.
### All magic starts here.
###
### Frank Terbeck <ft@bewatermyfriend.org>
### Last-Modified: Tue Dec 25 17:24:26 2007
###
### URI: <http://ft.bewatermyfriend.org/comp/zsh.html>
###

### startup message
(( ZSHRC_VERBOSE > 0 )) && printf 'Starting zsh v%s\n' ${ZSH_VERSION}

### this array will contain the files we'll try to source
ZRCS=()

### helper functions {{{

### $ZRCS[] builder;
###   + handles files that shouldn't give errors if they don't exist
function zrcsource() { #{{{
    setopt local_options
    ### Note that zsh version 3.0.5 and earlier needs extendedglob
    ### to be switched on to make '~/...' expansions work in ZRCSOURCE_DIR.
    ### This does not hurt in newer versions, so I'll set this here.
    setopt extended_glob
    local file
    file="${ZRC_SOURCE_DIR}/${1}"
    if [[ -r ${~file} ]] ; then
        ZRCS=( ${ZRCS} ${~file} )
    elif [[ -z ${2} ]] ; then
        ZRCS=( ${ZRCS} ${~file} )
    else
        (( ZSHRC_VERBOSE > 0 )) && printf 'zshrc: ignoring non-existant file: %s\n' ${~file}
    fi
#}}}

### Okay, this is overkill. But this config got too big a long time ago.
### So, who cares? :-)
### Anyway: Since this config is split into various files, some files
### depend on others to be sourced already. Because of that, I introduced
### the possibility of every file added to $ZRCS[] via zrcsource() to start
### with '#zdep ...' in the 1st line (where ... is a comma seperated list of
### files that file requires to be loaded already).
###
### To cut a long story short: zdepend() resorts $ZRCS[] to reflect the
### information found in the #zdep lines.
function zdepend() { #{{{
    # be verbose if $ZSHRC_VERBOSE >= 5
    local zdepdebug=0
    (( zdepdebug == 1 )) && set -x
    local added=1 untagged=0 satisfied subsat
    local sortedRCS ; sortedRCS=()
    local file buf tmp tag istag dep deplist sorted
    local deps tags ; deps=() ; tags=( __all__ __begin__ __end__ )

    ### read the #zdep lines {{{
    ### yes, this is insane. :-) - But I want to know if it's doable.
    for file in ${ZRCS} ; do
        read buf < $file
        if [[ ${buf} !=  '#zdep '* ]] ; then
            ### files names 'zshrc.local' are always tagged __end__, if the #zdep line is missing.
            if [[ ${file} == *'/zshrc.local' ]] ; then
                deps=(${deps} "${file}:__end__")
            else
                deps=(${deps} "${file}:")
            fi
            continue
        fi
        buf="${buf#\#zdep }"
        tmp=(${(s:,:)buf})
        if [[ -n ${tmp[1]} ]] ; then
            istag=0
            for tag in ${tags} ; do
                if [[ ${tag} == ${tmp[1]} ]] ; then
                    istag=1
                    break
                fi
            done
            if (( istag > 0 )) ; then
                deps=(${deps} "${file}:${tmp[1]}")
                continue
            fi
            buf="${ZRC_SOURCE_DIR}/${tmp[1]}"
            shift tmp
        else
            buf=""
        fi
        for i in ${tmp} ; do
            for tag in ${tags} ; do
                if [[ ${tag} == ${i} ]] ; then
                    istag=1
                    break
                fi
            done
            if (( istag > 0 )) ; then
                deps=(${deps} "${file}:${i}")
                break
            fi
            buf="${buf},${ZRC_SOURCE_DIR}/${i}"
        done
        tmp=""
        deps=(${deps} "${file}:${buf#\#zdep }")
    done
    ### }}}
    for file in ${deps} ; do [[ ${file} != *:__*__ ]] && untagged=$((untagged + 1)) ; done
    for file in ${deps} ; do [[ ${file} == *:__begin__ ]] && sortedRCS=(${sortedRCS} ${file%:*}) ; done
    untagged=$((untagged + ${#sortedRCS}))
    ### resolve dependencies {{{
    ### okay, reading the '#zdep' lines wasn't too cheap. Yet, this
    ### loop is really expensive. But since it only handles a few strings,
    ### I'll do it. :-)
    while true ; do
        if (( added > 0 )) ; then
            added=0
        else
            printf "zdepend(): Dependency problems. Giving up.\n"
            print -l ${sortedRCS}
            return 1
        fi
        for tmp in ${deps} ; do
            file=${tmp%:*} ; deplist=${tmp#*:} ; satisfied=1
            for sorted in ${sortedRCS} ; do [[ ${sorted} == ${file} ]] && continue 2 ; done
            for dep in ${(s:,:)deplist} ; do
                for sorted in ${sortedRCS} ; do
                    subsat=0
                    [[ ${sorted} == ${dep} ]] && subsat=1 && break
                done
                    (( subsat == 0 )) && satisfied=0 && break
            done
            (( satisfied > 0 )) && sortedRCS=(${sortedRCS} ${file%:*}) && added=$((added + 1))
        done
        (( ${#sortedRCS} >= untagged )) && break
    done
    ### }}}
    for file in ${deps} ; do [[ ${file} == *:__all__   ]] && sortedRCS=(${sortedRCS} ${file%:*}) ; done
    for file in ${deps} ; do [[ ${file} == *:__end__   ]] && sortedRCS=(${sortedRCS} ${file%:*}) ; done
    (( zdepdebug == 1 )) && set +x
    (( ZSHRC_VERBOSE >= 5 )) && printf 'zshrc source order:\n' && for tmp in ${sortedRCS} ; do printf '    + %s\n' "${tmp}" ; done
    ZRCS=(${sortedRCS})
    return 0
#}}}

### this VERSION_* array solution could be more elegant,
### but zsh versions prior to 3.1.6 do not support associative arrays.
### so, to stay backwards compatible we do not use them here.
VERSION_TABLE=( #{{{
    "3.0.6" "3.1.4" "3.1.6" "3.1.7"
    "4.0.2" "4.2.1" "4.2.2"
    "3.0"   "3.1"   "4.0"   "4.1"
    "4.2"   "4.3"
#}}}

VERSION_SHORT=( #{{{
    "306" "314" "316" "317"
    "402" "421" "422"
    "30"  "31"  "40"  "41"
    "42"  "43"
#}}}

VERSION_CHECKS_ATLEAST=( #{{{
    '${ZSH_VERSION} == 3.0.<6->* || ${ZSH_VERSION} == 3.<1->.<->* || ${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == 3.1.<4->* || ${ZSH_VERSION} == 3.<2->.<->* || ${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == 3.1.<6->* || ${ZSH_VERSION} == 3.<2->.<->* || ${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == 3.1.<7->* || ${ZSH_VERSION} == 3.<2->.<->* || ${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == 4.0.<2->* || ${ZSH_VERSION} == 4.<1->.<->* || ${ZSH_VERSION} == <5->.<->*'
    '${ZSH_VERSION} == 4.2.<1->* || ${ZSH_VERSION} == 4.<3->.<->* || ${ZSH_VERSION} == <5->.<->*'
    '${ZSH_VERSION} == 4.2.<2->* || ${ZSH_VERSION} == 4.<3->.<->* || ${ZSH_VERSION} == <5->.<->*'
    '${ZSH_VERSION} == <3->.<->*'
    '${ZSH_VERSION} == 3.<1->.<->* || ${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == <4->.<->*'
    '${ZSH_VERSION} == 4.<1->.<->* || ${ZSH_VERSION} == <5->.<->*'
    '${ZSH_VERSION} == 4.<2->.<->* || ${ZSH_VERSION} == <5->.<->*'
    '${ZSH_VERSION} == 4.<3->.<->* || ${ZSH_VERSION} == <5->.<->*'
#}}}

VERSION_CHECKS=( #{{{
    '${ZSH_VERSION} == 3.0.6' '${ZSH_VERSION} == 3.1.4' '${ZSH_VERSION} == 3.1.6'
    '${ZSH_VERSION} == 3.1.7' '${ZSH_VERSION} == 4.0.2' '${ZSH_VERSION} == 4.2.1'
    '${ZSH_VERSION} == 4.2.2'
    '${ZSH_VERSION} == 3.0.*' '${ZSH_VERSION} == 3.1.*' '${ZSH_VERSION} == 4.0.*'
    '${ZSH_VERSION} == 4.1.*' '${ZSH_VERSION} == 4.2.*' '${ZSH_VERSION} == 4.3.*'
#}}}

### generating zis_*() {{{

if [[ ${#VERSION_TABLE} != ${#VERSION_CHECKS_ATLEAST}
   || ${#VERSION_TABLE} != ${#VERSION_SHORT}
   || ${#VERSION_TABLE} != ${#VERSION_CHECKS}         ]] ; then

    printf 'Automatic zis_*() generation failed! Using fallback. Please check.\n'
    for i in {1..${#VERSION_TABLE}} ;do
        eval "function zis_${VERSION_SHORT[$i]}() { return 0 }"
    done
else
    for i in {1..${#VERSION_TABLE}} ; do

        eval "function zis_${VERSION_SHORT[$i]}() { \
if [[ \${1} == \"atleast\" ]] ; then [[ ${VERSION_CHECKS_ATLEAST[$i]} ]] && return 0 ; \
else [[ ${VERSION_CHECKS[$i]} ]] && return 0 ; fi ; \
(( ZSHRC_VERBOSE > 3 )) && printf \"  + zis_${VERSION_SHORT[$i]}: this is not %s (%s)\\n\" ${VERSION_TABLE[$i]}; return 1 }"

    done
fi

### }}}

### wrapper for autoload
function zrcautoload() { #{{{
    setopt local_options
    setopt extended_glob
    local fdir ffile
    local -i ffound
    ffile=${1}
    (( found = 0 ))
    for fdir in ${fpath} ; do
        [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
    done
    if (( ffound == 0 )) ; then
        (( ZSHRC_VERBOSE > 1 )) && printf "  zrcautoload: cannot find %s\n" ${ffile}
        return 1
    fi
    (( ZSHRC_VERBOSE > 2 )) && printf "  zrcautoload: loading %s\n" ${ffile}
    if zis_316 "atleast" ; then
        autoload -U ${ffile} || return 1
    else
        autoload ${ffile}    || return 1
    fi
    return 0
#}}}

### check if rc needs recompilation
function zrcneedcomp() { #{{{
    local recomp
    local rc=${1:t}
    if [[ -z ${1} ]] ; then
        printf "usage: ${0} <rcfile>\n"
        return 0
    fi
    if ! zis_317 "atleast" ; then
        (( ZSHRC_VERBOSE > 3 )) && printf "  zrcneedcomp(): rccompilation needs at least zsh v3.1.7\n"
        return 0
    fi

    if [[ ! -e ${1}.zwc ]] ; then
        (( ZSHRC_VERBOSE > 2 )) && printf "  zrcneedcomp(): ${rc}.zwc does not exist,\n    - marking for compilation.\n"
        return 1
    fi
    if [[ ${1} -nt ${1}.zwc ]] ; then
        (( ZSHRC_VERBOSE > 2 )) && printf "  zrcneedcomp(): ${rc} is newer than ${rc}.zwc,\n"
        recomp=1
    elif ! zcompile -t ${1}.zwc >/dev/null 2>&1 ; then
        (( ZSHRC_VERBOSE > 2 )) && printf "  zrcneedcomp(): ${rc}.zwc is compiled for different zsh version,\n"
        recomp=1
    fi
    if (( recomp > 0 )) ; then
        (( ZSHRC_VERBOSE > 2 )) && printf "    - marking for recompilation.\n"
        return 2
    fi
    return 0
#}}}

### }}}

### warm greeting to those living in stone age ;) {{{
if ! zis_40 "atleast" ; then
    printf "\n"
    printf "  +----------------------------------------------------------------------\n"
    printf "  |\n"
    printf "  |  Howdy stone-ager!\n"
    printf "  |\n"
    printf "  |    You are running version %s of zsh.\n" ${ZSH_VERSION}
    printf "  |    That is quite old.\n"
    printf "  |\n"
    printf "  |    You should consider updating to at least v4.0\n"
    printf "  |    If that is not up to you, bug your admin until he does. ;)\n"
    printf "  |    The newer versions do really have nice features\n"
    printf "  |    that these fossils do not.\n"
    printf "  |\n"
    printf "  |    The completion system improves with every release. Believe me.\n"
    printf "  |\n"
    printf "  |    Versions v4.3+ have multibyte support built in.\n"
    printf "  |    So, if you are in a UTF-8 locale, that is for you.\n"
    printf "  |\n"
    printf "  |    Anyway, have fun using zsh. :-)\n"
    printf "  |\n\n"
fi #}}}

### build $ZRCS[]
zrcsource "aliases"       ### setup aliases
### setup proper completion system for current zsh version
if zis_317 "atleast" ; then
    zrcsource "compsys"
else
    zrcsource "compctl"
fi
zrcsource "misc"          ### other configuration
zrcsource "modules"       ### load modules
zrcsource "options"       ### setup zsh's options
zrcsource "path"          ### set *path
zrcsource "vars"          ### setup variables
zrcsource "zcleanup"      ### cleanups
zrcsource "zfunct"        ### functions file
zrcsource "zle"           ### setup zsh's line editor
zrcsource "zshrc.local"   '__local_settings;_do_not_care_if_it_is_missing__'

### re-sort $ZRCS[] based on #zdep lines.
zdepend

### compile 'zshrc' and 'zshrc.real' if needed.
if (( ZSHRC_COMPILE > 0 )) && zis_317 "atleast" ; then #{{{
    for rc in 'zshrc' 'zshrc.real' ; do
    if [[ -r "${ZRC_SOURCE_DIR}/${rc}" ]] ; then
        zrcneedcomp "${ZRC_SOURCE_DIR}/${rc}"
        needc=${?}
        if (( needc > 0)) ; then
            if (( needc == 1 )) ; then
                (( ZSHRC_VERBOSE > 0 )) && printf "zshrc:   compiling ${rc}.zwc\n"
            elif (( needc == 2 )) ; then
                (( ZSHRC_VERBOSE > 0 )) && printf "zshrc: recompiling ${rc}.zwc\n"
                rm -f "${ZRC_SOURCE_DIR}/${rc}.zwc"
            fi
            zcompile -URz "${ZRC_SOURCE_DIR}/${rc}"
        fi
    fi
    done
fi #}}}
### and finally try to source the files in $ZRCS[]
for rc in ${ZRCS} ; do #{{{
    if [[ -r ${rc} ]] ; then
        (( ZSHRC_VERBOSE > 0 )) && printf "zshrc: loading %s\n" ${rc}

        ### zcompile support
        if (( ZSHRC_COMPILE > 0 )) ; then
            zrcneedcomp ${rc}
            needc=${?}
            if (( needc > 0)) ; then
                if (( needc == 1 )) ; then
                    (( ZSHRC_VERBOSE > 0 )) && printf "zshrc:   compiling ${rc}.zwc\n"
                elif (( needc == 2 )) ; then
                    (( ZSHRC_VERBOSE > 0 )) && printf "zshrc: recompiling ${rc}.zwc\n"
                    rm -f ${rc}.zwc
                fi
                zcompile -URz ${rc}
            fi
        fi
        ### End of zcompile support

        source ${rc}
    else
        printf "zshrc: could not load %s\n" ${rc}
    fi
done #}}}