diff --git a/README.md b/README.md index e8b543c..aa28cf7 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,15 @@ cd ~/server_cli_tools | # | Component | What it does | |---|-----------|-------------| | 1 | **Core packages** | `vim`, `bat`, `eza`, `fzf`, `htop`, `tmux`, `zsh`, `ripgrep`, `fd-find`, `zoxide`, `git-delta` | -| 2 | **Zsh + Oh-My-Zsh** | Shell, plugins (`zsh-autosuggestions`, `zsh-syntax-highlighting`, `z`), custom prompt theme | +| 2 | **Zsh + Oh-My-Zsh** | Shell, plugins (`zsh-autosuggestions`, `zsh-syntax-highlighting`, `z`), `bira` prompt theme | | 3 | **Aliases + tools** | General, git, and docker aliases with a self-documenting help system (`h`) | | 4 | **Terminal configs** | `bat` theme (base16) | | 5 | **Docker** | `docker.io` via apt, service enabled, user added to `docker` group, management aliases | | 6 | **Git config** | `git-delta` as pager with side-by-side diffs | +> **NOTE:** There's minimal custom theme in `/configs/zsh/zhann-elvis.zsh-theme`. To apply it toggle `ZSH_THEME` and uncomment sourcing it in `~/.zshrc` after install. +> For more themes, see [Oh-My-Zsh themes](https://github.com/ohmyzsh/ohmyzsh/wiki/themes). + ## Alias highlights Type `h` after installation to see all aliases with descriptions. Some highlights: @@ -63,8 +66,7 @@ server_cli_tools/ custom_tools/ backup_dotfiles.sh # backup conflicting dotfiles bat/config # bat theme - zsh/zhann-elvis.zsh-theme # custom zsh prompt (git-aware) - zshrc # .zshrc with oh-my-zsh + plugins + zshrc # .zshrc with oh-my-zsh, bira theme, plugins ``` ## Customization diff --git a/configs/zshrc b/configs/zshrc index dd3b462..44669d0 100644 --- a/configs/zshrc +++ b/configs/zshrc @@ -2,7 +2,8 @@ export ZSH="$HOME/.oh-my-zsh" export ALIASES="$HOME/.config/aliases" export CT_DIR="$HOME/.config/custom_tools" export EDITOR="vim" -ZSH_THEME="" +# ZSH_THEME="" +ZSH_THEME="bira" DISABLE_AUTO_TITLE="true" plugins=( git @@ -11,7 +12,7 @@ plugins=( z ) source $ZSH/oh-my-zsh.sh -source $HOME/.config/zsh/zhann-elvis.zsh-theme +# source $HOME/.config/zsh/zhann-elvis.zsh-theme source $ALIASES/.aliases autoload -Uz zcalc [ -f /usr/share/doc/fzf/examples/key-bindings.zsh ] && source /usr/share/doc/fzf/examples/key-bindings.zsh diff --git a/install.sh b/install.sh index eee8e51..f25d233 100755 --- a/install.sh +++ b/install.sh @@ -13,17 +13,17 @@ BACKUP_DIR="$HOME/.server_cli_tools_bkp/$(date +%Y%m%d-%H%M%S)" # SSH from Ghostty and other clients forwards TERM values (e.g. xterm-ghostty) # that remote servers often lack in terminfo — breaks clear/tput and colors. if ! infocmp "${TERM:-}" &>/dev/null; then - for _term_fallback in xterm-256color xterm screen dumb; do - if infocmp "$_term_fallback" &>/dev/null; then - export TERM="$_term_fallback" - break - fi - done - unset _term_fallback + for _term_fallback in xterm-256color xterm screen dumb; do + if infocmp "$_term_fallback" &>/dev/null; then + export TERM="$_term_fallback" + break + fi + done + unset _term_fallback fi # Colors (matching the dotfiles convention) -e_err() { echo -e "\e[1;31m$1\e[0m"; } +e_err() { echo -e "\e[1;31m$1\e[0m"; } e_info() { echo -e "\e[1;34m$1\e[0m"; } e_succ() { echo -e "\e[1;32m$1\e[0m"; } e_warn() { echo -e "\e[1;38;5;208m$1\e[0m"; } @@ -36,69 +36,69 @@ SKIPPED=() # --------------------------------------------------------------------------- backup_file() { - local src="$1" - if [ -e "$src" ]; then - local rel="${src#$HOME/}" - local dest="$BACKUP_DIR/$rel" - mkdir -p "$(dirname "$dest")" - cp -a "$src" "$dest" - e_info " Backed up $src" - fi + local src="$1" + if [ -e "$src" ]; then + local rel="${src#$HOME/}" + local dest="$BACKUP_DIR/$rel" + mkdir -p "$(dirname "$dest")" + cp -a "$src" "$dest" + e_info " Backed up $src" + fi } copy_config() { - local src="$1" dest="$2" - backup_file "$dest" - mkdir -p "$(dirname "$dest")" - cp -a "$src" "$dest" + local src="$1" dest="$2" + backup_file "$dest" + mkdir -p "$(dirname "$dest")" + cp -a "$src" "$dest" } copy_dir() { - local src="$1" dest="$2" - if [ -d "$dest" ]; then - backup_file "$dest" - fi - mkdir -p "$dest" - cp -a "$src"/. "$dest"/ + local src="$1" dest="$2" + if [ -d "$dest" ]; then + backup_file "$dest" + fi + mkdir -p "$dest" + cp -a "$src"/. "$dest"/ } command_exists() { - command -v "$1" >/dev/null 2>&1 + command -v "$1" >/dev/null 2>&1 } safe_clear() { - clear 2>/dev/null || printf '\033[H\033[2J' + clear 2>/dev/null || printf '\033[H\033[2J' } check_os() { - if [ ! -f /etc/os-release ]; then - e_err "Cannot detect OS. This script supports Ubuntu/Debian only." - exit 1 - fi - . /etc/os-release - case "$ID" in - ubuntu|debian) ;; - *) - e_warn "Detected $ID — this script is designed for Ubuntu/Debian." - e_warn "Package installation may not work. Configs will still be copied." - ;; - esac + if [ ! -f /etc/os-release ]; then + e_err "Cannot detect OS. This script supports Ubuntu/Debian only." + exit 1 + fi + . /etc/os-release + case "$ID" in + ubuntu | debian) ;; + *) + e_warn "Detected $ID — this script is designed for Ubuntu/Debian." + e_warn "Package installation may not work. Configs will still be copied." + ;; + esac } apt_install() { - local packages=("$@") - local to_install=() - for pkg in "${packages[@]}"; do - if dpkg -s "$pkg" &>/dev/null; then - e_info " $pkg is already installed" - else - to_install+=("$pkg") - fi - done - if [ ${#to_install[@]} -gt 0 ]; then - e_info " Installing: ${to_install[*]}" - sudo apt-get install -y "${to_install[@]}" + local packages=("$@") + local to_install=() + for pkg in "${packages[@]}"; do + if dpkg -s "$pkg" &>/dev/null; then + e_info " $pkg is already installed" + else + to_install+=("$pkg") fi + done + if [ ${#to_install[@]} -gt 0 ]; then + e_info " Installing: ${to_install[*]}" + sudo apt-get install -y "${to_install[@]}" + fi } # --------------------------------------------------------------------------- @@ -106,159 +106,159 @@ apt_install() { # --------------------------------------------------------------------------- install_core_packages() { - e_info "\n[1/6] Core packages" - sudo apt-get update -qq + e_info "\n[1/6] Core packages" + sudo apt-get update -qq - apt_install curl vim bat fzf htop tmux zsh ripgrep fd-find zoxide + apt_install curl vim bat fzf htop tmux zsh ripgrep fd-find zoxide - # bat is installed as 'batcat' on Debian/Ubuntu - if command_exists batcat && ! command_exists bat; then - sudo ln -sf /usr/bin/batcat /usr/local/bin/bat - e_info " Symlinked batcat -> bat" - fi + # bat is installed as 'batcat' on Debian/Ubuntu + if command_exists batcat && ! command_exists bat; then + sudo ln -sf /usr/bin/batcat /usr/local/bin/bat + e_info " Symlinked batcat -> bat" + fi - # eza — not in all distro repos, try apt first, fall back to cargo/binary - if ! command_exists eza; then - if apt-cache show eza &>/dev/null; then - apt_install eza - else - e_warn " eza not in apt repos. Install manually: https://github.com/eza-community/eza" - fi + # eza — not in all distro repos, try apt first, fall back to cargo/binary + if ! command_exists eza; then + if apt-cache show eza &>/dev/null; then + apt_install eza else - e_info " eza is already installed" + e_warn " eza not in apt repos. Install manually: https://github.com/eza-community/eza" fi + else + e_info " eza is already installed" + fi - # git-delta - if ! command_exists delta; then - if apt-cache show git-delta &>/dev/null; then - apt_install git-delta - else - e_warn " git-delta not in apt repos. Install from: https://github.com/dandavison/delta/releases" - fi + # git-delta + if ! command_exists delta; then + if apt-cache show git-delta &>/dev/null; then + apt_install git-delta else - e_info " delta is already installed" + e_warn " git-delta not in apt repos. Install from: https://github.com/dandavison/delta/releases" fi + else + e_info " delta is already installed" + fi - INSTALLED+=("core-packages") + INSTALLED+=("core-packages") } install_zsh() { - e_info "\n[2/6] Zsh + Oh-My-Zsh" + e_info "\n[2/6] Zsh + Oh-My-Zsh" - if ! command_exists zsh; then - apt_install zsh + if ! command_exists zsh; then + apt_install zsh + fi + + # Oh-My-Zsh + if [ ! -d "$HOME/.oh-my-zsh" ]; then + e_info " Installing Oh-My-Zsh..." + RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + else + e_info " Oh-My-Zsh already installed" + fi + + # Plugins + local zsh_custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + + if [ ! -d "$zsh_custom/plugins/zsh-autosuggestions" ]; then + e_info " Cloning zsh-autosuggestions..." + git clone --quiet https://github.com/zsh-users/zsh-autosuggestions "$zsh_custom/plugins/zsh-autosuggestions" + else + e_info " zsh-autosuggestions already installed" + fi + + if [ ! -d "$zsh_custom/plugins/zsh-syntax-highlighting" ]; then + e_info " Cloning zsh-syntax-highlighting..." + git clone --quiet https://github.com/zsh-users/zsh-syntax-highlighting.git "$zsh_custom/plugins/zsh-syntax-highlighting" + else + e_info " zsh-syntax-highlighting already installed" + fi + + # Theme + # mkdir -p "$HOME/.config/zsh" + # copy_config "$CONFIGS/zsh/zhann-elvis.zsh-theme" "$HOME/.config/zsh/zhann-elvis.zsh-theme" + # e_info " Installed zhann-elvis.zsh-theme" + + # .zshrc + copy_config "$CONFIGS/zshrc" "$HOME/.zshrc" + e_info " Installed .zshrc" + + # Change default shell to zsh (if not already) + if [ "$(basename "$SHELL")" != "zsh" ]; then + e_info " Changing default shell to zsh..." + if command_exists chsh; then + chsh -s "$(which zsh)" || e_warn " chsh failed — change shell manually: chsh -s \$(which zsh)" fi + fi - # Oh-My-Zsh - if [ ! -d "$HOME/.oh-my-zsh" ]; then - e_info " Installing Oh-My-Zsh..." - RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended - else - e_info " Oh-My-Zsh already installed" - fi - - # Plugins - local zsh_custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" - - if [ ! -d "$zsh_custom/plugins/zsh-autosuggestions" ]; then - e_info " Cloning zsh-autosuggestions..." - git clone --quiet https://github.com/zsh-users/zsh-autosuggestions "$zsh_custom/plugins/zsh-autosuggestions" - else - e_info " zsh-autosuggestions already installed" - fi - - if [ ! -d "$zsh_custom/plugins/zsh-syntax-highlighting" ]; then - e_info " Cloning zsh-syntax-highlighting..." - git clone --quiet https://github.com/zsh-users/zsh-syntax-highlighting.git "$zsh_custom/plugins/zsh-syntax-highlighting" - else - e_info " zsh-syntax-highlighting already installed" - fi - - # Theme - mkdir -p "$HOME/.config/zsh" - copy_config "$CONFIGS/zsh/zhann-elvis.zsh-theme" "$HOME/.config/zsh/zhann-elvis.zsh-theme" - e_info " Installed zhann-elvis.zsh-theme" - - # .zshrc - copy_config "$CONFIGS/zshrc" "$HOME/.zshrc" - e_info " Installed .zshrc" - - # Change default shell to zsh (if not already) - if [ "$(basename "$SHELL")" != "zsh" ]; then - e_info " Changing default shell to zsh..." - if command_exists chsh; then - chsh -s "$(which zsh)" || e_warn " chsh failed — change shell manually: chsh -s \$(which zsh)" - fi - fi - - INSTALLED+=("zsh") + INSTALLED+=("zsh") } install_aliases() { - e_info "\n[3/6] Aliases + custom tools" + e_info "\n[3/6] Aliases + custom tools" - copy_dir "$CONFIGS/aliases" "$HOME/.config/aliases" - chmod +x "$HOME/.config/aliases"/.aliases "$HOME/.config/aliases"/.functions.sh 2>/dev/null || true - e_info " Installed aliases to ~/.config/aliases/" + copy_dir "$CONFIGS/aliases" "$HOME/.config/aliases" + chmod +x "$HOME/.config/aliases"/.aliases "$HOME/.config/aliases"/.functions.sh 2>/dev/null || true + e_info " Installed aliases to ~/.config/aliases/" - copy_dir "$CONFIGS/custom_tools" "$HOME/.config/custom_tools" - chmod +x "$HOME/.config/custom_tools"/*.sh 2>/dev/null || true - e_info " Installed custom tools to ~/.config/custom_tools/" + copy_dir "$CONFIGS/custom_tools" "$HOME/.config/custom_tools" + chmod +x "$HOME/.config/custom_tools"/*.sh 2>/dev/null || true + e_info " Installed custom tools to ~/.config/custom_tools/" - INSTALLED+=("aliases" "custom-tools") + INSTALLED+=("aliases" "custom-tools") } install_terminal_configs() { - e_info "\n[4/6] Terminal configs (bat)" + e_info "\n[4/6] Terminal configs (bat)" - mkdir -p "$HOME/.config/bat" - copy_config "$CONFIGS/bat/config" "$HOME/.config/bat/config" - e_info " Installed bat config (theme: base16)" + mkdir -p "$HOME/.config/bat" + copy_config "$CONFIGS/bat/config" "$HOME/.config/bat/config" + e_info " Installed bat config (theme: base16)" - INSTALLED+=("terminal-configs") + INSTALLED+=("terminal-configs") } install_docker() { - e_info "\n[5/6] Docker" + e_info "\n[5/6] Docker" - sudo apt-get update -qq - apt_install docker.io + sudo apt-get update -qq + apt_install docker.io - if command_exists systemctl; then - sudo systemctl enable --now docker 2>/dev/null \ - || e_warn " Could not enable docker service — start manually: sudo systemctl start docker" - fi + if command_exists systemctl; then + sudo systemctl enable --now docker 2>/dev/null || + e_warn " Could not enable docker service — start manually: sudo systemctl start docker" + fi - if id -nG "$USER" 2>/dev/null | grep -qw docker; then - e_info " $USER is already in the docker group" - else - e_info " Adding $USER to the docker group..." - sudo usermod -aG docker "$USER" - e_warn " Log out and back in (or run: newgrp docker) for group membership to apply" - fi + if id -nG "$USER" 2>/dev/null | grep -qw docker; then + e_info " $USER is already in the docker group" + else + e_info " Adding $USER to the docker group..." + sudo usermod -aG docker "$USER" + e_warn " Log out and back in (or run: newgrp docker) for group membership to apply" + fi - mkdir -p "$HOME/.config/aliases" - copy_config "$CONFIGS/aliases/.docker_aliases" "$HOME/.config/aliases/.docker_aliases" - e_info " Installed Docker aliases" + mkdir -p "$HOME/.config/aliases" + copy_config "$CONFIGS/aliases/.docker_aliases" "$HOME/.config/aliases/.docker_aliases" + e_info " Installed Docker aliases" - INSTALLED+=("docker") + INSTALLED+=("docker") } install_git_config() { - e_info "\n[6/6] Git config (delta pager)" + e_info "\n[6/6] Git config (delta pager)" - if ! command_exists delta; then - e_warn " git-delta not installed — config will be ready when delta is available" - fi + if ! command_exists delta; then + e_warn " git-delta not installed — config will be ready when delta is available" + fi - local gitconfig="$HOME/.gitconfig" + local gitconfig="$HOME/.gitconfig" - # Only inject delta config if not already present - if [ -f "$gitconfig" ] && grep -q '\[delta\]' "$gitconfig" 2>/dev/null; then - e_info " Delta config already present in ~/.gitconfig" - else - e_info " Adding delta pager config to ~/.gitconfig" - cat >> "$gitconfig" << 'DELTA' + # Only inject delta config if not already present + if [ -f "$gitconfig" ] && grep -q '\[delta\]' "$gitconfig" 2>/dev/null; then + e_info " Delta config already present in ~/.gitconfig" + else + e_info " Adding delta pager config to ~/.gitconfig" + cat >>"$gitconfig" <<'DELTA' [core] pager = delta @@ -271,9 +271,9 @@ install_git_config() { [merge] conflictStyle = zdiff3 DELTA - fi + fi - INSTALLED+=("git-config") + INSTALLED+=("git-config") } # --------------------------------------------------------------------------- @@ -281,60 +281,63 @@ DELTA # --------------------------------------------------------------------------- uninstall() { - e_warn "This will remove configs installed by Server CLI Tools." - e_warn "Installed packages (apt) will NOT be removed." - echo "" - printf "Continue? [y/N] " - read -r confirm - case "$confirm" in - y|Y) ;; - *) echo "Aborted."; exit 0 ;; - esac + e_warn "This will remove configs installed by Server CLI Tools." + e_warn "Installed packages (apt) will NOT be removed." + echo "" + printf "Continue? [y/N] " + read -r confirm + case "$confirm" in + y | Y) ;; + *) + echo "Aborted." + exit 0 + ;; + esac - local removed=() + local removed=() - # Aliases + custom tools - if [ -d "$HOME/.config/aliases" ]; then - rm -rf "$HOME/.config/aliases" - removed+=("aliases") - fi - if [ -d "$HOME/.config/custom_tools" ]; then - rm -rf "$HOME/.config/custom_tools" - removed+=("custom-tools") - fi + # Aliases + custom tools + if [ -d "$HOME/.config/aliases" ]; then + rm -rf "$HOME/.config/aliases" + removed+=("aliases") + fi + if [ -d "$HOME/.config/custom_tools" ]; then + rm -rf "$HOME/.config/custom_tools" + removed+=("custom-tools") + fi - # Terminal configs - if [ -f "$HOME/.config/bat/config" ]; then - rm -f "$HOME/.config/bat/config" - removed+=("bat-config") - fi - # Zsh theme + zshrc - if [ -f "$HOME/.config/zsh/zhann-elvis.zsh-theme" ]; then - rm -f "$HOME/.config/zsh/zhann-elvis.zsh-theme" - removed+=("zsh-theme") - fi - if [ -f "$HOME/.zshrc" ]; then - rm -f "$HOME/.zshrc" - removed+=("zshrc") - fi + # Terminal configs + if [ -f "$HOME/.config/bat/config" ]; then + rm -f "$HOME/.config/bat/config" + removed+=("bat-config") + fi + # Zsh theme + zshrc + if [ -f "$HOME/.config/zsh/zhann-elvis.zsh-theme" ]; then + rm -f "$HOME/.config/zsh/zhann-elvis.zsh-theme" + removed+=("zsh-theme") + fi + if [ -f "$HOME/.zshrc" ]; then + rm -f "$HOME/.zshrc" + removed+=("zshrc") + fi - # Oh-My-Zsh plugins (only the ones we installed) - local zsh_custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" - if [ -d "$zsh_custom/plugins/zsh-autosuggestions" ]; then - rm -rf "$zsh_custom/plugins/zsh-autosuggestions" - removed+=("zsh-autosuggestions") - fi - if [ -d "$zsh_custom/plugins/zsh-syntax-highlighting" ]; then - rm -rf "$zsh_custom/plugins/zsh-syntax-highlighting" - removed+=("zsh-syntax-highlighting") - fi + # Oh-My-Zsh plugins (only the ones we installed) + local zsh_custom="${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}" + if [ -d "$zsh_custom/plugins/zsh-autosuggestions" ]; then + rm -rf "$zsh_custom/plugins/zsh-autosuggestions" + removed+=("zsh-autosuggestions") + fi + if [ -d "$zsh_custom/plugins/zsh-syntax-highlighting" ]; then + rm -rf "$zsh_custom/plugins/zsh-syntax-highlighting" + removed+=("zsh-syntax-highlighting") + fi - # Git config — strip delta block - local gitconfig="$HOME/.gitconfig" - if [ -f "$gitconfig" ] && grep -q '\[delta\]' "$gitconfig" 2>/dev/null; then - local tmp - tmp=$(mktemp) - awk ' + # Git config — strip delta block + local gitconfig="$HOME/.gitconfig" + if [ -f "$gitconfig" ] && grep -q '\[delta\]' "$gitconfig" 2>/dev/null; then + local tmp + tmp=$(mktemp) + awk ' /^\[core\]/ { if (skip==0) { peek=1; hold=$0; next } } peek==1 { if ($0 ~ /pager *= *delta/) { skip=1; next } @@ -347,42 +350,42 @@ uninstall() { /^\[/ { skip=0 } skip { next } { print } - ' "$gitconfig" > "$tmp" - mv "$tmp" "$gitconfig" - removed+=("git-delta-config") - fi + ' "$gitconfig" >"$tmp" + mv "$tmp" "$gitconfig" + removed+=("git-delta-config") + fi + echo "" + if [ ${#removed[@]} -gt 0 ]; then + e_succ "Removed:" + for item in "${removed[@]}"; do + echo " - $item" + done + else + e_info "Nothing to remove." + fi + + # Offer to restore backups + local bkp_base="$HOME/.server_cli_tools_bkp" + if [ -d "$bkp_base" ]; then echo "" - if [ ${#removed[@]} -gt 0 ]; then - e_succ "Removed:" - for item in "${removed[@]}"; do - echo " - $item" - done - else - e_info "Nothing to remove." + local latest + latest=$(ls -1t "$bkp_base" 2>/dev/null | head -n1) + if [ -n "$latest" ]; then + e_info "Backup found: $bkp_base/$latest" + printf "Restore from this backup? [y/N] " + read -r restore + case "$restore" in + y | Y) + cp -a "$bkp_base/$latest"/. "$HOME"/ + e_succ "Restored from $bkp_base/$latest" + ;; + *) e_info "Skipping restore." ;; + esac fi + fi - # Offer to restore backups - local bkp_base="$HOME/.server_cli_tools_bkp" - if [ -d "$bkp_base" ]; then - echo "" - local latest - latest=$(ls -1t "$bkp_base" 2>/dev/null | head -n1) - if [ -n "$latest" ]; then - e_info "Backup found: $bkp_base/$latest" - printf "Restore from this backup? [y/N] " - read -r restore - case "$restore" in - y|Y) - cp -a "$bkp_base/$latest"/. "$HOME"/ - e_succ "Restored from $bkp_base/$latest" - ;; - *) e_info "Skipping restore." ;; - esac - fi - fi - - echo "" + echo "" } # --------------------------------------------------------------------------- @@ -390,104 +393,104 @@ uninstall() { # --------------------------------------------------------------------------- COMPONENTS=( - "Core packages (vim, bat, eza, fzf, htop, tmux, rg, fd, zoxide, delta)" - "Zsh + Oh-My-Zsh (shell, plugins, theme)" - "Aliases + custom tools" - "Terminal configs (bat)" - "Docker (engine + aliases)" - "Git config (delta pager)" + "Core packages (vim, bat, eza, fzf, htop, tmux, rg, fd, zoxide, delta)" + "Zsh + Oh-My-Zsh (shell, plugins)" + "Aliases + custom tools" + "Terminal configs (bat)" + "Docker (engine + aliases)" + "Git config (delta pager)" ) INSTALLERS=( - install_core_packages - install_zsh - install_aliases - install_terminal_configs - install_docker - install_git_config + install_core_packages + install_zsh + install_aliases + install_terminal_configs + install_docker + install_git_config ) show_menu() { - local count=${#COMPONENTS[@]} - local selected=() + local count=${#COMPONENTS[@]} + local selected=() + for ((i = 0; i < count; i++)); do + selected+=(1) + done + + while true; do + safe_clear + echo "" + e_info "Server CLI Tools — Installer" + echo "=============================" + echo "" + echo "Select components (enter number to toggle, a=all, n=none):" + echo "" + for ((i = 0; i < count; i++)); do - selected+=(1) + local mark=" " + if [ "${selected[$i]}" -eq 1 ]; then + mark=" x " + fi + printf " [%s] %d) %s\n" "$mark" "$((i + 1))" "${COMPONENTS[$i]}" done - while true; do - safe_clear - echo "" - e_info "Server CLI Tools — Installer" - echo "=============================" - echo "" - echo "Select components (enter number to toggle, a=all, n=none):" - echo "" + echo "" + echo " [a] Select all [n] Select none [Enter] Install [q] Quit" + echo "" + printf " > " + read -r choice - for ((i = 0; i < count; i++)); do - local mark=" " - if [ "${selected[$i]}" -eq 1 ]; then - mark=" x " - fi - printf " [%s] %d) %s\n" "$mark" "$((i + 1))" "${COMPONENTS[$i]}" - done + case "$choice" in + q | Q) + echo "Aborted." + exit 0 + ;; + a | A) + for ((i = 0; i < count; i++)); do + selected[$i]=1 + done + ;; + n | N) + for ((i = 0; i < count; i++)); do + selected[$i]=0 + done + ;; + "") + # Run selected installers + local any=0 + for ((i = 0; i < count; i++)); do + if [ "${selected[$i]}" -eq 1 ]; then + any=1 + fi + done + if [ "$any" -eq 0 ]; then + e_warn "Nothing selected!" + sleep 1 + continue + fi - echo "" - echo " [a] Select all [n] Select none [Enter] Install [q] Quit" - echo "" - printf " > " - read -r choice - - case "$choice" in - q|Q) - echo "Aborted." - exit 0 - ;; - a|A) - for ((i = 0; i < count; i++)); do - selected[$i]=1 - done - ;; - n|N) - for ((i = 0; i < count; i++)); do - selected[$i]=0 - done - ;; - "") - # Run selected installers - local any=0 - for ((i = 0; i < count; i++)); do - if [ "${selected[$i]}" -eq 1 ]; then - any=1 - fi - done - if [ "$any" -eq 0 ]; then - e_warn "Nothing selected!" - sleep 1 - continue - fi - - echo "" - for ((i = 0; i < count; i++)); do - if [ "${selected[$i]}" -eq 1 ]; then - ${INSTALLERS[$i]} - else - SKIPPED+=("${COMPONENTS[$i]}") - fi - done - return - ;; - *) - if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$count" ]; then - local idx=$((choice - 1)) - if [ "${selected[$idx]}" -eq 1 ]; then - selected[$idx]=0 - else - selected[$idx]=1 - fi - fi - ;; - esac - done + echo "" + for ((i = 0; i < count; i++)); do + if [ "${selected[$i]}" -eq 1 ]; then + ${INSTALLERS[$i]} + else + SKIPPED+=("${COMPONENTS[$i]}") + fi + done + return + ;; + *) + if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$count" ]; then + local idx=$((choice - 1)) + if [ "${selected[$idx]}" -eq 1 ]; then + selected[$idx]=0 + else + selected[$idx]=1 + fi + fi + ;; + esac + done } # --------------------------------------------------------------------------- @@ -495,38 +498,38 @@ show_menu() { # --------------------------------------------------------------------------- print_summary() { - echo "" - echo "===========================================" - e_succ " Installation complete!" - echo "===========================================" - - if [ ${#INSTALLED[@]} -gt 0 ]; then - echo "" - e_succ "Installed:" - for item in "${INSTALLED[@]}"; do - echo " + $item" - done - fi - - if [ ${#SKIPPED[@]} -gt 0 ]; then - echo "" - e_warn "Skipped:" - for item in "${SKIPPED[@]}"; do - echo " - $item" - done - fi - - if [ -d "$BACKUP_DIR" ]; then - echo "" - e_info "Backups saved to: $BACKUP_DIR" - fi + echo "" + echo "===========================================" + e_succ " Installation complete!" + echo "===========================================" + if [ ${#INSTALLED[@]} -gt 0 ]; then echo "" - e_info "To apply changes, start a new shell or run:" - echo " exec zsh" + e_succ "Installed:" + for item in "${INSTALLED[@]}"; do + echo " + $item" + done + fi + + if [ ${#SKIPPED[@]} -gt 0 ]; then echo "" - e_info "Type 'h' to see all available aliases." + e_warn "Skipped:" + for item in "${SKIPPED[@]}"; do + echo " - $item" + done + fi + + if [ -d "$BACKUP_DIR" ]; then echo "" + e_info "Backups saved to: $BACKUP_DIR" + fi + + echo "" + e_info "To apply changes, start a new shell or run:" + echo " exec zsh" + echo "" + e_info "Type 'h' to see all available aliases." + echo "" } # --------------------------------------------------------------------------- @@ -534,62 +537,65 @@ print_summary() { # --------------------------------------------------------------------------- usage() { - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " --all Install all components (non-interactive)" - echo " --update Pull latest changes and re-run installer" - echo " --update --all Pull latest and install all (non-interactive)" - echo " --uninstall Remove installed configs (keeps packages)" - echo " --help Show this help message" - echo "" - echo "Without options, an interactive menu is shown." + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --all Install all components (non-interactive)" + echo " --update Pull latest changes and re-run installer" + echo " --update --all Pull latest and install all (non-interactive)" + echo " --uninstall Remove installed configs (keeps packages)" + echo " --help Show this help message" + echo "" + echo "Without options, an interactive menu is shown." } main() { - case "${1:-}" in - --help|-h) - usage - exit 0 - ;; - --uninstall) - uninstall - exit 0 - ;; - --update) - e_info "Pulling latest changes..." - git -C "$SCRIPT_DIR" pull || { e_err "git pull failed"; exit 1; } - echo "" - check_os - if [ "${2:-}" = "--all" ] || [ "${2:-}" = "-a" ]; then - e_info "Server CLI Tools — installing all components" - for installer in "${INSTALLERS[@]}"; do - $installer - done - else - show_menu - fi - print_summary - ;; - --all|-a) - check_os - e_info "Server CLI Tools — installing all components" - for installer in "${INSTALLERS[@]}"; do - $installer - done - print_summary - ;; - "") - check_os - show_menu - print_summary - ;; - *) - e_err "Unknown option: $1" - usage - exit 1 - ;; - esac + case "${1:-}" in + --help | -h) + usage + exit 0 + ;; + --uninstall) + uninstall + exit 0 + ;; + --update) + e_info "Pulling latest changes..." + git -C "$SCRIPT_DIR" pull || { + e_err "git pull failed" + exit 1 + } + echo "" + check_os + if [ "${2:-}" = "--all" ] || [ "${2:-}" = "-a" ]; then + e_info "Server CLI Tools — installing all components" + for installer in "${INSTALLERS[@]}"; do + $installer + done + else + show_menu + fi + print_summary + ;; + --all | -a) + check_os + e_info "Server CLI Tools — installing all components" + for installer in "${INSTALLERS[@]}"; do + $installer + done + print_summary + ;; + "") + check_os + show_menu + print_summary + ;; + *) + e_err "Unknown option: $1" + usage + exit 1 + ;; + esac } main "$@"