install.sh -
#!/bin/bash
set -euo pipefail

# --- Prompt Section (collect all user input here) ---

# Disk Selection
echo "Available disks:"
lsblk -d -o NAME,SIZE,MODEL
while true; do
  read -p "Enter Disk (e.g. sda, nvme0n1): " disk_input
  disk="/dev/${disk_input%/}"
  if [ ! -b "$disk" ]; then
    echo "Disk $disk does not exist. Try again."
    continue
  fi
  break
done

# Hostname
while true; do
  read -p "Hostname: " hostname
  [[ -z "$hostname" ]] && echo "Hostname cannot be empty." && continue
  break
done

# Root Password
while true; do
  read -s -p "Root password: " root_password
  echo
  read -s -p "Confirm root password: " root_password2
  echo
  [[ "$root_password" != "$root_password2" ]] && echo "Passwords do not match." && continue
  [[ -z "$root_password" ]] && echo "Password cannot be empty." && continue
  break
done

# Username
while true; do
  read -p "Username: " user
  [[ -z "$user" ]] && echo "Username cannot be empty." && continue
  break
done

# User Password
while true; do
  read -s -p "User password: " user_password
  echo
  read -s -p "Confirm user password: " user_password2
  echo
  [[ "$user_password" != "$user_password2" ]] && echo "Passwords do not match." && continue
  [[ -z "$user_password" ]] && echo "Password cannot be empty." && continue
  break
done

# Export variables for later use
export disk hostname root_password user user_password

# Partition Naming
if [[ "$disk" == *nvme* ]]; then
  part_prefix="${disk}p"
else
  part_prefix="${disk}"
fi

part1="${part_prefix}1"
part2="${part_prefix}2"

# Partitioning --
parted -s "$disk" mklabel gpt
parted -s "$disk" mkpart ESP fat32 1MiB 1025MiB
parted -s "$disk" set 1 esp on
parted -s "$disk" mkpart primary btrfs 1025MiB 100%

# Formatting
mkfs.vfat -F 32 -n EFI "$part1"
mkfs.btrfs -f -L ROOT "$part2"

mount "$part2" /mnt
# --

# mount -o subvolid=5 "$part2" /mnt
# btrfs subvolume delete /mnt/@ || true
btrfs subvolume create /mnt/@
[ ! -d /mnt/@home ] && btrfs subvolume create /mnt/@home
[ ! -d /mnt/@var ] && btrfs subvolume create /mnt/@var
[ ! -d /mnt/@pkg ] && btrfs subvolume create /mnt/@pkg
[ ! -d /mnt/@snapshots ] && btrfs subvolume create /mnt/@snapshots

umount /mnt

mount -o noatime,compress=lzo,ssd,space_cache=v2,discard=async,subvol=@ "$part2" /mnt
mkdir -p /mnt/{home,var,.snapshots,var/cache/pacman/pkg}
mount -o noatime,compress=lzo,ssd,space_cache=v2,discard=async,subvol=@home "$part2" /mnt/home
mount -o noatime,compress=lzo,ssd,space_cache=v2,discard=async,subvol=@var "$part2" /mnt/var
mount -o noatime,compress=lzo,ssd,space_cache=v2,discard=async,subvol=@pkg "$part2" /mnt/var/cache/pacman/pkg/
mount -o noatime,compress=zstd,ssd,space_cache=v2,discard=async,subvol=@snapshots "$part2" /mnt/.snapshots

# Mount EFI System Partition
mkdir -p /mnt/boot
mount "$part1" /mnt/boot

# Pacstrap stuff
install_pkgs=(
    base base-devel linux-zen linux-zen-headers linux-firmware sudo btrfs-progs
    man-db man-pages networkmanager network-manager-applet bash-completion ananicy-cpp zram-generator acpid power-profiles-daemon
    ntfs-3g exfat-utils mtools dosfstools intel-ucode inotify-tools
    grub grub-btrfs efibootmgr os-prober snapper snap-pac
    qemu-desktop virt-manager vde2 dnsmasq libvirt bridge-utils openbsd-netcat
    openssh ncdu bat eza fzf git github-cli ripgrep ripgrep-all sqlite dysk cronie ufw clamav
    sassc udiskie gvfs yt-dlp aria2 unrar 7zip unzip rsync jq reflector polkit polkit-gnome wget
    pipewire wireplumber pipewire-pulse pipewire-alsa pipewire-audio pipewire-jack
    xorg-xwayland xdg-desktop-portal-wlr xdg-desktop-portal-gtk
    sway swaybg swaylock swayidle swayimg autotiling flatpak ly hyprpicker
    mpv fuzzel qalculate-gtk discord firefox zathura kanshi pcmanfm-gtk3 gimp
    easyeffects lsp-plugins-lv2 mda.lv2 zam-plugins-lv2 calf
    foot nvtop htop fastfetch newsboat neovim tmux asciinema
    papirus-icon-theme noto-fonts noto-fonts-cjk noto-fonts-emoji ttc-iosevka ttf-iosevkaterm-nerd gnu-free-fonts
    wl-clip-persist wl-clipboard cliphist libnotify swaync grim slurp swayosd
    texlive-latex pandoc zathura-pdf-mupdf
    lua python uv python-black stylua pyright ollama
)

# Pacstrap with error handling
reflector --country 'India' --latest 10 --age 24 --sort rate --save /etc/pacman.d/mirrorlist
if ! pacstrap /mnt "${install_pkgs[@]}"; then
  echo "pacstrap failed. Please check the package list and network connection."
  exit 1
fi

# System Configuration
genfstab -U /mnt > /mnt/etc/fstab

# Exporting variables for chroot
cat > /mnt/root/install.conf <<EOF
hostname=$hostname
root_password=$root_password
user=$user
user_password=$user_password
EOF
chmod 600 /mnt/root/install.conf

# Run chroot.sh
cp "$(dirname "$0")/chroot.sh" /mnt/root/chroot.sh
chmod +x /mnt/root/chroot.sh
arch-chroot /mnt /root/chroot.sh

# Unmount and finalize
if mountpoint -q /mnt; then
  umount -R /mnt
fi
echo "Installation completed. Please reboot your system."

chroot.sh -
#!/bin/bash
set -euo pipefail

# Configuration
timezone="Asia/Kolkata"

# Load variables from install.conf
source /root/install.conf

# --- Set hostname ---
echo "$hostname" > /etc/hostname
echo "127.0.0.1  localhost" > /etc/hosts
echo "::1        localhost" >> /etc/hosts
echo "127.0.1.1  $hostname.localdomain  $hostname" >> /etc/hosts

# --- Set root password ---
echo "root:$root_password" | chpasswd

# --- Create user and set password ---
if ! id "$user" &>/dev/null; then
  useradd -m -G wheel,storage,video,audio,kvm,libvirt -s /bin/bash "$user"
  echo "$user:$user_password" | chpasswd
else
  echo "User $user already exists, skipping creation."
fi

# Local Setup
ln -sf "/usr/share/zoneinfo/$timezone" /etc/localtime
hwclock --systohc
sed -i 's/#en_US.UTF-8/en_US.UTF-8/g' /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf

# Sudo Configuration
echo "%wheel ALL=(ALL) ALL" > /etc/sudoers.d/wheel

# Bootloader
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB
sed -i 's/^#GRUB_DISABLE_OS_PROBER=false/GRUB_DISABLE_OS_PROBER=false/' /etc/default/grub
grub-mkconfig -o /boot/grub/grub.cfg

# Reflector and pacman Setup
sed -i '/^#Color$/c\Color' /etc/pacman.conf
mkdir -p /etc/xdg/reflector
cat > /etc/xdg/reflector/reflector.conf << REFCONF
--save /etc/pacman.d/mirrorlist
--protocol https
--country India
--latest 10
--age 24
--sort rate
REFCONF
reflector --country 'India' --latest 10 --age 24 --sort rate --save /etc/pacman.d/mirrorlist
systemctl enable reflector.timer

# Copy config and dotfiles as the user
su - "$user" -c '
  mkdir -p ~/Downloads ~/Documents/home ~/Public ~/Templates ~/Videos ~/Pictures/Screenshots ~/.config ~/.local/state/bash

  git clone https://github.com/zedonix/scripts.git ~/.scripts
  git clone https://github.com/zedonix/dotfiles.git ~/.dotfiles
  git clone https://github.com/zedonix/GruvboxGtk.git ~/Downloads/GruvboxGtk

  cp ~/.dotfiles/archpfp.png ~/Pictures/
  ln -sf ~/.dotfiles/.bashrc ~/.bashrc
  ln -sf ~/.dotfiles/home.html ~/Documents/home/home.html
  ln -sf ~/.dotfiles/archlinux.png ~/Documents/home/archlinux.png

  for link in foot fuzzel newsboat nvim sway tmux zathura swaync mpv mako; do
    ln -sf ~/.dotfiles/.config/$link/ ~/.config
  done
  git clone https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm
'

# Polkit/Firefox policy
mkdir -p /etc/firefox/policies
ln -sf /home/"$user"/.dotfiles/policies.json /etc/firefox/policies/policies.json

# Delete password
shred -u /root/install.conf

# zram config
cat > /etc/systemd/zram-generator.conf <<EOF
[zram0]
zram-size = ram * 2
compression-algorithm = zstd
swap-priority = 100
fs-type = swap
EOF

# Services
systemctl enable NetworkManager libvirtd sshd ananicy-cpp.service fstrim.timer ollama.service ly.service acpid power-profiles-daemon.service
freshclam
systemctl enable clamav-daemon.service clamav-freshclam.service

# Clean up package cache and Wrapping up
pacman -Scc --noconfirm

run.sh -
#!/usr/bin/env bash
set -e

SRC_DIR="$HOME/Downloads/GruvboxGtk"
DEST_DIR="$HOME/.local/share/themes"
THEME_NAME="Gruvbox-Dark"
THEME_DIR="${DEST_DIR}/${THEME_NAME}"
rm -rf "${THEME_DIR}"
mkdir -p "${THEME_DIR}"
# --- GTK2 ---
mkdir -p "${THEME_DIR}/gtk-2.0"
cp -r "${SRC_DIR}/main/gtk-2.0/common/"*'.rc' "${THEME_DIR}/gtk-2.0" 2>/dev/null || true
cp -r "${SRC_DIR}/assets/gtk-2.0/assets-common-Dark" "${THEME_DIR}/gtk-2.0/assets" 2>/dev/null || true
cp -r "${SRC_DIR}/assets/gtk-2.0/assets-Dark/"*.png "${THEME_DIR}/gtk-2.0/assets" 2>/dev/null || true
# --- GTK3 ---
mkdir -p "${THEME_DIR}/gtk-3.0"
cp -r "${SRC_DIR}/assets/gtk/scalable" "${THEME_DIR}/gtk-3.0/assets" 2>/dev/null || true
if [ -f "${SRC_DIR}/main/gtk-3.0/gtk-Dark.scss" ]; then
    sassc -M -t expanded "${SRC_DIR}/main/gtk-3.0/gtk-Dark.scss" "${THEME_DIR}/gtk-3.0/gtk.css"
    cp "${THEME_DIR}/gtk-3.0/gtk.css" "${THEME_DIR}/gtk-3.0/gtk-dark.css"
fi
# --- GTK4 ---
mkdir -p "${THEME_DIR}/gtk-4.0"
cp -r "${SRC_DIR}/assets/gtk/scalable" "${THEME_DIR}/gtk-4.0/assets" 2>/dev/null || true
if [ -f "${SRC_DIR}/main/gtk-4.0/gtk-Dark.scss" ]; then
    sassc -M -t expanded "${SRC_DIR}/main/gtk-4.0/gtk-Dark.scss" "${THEME_DIR}/gtk-4.0/gtk.css"
    cp "${THEME_DIR}/gtk-4.0/gtk.css" "${THEME_DIR}/gtk-4.0/gtk-dark.css"
fi
# --- index.theme ---
cat > "${THEME_DIR}/index.theme" <<EOF
[Desktop Entry]
Type=X-GNOME-Metatheme
Name=${THEME_NAME}
Comment=Gruvbox Dark GTK Theme
EOF
gsettings set org.gnome.desktop.interface gtk-theme 'Gruvbox-Dark'
gsettings set org.gnome.desktop.interface icon-theme "Papirus-Dark"
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'

# Mime setup
find /usr/share/applications -iname '*.desktop' -print0 | while IFS= read -r -d $'\0' d; do
  mime_types=$(grep -m1 '^MimeType=' "$d" | cut -d= -f2)
  [[ -z "$mime_types" ]] && continue
  IFS=';' read -ra mimes <<< "$mime_types"
  for m in "${mimes[@]}"; do
    [[ -z "$m" ]] && continue
    xdg-mime default "$(basename "$d")" "$m"
  done
done
for type in pdf x-pdf fdf xdp xfdf pdx; do xdg-mime default org.pwmt.zathura.desktop application/$type; done
for type in jpeg svg png gif webp bmp tiff; do xdg-mime default swayimg.desktop image/$type; done

# Firefox user.js linking
firefox
if [ -d ~/.mozilla/firefox ]; then
  dir=$(ls ~/.mozilla/firefox/ | grep ".default-release" | head -n1)
  if [ -n "$dir" ]; then
      ln -sf /home/$USER/.dotfiles/user.js /home/$USER/.mozilla/firefox/$dir/user.js
  fi
fi

# UFW setup
sudo ufw allow 20/tcp
sudo ufw allow 21/tcp
sudo ufw limit 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
sudo systemctl enable ufw

# Libvirt setup
sudo virsh net-autostart default

# Flatpak setup
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo

# Snapper setup
if mountpoint -q /.snapshots; then
  sudo umount /.snapshots/
fi
[[ -d /.snapshots ]] && sudo rm -rf /.snapshots/
sudo snapper -c root create-config / || true
sudo snapper -c home create-config /home || true
sudo mount -a

sudo systemctl enable --now snapper-timeline.timer
sudo systemctl enable --now snapper-cleanup.timer
sudo systemctl enable --now grub-btrfsd

# Take snapshot befor aur
sudo snapper -c root create -d "Before initial AUR"

# Running aur.sh
bash ~/.scripts/aur.sh

aur.sh -
#!/bin/bash

aur_dir="$HOME/.paru"
mkdir -p "$aur_dir"
cd "$aur_dir"

git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si

paru -S sway-audio-idle-inhibit-git sdl-ball auto-cpufreq && sudo snapper -c root create -d "After initial AUR"
sudo systemctl enable --now auto-cpufreq.service
ollama pull gemma3:1b