From f39f886c9fdbae815bc65dd9711ad0039147a2c9 Mon Sep 17 00:00:00 2001 From: Pepe44DEV Date: Fri, 29 May 2026 17:42:32 +0200 Subject: [PATCH] fullscreen TUI from start: pretty box drawings, module selection with y/N, progress bar during execution --- install.sh | 95 +++++++++++++-------------- lib/tui-fs.sh | 173 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 184 insertions(+), 84 deletions(-) diff --git a/install.sh b/install.sh index 34b9605..183810d 100755 --- a/install.sh +++ b/install.sh @@ -101,27 +101,18 @@ detect_environment() { tui_detect if ((!OMERON_HAS_GUM)) && have pacman; then - printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n' - printf '\033[1;36m O M E R O N — Modular System Setup Framework\033[0m\n' - printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n' - printf '\n' - printf ' \033[1;33mgum is not installed.\033[0m Installing it enables the full TUI experience.\n' - printf '\n' - - if tui_install_gum; then - printf ' \033[1;32m✓ gum installed!\033[0m\n' + tui_fs_show_msg "Installing gum for interactive TUI..." + tui_install_gum 2>/dev/null || true + tui_detect + if ((OMERON_HAS_GUM)); then + tui_fs_show_ok "gum installed" else - if ((OMERON_HAS_WHIPTAIL)); then - printf ' \033[1;33musing whiptail as fallback\033[0m\n' - else - printf ' \033[1;33musing basic text mode (install gum for UI: pacman -S gum)\033[0m\n' - fi + tui_fs_show_msg "using terminal prompts" fi - printf '\n' fi if ((!OMERON_FRESH_INSTALL)) && ((${#RUN_MODULES[@]} == 0)); then - log_info "Checking for fresh install..." + tui_fs_show_msg "Checking for fresh install..." if is_fresh_install; then OMERON_FRESH_INSTALL=1 export OMERON_FRESH_INSTALL @@ -131,9 +122,12 @@ detect_environment() { if ((OMERON_FRESH_INSTALL)); then if ((!OMERON_HAS_GUM)) && have pacman; then tui_install_gum 2>/dev/null || true + tui_detect fi if ! have paru && ! have yay; then + tui_fs_show_msg "Installing AUR helper..." install_aur_helper + tui_fs_show_ok "AUR helper ready" fi fi } @@ -181,11 +175,12 @@ collect_all_interactive() { fi local module_order=() + local idx=1 + local total=${#modules[@]} for mod in "${modules[@]}"; do local module_file="$OMERON_MODULE_DIR/$mod.sh" [[ -f "$module_file" ]] || continue - source "$module_file" 2>/dev/null || continue local description="" @@ -193,32 +188,35 @@ collect_all_interactive() { description="$(module_description)" fi + local required=0 if declare -F "module_required" >/dev/null 2>&1; then if module_required; then - module_order+=("$module_file") - continue + required=1 fi fi - printf ' ' - if tui_confirm "${description:-$mod}"; then + if ((required)); then + tui_fs_select_module "$idx" "$total" "$mod" "$description" 1 + module_order+=("$module_file") + ((idx++)) + continue + fi + + if tui_fs_select_module "$idx" "$total" "$mod" "$description" 0; then module_order+=("$module_file") fi + ((idx++)) done + if ! tui_fs_confirm_start "${#module_order[@]}"; then + exec 3>&- + return 1 + fi + printf '%s\n' "${module_order[@]}" >&3 exec 3>&- } -show_banner() { - tui_header "O M E R O N — Modular System Setup" - printf '\n' - if ((OMERON_FRESH_INSTALL)); then - tui_info "Fresh install: Hyprland + GPU drivers + all dependencies" - printf '\n' - fi -} - main() { OMERON_LOG_FILE="${OMERON_LOG_FILE:-$HOME/.local/share/omeron/install-$(date +%Y%m%d-%H%M%S).log}" export OMERON_LOG_FILE @@ -231,45 +229,42 @@ main() { log_info "Project: $OMERON_ROOT" sudo_init - trap 'sudo_cleanup' EXIT + trap 'sudo_cleanup; tui_fs_exit' EXIT + + tui_fs_init detect_environment - show_banner - - tui_separator - printf '\n' - if ! tui_confirm "Continue with installation"; then - tui_info "Installation cancelled." - exit 0 - fi - printf '\n' - local modules_to_run=() if ((${#RUN_MODULES[@]})); then mapfile -t modules_to_run < <(collect_modules) else - mapfile -t modules_to_run < <(collect_all_interactive) + local collected + collected="$(collect_all_interactive)" || { + tui_fs_exit + exit 0 + } + mapfile -t modules_to_run <<< "$collected" fi if ((${#modules_to_run[@]} == 0)); then - tui_warn "No modules selected. Nothing to do." + tui_fs_show_msg "No modules selected. Nothing to do." + tui_fs_exit exit 0 fi + tui_fs_start_execution + local total=${#modules_to_run[@]} local idx=1 - tui_fs_init - local fs_active=$? - for module_path in "${modules_to_run[@]}"; do local description="" if source "$module_path" 2>/dev/null && declare -F "module_description" >/dev/null 2>&1; then description="$(module_description)" fi - ((fs_active == 0)) && tui_fs_set_overall "$idx" "$total" "${description:-$(basename "$module_path" .sh)}" + tui_fs_set_step "$idx" "$total" "${description:-$(basename "$module_path" .sh)}" printf '\n' log_step "$idx" "$total" "${description:-$(basename "$module_path" .sh)}" @@ -278,17 +273,17 @@ main() { if declare -F "module_required" >/dev/null 2>&1; then source "$module_path" if module_required 2>/dev/null; then - ((fs_active == 0)) && tui_fs_exit + tui_fs_exit tui_error "Required module failed. Aborting." exit $rc fi fi - tui_warn "Module completed with warnings" + tui_fs_show_msg "Module completed with warnings" } ((idx++)) done - ((fs_active == 0)) && tui_fs_exit + tui_fs_exit printf '\n' tui_header "O M E R O N — Done" diff --git a/lib/tui-fs.sh b/lib/tui-fs.sh index 6375dfd..7c37bea 100644 --- a/lib/tui-fs.sh +++ b/lib/tui-fs.sh @@ -3,14 +3,12 @@ TUI_FS_ACTIVE=0 TUI_FS_ROWS=0 TUI_FS_COLS=0 -TUI_FS_OVERALL_CURRENT=0 -TUI_FS_OVERALL_TOTAL=0 -TUI_FS_MODULE_LABEL="" +TUI_FS_CURRENT=0 +TUI_FS_TOTAL=0 +TUI_FS_LABEL="" TUI_FS_SAVED_STTY="" tui_fs_init() { - ((OMERON_HAS_GUM)) || return 1 - TUI_FS_SAVED_STTY=$(stty -g 2>/dev/null || true) TUI_FS_ROWS=$(tput lines 2>/dev/null || echo 24) TUI_FS_COLS=$(tput cols 2>/dev/null || echo 80) @@ -20,6 +18,7 @@ tui_fs_init() { tput clear 2>/dev/null || true TUI_FS_ACTIVE=1 + _tui_fs_draw_selection_banner } tui_fs_exit() { @@ -30,50 +29,156 @@ tui_fs_exit() { [[ -n "$TUI_FS_SAVED_STTY" ]] && stty "$TUI_FS_SAVED_STTY" 2>/dev/null || true } -tui_fs_set_overall() { - TUI_FS_OVERALL_CURRENT=$1 - TUI_FS_OVERALL_TOTAL=$2 - TUI_FS_MODULE_LABEL="${3:-}" - _tui_fs_draw_screen +_tui_fs_hline() { + local len=$1 + local i + for ((i=0; i/dev/null || true + _tui_fs_title +} + +tui_fs_show_msg() { + [[ "$TUI_FS_ACTIVE" -eq 0 ]] && { printf '%s\n' "$*"; return; } + printf ' \033[1;34m▶\033[0m %s\n' "$*" +} + +tui_fs_show_ok() { + [[ "$TUI_FS_ACTIVE" -eq 0 ]] && { printf '%s\n' "$*"; return; } + printf ' \033[1;32m✓\033[0m %s\n' "$*" +} + +tui_fs_start_execution() { + [[ "$TUI_FS_ACTIVE" -eq 0 ]] && return + TUI_FS_CURRENT=0 + TUI_FS_TOTAL=0 + TUI_FS_LABEL="" +} + +tui_fs_set_step() { + [[ "$TUI_FS_ACTIVE" -eq 0 ]] && return + TUI_FS_CURRENT=$1 + TUI_FS_TOTAL=$2 + TUI_FS_LABEL="${3:-}" + _tui_fs_draw_exec_header +} + +_tui_fs_draw_exec_header() { [[ "$TUI_FS_ACTIVE" -eq 0 ]] && return tput cup 0 0 2>/dev/null || true tput clear 2>/dev/null || true local cols=$TUI_FS_COLS - local cols_safe=$((cols > 60 ? cols : 60)) + local c=$((cols - 4)) + ((c < 30)) && c=30 + local hline + hline="$(_tui_fs_hline "$c")" - printf "\033[7m %-*s\033[0m\n" $((cols_safe - 2)) " Omeron — Modular System Setup" - - if [[ -n "$TUI_FS_MODULE_LABEL" ]]; then - printf " Module: %-*s" $((cols_safe - 18)) "$TUI_FS_MODULE_LABEL" - if ((TUI_FS_OVERALL_TOTAL > 0)); then - printf " [%d/%d]" "$TUI_FS_OVERALL_CURRENT" "$TUI_FS_OVERALL_TOTAL" - fi - printf "\n" - else - printf "\n" + printf '\033[1;36m╭%s╮\033[0m\n' "$hline" + local title="◆ Omeron" + if [[ -n "$TUI_FS_LABEL" ]]; then + title+=" — ${TUI_FS_LABEL}" fi - - local bar_width=$((cols_safe - 16)) - ((bar_width < 10)) && bar_width=10 + printf '\033[1;36m│\033[0m \033[1;37m%-*s\033[0m \033[1;36m│\033[0m\n' "$c" "$title" local progress=0 - if ((TUI_FS_OVERALL_TOTAL > 0)); then - progress=$(( TUI_FS_OVERALL_CURRENT * 100 / TUI_FS_OVERALL_TOTAL )) + if ((TUI_FS_TOTAL > 0)); then + progress=$(( TUI_FS_CURRENT * 100 / TUI_FS_TOTAL )) ((progress > 100)) && progress=100 fi - printf " " + local bar_width=$((c - 24)) + ((bar_width < 10)) && bar_width=10 local filled=$(( progress * bar_width / 100 )) + local bar="" local i - for ((i=0; i/dev/null || true + tput ed 2>/dev/null || true + + printf ' \033[1;36m┌─\033[0m \033[1;37mModule %d/%d\033[0m\n' "$idx" "$total" + printf ' \033[1;36m│\033[0m\n' + printf ' \033[1;36m│\033[0m \033[1;37m%s\033[0m\n' "$description" + printf ' \033[1;36m│\033[0m \033[2m%s\033[0m\n' "$label" + printf ' \033[1;36m└─\033[0m\n' + printf '\n' + + if ((required)); then + printf ' \033[1;33m▶\033[0m required module\n' + printf '\n' + printf ' Press any key to continue... ' + read -n 1 -s -r + printf '\n' + return 0 + fi + + if ((OMERON_HAS_GUM)); then + gum confirm "Include this module?" + return $? + fi + + printf ' \033[1;36m?\033[0m Include this module? \033[1m[Y/n]\033[0m ' + read -r response + response="${response:-Y}" + [[ "$response" =~ ^[yY](es)?$ ]] + return $? +} + +tui_fs_confirm_start() { + local count="$1" + [[ "$TUI_FS_ACTIVE" -eq 0 ]] && return 0 + + tput cup 4 0 2>/dev/null || true + tput ed 2>/dev/null || true + + printf ' \033[1;36m┌─\033[0m \033[1;37mSelection Complete\033[0m\n' + printf ' \033[1;36m│\033[0m\n' + printf ' \033[1;36m│\033[0m \033[1;37m%d\033[0m module(s) selected\n' "$count" + printf ' \033[1;36m└─\033[0m\n' + printf '\n' + + if ((OMERON_HAS_GUM)); then + gum confirm "Start installation?" + return $? + fi + + printf ' \033[1;36m?\033[0m Start installation? \033[1m[Y/n]\033[0m ' + read -r response + response="${response:-Y}" + [[ "$response" =~ ^[yY](es)?$ ]] + return $? }