feat(shell): Kalina-CI-Prompt und Installer fuer weitere Maschinen (#2)

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.
This commit is contained in:
Kalina committed 2026-11-02 18:29:25 +01:00
1 parent ad5a3f0c6a
commit 6882349bf4
4 files changed
+710

No files matched your search

+176
View File
@@ -0,0 +1,176 @@
# 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