#!/usr/bin/env bash set -euo pipefail # Keep select menus one item per line for screen readers. export COLUMNS=1 missingRequired=() installPlan=() add_missing_package() { local package="$1" local existing for existing in "${missingRequired[@]}"; do [[ "$existing" == "$package" ]] && return done missingRequired+=("$package") } add_install_package() { local package="$1" local existing for existing in "${installPlan[@]}"; do [[ "$existing" == "$package" ]] && return done installPlan+=("$package") } command_exists() { command -v "$1" &> /dev/null } python_import_works() { local code="$1" command_exists python3 && python3 -c "$code" &> /dev/null } has_any_command() { local commandName for commandName in "$@"; do if command_exists "$commandName"; then return 0 fi done return 1 } prompt_install() { local prompt="$1" shift local packages=("$@") local choice printf '%s\n' "$prompt" printf 'Packages: %s\n' "${packages[*]}" PS3="Select an option: " select choice in "Yes" "Exit installer"; do case "$choice" in "Yes") for package in "${packages[@]}"; do add_install_package "$package" done return ;; "Exit installer") echo "Exiting without installing packages." exit 1 ;; *) echo "Please choose 1 or 2." ;; esac done } install_packages() { if command_exists yay; then yay -S --needed "$@" else sudo pacman -S --needed "$@" fi } prompt_install_choice() { local prompt="$1" shift local choice local index local reply local options=("Skip" "$@" "Exit installer") local packages printf '%s\n' "$prompt" while true; do for index in "${!options[@]}"; do printf '%d) %s\n' "$((index + 1))" "${options[$index]}" done read -r -p "Select a package to install [1]: " reply if [[ -z "$reply" ]]; then reply=1 fi if [[ ! "$reply" =~ ^[0-9]+$ ]] || (( reply < 1 || reply > ${#options[@]} )); then echo "Please choose a listed option." continue fi choice="${options[$((reply - 1))]}" case "$choice" in "Skip") return ;; "Exit installer") echo "Exiting without installing packages." exit 1 ;; *) read -r -a packages <<< "$choice" for package in "${packages[@]}"; do add_install_package "$package" done return ;; esac done } check_required_dependencies() { command_exists dialog || add_missing_package dialog command_exists i3 || add_missing_package i3-wm command_exists jq || add_missing_package jq command_exists python3 || add_missing_package python command_exists rsync || add_missing_package rsync command_exists yad || add_missing_package yad command_exists xdotool || add_missing_package xdotool command_exists xdg-open || add_missing_package xdg-utils if ! python_import_works 'import i3ipc'; then add_missing_package python-i3ipc fi if ! python_import_works 'import gi; gi.require_version("Atk", "1.0"); gi.require_version("Gdk", "3.0"); gi.require_version("Gio", "2.0"); gi.require_version("GLib", "2.0"); gi.require_version("Gtk", "3.0"); from gi.repository import Atk, Gdk, Gio, GLib, Gtk'; then add_missing_package python-gobject fi if ! command_exists pandoc && ! command_exists markdown; then add_missing_package discount fi } check_provider_dependencies() { local emailChoices=(thunderbird evolution) local browserChoices=(firefox chromium epiphany midori seamonkey vivaldi) local screenReaderChoices=(orca) if command_exists yay; then emailChoices+=(betterbird) browserChoices+=(brave-bin) screenReaderChoices+=(cthulhu) fi if ! has_any_command betterbird evolution thunderbird; then prompt_install_choice "Missing email client. Select one to install." "${emailChoices[@]}" fi if ! has_any_command brave chromium epiphany firefox google-chrome-stable google-chrome-unstable microsoft-edge-stable microsoft-edge-beta microsoft-edge-dev midori seamonkey vivaldi; then prompt_install_choice "Missing web browser. Select one to install." "${browserChoices[@]}" fi if ! has_any_command emacs geany gedit kate kwrite l3afpad leafpad libreoffice mousepad pluma; then prompt_install_choice "Missing graphical text editor. Select one to install." geany gedit kate kwrite l3afpad leafpad libreoffice-fresh mousepad pluma fi if ! has_any_command caja nemo nautilus pcmanfm pcmanfm-qt thunar; then prompt_install_choice "Missing file manager. Select one to install." pcmanfm thunar caja nemo nautilus pcmanfm-qt fi if ! has_any_command mate-terminal lxterminal gnome-terminal terminator xfce4-terminal tilix ptyxis kgx sakura roxterm termit guake tilda qterminal konsole && { ! command_exists xterm || ! command_exists fenrir; }; then prompt_install_choice "Missing supported accessible terminal. Select one to install." mate-terminal lxterminal gnome-terminal terminator xfce4-terminal tilix ptyxis kgx sakura qterminal konsole "xterm fenrir" fi if ! has_any_command cthulhu orca; then prompt_install_choice "Missing screen reader. Select one to install." "${screenReaderChoices[@]}" fi } add_optional_dependencies() { command_exists bc || add_install_package bc command_exists notify-send || add_install_package libnotify command_exists pamixer || add_install_package pamixer command_exists playerctl || add_install_package playerctl command_exists scrot || add_install_package scrot command_exists sox || add_install_package sox command_exists udiskie || add_install_package udiskie command_exists xclip || add_install_package xclip command_exists xprintidle || add_install_package xprintidle command_exists xset || add_install_package xorg-xset echo "Skipping optional packages that need manual choice or are intentionally not installed automatically:" echo " dex" echo " tesseract" echo " xzoom" } if ! command_exists pacman && ! command_exists yay; then echo "This helper is for Arch Linux systems with pacman or yay." exit 1 fi check_required_dependencies if [[ ${#missingRequired[@]} -gt 0 ]]; then prompt_install "Missing required I38 dependencies. Add them to the install list?" "${missingRequired[@]}" fi check_provider_dependencies add_optional_dependencies if [[ ${#installPlan[@]} -gt 0 ]]; then echo "Installing selected packages:" printf ' %s\n' "${installPlan[@]}" install_packages "${installPlan[@]}" else echo "No packages selected for installation." fi echo "I38 dependency check complete."