#!/bin/bash set -euo pipefail # ============================= # COLORS & LOGGING # ============================= RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${BLUE}[INFO]${NC} $*"; } ok() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } err() { echo -e "${RED}[ERROR]${NC} $*" >&2; } # ============================= # CONFIG # ============================= CONFIG_FILES=( ".alias|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/alias" ".func|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/func" ".pathrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/pathrc" ".sourcerc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/sourcerc" ".vimrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/vimrc" ".zshrc|https://gist.githubusercontent.com/weehongkoh/72bdb76beacacf2ca3dd39a72395b9ee/raw/zshrc" ) # ============================= # REQUIREMENTS # ============================= check_requirements() { if [[ $EUID -eq 0 ]]; then err "Do not run as root on macOS" exit 1 fi } # ============================= # INSTALLATION FUNCTIONS # ============================= configure_git() { log "Configuring Git..." read -p "Git name (leave empty to skip): " name read -p "Git email (leave empty to skip): " email if [[ -n "$name" ]]; then git config --global user.name "$name" fi if [[ -n "$email" ]]; then git config --global user.email "$email" fi ok "Git configured" } install_oh_my_zsh() { if [[ -d "$HOME/.oh-my-zsh" ]]; then ok "Oh My Zsh already installed" return fi log "Installing Oh My Zsh..." RUNZSH=no CHSH=no KEEP_ZSHRC=yes \ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" ok "Oh My Zsh installed" } install_plugins() { log "Installing plugins..." local dir="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins" [[ -d "$dir/zsh-autosuggestions" ]] || git clone https://github.com/zsh-users/zsh-autosuggestions "$dir/zsh-autosuggestions" [[ -d "$dir/zsh-syntax-highlighting" ]] || git clone https://github.com/zsh-users/zsh-syntax-highlighting "$dir/zsh-syntax-highlighting" ok "Plugins installed" } install_theme() { log "Installing Spaceship theme..." local themes="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes" local dir="$themes/spaceship-prompt" [[ -d "$dir" ]] || git clone https://github.com/spaceship-prompt/spaceship-prompt.git "$dir" --depth=1 ln -sf "$dir/spaceship.zsh-theme" "$themes/spaceship.zsh-theme" ok "Theme installed" } clean_macos_aliases() { local alias_file="$HOME/.alias" if [[ -f "$alias_file" ]]; then log "Patching .alias for macOS (removing apt-get and xclip blocks)..." # Delete the multiline apt-get block (from the comment down to the final command) sed -i '' '/# System update & cleanup/,/sudo apt-get clean/d' "$alias_file" # Delete the xclip block sed -i '' '/# xclip shortcuts/,/xclip -selection clipboard/d' "$alias_file" ok "macOS incompatibilities removed from .alias" fi } download_configs() { log "Downloading custom config files..." local backup="$HOME/.config_backup_$(date +%Y%m%d_%H%M%S)" mkdir -p "$backup" for entry in "${CONFIG_FILES[@]}"; do local f="${entry%%|*}" local url="${entry##*|}" if [[ -f "$HOME/$f" ]]; then cp "$HOME/$f" "$backup/" fi log "Fetching $f ..." curl -fsSL "$url" -o "$HOME/$f" || warn "Failed to download $f" done # Automatically clean up the macOS incompatible aliases after downloading clean_macos_aliases ok "Configs downloaded (Backup at $backup)" } update_zshrc() { local zshrc="$HOME/.zshrc" log "Updating .zshrc..." if [[ ! -f "$zshrc" ]]; then warn ".zshrc not found, creating new one..." touch "$zshrc" fi # macOS BSD sed requires '-i ''' for in-place editing grep -q 'ZSH_THEME="spaceship"' "$zshrc" || sed -i '' 's/ZSH_THEME=".*"/ZSH_THEME="spaceship"/' "$zshrc" grep -q 'zsh-autosuggestions' "$zshrc" || sed -i '' 's/plugins=(/plugins=(zsh-autosuggestions /' "$zshrc" grep -q 'zsh-syntax-highlighting' "$zshrc" || sed -i '' 's/plugins=(/plugins=(zsh-syntax-highlighting /' "$zshrc" ok ".zshrc updated with plugins and theme" } switch_shell() { log "Starting Zsh session..." echo -e "${YELLOW}Type 'exit' to return to this installer menu.${NC}" echo "----------------------------------------" zsh -l echo "----------------------------------------" ok "Returned from Zsh session" } # ============================= # INTERACTIVE MENU # ============================= show_menu() { echo "===========================================" echo "macOS Zsh Setup - Choose what to do" echo "===========================================" echo " 0) Run ALL steps (1-7)" echo " 1) Configure Git" echo " 2) Install Oh My Zsh" echo " 3) Install plugins (autosuggestions, syntax highlighting)" echo " 4) Install Spaceship theme" echo " 5) Download custom configs (~/.alias, .vimrc, etc.)" echo " 6) Update ~/.zshrc for plugins & theme" echo " 7) Switch to Zsh (Temporary Sub-shell)" echo " 8) Quit" echo "===========================================" echo "Inputs: '0' (All), '1 3 4' (Specific), '0 !1 !5' (All except 1 and 5)" } run_choices() { local input read -p "Select: " input input="${input//,/ }" # replace commas with spaces if used local -a to_run=() local -a to_exclude=() # Parse positive selections and negative exclusions for item in $input; do if [[ "$item" == !* ]]; then to_exclude+=("${item:1}") # Strip the '!' character elif [[ "$item" == "0" ]]; then to_run+=(1 2 3 4 5 6 7) else to_run+=("$item") fi done # Protect against empty arrays crashing older bash versions with 'set -u' if [[ ${#to_run[@]} -gt 0 ]]; then for choice in "${to_run[@]}"; do local skip=false if [[ ${#to_exclude[@]} -gt 0 ]]; then for ex in "${to_exclude[@]}"; do if [[ "$choice" == "$ex" ]]; then skip=true break fi done fi $skip && continue case "$choice" in 1) configure_git ;; 2) install_oh_my_