# 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