]> git.rmz.io Git - dotfiles.git/blob - zsh/lib/prompt.zsh
zsh: vi-mode and new prompt
[dotfiles.git] / zsh / lib / prompt.zsh
1 hostcolor=green
2 [[ $(hostname) == "tardis" ]] && hostcolor=red
3
4 precmd() {
5 PROMPT='%T %n@%{$fg[$hostcolor]%}%m%{$reset_color%}%-0>..>$(git_prompt_status)%>>
6 %(?..%{$fg_bold[white]%}%?%{$reset_color%})$(vi_prompt_info)%{%(!.$fg[red]❰.$fg[green]❱)%1G%} '
7 RPROMPT='%{$fg[green]%}%~%{$reset_color%}'
8 }
9
10 vi_prompt_info() {
11 local vicmd="$fg_bold[green]❰$reset_color%1G"
12 local viins="$fg_bold[blue]❱$reset_color%1G"
13 printf '%s' "%{${${KEYMAP/vicmd/$vicmd}/(main|viins)/$viins}%}"
14 }
15
16 function zle-line-init zle-line-finish zle-keymap-select {
17 zle reset-prompt
18 zle -R
19 }
20
21 zle -N zle-line-init
22 zle -N zle-line-finish
23 zle -N zle-keymap-select
24
25 # reset zle on resize
26 TRAPWINCH() {
27 zle && { zle reset-prompt; zle -R }
28 }
29
30 # Get the status of the working tree
31 git_prompt_status() {
32 local branch ahead behind
33 local added deleted modified renamed unmerged untracked dirty
34 # Use porcelain status for easy parsing.
35 local status_cmd="git status --porcelain -b"
36
37 # Get current status.
38 while IFS=$'\n' read line; do
39 if [[ "$line" == \#\#\ * ]]; then
40 [[ "$line" =~ '## ([^.]*)\.\.\.(.*)' ]] && branch=$match[1]
41 [[ "$line" =~ 'ahead ([0-9]+)' ]] && ahead=$match[1]
42 [[ "$line" =~ 'behind ([0-9]+)' ]] && behind=$match[1]
43 else
44 # Count added, deleted, modified, renamed, unmerged, untracked, dirty.
45 # T (type change) is undocumented, see http://git.io/FnpMGw.
46 # index
47 [[ "$line" == M[\ MTD]\ * ]] && (( updated++ ))
48 [[ "$line" == [AC][\ MTD]\ * ]] && (( added++ ))
49 [[ "$line" == D[\ MT]\ * ]] && (( deleted++ ))
50 [[ "$line" == R[\ MTD]\ * ]] && (( renamed++ ))
51
52 # work tree
53 [[ "$line" == [\ MARCT]M\ * ]] && (( modified++ ))
54 [[ "$line" == [\ MARCT]D\ * ]] && (( deleted_wt++ ))
55 [[ "$line" == \?\?\ * ]] && (( untracked++ ))
56
57 # morge conflicts
58 [[ "$line" == (AA|DD|U?|?U)\ * ]] && (( unmerged++ ))
59 fi
60 done < <(${(z)status_cmd} 2> /dev/null)
61
62 local git_status=" %{$fg[yellow]%}"
63
64 # Format branch
65 if [[ -n $branch ]]; then
66 git_status+="$branch"
67 else
68 git_status+="$(git rev-parse --short HEAD 2> /dev/null)"
69 [[ $? -ne 0 ]] && return
70 fi
71
72 # Format upstream
73 local upstream_str
74 (( ahead > 0 )) && upstream_str+="%{$fg[blue]%} >$ahead"
75 (( behind > 0 )) && upstream_str+="%{$fg[blue]%} <$behind"
76 git_status+="$upstream_str"
77
78 # Format stashed
79 stashed=$(git stash list | wc -l)
80 if (( stashed > 0 )) then
81 stashed_str+="%{$fg_bold[cyan]%} ⋎$stashed%{$reset_color%}"
82 fi
83 git_status+="$stashed_str"
84
85 # Format index
86 local index_str
87 (( updated > 0 )) && index_str+="%{$fg[green]%} *$updated"
88 (( added > 0 )) && index_str+="%{$fg[green]%} +$added"
89 (( deleted > 0 )) && index_str+="%{$fg[green]%} -$deleted"
90 (( renamed > 0 )) && index_str+="%{$fg[green]%} ≈$renamed"
91 git_status+="$index_str"
92
93 # Format working tree
94 local wt_str
95 (( modified > 0 )) && wt_str+="%{$fg[red]%} *$modified"
96 (( deleted_wt > 0 )) && wt_str+="%{$fg[red]%} -$deleted_wt"
97 (( untracked > 0 )) && wt_str+="%{$fg[red]%} +$untracked"
98 (( unmerged > 0 )) && wt_str+="%{$fg[magenta]%} ♒$unmerged"
99 git_status+="$wt_str"
100
101 git_status+="%{$reset_color%}"
102
103 echo $git_status
104 }
105
106 function print_if_fits() {
107 local zero length
108
109 zero='%([BSUbfksu]|([FB]|){*})'
110 length=${#${(S%%)1//$~zero/}}
111 echo "%-$length(l.$1.)"
112 }