Created
February 12, 2026 02:22
-
-
Save tomdavidson/45a7f4cb23cfe9749490214b7df4cc9a to your computer and use it in GitHub Desktop.
Few bash UI functions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ============================================ | |
| # UI Library - User Interface Functions | |
| # No dependencies - pure output/input | |
| # ============================================ | |
| # Color codes | |
| readonly COLOR_RESET='\033[0m' | |
| readonly COLOR_RED='\033[0;31m' | |
| readonly COLOR_GREEN='\033[0;32m' | |
| readonly COLOR_YELLOW='\033[1;33m' | |
| readonly COLOR_BLUE='\033[0;34m' | |
| readonly COLOR_CYAN='\033[0;36m' | |
| # ============================================ | |
| # Output Functions | |
| # ============================================ | |
| lib_print_info() { | |
| local message="$1" | |
| echo -e "${COLOR_BLUE}[INFO]${COLOR_RESET} $message" | |
| } | |
| lib_print_success() { | |
| local message="$1" | |
| echo -e "${COLOR_GREEN}[SUCCESS]${COLOR_RESET} $message" | |
| } | |
| lib_print_warn() { | |
| local message="$1" | |
| echo -e "${COLOR_YELLOW}[WARN]${COLOR_RESET} $message" >&2 | |
| } | |
| lib_print_error() { | |
| local message="$1" | |
| local exit_code="${2:-}" | |
| echo -e "${COLOR_RED}[ERROR]${COLOR_RESET} $message" >&2 | |
| if [[ -n "$exit_code" ]]; then | |
| exit "$exit_code" | |
| fi | |
| } | |
| lib_print_step() { | |
| local step="$1" | |
| local message="$2" | |
| echo -e "\n${COLOR_CYAN}==>${COLOR_RESET} ${COLOR_GREEN}Step $step:${COLOR_RESET} $message\n" | |
| } | |
| lib_print_header() { | |
| local message="$1" | |
| local line=$(printf '=%.0s' {1..60}) | |
| echo -e "\n${COLOR_CYAN}$line${COLOR_RESET}" | |
| echo -e "${COLOR_CYAN}$message${COLOR_RESET}" | |
| echo -e "${COLOR_CYAN}$line${COLOR_RESET}\n" | |
| } | |
| # ============================================ | |
| # Input Functions | |
| # ============================================ | |
| lib_prompt_yes_no() { | |
| local prompt="$1" | |
| local default="${2:-n}" # Default to 'n' if not specified | |
| local response | |
| if [[ "$default" == "y" ]]; then | |
| prompt="$prompt [Y/n]: " | |
| else | |
| prompt="$prompt [y/N]: " | |
| fi | |
| while true; do | |
| read -rp "$prompt" response | |
| response="${response:-$default}" # Use default if empty | |
| response=$(echo "$response" | tr '[:upper:]' '[:lower:]') | |
| case "$response" in | |
| y|yes) | |
| return 0 | |
| ;; | |
| n|no) | |
| return 1 | |
| ;; | |
| *) | |
| lib_print_warn "Please answer 'y' or 'n'" | |
| ;; | |
| esac | |
| done | |
| } | |
| lib_prompt_input() { | |
| local prompt="$1" | |
| local default="$2" | |
| local response | |
| if [[ -n "$default" ]]; then | |
| read -rp "$prompt [$default]: " response | |
| echo "${response:-$default}" | |
| else | |
| read -rp "$prompt: " response | |
| echo "$response" | |
| fi | |
| } | |
| lib_prompt_select() { | |
| local prompt="$1" | |
| shift | |
| local options=("$@") | |
| local choice | |
| echo "$prompt" | |
| for i in "${!options[@]}"; do | |
| echo " $((i+1))) ${options[$i]}" | |
| done | |
| while true; do | |
| read -rp "Enter selection [1-${#options[@]}]: " choice | |
| if [[ "$choice" =~ ^[0-9]+$ ]] && \ | |
| [[ "$choice" -ge 1 ]] && \ | |
| [[ "$choice" -le "${#options[@]}" ]]; then | |
| echo "${options[$((choice-1))]}" | |
| return 0 | |
| else | |
| lib_print_warn "Invalid selection. Please enter a number between 1 and ${#options[@]}" | |
| fi | |
| done | |
| } | |
| lib_prompt_confirm_destructive() { | |
| local action="$1" | |
| local target="$2" | |
| lib_print_warn "DESTRUCTIVE OPERATION" | |
| lib_print_warn "Action: $action" | |
| lib_print_warn "Target: $target" | |
| lib_print_warn "This operation CANNOT be undone!" | |
| echo "" | |
| if ! lib_prompt_yes_no "Are you absolutely sure you want to proceed?" "n"; then | |
| lib_print_info "Operation cancelled by user" | |
| return 1 | |
| fi | |
| # Double confirmation for extra safety | |
| lib_print_warn "Type 'yes' to confirm (not just 'y'):" | |
| local confirmation | |
| read -rp "> " confirmation | |
| if [[ "$confirmation" != "yes" ]]; then | |
| lib_print_info "Operation cancelled" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # ============================================ | |
| # Progress Functions | |
| # ============================================ | |
| lib_spinner() { | |
| local pid=$1 | |
| local message="${2:-Processing}" | |
| local delay=0.1 | |
| local spinstr='|/-\' | |
| echo -n "$message " | |
| while kill -0 "$pid" 2>/dev/null; do | |
| local temp=${spinstr#?} | |
| printf "[%c]" "$spinstr" | |
| spinstr=$temp${spinstr%"$temp"} | |
| sleep $delay | |
| printf "\b\b\b" | |
| done | |
| printf "\b\b\b \b\b\b" | |
| } | |
| lib_progress_bar() { | |
| local current=$1 | |
| local total=$2 | |
| local width=50 | |
| local percentage=$((current * 100 / total)) | |
| local filled=$((width * current / total)) | |
| local empty=$((width - filled)) | |
| printf "\rProgress: [" | |
| printf "%${filled}s" | tr ' ' '=' | |
| printf "%${empty}s" | tr ' ' '-' | |
| printf "] %3d%%" "$percentage" | |
| if [[ $current -eq $total ]]; then | |
| echo "" | |
| fi | |
| } | |
| # ============================================ | |
| # Formatting Functions | |
| # ============================================ | |
| lib_format_size() { | |
| local size_bytes=$1 | |
| local units=("B" "KB" "MB" "GB" "TB") | |
| local unit_index=0 | |
| local size=$size_bytes | |
| while [[ $size -gt 1024 && $unit_index -lt 4 ]]; do | |
| size=$((size / 1024)) | |
| ((unit_index++)) | |
| done | |
| echo "${size}${units[$unit_index]}" | |
| } | |
| lib_format_list() { | |
| local title="$1" | |
| shift | |
| local items=("$@") | |
| echo "$title:" | |
| for item in "${items[@]}"; do | |
| echo " • $item" | |
| done | |
| } | |
| lib_print_key_value() { | |
| local key="$1" | |
| local value="$2" | |
| printf " %-25s : %s\n" "$key" "$value" | |
| } | |
| # ============================================ | |
| # Validation Helper (display only) | |
| # ============================================ | |
| lib_display_validation_error() { | |
| local field="$1" | |
| local error="$2" | |
| lib_print_error "Validation failed for '$field': $error" | |
| } | |
| # ============================================ | |
| # Box Drawing | |
| # ============================================ | |
| lib_print_box() { | |
| local message="$1" | |
| local length=${#message} | |
| local border=$(printf '─%.0s' $(seq 1 $((length + 2)))) | |
| echo "┌${border}┐" | |
| echo "│ ${message} │" | |
| echo "└${border}┘" | |
| } | |
| lib_print_summary() { | |
| local title="$1" | |
| shift | |
| local items=("$@") | |
| lib_print_box "$title" | |
| for item in "${items[@]}"; do | |
| echo " $item" | |
| done | |
| echo "" | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment