lp-gitcrux/gitcrux.theme

486 lines
18 KiB
Text

# Center the given $1 text with spaces to fit a string of length $2.
_gitcrux_centered() {
local text width padl padr span diff i
text="$1"
width="$2"
__lp_strip_escapes "$text"
raw_text="$ret"
if (( ${#raw_text} > width )); then
# gitcrux_centered="${text:0:width-1}…"
gitcrux_centered="$text"
return 2
elif (( ${#raw_text} == width )); then
gitcrux_centered="$text"
else
span=$((width - ${#raw_text}))
diff=$(( span/2 ))
padl=""
padr=""
for (( i=0; i < diff; i++ )) ; do
padl+=" "
padr+=" "
done
if (( span % 2 > 0 )); then
padr+=" "
fi
gitcrux_centered="${padl}${text}${padr}"
fi
}
_gitcrux_arrow() {
local in start end color from to text color_body color_ends
gitcrux_arrow=""
in="$1"
start="$2"
end="$3"
color="$4"
from=$(($5 * GITCRUX_COL_WIDTH - GITCRUX_COL_WIDTH/2))
to=$(($6 * GITCRUX_COL_WIDTH - GITCRUX_COL_WIDTH/2 - 1))
text="$7"
local lp_terminal_format
lp_terminal_format ${color}
color_body="$lp_terminal_format"
lp_terminal_format -3 -1
color_ends="$lp_terminal_format"
span=$((to-from-${#start}-${#end}))
if (( from > ${#in} || to > ${#in} )); then
return 2
else
if (( ${#text} > span )); then
return 3
fi
fi
_gitcrux_centered "$text" $span
gitcrux_arrow="${in:0:from}${color_ends}${start}${color_body}${gitcrux_centered}${color_ends}${end}${NO_COL}${in:to:${#in}}"
}
_gitcrux_VCS_header() {
GITCRUX_VCS=""
local head_remote= head_repo= head_stage= head_branch=
# REMOTE
head_remote="remote" # TODO
# REPO
head_repo="${_GITCRUX_HEAD_REPO}"
local has_commit=
if _lp_vcs_commits_off_remote; then
if [[ "$lp_vcs_commit_behind" != "0" ]]; then
head_remote+="(${LP_COLOR_COMMITS_BEHIND}$lp_vcs_commit_behind${NO_COL})"
fi
if [[ "$lp_vcs_commit_ahead" != "0" ]]; then
head_repo+="(${LP_COLOR_COMMITS}$lp_vcs_commit_ahead${NO_COL})"
fi
fi
# STAGE
LP_TIME_ANALOG=1
_lp_analog_time
head_stage="$lp_analog_time"
# head_stage="STAGE"
local ret
gitcrux_has_lines=
gitcrux_has_lines_total=0
if _lp_vcs_uncommitted_files; then
_lp_vcs_unstaged_lines; ret=$?
# Only show unstaged changes if the VCS supports staging, otherwise
# show uncommitted changes
if (( ret == 0 )); then
gitcrux_has_lines="+$lp_vcs_unstaged_i_lines/-$lp_vcs_unstaged_d_lines"
gitcrux_has_lines_total=$(( gitcrux_has_lines_total + lp_vcs_unstaged_i_lines + lp_vcs_unstaged_d_lines ))
elif (( ret == 1 )); then
gitcrux_has_lines="+0/-0"
else
_lp_vcs_uncommitted_lines
gitcrux_has_lines="+$lp_vcs_uncommitted_i_lines/-$lp_vcs_uncommitted_d_lines"
gitcrux_has_lines_total=$(( gitcrux_has_lines_total + lp_vcs_uncommitted_i_lines + lp_vcs_uncommitted_d_lines ))
fi
fi
if [[ "$gitcrux_has_lines" ]]; then
head_stage="${LP_COLOR_DIFF}${gitcrux_has_lines}${NO_COL}"
fi
# BRANCH
if _lp_vcs_branch; then
head_branch="$lp_vcs_branch"
if _lp_vcs_bookmark; then
head_branch+=": $lp_vcs_bookmark"
fi
elif _lp_vcs_bookmark; then
head_branch="$lp_vcs_bookmark"
elif _lp_vcs_tag; then
head_branch="tag: $lp_vcs_tag"
else
_lp_vcs_commit_id
head_branch="${lp_vcs_commit_id:0:7}"
fi
if _lp_vcs_head_status; then
# NOTE: Replace the branch name.
head_branch="[${LP_COLOR_CHANGES}${lp_vcs_head_status}"
if [[ "${lp_vcs_head_details-}" ]]; then
head_branch+=":${lp_vcs_head_details}"
fi
head_branch+="${NO_COL}]"
fi
if _lp_vcs_untracked_files; then
head_branch+="(${LP_COLOR_CHANGES}${lp_vcs_untracked_files}${NO_COL})"
fi
# STASH
_GITCRUX_HEAD_STASH="stash"
head_stash="${_GITCRUX_HEAD_STASH}"
if _lp_vcs_stash_count; then
head_stash+="(${LP_COLOR_COMMITS}${lp_vcs_stash_count})"
fi
# COLUMNS
if [[ "$GITCRUX_COL_DYNAMIC" ]]; then
for col in "${head_remote}" "${head_repo}" "${head_stage}" "${head_branch}" "${head_stash}"; do
if (( ${#col} > GITCRUX_COL_WIDTH )); then
__lp_strip_escapes "${col}"
GITCRUX_COL_WIDTH="${#ret}"
fi
done
fi
# At least some spacing.
GITCRUX_COL_WIDTH=$((GITCRUX_COL_WIDTH+2))
gitcrux_VCS_header=""
_GITCRUX_HEADER_LINE=""
for col in "${head_remote}" "${head_repo}" "${head_stage}" "${head_branch}" "${head_stash}"; do
_gitcrux_centered "│" $GITCRUX_COL_WIDTH
_GITCRUX_HEADER_LINE+="$gitcrux_centered"
_gitcrux_centered "${col}" $GITCRUX_COL_WIDTH
gitcrux_VCS_header+="$gitcrux_centered"
done
}
_gitcrux_explain() {
local n=$'\n'
if (( GITCRUX_SHOW_EXPLANATION )); then
lp_terminal_format ${GITCRUX_COLOR_EXPLANATION}
GITCRUX_VCS+="${lp_terminal_format}${1}${NO_COL}"
fi
GITCRUX_VCS+="${n}"
}
_gitcrux_VCS() {
local n=$'\n' explanation="#"
_gitcrux_VCS_header
GITCRUX_VCS+="${gitcrux_VCS_header}${n}"
# GITCRUX_VCS+="${_GITCRUX_HEADER_LINE}${n}"
# Available states:
# - $lp_vcs_commit_behind
# - $lp_vcs_commit_ahead
# - $gitcrux_has_lines:
# - $lp_vcs_unstaged_i_lines
# - $lp_vcs_unstaged_d_lines
# OR (depending on VCS)
# - $lp_vcs_uncommitted_i_lines
# - $lp_vcs_uncommitted_d_lines
# - $lp_vcs_head_status
# - $lp_vcs_head_details
# - $lp_vcs_untracked_files
# - $lp_vcs_stash_count
# COLORS
local color_lines="$GITCRUX_COLOR_WEAK"
if (( gitcrux_has_lines_total > GITCRUX_THRESH_LINES_NORMAL )); then
if (( gitcrux_has_lines_total > GITCRUX_THRESH_LINES_STRONG )); then
color_lines="$GITCRUX_COLOR_STRONG"
else
color_lines="$GITCRUX_COLOR_NORMAL"
fi
fi
local color_behind="$GITCRUX_COLOR_WEAK"
if (( lp_vcs_commit_behind > GITCRUX_THRESH_BEHIND_NORMAL )); then
if (( lp_vcs_commit_behind > GITCRUX_THRESH_BEHIND_STRONG )); then
color_behind="$GITCRUX_COLOR_STRONG"
else
color_behind="$GITCRUX_COLOR_NORMAL"
fi
fi
local color_ahead="$GITCRUX_COLOR_WEAK"
if (( lp_vcs_commit_ahead > GITCRUX_THRESH_AHEAD_NORMAL )); then
if (( lp_vcs_commit_ahead > GITCRUX_THRESH_AHEAD_STRONG )); then
color_ahead="$GITCRUX_COLOR_STRONG"
else
color_ahead="$GITCRUX_COLOR_NORMAL"
fi
fi
local color_stash="$GITCRUX_COLOR_WEAK"
if (( lp_vcs_stash_count > GITCRUX_THRESH_STASH_NORMAL )); then
if (( lp_vcs_stash_count > GITCRUX_THRESH_STASH_STRONG )); then
color_stash="$GITCRUX_COLOR_STRONG"
else
color_stash="$GITCRUX_COLOR_NORMAL"
fi
fi
local color_add="$GITCRUX_COLOR_WEAK"
local add_count=$(( gitcrux_has_lines_total + lp_vcs_untracked_files ))
if (( add_count > GITCRUX_THRESH_ADD_NORMAL )); then
if (( add_count > GITCRUX_THRESH_ADD_STRONG )); then
color_add="$GITCRUX_COLOR_STRONG"
else
color_add="$GITCRUX_COLOR_NORMAL"
fi
fi
# FLOWCHART
if [[ "$lp_vcs_type" != "git" ]]; then
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" "${GITCRUX_ARROW_RIGHT[0]}" "${GITCRUX_ARROW_LEFT[1]}" "${GITCRUX_COLOR_MSG}" 1 5 "Unsupported VCS, cannot provide hints"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
else # VCS is git
if [[ "$lp_vcs_head_status" ]]; then
if [[ "$lp_vcs_head_status" == *"REBASE"* ]]; then
explanation+=" currently rebasing"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "${GITCRUX_COLOR_NORMAL}" 3 4 "add"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # Unknown head status.
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" "${GITCRUX_ARROW_RIGHT[0]}" "${GITCRUX_ARROW_LEFT[1]}" "${GITCRUX_COLOR_MSG}" 1 5 "Unsupported head status, cannot provide hints"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
fi
else # No specific head status.
if (( lp_vcs_commit_behind > 0 )); then
explanation+=" behind the remote"
if [[ "$gitcrux_has_lines" ]]; then
explanation+=" with $gitcrux_has_lines_total local modifications"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "$color_lines" 4 5 "save"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "$color_behind" 1 4 "pull"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$color_lines" 4 5 "pop"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # Do not have diff.
explanation+=" without local modifications"
if (( lp_vcs_stash_count > 0 )); then
explanation+=" but with $lp_vcs_stash_count stash"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "$color_behind" 1 4 "pull"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$stash_color" 4 5 "pop"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # No stash.
explanation+=" and no stash"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "$color_behind" 1 4 "pull"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
fi
fi
else # No commit behind.
if [[ "$gitcrux_has_lines" || "$lp_vcs_untracked_files" ]]; then
explanation+=" having $add_count local modification or untracked files"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$color_add" 3 4 "add"
GITCRUX_VCS+="${gitcrux_arrow}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$color_add" 2 3 "commit"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # Do not have diff.
explanation+=" no local modification nor untracked files"
if (( lp_vcs_stash_count > 0 )); then
explanation+=", but with $lp_vcs_stash_count stash"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$color_stash" 4 5 "pop"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # Do not have stash.
explanation+=" and no stash"
if (( lp_vcs_commit_ahead > 0 )); then
explanation+=", but with $lp_vcs_commit_ahead ahead of the remote"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "$color_ahead" 1 2 "push"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
else # No commit ahead.
explanation+=" and not ahead of the remote"
if [[ "$head_branch" == *"master"* || "$head_branch" == *"main"* ]]; then
explanation+=", but clean and on main/master"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "$GITCRUX_COLOR_NORMAL" 2 4 "branch"
GITCRUX_VCS+="${gitcrux_arrow}"
_gitcrux_explain "${explanation}"
fi # Main branch.
fi # Commits ahead.
fi # Stash.
fi # Has lines or untracked files.
fi # Commits behind.
fi # Head status.
fi # VCS is git.
}
_gitcrux_remove_lp_escapes() {
gitcrux_remove_lp_escapes="$1"
gitcrux_remove_lp_escapes="${gitcrux_remove_lp_escapes//"$_LP_OPEN_ESC"}"
gitcrux_remove_lp_escapes="${gitcrux_remove_lp_escapes//"$_LP_CLOSE_ESC"}"
}
# Print the whole chart of hints.
gitcrux() {
local n=$'\n'
_GITCRUX_HEAD_REPO="${PWD##*/}"
_gitcrux_VCS_header
_gitcrux_remove_lp_escapes "${gitcrux_VCS_header}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_remove_lp_escapes "${_GITCRUX_HEADER_LINE}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "0 220 1" 1 4 "pull"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "0 45 1" 2 4 "branch"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "0 183 1" 4 5 "save"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "0 46 1" 3 4 "add"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "0 202 1" 2 3 "commit"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "0 183 1" 4 5 "pop"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_RIGHT[@]} "0 208 1" 2 4 "merge master"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
_gitcrux_arrow "$_GITCRUX_HEADER_LINE" ${GITCRUX_ARROW_LEFT[@]} "0 220 1" 1 2 "push"
_gitcrux_remove_lp_escapes "${gitcrux_arrow}"
printf '%s' "${gitcrux_remove_lp_escapes}${n}"
}
# This function is called when the prompt is activated,
# either at the very beginning of the shell session,
# either when the user call `lp_theme`.
_lp_gitcrux_theme_activate() {
_lp_default_theme_activate
GITCRUX_ARROW_RIGHT=( ${GITCRUX_ARROW_RIGHT[@]+"${GITCRUX_ARROW_RIGHT[@]}"} )
[[ ${#GITCRUX_ARROW_RIGHT[@]} == 0 ]] && GITCRUX_ARROW_RIGHT=( "" "" )
GITCRUX_ARROW_LEFT=( ${GITCRUX_ARROW_LEFT[@]+"${GITCRUX_ARROW_LEFT[@]}"} )
[[ ${#GITCRUX_ARROW_LEFT[@]} == 0 ]] && GITCRUX_ARROW_LEFT=( "" "" )
# Thresholds.
GITCRUX_THRESH_BEHIND_NORMAL=${GITCRUX_THRESH_BEHIND_NORMAL:-2}
GITCRUX_THRESH_BEHIND_STRONG=${GITCRUX_THRESH_BEHIND_STRONG:-5}
GITCRUX_THRESH_AHEAD_NORMAL=${GITCRUX_THRESH_AHEAD_NORMAL:-2}
GITCRUX_THRESH_AHEAD_STRONG=${GITCRUX_THRESH_AHEAD_STRONG:-5}
GITCRUX_THRESH_LINES_NORMAL=${GITCRUX_THRESH_LINES_NORMAL:-100}
GITCRUX_THRESH_LINES_STRONG=${GITCRUX_THRESH_LINES_STRONG:-500}
GITCRUX_THRESH_ADD_NORMAL=${GITCRUX_THRESH_ADD_NORMAL:-100}
GITCRUX_THRESH_ADD_STRONG=${GITCRUX_THRESH_ADD_STRONG:-500}
GITCRUX_THRESH_STASH_NORMAL=${GITCRUX_THRESH_STASH_NORMAL:-1}
GITCRUX_THRESH_STASH_STRONG=${GITCRUX_THRESH_STASH_STRONG:-5}
# Light blue.
GITCRUX_COLOR_WEAK=${GITCRUX_COLOR_WEAK:-"0 195 0"}
# Blue bold.
GITCRUX_COLOR_NORMAL=${GITCRUX_COLOR_NORMAL:-"0 39 1"}
# Red/pink bold.
GITCRUX_COLOR_STRONG=${GITCRUX_COLOR_STRONG:-"0 220 1"}
# Grey.
GITCRUX_COLOR_MSG=${GITCRUX_COLOR_MSG:-"0 244 0"}
lp_terminal_format # Dark green.
GITCRUX_COLOR_EXPLANATION=${GITCRUX_COLOR_EXPLANATION:-"28 -1 0"}
# Width of a single column.
GITCRUX_COL_WIDTH=${GITCRUX_COL_WIDTH:-0}
# Increase column width if at least one of the column text is larger than GITCRUX_COL_WIDTH.
GITCRUX_COL_DYNAMIC=${GITCRUX_COL_DYNAMIC:-1}
# Show a sentence explaining why the hint is shown.
GITCRUX_SHOW_EXPLANATION=${GITCRUX_SHOW_EXPLANATION:-1}
}
# This function is called everytime the user change their directory.
# It should set up any data that does not change when the user stays in the same directory.
_lp_gitcrux_theme_directory() {
_lp_default_theme_directory
_GITCRUX_HEAD_REPO="${PWD##*/}"
}
# This function is called every time the prompt is displayed,
# that is, between commands.
_lp_gitcrux_theme_prompt() {
_lp_default_theme_prompt_data
local n=$'\n'
if [[ -z "${LP_PS1-}" ]]; then
# Add user-defined prefix, battery, load, temperature, wifi and jobs.
PS1="${LP_PS1_PREFIX}${LP_BATT}${LP_LOAD}${LP_TEMP}${LP_WIFI}${LP_JOBS}"
# Add multiplexer brackets, user, host, permissions colon, working directory, dirstack, proxy, watched environment variables and nested shell level.
PS1+="${LP_BRACKET_OPEN}${LP_USER}${LP_HOST}${LP_PERM}${LP_PWD}${LP_DIRSTACK}${LP_BRACKET_CLOSE}${LP_PROXY}${LP_ENVVARS}${LP_SHLVL}"
# Add the list of development environments/config/etc.
PS1+="${LP_DEV_ENV}"
# Add last runtime, return code & meaning.
PS1+="${LP_RUNTIME}${LP_ERR}${LP_ERR_MEANING}"
# Add VCS infos
# If root, the info has not been collected unless LP_ENABLE_VCS_ROOT
# is set.
if _lp_find_vcs; then
_gitcrux_VCS
PS1+="${n}${GITCRUX_VCS}"
fi
# prompt mark and user-defined postfix
PS1+="${LP_MARK_PREFIX}${LP_COLOR_MARK}${LP_MARK}${LP_PS1_POSTFIX}"
# Get the core sections without prompt escapes and make them into a title.
_lp_formatted_title "${LP_PS1_PREFIX}${LP_BRACKET_OPEN}${LP_USER}${LP_HOST}${LP_MARK_PERM}${lp_path-}${LP_BRACKET_CLOSE}${LP_MARK_PREFIX}${LP_MARK}${LP_PS1_POSTFIX}"
else
PS1=$LP_PS1
fi
}