decl str docsclient

hook global WinSetOption filetype=git-log %{
    addhl group git-log-highlight
    addhl -group git-log-highlight regex '^(commit) ([0-9a-f]+)$' 1:yellow 2:red
    addhl -group git-log-highlight regex '^([a-zA-Z_-]+:) (.*?)$' 1:green 2:magenta
}

hook global WinSetOption filetype=(?!git-log).* %{
    rmhl git-log-highlight
}

decl line-flag-list git_blame_flags
decl line-flag-list git_diff_flags

def -shell-params git %{ %sh{
    show_git_cmd_output() {
        local filetype
        case "$1" in
           show|diff) filetype=diff ;;
           log)  filetype=git-log ;;
        esac
        tmpfile=$(mktemp /tmp/kak-git-XXXXXX)
        if git "$@" > ${tmpfile}; then
            [ -n "$kak_opt_docsclient" ] && echo "eval -client '$kak_opt_docsclient' %{"

            echo "edit! -scratch *git*
                  exec |cat<space>${tmpfile}<ret>gk
                  nop %sh{rm ${tmpfile}}
                  set buffer filetype '${filetype}'"

            [ -n "$kak_opt_docsclient" ] && echo "}"
        else
           echo "echo %{git $@ failed, see *debug* buffer}"
           rm ${tmpfile}
        fi
    }

    run_git_blame() {
        (
            echo "eval -client '$kak_client' %{
                      try %{ addhl flag_lines magenta git_blame_flags }
                      set buffer=$kak_buffile git_blame_flags ''
                  }" | kak -p ${kak_session}
            declare -A authors
            declare -A dates
            send_flags() {
                if [ -z "$line" ]; then return; fi
                text=$(echo "${sha:0:8} ${dates[$sha]} ${authors[$sha]}" | sed -e 's/:/\\:/g')
                flag="$line|black|$text"
                for (( i=1; $i < $count; i++ )); do
                    flag="$flag:$(($line+$i))|black|$text"
                done
                echo "set -add buffer=$kak_buffile git_blame_flags %{${flag}}" | kak -p ${kak_session}
            }
            git blame --incremental $kak_buffile | ( while read blame_line; do
                if [[ $blame_line =~ ([0-9a-f]{40}).([0-9]+).([0-9]+).([0-9]+) ]]; then
                    send_flags
                    sha=${BASH_REMATCH[1]}
                    line=${BASH_REMATCH[3]}
                    count=${BASH_REMATCH[4]}
                elif [[ $blame_line =~ author[^-](.*) ]]; then
                    authors[$sha]=${BASH_REMATCH[1]}
                elif [[ $blame_line =~ author-time.([0-9]*) ]]; then
                    dates[$sha]="$(date -d @${BASH_REMATCH[1]} +'%F %T')"
                fi
            done; send_flags )
        ) >& /dev/null < /dev/null &
    }

    update_diff() {
        git diff -U0 $kak_buffile | {
            local line=0
            local flags="0|red|."
            while read; do
                if [[ $REPLY =~ ^---.* ]]; then
                    continue
                elif [[ $REPLY =~ ^@@.-[0-9]+(,[0-9]+)?.\+([0-9]+)(,[0-9]+)?.@@.* ]]; then
                    line=${BASH_REMATCH[2]}
                elif [[ $REPLY =~ ^\+ ]]; then
                    flags="$flags:$line|green|+"
                    ((line++))
                elif [[ $REPLY =~ ^\- ]]; then
                    flags="$flags:$line|red|-"
                fi
            done
            echo "set buffer git_diff_flags '$flags'"
        }
    }

    case "$1" in
       show|log|diff) show_git_cmd_output "$@" ;;
       blame) run_git_blame ;;
       show-diff)
           echo "try %{ addhl flag_lines black git_diff_flags }"
           update_diff
           ;;
       update-diff) update_diff ;;
       add)
           name="${2:-${kak_buffile}}"
           if git add -- "${name}"; then
              echo "echo -color Information 'git: added ${name}'"
           else
              echo "echo -color Error 'git: unable to add ${name}'"
           fi
           ;;
       *) echo "echo %{unknown git command '$1'}"; exit ;;
    esac

}}