feat(install): rewrite install.sh with interactive mode selection

- 3 install modes: Full, Minimal, Custom (pick categories)
- Dry-run flag (-n) to preview packages without installing
- Progress bar with percentage during package install
- Better visual hierarchy with section headers and dividers
- Package categories: Core, Shell, Hyprland, UI, Hardware, Network, Audio, Build
- Failed package summary at end
- Cleaner banner and completion output
This commit is contained in:
sankalp committed 2026-07-18 15:12:21 +05:45
1 parent 6d9057cd06
commit ab9b9df4e1
1 file changed
+284 -186
+284 -186
View File
@@ -10,104 +10,156 @@
# A hackable shell for Hyprland # A hackable shell for Hyprland
# Installation Script for Arch Linux # Installation Script for Arch Linux
# #
# Repository: https://github.com/S4NKALP/Modus --branch macos # Repository: https://github.com/S4NKALP/Modus
# License: GPLv3 # License: GPLv3
set -e set -e
set -u set -u
set -o pipefail set -o pipefail
# ── CLI flags ──────────────────────────────────────────────────────
AUTO_YES=false AUTO_YES=false
DRY_RUN=false
MINIMAL=false
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
-y|--yes) AUTO_YES=true ;; -y|--yes) AUTO_YES=true ;;
-n|--dry-run) DRY_RUN=true ;;
-m|--minimal) MINIMAL=true ;;
-h|--help)
echo "Usage: install.sh [OPTIONS]"
echo ""
echo "Options:"
echo " -y, --yes Skip all prompts"
echo " -n, --dry-run Show what would be installed without installing"
echo " -m, --minimal Install only core packages"
echo " -h, --help Show this help"
exit 0
;;
esac esac
done done
REPO_URL="https://github.com/S4NKALP/Modus.git" REPO_URL="https://github.com/S4NKALP/Modus.git"
INSTALL_DIR="$HOME/.config/Modus" INSTALL_DIR="$HOME/.config/Modus"
PACKAGES=( # ── Package definitions ────────────────────────────────────────────
CORE_PACKAGES=(
uv uv
fabric-cli-git fabric-cli-git
uwsm
)
SHELL_PACKAGES=(
cliphist cliphist
gnome-bluetooth-3.0
slurp slurp
ffmpeg grim
swappy
wl-clipboard
wtype
libnotify
playerctl
matugen-bin
)
HYPRLAND_PACKAGES=(
hypridle hypridle
hyprsunset hyprsunset
hyprpicker hyprpicker
hyprshot hyprshot
grim
libnotify
matugen-bin
playerctl
gtk-session-lock gtk-session-lock
)
UI_PACKAGES=(
awww awww
apple-fonts apple-fonts
swappy
wl-clipboard
webp-pixbuf-loader webp-pixbuf-loader
wf-recorder cinnamon-desktop
libmediaart
)
HARDWARE_PACKAGES=(
acpi acpi
brightnessctl brightnessctl
power-profiles-daemon power-profiles-daemon
uwsm
cinnamon-desktop
ddcutil ddcutil
at-spi2-core at-spi2-core
gcc )
make
pkgconf NETWORK_PACKAGES=(
appmenu-gtk-module
libdbusmenu-gtk3
libdbusmenu-qt5
meson
ninja
wayland-protocols
libmediaart
networkmanager networkmanager
network-manager-applet network-manager-applet
blueman blueman
libqalculate
wtype
pipewire
libpulse
pciutils
gtk-layer-shell
librsvg
gobject-introspection
) )
# Colors and formatting AUDIO_PACKAGES=(
pipewire
libpulse
)
BUILD_PACKAGES=(
gcc
make
pkgconf
meson
ninja
wayland-protocols
gobject-introspection
gtk-layer-shell
librsvg
libqalculate
appmenu-gtk-module
libdbusmenu-gtk3
libdbusmenu-qt5
pciutils
wf-recorder
ffmpeg
)
ALL_PACKAGES=(
"${CORE_PACKAGES[@]}"
"${SHELL_PACKAGES[@]}"
"${HYPRLAND_PACKAGES[@]}"
"${UI_PACKAGES[@]}"
"${HARDWARE_PACKAGES[@]}"
"${NETWORK_PACKAGES[@]}"
"${AUDIO_PACKAGES[@]}"
"${BUILD_PACKAGES[@]}"
)
# ── Colors ─────────────────────────────────────────────────────────
if [ -t 1 ]; then if [ -t 1 ]; then
GREEN=$(tput setaf 2) GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3) YELLOW=$(tput setaf 3)
RED=$(tput setaf 1) RED=$(tput setaf 1)
CYAN=$(tput setaf 6) CYAN=$(tput setaf 6)
BLUE=$(tput setaf 4) BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
BOLD=$(tput bold) BOLD=$(tput bold)
DIM=$(tput dim) DIM=$(tput dim)
RESET=$(tput sgr0) RESET=$(tput sgr0)
else else
GREEN="" YELLOW="" RED="" CYAN="" BLUE="" BOLD="" DIM="" RESET="" GREEN="" YELLOW="" RED="" CYAN="" BLUE="" MAGENTA="" BOLD="" DIM="" RESET=""
fi fi
# Status symbols
ARROW="→" ARROW="→"
CHECK="✔" CHECK="✔"
CROSS="✖" CROSS="✖"
INFO="ℹ" INFO="ℹ"
WARN="⚠" WARN="⚠"
BULLET="•"
# Progress tracking # ── Helpers ────────────────────────────────────────────────────────
TOTAL_STEPS=12 header() {
CURRENT_STEP=0 echo ""
echo -e " ${BOLD}${CYAN}╔══════════════════════════════════════════════╗${RESET}"
echo -e " ${BOLD}${CYAN}║${RESET} ${BOLD}Modus Installer${RESET} ${DIM}v2.0${RESET} ${BOLD}${CYAN}║${RESET}"
echo -e " ${BOLD}${CYAN}╚══════════════════════════════════════════════╝${RESET}"
echo ""
}
# Function for progress indicator section() {
progress() { echo ""
CURRENT_STEP=$((CURRENT_STEP + 1)) echo -e " ${BOLD}${MAGENTA}── $1 ──${RESET}"
echo -e "\n${BOLD}${BLUE}[${CURRENT_STEP}/${TOTAL_STEPS}]${RESET} ${BOLD}$1${RESET}"
} }
step() { step() {
@@ -123,13 +175,33 @@ warn() {
} }
error() { error() {
echo -e "\n${RED}${CROSS}${RESET} ${RED}${BOLD}ERROR:${RESET} ${RED}$1${RESET}\n" >&2 echo -e " ${RED}${CROSS}${RESET} ${RED}$1${RESET}"
} }
info() { info() {
echo -e " ${BLUE}${INFO}${RESET} ${DIM}$1${RESET}" echo -e " ${BLUE}${INFO}${RESET} ${DIM}$1${RESET}"
} }
divider() {
echo -e " ${DIM}──────────────────────────────────────────────${RESET}"
}
confirm() {
local prompt="$1"
local default="${2:-n}"
local yn
if [ "$AUTO_YES" = true ]; then
return 0
fi
if [ "$default" = "y" ]; then
read -rp " ${BOLD}${prompt} [Y/n]:${RESET} " yn
[[ ! "$yn" =~ ^[Nn]$ ]]
else
read -rp " ${BOLD}${prompt} [y/N]:${RESET} " yn
[[ "$yn" =~ ^[Yy]$ ]]
fi
}
spinner() { spinner() {
local pid=$1 local pid=$1
local message=$2 local message=$2
@@ -141,34 +213,36 @@ spinner() {
i=$(((i + 1) % 10)) i=$(((i + 1) % 10))
sleep 0.1 sleep 0.1
done done
printf "\r" printf "\r %b%s%b %s\n" "$GREEN" "${CHECK}" "$RESET" "$message"
} }
# Cleanup handler print_packages() {
local -n pkgs=$1
local count=${#pkgs[@]}
echo -e " ${DIM}${BULLET}${RESET} ${BOLD}$2${RESET} ${DIM}(${count} packages)${RESET}"
for pkg in "${pkgs[@]}"; do
echo -e " ${DIM}${BULLET}${RESET} ${pkg}"
done
}
# ── Cleanup ────────────────────────────────────────────────────────
cleanup() { cleanup() {
if [ -n "${SUDO_KEEPER_PID:-}" ]; then if [ -n "${SUDO_KEEPER_PID:-}" ]; then
kill $SUDO_KEEPER_PID 2>/dev/null || true kill "$SUDO_KEEPER_PID" 2>/dev/null || true
fi fi
} }
trap cleanup EXIT INT TERM trap cleanup EXIT INT TERM
# Header # ── Banner ─────────────────────────────────────────────────────────
clear clear
echo -e "${BOLD}${CYAN}" header
cat << "EOF"
███╗ ███╗ ██████╗ ██████╗ ██╗ ██╗███████╗
████╗ ████║██╔═══██╗██╔══██╗██║ ██║██╔════╝
██╔████╔██║██║ ██║██║ ██║██║ ██║███████╗
██║╚██╔╝██║██║ ██║██║ ██║██║ ██║╚════██║
██║ ╚═╝ ██║╚██████╔╝██████╔╝╚██████╔╝███████║
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
EOF
echo -e "${RESET}"
echo -e "${BOLD} A hackable shell for Hyprland${RESET}"
echo -e "${DIM} Installation Script v1.0${RESET}\n"
# Pre-flight checks echo -e " ${BOLD}A hackable shell for Hyprland${RESET}"
progress "Pre-flight checks" echo -e " ${DIM}https://github.com/S4NKALP/Modus${RESET}"
echo ""
# ── Pre-flight checks ─────────────────────────────────────────────
section "Pre-flight checks"
step "Checking operating system..." step "Checking operating system..."
if ! grep -qi "arch" /etc/os-release; then if ! grep -qi "arch" /etc/os-release; then
@@ -184,25 +258,68 @@ if [ "$(id -u)" -eq 0 ]; then
fi fi
success "Running as regular user" success "Running as regular user"
step "Checking system requirements..." step "Checking git..."
if ! command -v git &>/dev/null; then if ! command -v git &>/dev/null; then
error "git is not installed. Please install it first: sudo pacman -S git" error "git is not installed. Run: sudo pacman -S git"
exit 1 exit 1
fi fi
success "All requirements met" success "git found"
# Sudo authentication # ── Install mode selection ────────────────────────────────────────
progress "Requesting permissions" section "Install mode"
info "Some packages require root privileges for installation" if [ "$MINIMAL" = true ]; then
echo "" PACKAGES=("${CORE_PACKAGES[@]}")
if ! sudo -v; then info "Minimal mode: ${#PACKAGES[@]} core packages only"
elif [ "$AUTO_YES" = true ]; then
PACKAGES=("${ALL_PACKAGES[@]}")
info "Full install: ${#PACKAGES[@]} packages"
else
echo -e " ${BOLD}Choose install mode:${RESET}"
echo ""
echo -e " ${GREEN}${ARROW}${RESET} ${BOLD}1) Full${RESET} ${DIM}— everything (${#ALL_PACKAGES[@]} packages)${RESET}"
echo -e " ${YELLOW}${ARROW}${RESET} ${BOLD}2) Minimal${RESET} ${DIM}— core only (${#CORE_PACKAGES[@]} packages)${RESET}"
echo -e " ${CYAN}${ARROW}${RESET} ${BOLD}3) Custom${RESET} ${DIM}— pick categories${RESET}"
echo ""
read -rp " ${BOLD}Select [1-3]:${RESET} " mode_choice
case "$mode_choice" in
2)
PACKAGES=("${CORE_PACKAGES[@]}")
;;
3)
PACKAGES=("${CORE_PACKAGES[@]}")
echo ""
for cat in "SHELL:Shell tools" "HYPRLAND:Hyprland extras" "UI:Desktop widgets" "HARDWARE:Hardware control" "NETWORK:Bluetooth & network" "AUDIO:Audio" "BUILD:Build tools"; do
local_name="${cat%%:*}"
local_label="${cat#*:}"
local_ref="${local_name}_PACKAGES[@]"
local_count="${#${!local_ref}}"
if confirm "${local_label} (${local_count} packages)?" "y"; then
PACKAGES+=("${!local_ref}")
fi
done
;;
*)
PACKAGES=("${ALL_PACKAGES[@]}")
;;
esac
fi
divider
echo -e " ${BOLD}Will install ${GREEN}${#PACKAGES[@]}${RESET}${BOLD} packages${RESET}"
divider
# ── Sudo ───────────────────────────────────────────────────────────
section "Permissions"
info "Some packages require root privileges"
if ! sudo -v 2>/dev/null; then
error "Sudo authentication failed" error "Sudo authentication failed"
exit 1 exit 1
fi fi
success "Permissions granted" success "Sudo authenticated"
# Keep sudo alive
while true; do while true; do
sudo -n true sudo -n true
sleep 60 sleep 60
@@ -210,65 +327,62 @@ while true; do
done 2>/dev/null & done 2>/dev/null &
SUDO_KEEPER_PID=$! SUDO_KEEPER_PID=$!
# Show package list # ── Show package list ─────────────────────────────────────────────
progress "Package information" section "Packages"
info "Total packages to install: ${BOLD}${#PACKAGES[@]}${RESET}" if [ "$DRY_RUN" = true ]; then
echo ""
if [ "$AUTO_YES" = false ]; then
read -rp " ${YELLOW}${INFO}${RESET} View full package list? (y/N): " view_packages
else
view_packages="n"
fi
if [[ "$view_packages" =~ ^[Yy]$ ]]; then
echo "" echo ""
printf " ${DIM}• %s${RESET}\n" "${PACKAGES[@]}" printf " ${DIM}%s${RESET}\n" "${PACKAGES[@]}"
echo "" echo ""
fi info "Dry run — no packages will be installed"
# Confirmation
if [ "$AUTO_YES" = false ]; then
read -rp " ${BOLD}Proceed with installation? (y/N):${RESET} " confirm
else
confirm="y"
fi
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
warn "Installation cancelled by user"
exit 0 exit 0
fi fi
# AUR helper setup if confirm "View full package list?"; then
progress "Setting up AUR helper" echo ""
printf " ${DIM}${BULLET} %s${RESET}\n" "${PACKAGES[@]}"
echo ""
fi
aur_helper="yay" if ! confirm "Proceed with installation?"; then
warn "Cancelled"
exit 0
fi
# ── AUR helper ─────────────────────────────────────────────────────
section "AUR helper"
AUR=""
if command -v paru &>/dev/null; then if command -v paru &>/dev/null; then
aur_helper="paru" AUR="paru"
success "Found paru" success "Using paru"
elif command -v yay &>/dev/null; then elif command -v yay &>/dev/null; then
success "Found yay" AUR="yay"
success "Using yay"
else else
step "Installing yay-bin..." step "Installing yay-bin..."
tmpdir=$(mktemp -d) tmpdir=$(mktemp -d)
( (
git clone --quiet --depth=1 https://aur.archlinux.org/yay-bin.git "$tmpdir/yay-bin" 2>/dev/null || true git clone --quiet --depth=1 https://aur.archlinux.org/yay-bin.git "$tmpdir/yay-bin"
cd "$tmpdir/yay-bin" cd "$tmpdir/yay-bin"
makepkg -si --noconfirm >/dev/null 2>&1 makepkg -si --noconfirm >/dev/null 2>&1
) & ) &
spinner $! "Building yay-bin..." spinner $! "Building yay-bin"
wait $! || { wait $! || {
error "Failed to install yay-bin" error "Failed to install yay-bin"
rm -rf "$tmpdir" rm -rf "$tmpdir"
exit 1 exit 1
} }
rm -rf "$tmpdir" rm -rf "$tmpdir"
success "yay-bin installed successfully" AUR="yay"
success "yay-bin installed"
fi fi
# Repository setup # ── Repository ─────────────────────────────────────────────────────
progress "Setting up Modus repository" section "Repository"
if [ -d "$INSTALL_DIR" ]; then if [ -d "$INSTALL_DIR" ]; then
step "Updating existing repository..." step "Pulling latest changes..."
git -C "$INSTALL_DIR" pull --quiet 2>/dev/null || true git -C "$INSTALL_DIR" pull --quiet 2>/dev/null || true
success "Repository updated" success "Repository updated"
else else
@@ -276,70 +390,59 @@ else
git clone --quiet "$REPO_URL" "$INSTALL_DIR" 2>/dev/null || true git clone --quiet "$REPO_URL" "$INSTALL_DIR" 2>/dev/null || true
success "Repository cloned" success "Repository cloned"
fi fi
info "Location: ${INSTALL_DIR}" info "${INSTALL_DIR}"
# Package installation # ── Install packages ──────────────────────────────────────────────
progress "Installing packages" section "Installing packages"
step "Syncing package databases..." step "Syncing databases..."
$aur_helper -Syy --noconfirm >/dev/null 2>&1 || true $AUR -Syy --noconfirm >/dev/null 2>&1 || true
success "Database synced" success "Databases synced"
step "Installing required packages (this may take a while)..."
installed=0 installed=0
failed=0 failed=0
failed_pkgs=()
total=${#PACKAGES[@]}
for pkg in "${PACKAGES[@]}"; do for pkg in "${PACKAGES[@]}"; do
if $aur_helper -S --needed --noconfirm "$pkg" >/dev/null 2>&1; then if $AUR -S --needed --noconfirm "$pkg" >/dev/null 2>&1; then
installed=$((installed + 1)) installed=$((installed + 1))
else else
failed=$((failed + 1)) failed=$((failed + 1))
warn "Failed to install: $pkg" failed_pkgs+=("$pkg")
fi fi
printf "\r %b%s%b Progress: %s/%s packages" "$CYAN" "$ARROW" "$RESET" "$installed" "${#PACKAGES[@]}" pct=$((installed * 100 / total))
printf "\r ${CYAN}${ARROW}${RESET} [%-50s] %3d%% (%d/%d)" "$(printf '#%.0s' $(seq 1 $((pct / 2))))" "$pct" "$installed" "$total"
done done
echo "" echo ""
if [ $failed -eq 0 ]; then if [ $failed -eq 0 ]; then
success "All packages installed successfully" success "All ${installed} packages installed"
else else
warn "$failed package(s) failed to install" warn "${failed} package(s) failed:"
for pkg in "${failed_pkgs[@]}"; do
echo -e " ${RED}${CROSS}${RESET} ${pkg}"
done
fi fi
# Update check # ── Build native modules ──────────────────────────────────────────
step "Checking for package updates..." section "Building native modules"
outdated=$($aur_helper -Qu 2>/dev/null | awk '{print $1}' || true)
to_update=()
for pkg in "${PACKAGES[@]}"; do
if echo "$outdated" | grep -q "^$pkg\$"; then
to_update+=("$pkg")
fi
done
if [ ${#to_update[@]} -gt 0 ]; then
step "Updating ${#to_update[@]} outdated package(s)..."
$aur_helper -S --noconfirm "${to_update[@]}" >/dev/null 2>&1 || true
success "Packages updated"
else
success "All packages are up-to-date"
fi
progress "Building Global Menu shim"
# Global Menu shim
step "Compiling libmenu_button_shim.so..." step "Compiling libmenu_button_shim.so..."
SHIM_SRC="$INSTALL_DIR/src/window/globalmenu/libmenu_button_shim.c" SHIM_SRC="$INSTALL_DIR/src/window/globalmenu/libmenu_button_shim.c"
SHIM_OUT="$INSTALL_DIR/src/window/globalmenu/libmenu_button_shim.so" SHIM_OUT="$INSTALL_DIR/src/window/globalmenu/libmenu_button_shim.so"
if [ -f "$SHIM_SRC" ]; then if [ -f "$SHIM_SRC" ]; then
if gcc -shared -fPIC -O2 -o "$SHIM_OUT" "$SHIM_SRC" "$(pkg-config --cflags --libs gtk+-3.0)" -ldl 2>/dev/null; then if gcc -shared -fPIC -O2 -o "$SHIM_OUT" "$SHIM_SRC" "$(pkg-config --cflags --libs gtk+-3.0)" -ldl 2>/dev/null; then
success "libmenu_button_shim.so built successfully" success "libmenu_button_shim.so built"
else else
warn "Failed to compile libmenu_button_shim.so - global menu may not work" warn "Failed to compile shim — global menu may not work"
fi fi
else else
warn "libmenu_button_shim.c not found - skipping shim build" warn "Shim source not found — skipped"
fi fi
progress "Building App Capture module" # App Capture
step "Compiling libappcapture.so..." step "Compiling libappcapture.so..."
if [ -d "$INSTALL_DIR/src/window/switcher/app-capture" ]; then if [ -d "$INSTALL_DIR/src/window/switcher/app-capture" ]; then
if ( if (
@@ -347,38 +450,35 @@ if [ -d "$INSTALL_DIR/src/window/switcher/app-capture" ]; then
meson setup builddir --wipe >/dev/null 2>&1 || meson setup builddir >/dev/null 2>&1 meson setup builddir --wipe >/dev/null 2>&1 || meson setup builddir >/dev/null 2>&1
meson compile -C builddir >/dev/null 2>&1 meson compile -C builddir >/dev/null 2>&1
); then ); then
success "libappcapture.so built successfully" success "libappcapture.so built"
else else
warn "Failed to compile App Capture module" warn "Failed to compile app-capture"
fi fi
else else
warn "App Capture module directory not found" warn "App-capture source not found — skipped"
fi fi
progress "Configuring Hyprland" # ── Hyprland config ───────────────────────────────────────────────
section "Hyprland configuration"
HYPR_CONFIG="$HOME/.config/hypr/hyprland.lua" HYPR_CONFIG="$HOME/.config/hypr/hyprland.lua"
MODUS_MODULE_LINE="dofile(\"$INSTALL_DIR/config/hypr/modus.lua\")" MODUS_MODULE_LINE="dofile(\"$INSTALL_DIR/config/hypr/modus.lua\")"
if [ -f "$HYPR_CONFIG" ]; then if [ -f "$HYPR_CONFIG" ]; then
step "Checking Hyprland Lua configuration..."
if grep -qF "$MODUS_MODULE_LINE" "$HYPR_CONFIG"; then if grep -qF "$MODUS_MODULE_LINE" "$HYPR_CONFIG"; then
success "Modus module already loaded" success "Modus module already in hyprland.lua"
else else
step "Adding Modus module to Hyprland Lua config..." step "Adding Modus module to hyprland.lua..."
{ {
echo "" echo ""
echo "-- Modus configuration" echo "-- Modus configuration"
echo "$MODUS_MODULE_LINE" echo "$MODUS_MODULE_LINE"
} >> "$HYPR_CONFIG" } >> "$HYPR_CONFIG"
success "Module added"
success "Modus configuration added"
fi fi
else else
warn "Hyprland Lua config not found at $HYPR_CONFIG" warn "hyprland.lua not found at ${HYPR_CONFIG}"
info "You may need to manually add: $MODUS_MODULE_LINE" info "Add manually: ${MODUS_MODULE_LINE}"
fi fi
step "Symlinking hypridle.conf..." step "Symlinking hypridle.conf..."
@@ -387,16 +487,14 @@ HYPRIDLE_CONF="$INSTALL_DIR/config/hypr/hypridle.conf"
HYPRIDLE_TARGET="$HYPR_DIR/hypridle.conf" HYPRIDLE_TARGET="$HYPR_DIR/hypridle.conf"
mkdir -p "$HYPR_DIR" mkdir -p "$HYPR_DIR"
if [ -f "$HYPRIDLE_CONF" ]; then if [ -f "$HYPRIDLE_CONF" ]; then
if [ -L "$HYPRIDLE_TARGET" ]; then
rm "$HYPRIDLE_TARGET"
fi
ln -sf "$HYPRIDLE_CONF" "$HYPRIDLE_TARGET" ln -sf "$HYPRIDLE_CONF" "$HYPRIDLE_TARGET"
success "hypridle.conf symlinked" success "hypridle.conf symlinked"
else else
warn "hypridle.conf not found at $HYPRIDLE_CONF" warn "hypridle.conf not found — skipped"
fi fi
progress "Configuring global environment" # ── Environment ───────────────────────────────────────────────────
section "Global environment"
APP_CONF_DIR="$HOME/.config/environment.d" APP_CONF_DIR="$HOME/.config/environment.d"
APP_CONF_FILE="$APP_CONF_DIR/appmenu.conf" APP_CONF_FILE="$APP_CONF_DIR/appmenu.conf"
@@ -407,7 +505,7 @@ cat > "$APP_CONF_FILE" << 'EOF'
GTK_MODULES=appmenu-gtk-module GTK_MODULES=appmenu-gtk-module
UBUNTU_MENUPROXY=1 UBUNTU_MENUPROXY=1
EOF EOF
success "Environment config written to $APP_CONF_FILE" success "environment.d/appmenu.conf written"
PAM_FILE="$HOME/.pam_environment" PAM_FILE="$HOME/.pam_environment"
step "Updating pam_environment..." step "Updating pam_environment..."
@@ -417,9 +515,11 @@ for entry in "GTK_MODULES DEFAULT=appmenu-gtk-module" "UBUNTU_MENUPROXY DEFAULT=
echo "$entry" >> "$PAM_FILE" echo "$entry" >> "$PAM_FILE"
fi fi
done done
success ".pam_environment updated" success "pam_environment updated"
# ── Matugen ────────────────────────────────────────────────────────
section "Matugen"
progress "Configuring Matugen"
MATUGEN_CONFIG="$HOME/.config/matugen/config.toml" MATUGEN_CONFIG="$HOME/.config/matugen/config.toml"
MODUS_BLOCK='[templates.modus] MODUS_BLOCK='[templates.modus]
@@ -432,34 +532,30 @@ input_path = "~/.config/Modus/config/matugen/templates/hyprland-colors.lua"
output_path = "~/.config/Modus/config/matugen/colors.lua"' output_path = "~/.config/Modus/config/matugen/colors.lua"'
if [ -f "$MATUGEN_CONFIG" ]; then if [ -f "$MATUGEN_CONFIG" ]; then
step "Checking matugen config..."
# ---- Modus1 ----
if grep -qF "[templates.modus]" "$MATUGEN_CONFIG"; then if grep -qF "[templates.modus]" "$MATUGEN_CONFIG"; then
success "modus1 template already exists" success "Modus template already configured"
else else
step "Adding modus1 template..." step "Adding Modus template..."
echo "" >> "$MATUGEN_CONFIG" echo "" >> "$MATUGEN_CONFIG"
echo "$MODUS_BLOCK" >> "$MATUGEN_CONFIG" echo "$MODUS_BLOCK" >> "$MATUGEN_CONFIG"
success "modus template added" success "Modus template added"
fi fi
# ---- Hyprland ----
if grep -qF "[templates.hyprland]" "$MATUGEN_CONFIG"; then if grep -qF "[templates.hyprland]" "$MATUGEN_CONFIG"; then
success "hyprland template already exists" success "Hyprland template already configured"
else else
step "Adding hyprland template..." step "Adding Hyprland template..."
echo "" >> "$MATUGEN_CONFIG" echo "" >> "$MATUGEN_CONFIG"
echo "$HYPR_BLOCK" >> "$MATUGEN_CONFIG" echo "$HYPR_BLOCK" >> "$MATUGEN_CONFIG"
success "hyprland template added" success "Hyprland template added"
fi fi
else else
warn "matugen config not found at $MATUGEN_CONFIG" warn "matugen config not found at ${MATUGEN_CONFIG}"
info "Create it first or install matugen" info "Install matugen first, then re-run this script"
fi fi
progress "Launching Modus" # ── Launch ─────────────────────────────────────────────────────────
section "Launch"
step "Stopping existing instances..." step "Stopping existing instances..."
if killall modus 2>/dev/null; then if killall modus 2>/dev/null; then
@@ -474,24 +570,26 @@ if uwsm app -- uv run --project "$INSTALL_DIR" start >/dev/null 2>&1 & then
disown disown
sleep 2 sleep 2
if pgrep -x "modus" >/dev/null; then if pgrep -x "modus" >/dev/null; then
success "Modus is now running" success "Modus is running"
else else
warn "Modus may not have started correctly" warn "Modus may not have started — check logs"
fi fi
else else
error "Failed to start Modus" error "Failed to start Modus"
exit 1 exit 1
fi fi
# Completion # ── Summary ────────────────────────────────────────────────────────
echo "" echo ""
echo -e "${GREEN}${BOLD}╔════════════════════════════════════════╗${RESET}" echo -e " ${GREEN}${BOLD}╔══════════════════════════════════════════╗${RESET}"
echo -e "${GREEN}${BOLD}║ ║${RESET}" echo -e " ${GREEN}${BOLD}║${RESET} ${GREEN}${BOLD}║${RESET}"
echo -e "${GREEN}${BOLD}║ Installation completed! ║${RESET}" echo -e " ${GREEN}${BOLD}║${RESET} ${GREEN}${BOLD}Installation complete!${RESET} ${GREEN}${BOLD}║${RESET}"
echo -e "${GREEN}${BOLD}║ ║${RESET}" echo -e " ${GREEN}${BOLD}║${RESET} ${GREEN}${BOLD}║${RESET}"
echo -e "${GREEN}${BOLD}╚════════════════════════════════════════╝${RESET}" echo -e " ${GREEN}${BOLD}╚══════════════════════════════════════════╝${RESET}"
echo "" echo ""
info "Modus is running in the background" divider
info "Config location: ${INSTALL_DIR}" info "Packages: ${GREEN}${installed}${RESET} installed${RED:+, ${failed} failed}"
info "Repository: ${REPO_URL}" info "Location: ${INSTALL_DIR}"
info "Config: ${INSTALL_DIR}/config/"
divider
echo "" echo ""