mirror of
https://github.com/samsonjs/config.git
synced 2026-06-25 05:09:09 +00:00
Bold magenta on the unique prefix, gray on the rest, matching jj's own log output. Gray parens instead of yellow. Empty marker moved to the diff-stat slot for a uniform layout.
395 lines
10 KiB
Text
395 lines
10 KiB
Text
# sjs's prompt theme
|
|
|
|
autoload -U zgitinit
|
|
zgitinit
|
|
|
|
prompt_sjs_help () {
|
|
cat <<'EOF'
|
|
|
|
prompt sjs
|
|
|
|
EOF
|
|
}
|
|
|
|
revstring() {
|
|
git describe --always $1 2>/dev/null ||
|
|
git rev-parse --short $1 2>/dev/null
|
|
}
|
|
|
|
coloratom() {
|
|
local off=$1 atom=$2
|
|
if [[ $atom[1] == [[:upper:]] ]]; then
|
|
off=$(( $off + 60 ))
|
|
fi
|
|
echo $(( $off + $colorcode[${(L)atom}] ))
|
|
}
|
|
colorword() {
|
|
local fg=$1 bg=$2 att=$3
|
|
local -a s
|
|
|
|
if [ -n "$fg" ]; then
|
|
s+=$(coloratom 30 $fg)
|
|
fi
|
|
if [ -n "$bg" ]; then
|
|
s+=$(coloratom 40 $bg)
|
|
fi
|
|
if [ -n "$att" ]; then
|
|
s+=$attcode[$att]
|
|
fi
|
|
|
|
echo "%{"$'\e['${(j:;:)s}m"%}"
|
|
}
|
|
|
|
prompt_sjs_setup() {
|
|
typeset -A colorcode
|
|
colorcode[black]=0
|
|
colorcode[red]=1
|
|
colorcode[green]=2
|
|
colorcode[yellow]=3
|
|
colorcode[blue]=4
|
|
colorcode[magenta]=5
|
|
colorcode[cyan]=6
|
|
colorcode[white]=7
|
|
colorcode[default]=9
|
|
colorcode[k]=$colorcode[black]
|
|
colorcode[r]=$colorcode[red]
|
|
colorcode[g]=$colorcode[green]
|
|
colorcode[y]=$colorcode[yellow]
|
|
colorcode[b]=$colorcode[blue]
|
|
colorcode[m]=$colorcode[magenta]
|
|
colorcode[c]=$colorcode[cyan]
|
|
colorcode[w]=$colorcode[white]
|
|
colorcode[.]=$colorcode[default]
|
|
|
|
typeset -A attcode
|
|
attcode[none]=00
|
|
attcode[bold]=01
|
|
attcode[faint]=02
|
|
attcode[standout]=03
|
|
attcode[underline]=04
|
|
attcode[blink]=05
|
|
attcode[reverse]=07
|
|
attcode[conceal]=08
|
|
attcode[normal]=22
|
|
attcode[no-standout]=23
|
|
attcode[no-underline]=24
|
|
attcode[no-blink]=25
|
|
attcode[no-reverse]=27
|
|
attcode[no-conceal]=28
|
|
|
|
local -A pc
|
|
pc[default]='default'
|
|
pc[date]='cyan'
|
|
pc[time]='Black'
|
|
pc[host]='Green'
|
|
pc[user]='cyan'
|
|
pc[punc]='yellow'
|
|
pc[line]='magenta'
|
|
pc[hist]='green'
|
|
pc[path]='Cyan'
|
|
pc[shortpath]='default'
|
|
pc[rc]='red'
|
|
pc[scm_branch]='Cyan'
|
|
pc[scm_commitid]='Yellow'
|
|
pc[scm_changeid]='Magenta'
|
|
pc[scm_changeid_rest]='Black'
|
|
pc[paren]='Black'
|
|
pc[scm_status_dirty]='Red'
|
|
pc[scm_status_staged]='Green'
|
|
pc[#]='Yellow'
|
|
for cn in ${(k)pc}; do
|
|
pc[${cn}]=$(colorword $pc[$cn])
|
|
done
|
|
pc[scm_changeid]=$(colorword Magenta . bold)
|
|
pc[scm_changeid_rest]=$(colorword Black . normal)
|
|
pc[reset]=$(colorword . . 00)
|
|
|
|
typeset -Ag sjs_prompt_colors
|
|
sjs_prompt_colors=(${(kv)pc})
|
|
|
|
local p_rc
|
|
|
|
PROMPT=
|
|
PROMPT+="\$(prompt_sjs_scm_jj)"
|
|
PROMPT+="$pc[time][%t]$pc[reset] "
|
|
PROMPT+="%(?..$pc[rc]-%1v- $pc[reset])"
|
|
PROMPT+="$pc[path]%(2~.%~.%/)$pc[reset]"
|
|
PROMPT+="\$(prompt_sjs_scm_branch)"
|
|
PROMPT+=" $pc[#]%#$pc[reset] "
|
|
|
|
RPROMPT="$pc[user]%n$pc[reset]@$pc[host]%m$pc[reset]"
|
|
|
|
export PROMPT RPROMPT
|
|
precmd_functions+='prompt_sjs_precmd'
|
|
}
|
|
|
|
prompt_sjs_precmd() {
|
|
local ex=$?
|
|
psvar=()
|
|
|
|
if [[ $ex -ge 128 ]]; then
|
|
sig=$signals[$ex-127]
|
|
psvar[1]="sig${(L)sig}"
|
|
else
|
|
psvar[1]="$ex"
|
|
fi
|
|
}
|
|
|
|
prompt_sjs_scm_status() {
|
|
zgit_isgit || return
|
|
local -A pc
|
|
pc=(${(kv)sjs_prompt_colors})
|
|
|
|
head=$(zgit_head)
|
|
gitcommit=$(revstring $head)
|
|
|
|
local -a commits
|
|
|
|
if zgit_rebaseinfo; then
|
|
orig_commit=$(revstring $zgit_info[rb_head])
|
|
orig_name=$(git name-rev --name-only $zgit_info[rb_head])
|
|
orig="$pc[scm_branch]$orig_name$pc[punc]($pc[scm_commitid]$orig_commit$pc[punc])"
|
|
onto_commit=$(revstring $zgit_info[rb_onto])
|
|
onto_name=$(git name-rev --name-only $zgit_info[rb_onto])
|
|
onto="$pc[scm_branch]$onto_name$pc[punc]($pc[scm_commitid]$onto_commit$pc[punc])"
|
|
|
|
if [ -n "$zgit_info[rb_upstream]" ] && [ $zgit_info[rb_upstream] != $zgit_info[rb_onto] ]; then
|
|
upstream_commit=$(revstring $zgit_info[rb_upstream])
|
|
upstream_name=$(git name-rev --name-only $zgit_info[rb_upstream])
|
|
upstream="$pc[scm_branch]$upstream_name$pc[punc]($pc[scm_commitid]$upstream_commit$pc[punc])"
|
|
commits+="rebasing $upstream$pc[reset]..$orig$pc[reset] onto $onto$pc[reset]"
|
|
else
|
|
commits+="rebasing $onto$pc[reset]..$orig$pc[reset]"
|
|
fi
|
|
|
|
local -a revs
|
|
revs=($(git rev-list $zgit_info[rb_onto]..HEAD))
|
|
if [ $#revs -gt 0 ]; then
|
|
commits+="\n$#revs commits in"
|
|
fi
|
|
|
|
if [ -f $zgit_info[dotest]/message ]; then
|
|
mess=$(head -n1 $zgit_info[dotest]/message)
|
|
commits+="on $mess"
|
|
fi
|
|
elif [ -n "$gitcommit" ]; then
|
|
local track_merge=$(zgit_tracking_merge)
|
|
if [ -n "$track_merge" ]; then
|
|
if git rev-parse --verify -q $track_merge >/dev/null; then
|
|
local track_remote=$(zgit_tracking_remote)
|
|
local tracked=$(revstring $track_merge 2>/dev/null)
|
|
|
|
local -a revs
|
|
revs=($(git rev-list --reverse $track_merge..HEAD))
|
|
if [ $#revs -gt 0 ]; then
|
|
local base=$(revstring $revs[1]~1)
|
|
local base_name=$(git name-rev --name-only $base)
|
|
local base_short=$(revstring $base)
|
|
local word_commits
|
|
if [ $#revs -gt 1 ]; then
|
|
word_commits='commits'
|
|
else
|
|
word_commits='commit'
|
|
fi
|
|
|
|
local conj="since"
|
|
if [[ "$base" == "$tracked" ]]; then
|
|
conj+=" tracked"
|
|
tracked=
|
|
fi
|
|
commits+="$#revs $word_commits $conj $pc[scm_branch]$base_name$pc[punc]($pc[scm_commitid]$base_short$pc[punc])$pc[reset]"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
gitsvn=$(git rev-parse --verify -q --short git-svn)
|
|
if [ $? -eq 0 ]; then
|
|
gitsvnrev=$(zgit_svnhead $gitsvn)
|
|
gitsvn=$(revstring $gitsvn)
|
|
if [ -n "$gitsvnrev" ]; then
|
|
local svninfo=''
|
|
local -a revs
|
|
svninfo+="$pc[default]svn$pc[punc]:$pc[scm_branch]r$gitsvnrev"
|
|
revs=($(git rev-list git-svn..HEAD))
|
|
if [ $#revs -gt 0 ]; then
|
|
svninfo+="$pc[punc]@$pc[default]HEAD~$#revs"
|
|
svninfo+="$pc[punc]($pc[scm_commitid]$gitsvn$pc[punc])"
|
|
fi
|
|
commits+=$svninfo
|
|
fi
|
|
fi
|
|
|
|
if [ $#commits -gt 0 ]; then
|
|
echo -n " ${(j: :)commits}"
|
|
fi
|
|
}
|
|
|
|
prompt_sjs_in_jj() {
|
|
local d=$PWD
|
|
while [[ $d != / && -n $d ]]; do
|
|
[[ -d $d/.jj ]] && return 0
|
|
d=${d:h}
|
|
done
|
|
return 1
|
|
}
|
|
|
|
prompt_sjs_scm_jj() {
|
|
prompt_sjs_in_jj || return
|
|
local -A pc
|
|
pc=(${(kv)sjs_prompt_colors})
|
|
|
|
# sep: outer field separator. rsep: between parent records. fsep: within a parent record.
|
|
local sep=$'\x1f' rsep=$'\x1e' fsep=$'\x1d'
|
|
local tmpl='
|
|
change_id.shortest(8).prefix() ++ "'$sep'" ++
|
|
change_id.shortest(8).rest() ++ "'$sep'" ++
|
|
bookmarks.join(",") ++ "'$sep'" ++
|
|
if(empty, "1", "") ++ "'$sep'" ++
|
|
if(conflict, "1", "") ++ "'$sep'" ++
|
|
if(divergent, "1", "") ++ "'$sep'" ++
|
|
parents.map(|p|
|
|
p.bookmarks().join(",") ++ "'$fsep'" ++
|
|
p.change_id().shortest(8).prefix() ++ "'$fsep'" ++
|
|
p.change_id().shortest(8).rest()
|
|
).join("'$rsep'") ++ "'$sep'" ++
|
|
parents.map(|p| p.description().first_line()).join(" / ") ++ "'$sep'" ++
|
|
description.first_line()
|
|
'
|
|
|
|
local info
|
|
info=$(jj log -r @ --no-graph --color=never -T "$tmpl" 2>/dev/null) || return
|
|
|
|
local change_prefix change_rest bookmarks empty conflict divergent parents_data parent_desc desc
|
|
IFS=$sep read -r change_prefix change_rest bookmarks empty conflict divergent parents_data parent_desc desc <<< "$info"
|
|
|
|
local -a parent_records
|
|
parent_records=("${(@ps.$rsep.)parents_data}")
|
|
|
|
# splice parent_desc into the parens only for the single-parent case
|
|
local desc_in_parens=0
|
|
if [ -z "$desc" ] && [ -n "$parent_desc" ] && [ ${#parent_records} -eq 1 ] && [ -n "$parent_records[1]" ]; then
|
|
desc_in_parens=1
|
|
fi
|
|
|
|
local -a parent_displays
|
|
local rec
|
|
for rec in "${parent_records[@]}"; do
|
|
[ -z "$rec" ] && continue
|
|
local -a pf
|
|
pf=("${(@ps.$fsep.)rec}")
|
|
local p_bookmarks=$pf[1]
|
|
local p_prefix=$pf[2]
|
|
local p_rest=$pf[3]
|
|
local parent_str="$p_bookmarks$pc[paren]($pc[scm_changeid]$p_prefix$pc[scm_changeid_rest]$p_rest"
|
|
if [ $desc_in_parens -eq 1 ]; then
|
|
local truncated=$parent_desc
|
|
[ ${#parent_desc} -gt 60 ] && truncated="${parent_desc[1,60]}…"
|
|
truncated=${truncated//\%/%%}
|
|
parent_str+=" $pc[default]\"$truncated\"$pc[scm_branch]"
|
|
fi
|
|
parent_str+="$pc[paren])$pc[scm_branch]"
|
|
parent_displays+=$parent_str
|
|
done
|
|
local parent_display="${(j: / :)parent_displays}"
|
|
|
|
local desc_suffix=
|
|
if [ -n "$desc" ]; then
|
|
local truncated=$desc
|
|
[ ${#desc} -gt 80 ] && truncated="${desc[1,80]}…"
|
|
truncated=${truncated//\%/%%}
|
|
desc_suffix=" $pc[default]\"$truncated\"$pc[reset]"
|
|
elif [ -n "$parent_desc" ] && [ $desc_in_parens -eq 0 ]; then
|
|
local truncated=$parent_desc
|
|
[ ${#parent_desc} -gt 60 ] && truncated="${parent_desc[1,60]}…"
|
|
truncated=${truncated//\%/%%}
|
|
desc_suffix=" $pc[default]← \"$truncated\"$pc[reset]"
|
|
fi
|
|
|
|
local out=
|
|
local -a prefix_flags
|
|
[ -n "$conflict" ] && prefix_flags+='!'
|
|
[ -n "$divergent" ] && prefix_flags+=$'≠'
|
|
if [ $#prefix_flags -gt 0 ]; then
|
|
out+="$pc[scm_status_dirty]${(j::)prefix_flags}$pc[reset] "
|
|
fi
|
|
out+="$pc[scm_changeid]$change_prefix$pc[scm_changeid_rest]$change_rest$pc[reset]"
|
|
if [ -n "$bookmarks" ]; then
|
|
out+="$pc[paren]($pc[scm_branch]$bookmarks$pc[paren])$pc[reset]"
|
|
fi
|
|
|
|
if [ -n "$empty" ]; then
|
|
out+=" $pc[scm_status_dirty]∅$pc[reset]"
|
|
else
|
|
local summary
|
|
summary=$(jj diff --stat -r @ --ignore-working-copy 2>/dev/null | tail -n1)
|
|
local ins=0 del=0
|
|
[[ $summary =~ '([0-9]+) insertion' ]] && ins=$match[1]
|
|
[[ $summary =~ '([0-9]+) deletion' ]] && del=$match[1]
|
|
if [ "$ins" != 0 ] || [ "$del" != 0 ]; then
|
|
out+=" $pc[scm_status_staged]+$ins$pc[reset]/$pc[scm_status_dirty]-$del$pc[reset]"
|
|
fi
|
|
|
|
local summary_out
|
|
summary_out=$(jj diff --summary -r @ --ignore-working-copy 2>/dev/null)
|
|
local added=0 modified=0 deleted=0
|
|
local line
|
|
while IFS= read -r line; do
|
|
case "$line" in
|
|
'A '*) (( added++ )) ;;
|
|
'M '*|'R '*|'C '*) (( modified++ )) ;;
|
|
'D '*) (( deleted++ )) ;;
|
|
esac
|
|
done <<< "$summary_out"
|
|
local -a amd
|
|
[ $added -gt 0 ] && amd+="$pc[scm_status_staged]A$added$pc[reset]"
|
|
[ $modified -gt 0 ] && amd+="$pc[scm_commitid]M$modified$pc[reset]"
|
|
[ $deleted -gt 0 ] && amd+="$pc[scm_status_dirty]D$deleted$pc[reset]"
|
|
if [ $#amd -gt 0 ]; then
|
|
out+=" ${(j: :)amd}"
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$parent_display" ]; then
|
|
out+=" $pc[default]on $pc[scm_branch]$parent_display$pc[reset]"
|
|
fi
|
|
out+="$desc_suffix"
|
|
|
|
print -rn -- "$out"$'\n'"%{%}"
|
|
}
|
|
|
|
prompt_sjs_scm_branch() {
|
|
zgit_isgit || return
|
|
prompt_sjs_in_jj && return
|
|
local -A pc
|
|
pc=(${(kv)sjs_prompt_colors})
|
|
|
|
echo -n "$pc[punc]:$pc[scm_branch]$(zgit_head)"
|
|
|
|
if zgit_inworktree; then
|
|
if ! zgit_isindexclean; then
|
|
echo -n "$pc[scm_status_staged]+"
|
|
fi
|
|
|
|
local -a dirty
|
|
if ! zgit_isworktreeclean; then
|
|
dirty+='!'
|
|
fi
|
|
|
|
if zgit_hasunmerged; then
|
|
dirty+='*'
|
|
fi
|
|
|
|
if zgit_hasuntracked; then
|
|
dirty+='?'
|
|
fi
|
|
|
|
if [ $#dirty -gt 0 ]; then
|
|
echo -n "$pc[scm_status_dirty]${(j::)dirty}"
|
|
fi
|
|
fi
|
|
|
|
echo $pc[reset]
|
|
}
|
|
|
|
prompt_sjs_setup "$@"
|