#!/bin/bash set -euo pipefail # ====================== Defaults & Args ====================== WITH_TIDE=0 KEEP_PROMPT=0 VERBOSE=0 NO_PLUGINS=0 while [[ $# -gt 0 ]]; do case "$1" in --with-tide) WITH_TIDE=1 ;; --keep-prompt) KEEP_PROMPT=1 ;; --verbose) VERBOSE=1 ;; --no-plugins) NO_PLUGINS=1 ;; --) shift; break ;; *) echo "Unknown option: $1"; exit 1 ;; esac shift done # Default plugin set (safe; no prompt change) PLUGINS=("jethrokuan/z" "jorgebucaran/nvm.fish") if [[ $WITH_TIDE -eq 1 ]]; then PLUGINS+=("ilancosman/tide") fi log() { echo -e "• $*"; } ok() { echo -e "✓ $*"; } warn(){ echo -e "! $*" >&2; } # ====================== Progress Bar (single line) ====================== padright() { printf "%-28s" "$1"; } draw_bar() { local cur="$1" total="$2" label="$3" width=40 local percent=$(( cur * 100 / total )) (( percent > 100 )) && percent=100 local filled=$(( width * cur / total )) (( filled > width )) && filled=$width local empty=$(( width - filled )) printf "\rInstalling: %s [%s%s] %3d%%" \ "$(padright "$label")" \ "$(printf '%0.s#' $(seq 1 $filled))" \ "$(printf '%0.s.' $(seq 1 $empty))" \ "$percent" } # ====================== Platform Detect ====================== detect_platform() { if [[ "$OSTYPE" == "darwin"* ]]; then OS="macos"; PKG_MGR="brew" if ! command -v brew &>/dev/null; then log "Installing Homebrew…" /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile eval "$(/opt/homebrew/bin/brew shellenv)" ok "Homebrew installed" fi elif command -v apt &>/dev/null; then OS="debian"; PKG_MGR="apt" elif command -v dnf &>/dev/null; then OS="rhel"; PKG_MGR="dnf" elif command -v yum &>/dev/null; then OS="rhel"; PKG_MGR="yum" elif command -v pacman &>/dev/null; then OS="arch"; PKG_MGR="pacman" else warn "Unsupported platform"; exit 1; fi ok "Detected ${OS} (${PKG_MGR})" } # ====================== Debian repo/key ====================== install_gpg_if_needed() { if [[ "${OS}" == "debian" ]] && ! command -v gpg &>/dev/null; then log "Installing gnupg…" sudo apt update && sudo apt install -y gnupg ok "gnupg installed" fi } add_fish_repo_debian() { log "Adding Fish repo (Debian)…" echo 'deb http://download.opensuse.org/repositories/shells:/fish:/release:/4/Debian_12/ /' \ | sudo tee /etc/apt/sources.list.d/fish.list >/dev/null curl -fsSL https://download.opensuse.org/repositories/shells:fish:release:4/Debian_12/Release.key \ | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/fish.gpg >/dev/null sudo apt update ok "Repo added" } # ====================== Fish install/update ====================== install_fish() { log "Installing Fish…" case "$OS" in debian) add_fish_repo_debian; sudo apt install -y fish ;; rhel) sudo "$PKG_MGR" install -y fish ;; arch) sudo pacman -Sy --noconfirm fish ;; macos) brew install fish ;; esac ok "Fish installed" } update_fish_if_available() { log "Checking Fish updates…" case "$PKG_MGR" in apt) sudo apt update; apt list --upgradable 2>/dev/null | grep -q "^fish/" && sudo apt install -y fish || true ;; dnf|yum) sudo "$PKG_MGR" check-update || true; "$PKG_MGR" list updates | grep -q "^fish" && sudo "$PKG_MGR" update -y fish || true ;; pacman) sudo pacman -Sy --noconfirm; pacman -Qu | grep -q "^fish" && sudo pacman -S --noconfirm fish || true ;; brew) brew update; brew outdated | grep -q "^fish" && brew upgrade fish || true ;; esac ok "Fish up to date" } # ====================== Fisher & Plugins ====================== ensure_fisher() { # install Fisher quietly and idempotently if fish -c 'functions -q fisher' /dev/null 2>&1; then ok "Fisher already present" return fi log "Installing Fisher…" fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' /dev/null 2>&1 ok "Fisher installed" } install_plugins() { [[ $NO_PLUGINS -eq 1 ]] && { ok "Skipping plugins (per flag)"; return; } local total=${#PLUGINS[@]} [[ $total -eq 0 ]] && { ok "No plugins requested"; return; } if [[ $VERBOSE -eq 1 ]]; then for p in "${PLUGINS[@]}"; do echo "Installing (verbose): $p" fish -c "fisher install $p" /dev/null 2>&1 ) & pid=$! while kill -0 "$pid" 2>/dev/null; do draw_bar "$((i-1))" "$total" "$p" sleep 0.08 done draw_bar "$i" "$total" "$p" done echo ok "Plugins installed" # If Tide installed but user wants to keep default prompt if [[ $WITH_TIDE -eq 1 && $KEEP_PROMPT -eq 1 ]]; then log "Keeping default Fish prompt (disabling Tide init)…" rm -f ~/.config/fish/functions/fish_prompt.fish \ ~/.config/fish/conf.d/_tide_init.fish 2>/dev/null || true ok "Default prompt preserved" fi } # ====================== Main ====================== detect_platform install_gpg_if_needed if command -v fish &>/dev/null; then ok "Fish already installed" update_fish_if_available else install_fish fi ensure_fisher install_plugins ok "Fish + Fisher + plugins ready on ${OS}"