prompt.zsh: zweizeiliger zsh-Prompt aus den CI-Token (Tinte, Knochenweiss, Markenrot nur als Grafik, Text-Rot fuer Fehlercodes, Salbei nur an Git). install.sh: idempotent, sichert jede Datei, erkennt foot/qterminal/xfce4-terminal/xterm und prueft mit zsh -n, foot --check-config und xrdb.
177 lines
6.2 KiB
Bash
177 lines
6.2 KiB
Bash
# Kalina CI – zsh-Prompt
|
||
# ---------------------------------------------------------------------------
|
||
# Zweizeiliger Prompt in der Farbwelt von "Kalina CI Dark" (VS Code).
|
||
# Farbwerte: /home/mm/kalina-ci/tokens.json + Theme-Datei
|
||
# /home/mm/vscode/kalina-ci-theme/themes/kalina-ci-dark.json
|
||
# (terminal.ansi* = dieselben Rollen wie dort)
|
||
#
|
||
# ┌─ kalina ~/Projekte/kalina-ci main ✚1 ✎2 ·(venv) · 4.2s
|
||
# └─ ❯
|
||
#
|
||
# Abschalten: KALINA_CI_PROMPT=0 (vor dem source setzen)
|
||
# Truecolor: automatisch bei COLORTERM=truecolor/24bit; erzwingen mit
|
||
# KALINA_CI_TRUECOLOR=1, abschalten mit =0
|
||
# Kein Zeilenumbruch vor dem Prompt: KALINA_CI_NO_NEWLINE=1
|
||
|
||
[[ ${KALINA_CI_PROMPT:-1} == 0 ]] && return 0
|
||
|
||
zmodload zsh/datetime 2>/dev/null
|
||
autoload -Uz add-zsh-hook 2>/dev/null || true
|
||
|
||
typeset -g _KCI_TRUECOLOR=0
|
||
typeset -g _KCI_START=0 _KCI_DUR=0 _KCI_CODE=0 _KCI_FIRST=1
|
||
typeset -g _KCI_GIT=''
|
||
|
||
case ${COLORTERM:-} in
|
||
truecolor|24bit) _KCI_TRUECOLOR=1 ;;
|
||
esac
|
||
[[ ${TERM:-} == *-direct ]] && _KCI_TRUECOLOR=1
|
||
[[ -n ${KALINA_CI_TRUECOLOR:-} ]] && _KCI_TRUECOLOR=${KALINA_CI_TRUECOLOR}
|
||
|
||
# Hex -> Vordergrund-Sequenz, in %{ %} gewickelt (zsh rechnet sie sonst als Breite)
|
||
_kci_fg() {
|
||
local s=${1#\#}
|
||
local -i r=$(( 16#${s:0:2} )) g=$(( 16#${s:2:2} )) b=$(( 16#${s:4:2} ))
|
||
if (( _KCI_TRUECOLOR )); then
|
||
print -rn -- $'%{\e[38;2;'"${r};${g};${b}"$'m%}'
|
||
else
|
||
local -i ri=$(( (r * 5 + 127) / 255 )) gi=$(( (g * 5 + 127) / 255 )) bi=$(( (b * 5 + 127) / 255 ))
|
||
print -rn -- $'%{\e[38;5;'"$(( 16 + 36 * ri + 6 * gi + bi ))"$'m%}'
|
||
fi
|
||
}
|
||
|
||
# --- Palette (Rollen wie im Theme) -----------------------------------------
|
||
typeset -g _KCI_BONE=$(_kci_fg '#F5F5EF') # Text
|
||
typeset -g _KCI_ROT=$(_kci_fg '#C1121F') # Akzent/Grafik: Pfeil, i-Punkt
|
||
typeset -g _KCI_ROT_TXT=$(_kci_fg '#E0454F') # Text-Akzent (4,7:1 auf Tinte)
|
||
typeset -g _KCI_STEEL=$(_kci_fg '#3A4250') # Linien
|
||
typeset -g _KCI_STEEL_L=$(_kci_fg '#5C6675') # Sekundär-Meta
|
||
typeset -g _KCI_MUTED=$(_kci_fg '#8A94A2') # Host, Kommentar
|
||
typeset -g _KCI_BLUE=$(_kci_fg '#A3B6CB') # Branch
|
||
typeset -g _KCI_GREEN=$(_kci_fg '#7FA88C') # nur Git "hinzugefügt"
|
||
typeset -g _KCI_YELLOW=$(_kci_fg '#C7A46B') # nur Git "geändert" / venv
|
||
typeset -g _KCI_BRIGHTROT=$(_kci_fg '#FF6B75') # root
|
||
typeset -g _KCI_RESET=$'%{\e[0m%}'
|
||
typeset -g _KCI_BOLD=$'%{\e[1m%}'
|
||
|
||
# --- Git-Zustand einsammeln (ein Aufruf, keine Locks) ----------------------
|
||
_kci_git_info() {
|
||
reply=()
|
||
local out
|
||
out=$(command git --no-optional-locks -C "${PWD}" status --porcelain=v1 -b 2>/dev/null) || return 1
|
||
[[ -z $out ]] && return 1
|
||
local line=${out%%$'\n'*}
|
||
local br=${line#\#\# }
|
||
br=${br%%...*}
|
||
br=${br%% *}
|
||
local -i ahead=0 behind=0
|
||
[[ $line == *'[ahead '* ]] && ahead=${${line#*\[ahead }%%[,\]]*}
|
||
[[ $line == *'behind '* ]] && behind=${${line#*behind }%%[,\]]*}
|
||
local -i staged=0 mod=0 untracked=0
|
||
local l
|
||
for l in ${(f)out}; do
|
||
[[ $l == \#\#* ]] && continue
|
||
case $l in
|
||
'??'*) (( untracked++ )) ;;
|
||
[MTARCD]*) (( staged++ )); [[ ${l:1:1} != ' ' ]] && (( mod++ )) ;;
|
||
' '*) (( mod++ )) ;;
|
||
esac
|
||
done
|
||
(( ${#br} > 26 )) && br="${br:0:24}…"
|
||
reply=("$br" $staged $mod $untracked $ahead $behind)
|
||
}
|
||
|
||
_kci_preexec() { _KCI_START=$EPOCHREALTIME }
|
||
|
||
_kci_precmd() {
|
||
_KCI_CODE=$?
|
||
# allererster Prompt: $? stammt aus .zshrc, nicht aus einer Nutzereingabe
|
||
if (( _KCI_FIRST )); then _KCI_CODE=0; _KCI_FIRST=0; fi
|
||
if (( _KCI_START > 0 )); then
|
||
local -F 3 d=$(( EPOCHREALTIME - _KCI_START ))
|
||
_KCI_DUR=${d}
|
||
_KCI_START=0
|
||
else
|
||
_KCI_DUR=0
|
||
fi
|
||
[[ ${_KCI_DUR%.*} -lt 2 ]] && _KCI_DUR=0
|
||
|
||
local host=${(%):-%m}
|
||
local -i root=0
|
||
(( EUID == 0 )) && root=1
|
||
|
||
# Pfad: ~ für $HOME, tiefe Pfade auf die letzten drei Ebenen kürzen
|
||
local p
|
||
if [[ $PWD == $HOME ]]; then
|
||
p='~'
|
||
elif [[ $PWD == $HOME/* ]]; then
|
||
p="~${PWD#$HOME}"
|
||
else
|
||
p=$PWD
|
||
fi
|
||
if [[ $p != '~' && $p != '/' ]]; then
|
||
local -a parts=(${(s:/:)p})
|
||
(( ${#parts} > 4 )) && p="…/${(j:/:)parts[-3,-1]}"
|
||
fi
|
||
|
||
# Git
|
||
local gitseg=''
|
||
if _kci_git_info; then
|
||
local br=$reply[1]
|
||
gitseg=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_BLUE}${br}${_KCI_RESET}"
|
||
(( reply[2] )) && gitseg+=" ${_KCI_GREEN}✚${reply[2]}${_KCI_RESET}"
|
||
(( reply[3] )) && gitseg+=" ${_KCI_YELLOW}✎${reply[3]}${_KCI_RESET}"
|
||
(( reply[4] )) && gitseg+=" ${_KCI_STEEL_L}?${reply[4]}${_KCI_RESET}"
|
||
(( reply[5] )) && gitseg+=" ${_KCI_GREEN}↑${reply[5]}${_KCI_RESET}"
|
||
(( reply[6] )) && gitseg+=" ${_KCI_YELLOW}↓${reply[6]}${_KCI_RESET}"
|
||
fi
|
||
|
||
# Umgebung
|
||
local envseg=''
|
||
[[ -n ${VIRTUAL_ENV:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_YELLOW}${VIRTUAL_ENV:t}${_KCI_RESET}"
|
||
[[ -n ${CONDA_DEFAULT_ENV:-} && -z ${VIRTUAL_ENV:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_YELLOW}${CONDA_DEFAULT_ENV}${_KCI_RESET}"
|
||
[[ -n ${KALINA_SSH_HOST:-} ]] && envseg+=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_MUTED}ssh:${KALINA_SSH_HOST}${_KCI_RESET}"
|
||
|
||
local durseg=''
|
||
(( _KCI_DUR )) && durseg=" ${_KCI_STEEL}·${_KCI_RESET} ${_KCI_STEEL_L}$(printf '%.1fs' ${_KCI_DUR})${_KCI_RESET}"
|
||
|
||
local prefix=''
|
||
[[ ${KALINA_CI_NO_NEWLINE:-0} == 1 ]] || prefix=$'\n'
|
||
|
||
local hostsym=${_KCI_MUTED}
|
||
local marksym='❯'
|
||
local marksym_c=${_KCI_ROT}
|
||
if (( root )); then
|
||
hostsym=${_KCI_BRIGHTROT}
|
||
marksym='#'
|
||
marksym_c=${_KCI_BRIGHTROT}
|
||
fi
|
||
|
||
local codeseg=''
|
||
(( _KCI_CODE )) && codeseg="${_KCI_ROT_TXT}✗${_KCI_CODE}${_KCI_RESET} "
|
||
|
||
PROMPT="${prefix}${_KCI_STEEL}┌─${_KCI_RESET} ${hostsym}${host}${_KCI_RESET} ${_KCI_BONE}${p}${_KCI_RESET}${gitseg}${envseg}${durseg}"$'\n'
|
||
PROMPT+="${_KCI_STEEL}└─${_KCI_RESET} ${codeseg}${marksym_c}${marksym}${_KCI_RESET} "
|
||
|
||
RPROMPT=''
|
||
local -i j=${#jobstates}
|
||
(( j )) && RPROMPT="${_KCI_STEEL_L}⚙${j}${_KCI_RESET}"
|
||
}
|
||
|
||
if (( ${+functions[add-zsh-hook]} )); then
|
||
add-zsh-hook precmd _kci_precmd
|
||
add-zsh-hook preexec _kci_preexec
|
||
else
|
||
precmd_functions+=(_kci_precmd)
|
||
preexec_functions+=(_kci_preexec)
|
||
fi
|
||
|
||
# Initialer Prompt sofort beim Start (precmd feuert erst vor dem ersten Prompt)
|
||
if [[ -o interactive ]]; then
|
||
true
|
||
_kci_precmd
|
||
# doch noch kein Nutzerbefehl gelaufen: erster echter Prompt zeigt keinen Fehlercode
|
||
_KCI_FIRST=1
|
||
_KCI_CODE=0
|
||
fi
|