左プロンプトに git のブランチとステータスを、右プロンプトに git リポジトリとそれ以外のディレクトリを色分けして表示

下記を参考に、自分なりにやってみたんだけど・・・
show current git branch on zsh prompt (2) - Bart's Blog

function git_branch() {
    local git_dir branch

    git_dir=$(git rev-parse --git-dir 2> /dev/null) || return
    if test -d "$git_dir/../.dotest"; then
        branch="$(git symbolic-ref HEAD 2>/dev/null)"
    elif test -f "$git_dir/.dotest-merge/interactive"; then
        branch="$(cat "$git_dir/.dotest-merge/head-name")"
    elif test -d "$git_dir/.dotest-merge"; then
        branch="$(cat "$git_dir/.dotest-merge/head-name")"
    elif test -f "$git_dir/MERGE_HEAD"; then
        branch="$(git symbolic-ref HEAD 2>/dev/null)"
    else
        branch="$(git symbolic-ref HEAD 2>/dev/null)" || \
            branch="$(git describe --exact-match HEAD 2>/dev/null)" || \
            branch="$(cut -c1-7 "$git_dir/HEAD")..."
    fi

    echo -n "${branch#refs/heads/}"
}

function git_state() {
    local git_dir state

    git_dir=$(git rev-parse --git-dir 2> /dev/null) || return
    if test -d "$git_dir/../.dotest"; then
        if test -f "$git_dir/../.dotest/rebasing"; then
            state="rebase"
        elif test -f "$git_dir/../.dotest/applying"; then
            state="am"
        else
            state="am/rebase"
        fi
    elif test -f "$git_dir/.dotest-merge/interactive"; then
        state="rebase-i"
    elif test -d "$git_dir/.dotest-merge"; then
        state="rebase-m"
    elif test -f "$git_dir/MERGE_HEAD"; then
        state="merge"
    else
        test -f "$git_dir/BISECT_LOG" && state="bisect"
    fi

    echo -n "${state}"
}

function git_top_dir() {
    local git_dir
    git_dir=$(git rev-parse --git-dir 2> /dev/null) || return

    case $git_dir in 
        .git) git_dir="$(pwd)/.git";;
    esac 

    echo "${${git_dir:h}/$HOME/~}"
}

function rprompt_dir {
    local git_dir
    git_dir=${$(git_top_dir)%% }

    local short
    short="${PWD/$HOME/~}"

    if test -z "$git_dir" ; then
            echo -n "$short"
            return
    fi

    local lead rest
    lead=$git_dir
    rest=${${short#$lead}#/}

    echo -n "$lead%{$fg[cyan]%}/$rest"
}

function lprompt_git_state {
    local branch state
    branch=$(git_branch)
    state=$(git_state)

    if test -z "$branch" ; then
        return
    fi

    if test "$state" ; then
        state=":$state"
    fi

    echo -n "%{$fg[cyan]%}(${branch}${state})"
}

setopt prompt_subst

autoload -U colors
colors

PROMPT='${WINDOW:+"[$WINDOW]"}%{$fg[green]%}`whoami`%{$fg[blue]%}@%{$fg[red]%}`hostname -s``lprompt_git_state`%{$fg[green]%}%#%{$reset_color%} '
RPROMPT='%{$fg[yellow]%}[`rprompt_dir`%{$fg[red]%}:%!%{$fg[yellow]%}]%{$reset_color%}'

予想通りプロンプト表示が重かった。さて、最適化するか。

最適化してみた

関数を一つにまとめて、プロンプトは環境変数を参照するようにし、chpwd と preexec で環境変数に値を設定するように変更した。とても軽くなったので満足。
ただ・・・、zsh-templates を使う予定だったのに、手元の OSX 10.4 + zsh 4.3.6 で動作しなかったのが謎。(帰宅後に OSX 10.5 + zsh 4.3.6 で確認してみよ)

.zshrc.prompt

function _git_compute_vars() {
    export __ZSH_GIT_STATE=
    export __ZSH_GIT_DIR=

    local git_dir state branch

    git_dir=$(git rev-parse --git-dir 2> /dev/null) || return

    if test -d "$git_dir/../.dotest"; then
        if test -f "$git_dir/../.dotest/rebasing"; then
            state="rebase"
        elif test -f "$git_dir/../.dotest/applying"; then
            state="am"
        else
            state="am/rebase"
        fi
        branch="$(git symbolic-ref HEAD 2>/dev/null)"
    elif test -f "$git_dir/.dotest-merge/interactive"; then
        state="rebase-i"
        branch="$(cat "$git_dir/.dotest-merge/head-name")"
    elif test -d "$git_dir/.dotest-merge"; then
        state="rebase-m"
        branch="$(cat "$git_dir/.dotest-merge/head-name")"
    elif test -f "$git_dir/MERGE_HEAD"; then
        state="merge"
        branch="$(git symbolic-ref HEAD 2>/dev/null)"
    else
        test -f "$git_dir/BISECT_LOG" && state="bisect"
        branch="$(git symbolic-ref HEAD 2>/dev/null)" || \
            branch="$(git describe --exact-match HEAD 2>/dev/null)" || \
            branch="$(cut -c1-7 "$git_dir/HEAD")..."
    fi

    branch="${branch#refs/heads/}"

    if test "$state" ; then
        state=":$state"
    fi

    case $git_dir in 
        .git) git_dir="$(pwd)/.git";;
    esac 

    export __ZSH_GIT_STATE="%{$fg[cyan]%}(${branch}${state})"
    export __ZSH_GIT_DIR="${${git_dir:h}/$HOME/~}"
}

function _prompt_compute_vars() {
    _git_compute_vars

    local git_dir
    git_dir=${${__ZSH_GIT_DIR}%% }

    local short
    short="${PWD/$HOME/~}"

    if test -z "$git_dir" ; then
            export __ZSH_RPROMPT_DIR="$short"
            return
    fi

    local lead rest
    lead=$git_dir
    rest=${${short#$lead}#/}

    export __ZSH_RPROMPT_DIR="$lead%{$fg[cyan]%}/$rest"
}

function _git_preexec_update_vars() {
    case "$(history $HISTCMD)" in 
        *git*) _git_compute_vars ;;
    esac
}

setopt prompt_subst

autoload -U colors
colors

_prompt_compute_vars

PROMPT='${WINDOW:+"[$WINDOW]"}%{$fg[green]%}${USER}%{$fg[blue]%}@%{$fg[red]%}`hostname -s`${__ZSH_GIT_STATE}%{$fg[green]%}%#%{$reset_color%} '
RPROMPT='%{$fg[yellow]%}[${__ZSH_RPROMPT_DIR}%{$fg[red]%}:%!%{$fg[yellow]%}]%{$reset_color%}'

.zshrc 抜粋

function chpwd () {
    _reg_pwd_screennum
    _prompt_compute_vars
    _color_ls
}

function preexec () {
    _git_preexec_update_vars
}