# lean prompt theme
# by Miek Gieben: https://github.com/miekg/lean
#
# Based on Pure by Sindre Sorhus: https://github.com/sindresorhus/pure
# Colors used: (see Vim's iceberg theme)
# 242 is the gray that is used.
# 110 is the blue.
# 150 is the yellow.
#
# MIT License

COLOR1=${PROMPT_LEAN_COLOR1-"242"}
COLOR2=${PROMPT_LEAN_COLOR2-"110"}
COLOR3=${PROMPT_LEAN_COLOR3-"150"}

PROMPT_LEAN_TMUX=${PROMPT_LEAN_TMUX-"t "}
PROMPT_LEAN_PATH_PERCENT=${PROMPT_LEAN_PATH_PERCENT-60}
PROMPT_LEAN_NOTITLE=${PROMPT_LEAN_NOTITLE-0}
PROMPT_LEAN_CMD_MAX_EXEC_TIME=5
PROMPT_LEAN_ABBR_METHOD=${PROMPT_LEAN_ABBR_METHOD-"truncate"}
PROMPT_LEAN_VCS=${PROMPT_LEAN_VCS-1}
PROMPT_LEAN_PWD=${PROMPT_LEAN_PWD-1}

prompt_lean_help() {
  cat <<'EOF'
Lean is a one line prompt that tries to stay out of your face. It utilizes
the right side prompt for most information, like the current working directory
and version control system (only Git)info. The left side of the prompt is only
a '%'. The only other information shown on the left are the jobs numbers of
background jobs. When the exit code of a process isn't zero the prompt turns
red. If a process takes more then 5 (default) seconds to run the total running
time is shown in the next prompt.

You can invoke it thus:

  prompt lean

Several aspects Lean can be configured:

PROMPT_LEAN_TMUX:   used to indicate being in tmux, set to "t " by default
PROMPT_LEAN_LEFT:   executed to allow custom information in the left side
PROMPT_LEAN_RIGHT:  executed to allow custom information in the right side
PROMPT_LEAN_COLOR1: jobs and VCS info indicator color
PROMPT_LEAN_COLOR2: prompt character and directory color
PROMPT_LEAN_COLOR3: elapsed time indicator color
PROMPT_LEAN_VIMODE: used to determine whether or not to display indicator
PROMPT_LEAN_PWD:    when set to 0, disables showing CWD in the prompt
PROMPT_LEAN_VCS:    when set to 0, disables git details from the prompt, the
                    branch name is truncated if it's longer than 20
                    characters
PROMPT_LEAN_VIMODE_FORMAT:
                    defaults to "%F{red}[NORMAL]%f"
PROMPT_LEAN_NOTITLE:
                    used to determine wether or not to set title, set to 0
                    by default
PROMPT_LEAN_ABBR_METHOD:
                    used to indicate the abbreviation method for directory
                    paths. Set it either to 'truncate' (default) or 'shrink'
                    (fish-style working directory)
EOF
}

# turns seconds into human readable time, 165392 => 1d 21h 56m 32s
prompt_lean_human_time() {
    local tmp=$1
    local days=$(( tmp / 60 / 60 / 24 ))
    local hours=$(( tmp / 60 / 60 % 24 ))
    local minutes=$(( tmp / 60 % 60 ))
    local seconds=$(( tmp % 60 ))
    (( $days > 0 )) && echo -n "${days}d "
    (( $hours > 0 )) && echo -n "${hours}h "
    (( $minutes > 0 )) && echo -n "${minutes}m "
    echo "${seconds}s "
}

# fastest possible way to check if repo is dirty
prompt_lean_git_dirty() {
    if [[ $PROMPT_LEAN_VCS != 1 ]]; then
        return
    fi
    # check if we're in a git repo
    command git rev-parse --is-inside-work-tree &>/dev/null || return
    # check if it's dirty
    local umode="-uno" #|| local umode="-unormal"
    command test -n "$(git status --porcelain --ignore-submodules ${umode} 2>/dev/null | head -100)"

    (($? == 0)) && echo '+'
}

# displays the exec time of the last command if set threshold was exceeded
prompt_lean_cmd_exec_time() {
    local stop=$EPOCHSECONDS
    local start=${cmd_timestamp:-$stop}
    integer elapsed=$stop-$start
    (($elapsed > ${PROMPT_LEAN_CMD_MAX_EXEC_TIME})) && prompt_lean_human_time $elapsed
}

prompt_lean_set_title() {
    # prints: <cwd><space><optional machine if ssh - like rprompt><space><command>
    print -Pn "\e]0;"
    print -Pn "%1~"
    [[ "$SSH_CONNECTION" != '' ]] && print -Pn " %m"
    print -rn "     $1"
    print -Pn "\a"
}

prompt_lean_preexec() {
    typeset -g cmd_timestamp=$EPOCHSECONDS
    (($PROMPT_LEAN_NOTITLE != 1)) && prompt_lean_set_title "$1"
}

prompt_lean_pwd() {
    local lean_path="`print -Pn '%~'`"
    if (($#lean_path / $COLUMNS.0 * 100 > ${PROMPT_LEAN_PATH_PERCENT:=60})); then
		case "$PROMPT_LEAN_ABBR_METHOD" in
			"truncate") prompt_lean_abbr_truncate;;
			"shrink")   prompt_lean_abbr_shrink;;
		esac
        return
    fi
    print "$lean_path"
}

prompt_lean_abbr_truncate() {
	print -Pn '...%2/'
}

prompt_lean_abbr_shrink() {
	setopt local_options extendedglob histsubstpattern

	local lean_path=$(print -Pn '%~')
	local maxlen=$((PROMPT_LEAN_PATH_PERCENT * COLUMNS / 100))
	local prevlen=0

	# iterate until target length achieved or no more abbreviation possible
	while (($#lean_path > maxlen && $#lean_path != prevlen)); do
		prevlen=$#lean_path
		lean_path=${lean_path:s_(#b)([^/])([^/])##/_$match[1]/_}
	done

	echo $lean_path
}

prompt_lean_precmd() {
    [[ $PROMPT_LEAN_VCS == 1 ]] && vcs_info 2>/dev/null
    rehash

    local jobs
    local prompt_lean_jobs
    unset jobs
    for a (${(k)jobstates}) {
        j=$jobstates[$a];i='${${(@s,:,)j}[2]}'
        jobs+=($a${i//[^+-]/})
    }
    # print with [ ] and comma separated
    prompt_lean_jobs=""
    [[ -n $jobs ]] && prompt_lean_jobs="%F{"$COLOR1"}["${(j:,:)jobs}"] "

    local lean_vimode_default="%F{red}[NORMAL]%f"
    #If LEAN_VIMODE is set, set lean_vimode_indicator to either PROMPT_LEAN_VIMOD_FORMAT or a default value
    local lean_vimode_indicator="${PROMPT_LEAN_VIMODE:+${PROMPT_LEAN_VIMODE_FORMAT:-${lean_vimode_default}}}"

    prompt_lean_vimode="${${KEYMAP/vicmd/$lean_vimode_indicator}/(main|viins)/}"

    setopt promptsubst
    local vcs_info_str=''
    [[ $PROMPT_LEAN_VCS == 1 ]] && vcs_info_str='$vcs_info_msg_0_' # avoid https://github.com/njhartwell/pw3nage
    PROMPT="$prompt_lean_jobs%F{"$COLOR3"}${prompt_lean_tmux}%f`$PROMPT_LEAN_LEFT`%f%(?.%F{"$COLOR2"}.%B%F{203})%#%f%k%b "

    local lean_pwd=''
    [[ $PROMPT_LEAN_PWD == 1 ]] && lean_pwd=`prompt_lean_pwd`
    RPROMPT="%F{"$COLOR3"}`prompt_lean_cmd_exec_time`%f$prompt_lean_vimode%F{"$COLOR2"}$lean_pwd%F{"$COLOR1"}$vcs_info_str`prompt_lean_git_dirty`$prompt_lean_host%f`$PROMPT_LEAN_RIGHT`%f"

    (($PROMPT_LEAN_NOTITLE != 1)) && prompt_lean_set_title "$1"

    unset cmd_timestamp # reset value since `preexec` isn't always triggered
}

function zle-keymap-select {
    prompt_lean_precmd
    zle reset-prompt
}

prompt_lean_setup() {
    prompt_opts=(cr percent sp subst)

    zmodload zsh/datetime
    autoload -Uz add-zsh-hook
    [[ $PROMPT_LEAN_VCS == 1 ]] && autoload -Uz vcs_info

    [[ "$PROMPT_LEAN_VIMODE" != '' ]] && zle -N zle-keymap-select

    add-zsh-hook precmd prompt_lean_precmd
    add-zsh-hook preexec prompt_lean_preexec

    if [[ $PROMPT_LEAN_VCS == 1 ]]; then
        zstyle ':vcs_info:*' enable git
        zstyle ':vcs_info:git*' formats ' %20>...>%b%>>'
        zstyle ':vcs_info:git*' actionformats ' %20>...>%b%>>|%a'
    fi

    [[ "$SSH_CONNECTION" != '' ]] && prompt_lean_host=" %F{"$COLOR3"}%m%f"
    [[ "$TMUX" != '' ]] && prompt_lean_tmux=$PROMPT_LEAN_TMUX

    return 0
}

prompt_lean_setup "$@"
