From 6b60b64c8f990a97dd513b63b9d1791e270d6912 Mon Sep 17 00:00:00 2001 From: Bastien CHANOT Date: Mon, 5 Oct 2026 17:28:47 +0200 Subject: [PATCH] feat(zsh): macOS zshrc (oh-my-zsh) + bchanot theme porting the bash prompt --- zsh/bchanot.zsh-theme | 57 ++++++++++++++++++++++++++++++++++++ zsh/zshrc-osx | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 zsh/bchanot.zsh-theme create mode 100644 zsh/zshrc-osx diff --git a/zsh/bchanot.zsh-theme b/zsh/bchanot.zsh-theme new file mode 100644 index 0000000..d3d9bd3 --- /dev/null +++ b/zsh/bchanot.zsh-theme @@ -0,0 +1,57 @@ +# bchanot.zsh-theme — oh-my-zsh port of the bashrc prompt: +# ✔ (12ms) user [ ~/dir ] [branch -*+] > +# Mark + timer cyan (red ✘ on failure), user and brackets green (red for root), +# git segment blue. Deployed to ~/.oh-my-zsh/custom/themes by install.sh. + +zmodload zsh/datetime +autoload -Uz add-zsh-hook + +# Git segment, same rules as parse_git_branch/parse_git_dirty in the bashrc: +# " [branch bits]" with + (new, modified, renamed or untracked files), +# * (ahead of upstream) and - (deleted files). Empty outside a repo. +bchanot_git_info() { + local lines branch bits='' + lines="$(git status --porcelain --branch 2>/dev/null)" || return 0 + branch="$(git symbolic-ref --short HEAD 2>/dev/null)" || branch='(detached)' + if print -r -- "$lines" | grep -qE '^(\?\?|[MAR].|.M)'; then + bits='+' + fi + if print -r -- "${lines%%$'\n'*}" | grep -q '\[ahead '; then + bits="*$bits" + fi + if print -r -- "$lines" | grep -qE '^(D.|.D)'; then + bits="-$bits" + fi + print -r -- " [${branch}${bits:+ $bits}]" +} + +# Command timer: preexec stamps the start, precmd formats the elapsed time with +# the bashrc's rules (about 3 significant digits, us up to h). +bchanot_timer_start() { + _bchanot_cmd_start=$EPOCHREALTIME +} + +bchanot_timer_stop() { + integer delta_us us ms s m h + (( delta_us = (EPOCHREALTIME - ${_bchanot_cmd_start:-$EPOCHREALTIME}) * 1000000 )) + (( us = delta_us % 1000, ms = (delta_us / 1000) % 1000 )) + (( s = (delta_us / 1000000) % 60, m = (delta_us / 60000000) % 60 )) + (( h = delta_us / 3600000000 )) + if ((h > 0)); then _bchanot_timer_show=${h}h${m}m + elif ((m > 0)); then _bchanot_timer_show=${m}m${s}s + elif ((s >= 10)); then _bchanot_timer_show=${s}.$((ms / 100))s + elif ((s > 0)); then _bchanot_timer_show=${s}.$(printf %03d $ms)s + elif ((ms >= 100)); then _bchanot_timer_show=${ms}ms + elif ((ms > 0)); then _bchanot_timer_show=${ms}.$((us / 100))ms + else _bchanot_timer_show=${us}us + fi + unset _bchanot_cmd_start +} + +add-zsh-hook preexec bchanot_timer_start +add-zsh-hook precmd bchanot_timer_stop + +PROMPT='%B%(?.%F{cyan}✔.%F{red}✘) (${_bchanot_timer_show}) ' +PROMPT+='%(!.%F{red}.%F{green})%n [%f%b %~ %B%(!.%F{red}.%F{green})]' +PROMPT+='%F{blue}$(bchanot_git_info) %f%b> ' +RPROMPT='' diff --git a/zsh/zshrc-osx b/zsh/zshrc-osx new file mode 100644 index 0000000..10d2cc9 --- /dev/null +++ b/zsh/zshrc-osx @@ -0,0 +1,67 @@ +# zshrc for macOS: zsh + oh-my-zsh counterpart of bash/bashrc-osx (same env, +# aliases and dtach menu; the prompt lives in bchanot.zsh-theme). +# Machine-specific lines (nvm, bun, tokens...) go in ~/.zshrc.local, never here. + +# Homebrew on PATH (Apple Silicon: /opt/homebrew, Intel: /usr/local). +for brew_bin in /opt/homebrew/bin/brew /usr/local/bin/brew; do + if [ -x "$brew_bin" ]; then + eval "$("$brew_bin" shellenv)" + break + fi +done +unset brew_bin + +## oh-my-zsh (loaded first: the aliases below override its defaults, e.g. `d`) +export ZSH="$HOME/.oh-my-zsh" +ZSH_THEME="bchanot" +plugins=(git) +source "$ZSH/oh-my-zsh.sh" + +## Enable color support of ls and also add handy aliases +# Some colors (BSD ls: -G instead of GNU --color) +alias ls='ls -G' +alias grep='grep --color=auto' + +## Some export +# colored GCC warnings and errors +export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + +# Ensure ~/.local/bin is on PATH (pipx CLIs + personal scripts from bin/) +case ":$PATH:" in + *":$HOME/.local/bin:"*) ;; + *) export PATH="$HOME/.local/bin:$PATH" ;; +esac + +# History: none for root, near-unlimited otherwise (zsh has no -1 = unlimited). +if [[ $EUID == 0 ]] ; then + HISTSIZE=0 + SAVEHIST=0 +else + HISTSIZE=10000000 + SAVEHIST=10000000 +fi + +# Used for vim header +export VIUSER=bchanot +export VIMAIL=bchanot@gmail.fr + +# claude-dans-dtach : creer une session (claude tournant dans dtach, detache via Ctrl-\). +# Usage : cd ~/projets/seo && cc seo -> session nommee "seo". +# Pas de systemd sur macOS : dtach est lance directement (pas de slice cgroup). +dtach_claude() { + local name="${1:-claude-$(date +%H%M%S)}" + mkdir -p "$HOME/.dtach" + dtach -c "$HOME/.dtach/${name}" -e '^\' \ + bash -c 'set -a; [ -f "$HOME/.claude/.env" ] && . "$HOME/.claude/.env"; set +a; exec claude' +} +alias cc='dtach_claude' + +# Rappeler a la demande le menu de reprise. +alias d='source ~/.local/bin/dtach-router' + +# Reglages propres a cette machine (non versionnes). +[ -f "$HOME/.zshrc.local" ] && source "$HOME/.zshrc.local" + +# Au demarrage d'un shell interactif, proposer de reprendre une session dtach existante +# (silencieux si aucune). +case $- in *i*) [ -x "$HOME/.local/bin/dtach-router" ] && . "$HOME/.local/bin/dtach-router" ;; esac