export ZSH_CONFIG=$HOME/.config/zsh export OHMYZSH=$ZSH_CONFIG/oh-my-zsh export OHMYZSH_CUSTOM=$OHMYZSH/custom # Bootstrap banner — built dynamically so the box stays aligned regardless # of the version string length or terminal width. _bootstrap_banner() { local inner=61 # inner width (between the vertical bars) local pad line local title="Zsh bootstrap - one-time environment setup (v${ZSHRC_BOOTSTRAP_VERSION})" local rule=$(printf '═%.0s' {1..$inner}) local mid=$(printf '─%.0s' {1..$inner}) # left-pad the title by 2 spaces so it doesn't hug the left bar title=" $title" pad=$(( inner - ${#title} )) (( pad < 0 )) && pad=0 echo "" echo "╔${rule}╗" printf '║%s%*s║\n' "$title" "$pad" "" echo "╠${mid}╣" while IFS= read -r line; do line=" $line" pad=$(( inner - ${#line} )) (( pad < 0 )) && pad=0 printf '║%s%*s║\n' "$line" "$pad" "" done <<'EOF' This runs on first login or when the bootstrap version changes. It installs missing CLI tools and clones oh-my-zsh + plugins across distros. Network calls time out after ~30s so an unreachable host skips silently. The first run may take a minute; subsequent runs are a no-op. EOF echo "╚${rule}╝" echo "" } _bootstrap_banner unfunction _bootstrap_banner touch ~/.hushlogin mkdir -p "$HOME/.local/bin" mkdir -p "$ZSH_CONFIG" path+=("$HOME/.local/bin") # Package availability checks can hang on slow/unreachable mirrors (cold dnf # metadata, apt update, pacman -Sy). Wrap them in a 20s timeout so the bootstrap # never stalls the shell; a timed-out check just falls through to the next PM # or to the binary installers below. Verbose output so real builds (cargo) and # slow installs are visible as progress instead of an apparent hang. for p in git starship fzf eza rsync lazydocker fastfetch tmux bat zoxide; do if command -v $p >/dev/null; then echo " ok $p (already installed)" continue fi echo " ... $p (checking package managers)" if command -v brew >/dev/null; then echo " brew installing $p" && brew install $p && continue fi if command -v apt >/dev/null; then if timeout 20 apt-cache show $p >/dev/null 2>&1; then echo " apt installing $p" && sudo apt install -y $p && continue else echo " apt $p not available (or metadata check timed out)" fi fi if command -v dnf >/dev/null; then if timeout 20 dnf list available $p >/dev/null 2>&1; then echo " dnf installing $p" && sudo dnf install -y $p && continue else echo " dnf $p not available (or metadata check timed out)" fi fi if command -v pacman >/dev/null; then if timeout 20 pacman -Si $p >/dev/null 2>&1; then echo " pacman installing $p" && sudo pacman -Sy --noconfirm $p && continue else echo " pacman $p not available (or metadata check timed out)" fi fi if command -v cargo >/dev/null; then echo " cargo installing $p (may take a few minutes to compile)" && cargo install $p --locked && continue fi echo " FAIL could not install $p by any method; skipping" done if ! command -v starship >/dev/null; then echo " curl installing starship binary" curl -fsSL --connect-timeout 5 --max-time 30 https://starship.rs/install.sh | sh -s -- -b ~/.local/bin -y fi if ! command -v lazydocker >/dev/null; then echo " curl installing lazydocker binary" curl -fsSL --connect-timeout 5 --max-time 30 https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | \ DIR=$HOME/.local/bin bash fi # Debian/Ubuntu ships bat as 'batcat' and fd as 'fdfind'; symlink to the # canonical names so the zshrc integrations (which call bat/fd) work everywhere. if ! command -v bat >/dev/null && command -v batcat >/dev/null; then ln -sf "$(command -v batcat)" "$HOME/.local/bin/bat" fi if ! command -v fd >/dev/null && command -v fdfind >/dev/null; then ln -sf "$(command -v fdfind)" "$HOME/.local/bin/fd" fi # git-delta: the package is named 'git-delta' on every package manager but the # binary is 'delta' (name mismatch vs the install loop above), so install via the # same PM cascade using the real package name. Used by zshrc as GIT_PAGER. if ! command -v delta >/dev/null; then echo " ... delta (checking package managers, package name is 'git-delta')" if command -v brew >/dev/null; then echo " brew installing git-delta" && brew install git-delta elif command -v apt >/dev/null && timeout 20 apt-cache show git-delta >/dev/null 2>&1; then echo " apt installing git-delta" && sudo apt install -y git-delta elif command -v dnf >/dev/null && timeout 20 dnf list available git-delta >/dev/null 2>&1; then echo " dnf installing git-delta" && sudo dnf install -y git-delta elif command -v pacman >/dev/null && timeout 20 pacman -Si git-delta >/dev/null 2>&1; then echo " pacman installing git-delta" && sudo pacman -Sy --noconfirm git-delta elif command -v cargo >/dev/null; then echo " cargo installing git-delta (may take a few minutes to compile)" && cargo install git-delta --locked else echo " FAIL could not install delta; skipping" fi fi arch=$(uname -m) case "$arch" in x86_64) target_fast="linux-amd64" && target_eza="x86_64-unknown-linux-gnu" ;; aarch64|arm64) target_fast="linux-aarch64" && target_eza="aarch64-unknown-linux-gnu" ;; armv7l) target_fast="linux-armv7l" && target_eza="armv7-unknown-linux-gnueabihf" ;; esac if [[ -n $target_fast && -n $target_eza ]]; then if ! command -v fastfetch >/dev/null; then echo " curl installing fastfetch (github release tarball)" if curl -fsSL --connect-timeout 5 --max-time 30 -o /tmp/fastfetch.tar.gz \ "https://github.com/fastfetch-cli/fastfetch/releases/latest/download/fastfetch-${target_fast}.tar.gz" \ && tar -xzf /tmp/fastfetch.tar.gz -C /tmp 2>/dev/null; then ffdir=$(find /tmp -maxdepth 1 -type d -name 'fastfetch*' | head -1) if [[ -n "$ffdir" ]]; then cp "$ffdir/usr/bin/fastfetch" "$HOME/.local/bin/" chmod +x "$HOME/.local/bin/fastfetch" mkdir -p "$HOME/.local/share/fastfetch" cp -r "$ffdir/usr/share/fastfetch/"* "$HOME/.local/share/fastfetch/" fi rm -rf "$ffdir" /tmp/fastfetch.tar.gz else rm -f /tmp/fastfetch.tar.gz echo " FAIL could not download/extract fastfetch; skipping" fi fi if ! command -v eza >/dev/null; then echo " curl installing eza (github release tarball)" if curl -fsSL --connect-timeout 5 --max-time 30 -o /tmp/eza.tar.gz \ "https://github.com/eza-community/eza/releases/latest/download/eza_${target_eza}.tar.gz" \ && tar -xzf /tmp/eza.tar.gz -C "$HOME/.local/bin/" 2>/dev/null; then chmod +x "$HOME/.local/bin/eza" else rm -f /tmp/eza.tar.gz echo " FAIL could not download/extract eza; skipping" fi rm -f /tmp/eza.tar.gz fi fi mkdir -p "$HOME/.config/zsh" if [ ! -d "$OHMYZSH" ]; then echo " git cloning oh-my-zsh" GIT_TERMINAL_PROMPT=0 git -c http.lowSpeedLimit=1000 -c http.lowSpeedTime=10 \ clone --depth=1 https://github.com/ohmyzsh/ohmyzsh.git $OHMYZSH || \ echo " FAIL could not clone oh-my-zsh" fi for plug in \ "zsh-autosuggestions|https://github.com/zsh-users/zsh-autosuggestions" \ "fast-syntax-highlighting|https://github.com/zdharma-continuum/fast-syntax-highlighting" \ "fzf-tab|https://github.com/Aloxaf/fzf-tab" do name="${plug%%|*}" url="${plug##*|}" dir="$OHMYZSH_CUSTOM/plugins/$name" if [[ ! -d "$dir" ]]; then echo " git cloning $name" GIT_TERMINAL_PROMPT=0 git -c http.lowSpeedLimit=1000 -c http.lowSpeedTime=10 \ clone "$url" "$dir" 2>/dev/null || echo " FAIL could not clone $name" fi done # Cleanup [[ -d $HOME/.config/oh-my-zsh ]] && rm -rf "$HOME/.config/oh-my-zsh"