From 7832c34d896abcf0f4e63e1ddd69edc6b50fd3b5 Mon Sep 17 00:00:00 2001 From: Parteek Bindra <45378885+bindrap@users.noreply.github.com> Date: Wed, 26 Nov 2025 11:45:10 -0500 Subject: [PATCH 1/4] Improve wallpaper selection robustness --- cos_nov21/dotfiles/hypr/hyprland.conf | 49 +++++++---- .../dotfiles/hypr/scripts/wallpaper-lib.sh | 49 ++++++++--- .../dotfiles/hypr/scripts/wallpaper-select.sh | 82 +++++++++---------- 3 files changed, 109 insertions(+), 71 deletions(-) diff --git a/cos_nov21/dotfiles/hypr/hyprland.conf b/cos_nov21/dotfiles/hypr/hyprland.conf index 83795f3..8e0ff65 100644 --- a/cos_nov21/dotfiles/hypr/hyprland.conf +++ b/cos_nov21/dotfiles/hypr/hyprland.conf @@ -54,37 +54,53 @@ env = WLR_NO_HARDWARE_CURSORS,1 ##################### general { - gaps_in = 2 - gaps_out = 4 - border_size = 2 + gaps_in = 6 + gaps_out = 12 + border_size = 3 - col.active_border = rgba(89b4faee) - col.inactive_border = rgba(595959aa) + col.active_border = rgba(89b4faee) rgba(94e2d5ee) 45deg + col.inactive_border = rgba(3b3b4b88) layout = dwindle } decoration { - rounding = 0 + rounding = 12 - active_opacity = 1.0 - inactive_opacity = 1.0 + active_opacity = 0.96 + inactive_opacity = 0.86 - + drop_shadow = true + shadow_range = 24 + shadow_render_power = 3 + col.shadow = rgba(00000055) blur { - enabled = false + enabled = true + size = 10 + passes = 3 + new_optimizations = true + ignore_opacity = true + noise = 0.015 + contrast = 1.05 + brightness = 1.02 } } animations { enabled = true - bezier = simple, 0.16, 1, 0.3, 1 - - animation = windows, 1, 3, simple - animation = fade, 1, 3, simple - animation = workspaces, 1, 3, simple + bezier = easeOutQuint, 0.23, 1, 0.32, 1 + bezier = easeInBack, 0.36, -0.08, 0.68, -0.48 + bezier = fastSpring, 0.26, 1, 0.48, 1 + + animation = windows, 1, 8, easeOutQuint, popin 80% + animation = windowsOut, 1, 7, easeInBack, popin 80% + animation = border, 1, 12, fastSpring + animation = fade, 1, 7, easeOutQuint + animation = workspaces, 1, 6, easeOutQuint, slidevert + animation = specialWorkspace, 1, 6, easeOutQuint, slidevert + animation = layers, 1, 7, easeOutQuint, slide } dwindle { @@ -97,6 +113,9 @@ misc { disable_hyprland_logo = true disable_splash_rendering = true vrr = 0 + animate_manual_resizes = true + animate_mouse_windowdragging = true + focus_on_activate = true } diff --git a/cos_nov21/dotfiles/hypr/scripts/wallpaper-lib.sh b/cos_nov21/dotfiles/hypr/scripts/wallpaper-lib.sh index 6448cf5..b373eb7 100755 --- a/cos_nov21/dotfiles/hypr/scripts/wallpaper-lib.sh +++ b/cos_nov21/dotfiles/hypr/scripts/wallpaper-lib.sh @@ -2,22 +2,50 @@ # Shared wallpaper library functions # Used by wallpaper-next.sh, wallpaper-prev.sh, etc. -HYPR_DIR="$HOME/.config/hypr" -WALLPAPER_DIR="$HOME/Pictures/wallpapers" +HYPR_DIR="${HYPR_DIR:-$HOME/.config/hypr}" +WALLPAPER_PRIMARY_DIR="${WALLPAPER_PRIMARY_DIR:-$HOME/Pictures/wallpapers}" +WALLPAPER_SECONDARY_DIR="${WALLPAPER_SECONDARY_DIR:-$HOME/Pictures/Wallpapers}" + +get_wallpaper_roots() { + local roots=() + + if [ -d "$WALLPAPER_PRIMARY_DIR" ]; then + roots+=("$WALLPAPER_PRIMARY_DIR") + fi + + if [ -d "$WALLPAPER_SECONDARY_DIR" ]; then + roots+=("$WALLPAPER_SECONDARY_DIR") + fi + + printf '%s\n' "${roots[@]}" +} # Get list of available wallpapers get_wallpaper_list() { - local THEME_NAME=$(cat "$HYPR_DIR/.current-theme" 2>/dev/null || echo "default") + local THEME_NAME=$(cat "$HYPR_DIR/.current-theme" 2>/dev/null || echo "catppuccin-mocha") local WALLPAPER_LIST=() + local ROOT_DIRS=($(get_wallpaper_roots)) - # Check for theme-specific wallpapers - if [ -d "$WALLPAPER_DIR/$THEME_NAME" ]; then - WALLPAPER_LIST=($(find "$WALLPAPER_DIR/$THEME_NAME" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \) 2>/dev/null)) + if [ ${#ROOT_DIRS[@]} -eq 0 ]; then + return 1 fi - # Fallback to main wallpaper directory + # Check for theme-specific wallpapers + for dir in "${ROOT_DIRS[@]}"; do + if [ -d "$dir/$THEME_NAME" ]; then + while IFS= read -r file; do + WALLPAPER_LIST+=("$file") + done < <(find "$dir/$THEME_NAME" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \) 2>/dev/null) + fi + done + + # Fallback to main wallpaper directory (recursive to capture nested sets) if [ ${#WALLPAPER_LIST[@]} -eq 0 ]; then - WALLPAPER_LIST=($(find "$WALLPAPER_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \) 2>/dev/null)) + for dir in "${ROOT_DIRS[@]}"; do + while IFS= read -r file; do + WALLPAPER_LIST+=("$file") + done < <(find "$dir" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.webp" \) 2>/dev/null) + done fi if [ ${#WALLPAPER_LIST[@]} -eq 0 ]; then @@ -25,8 +53,7 @@ get_wallpaper_list() { fi # Sort for consistent order - IFS=$'\n' WALLPAPER_LIST=($(sort <<<"${WALLPAPER_LIST[*]}")) - unset IFS + mapfile -t WALLPAPER_LIST < <(printf '%s\n' "${WALLPAPER_LIST[@]}" | sort -u) printf '%s\n' "${WALLPAPER_LIST[@]}" } @@ -82,7 +109,7 @@ cycle_wallpaper() { local WALLPAPER_LIST=($(get_wallpaper_list)) if [ ${#WALLPAPER_LIST[@]} -eq 0 ]; then - notify-send "No Wallpapers" "No wallpapers found in $WALLPAPER_DIR" -u critical + notify-send "No Wallpapers" "No wallpapers found in $(get_wallpaper_roots | paste -sd ', ' -)" -u critical return 1 fi diff --git a/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh b/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh index 88a33f1..1a05703 100755 --- a/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh +++ b/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh @@ -1,69 +1,61 @@ #!/bin/bash # Interactive wallpaper selector with preview - Hyde Style -HYPR_DIR="$HOME/.config/hypr" -WALLPAPER_DIR="$HOME/Pictures/Wallpapers" -THEME_NAME=$(cat "$HYPR_DIR/.current-theme" 2>/dev/null || echo "catppuccin-mocha") +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/wallpaper-lib.sh" -# Get list of wallpapers -if [ -d "$WALLPAPER_DIR/$THEME_NAME" ]; then - WALLPAPER_LIST=("$WALLPAPER_DIR/$THEME_NAME"/*.{jpg,png,jpeg}) -else - WALLPAPER_LIST=("$WALLPAPER_DIR"/*.{jpg,png,jpeg}) -fi +HYPR_DIR="${HYPR_DIR:-$HOME/.config/hypr}" -# Remove glob patterns if no files found -WALLPAPER_LIST=("${WALLPAPER_LIST[@]}" | grep -v '\*') +mapfile -t WALLPAPER_LIST < <(get_wallpaper_list) +mapfile -t WALLPAPER_ROOTS < <(get_wallpaper_roots) if [ ${#WALLPAPER_LIST[@]} -eq 0 ]; then - notify-send "No Wallpapers" "No wallpapers found in $WALLPAPER_DIR" -u critical + notify-send "No Wallpapers" "No wallpapers found in $(get_wallpaper_roots | paste -sd ', ' -)" -u critical exit 1 fi -# Create menu entries +# Build a readable name that shows folder context for similarly named files +format_wallpaper_label() { + local path="$1" + local shortened="$path" + + for root in "${WALLPAPER_ROOTS[@]}"; do + case "$path" in + "$root"/*) + shortened="${path#"$root"/}" + break + ;; + esac + done + + echo "$shortened" +} + +# Create menu entries with deterministic indices so selection always resolves MENU_ENTRIES="" -CURRENT_WALLPAPER=$(cat "$HYPR_DIR/.current-wallpaper" 2>/dev/null) -for wallpaper in "${WALLPAPER_LIST[@]}"; do - if [ "$wallpaper" = "$CURRENT_WALLPAPER" ]; then - MENU_ENTRIES+="● $(basename "$wallpaper") (current)\n" - else - MENU_ENTRIES+=" $(basename "$wallpaper")\n" - fi +CURRENT_WALLPAPER=$(get_current_wallpaper) +for i in "${!WALLPAPER_LIST[@]}"; do + wallpaper="${WALLPAPER_LIST[$i]}" + marker=" " + [ "$wallpaper" = "$CURRENT_WALLPAPER" ] && marker="● " + + MENU_ENTRIES+="$i||$marker$(format_wallpaper_label "$wallpaper")\n" done # Show menu and get selection (prefer rofi, fallback to wofi) if command -v rofi >/dev/null 2>&1; then - SELECTED=$(echo -e "$MENU_ENTRIES" | rofi -dmenu -i -p "󰸉 Select Wallpaper" -theme-str 'window {width: 600px;} listview {lines: 12;}') + SELECTED=$(echo -e "$MENU_ENTRIES" | rofi -dmenu -i -p "󰸉 Select Wallpaper" -theme-str 'window {width: 720px;} listview {lines: 12;}') else - SELECTED=$(echo -e "$MENU_ENTRIES" | wofi --dmenu --prompt "󰸉 Select Wallpaper" --width 600 --height 400) + SELECTED=$(echo -e "$MENU_ENTRIES" | wofi --dmenu --prompt "󰸉 Select Wallpaper" --width 720 --height 440) fi if [ -z "$SELECTED" ]; then exit 0 fi -# Extract wallpaper name (remove marker and current indicator) -WALLPAPER_NAME=$(echo "$SELECTED" | sed 's/^[● ]*//' | sed 's/ (current)$//') - -# Find full path -for wallpaper in "${WALLPAPER_LIST[@]}"; do - if [ "$(basename "$wallpaper")" = "$WALLPAPER_NAME" ]; then - SELECTED_WALLPAPER="$wallpaper" - break - fi -done - -# Set wallpaper -if [ -n "$SELECTED_WALLPAPER" ]; then - if command -v swww >/dev/null 2>&1; then - swww img "$SELECTED_WALLPAPER" --transition-type fade --transition-fps 60 - else - killall hyprpaper 2>/dev/null - echo "preload = $SELECTED_WALLPAPER" > "$HYPR_DIR/hyprpaper.conf" - echo "wallpaper = ,$SELECTED_WALLPAPER" >> "$HYPR_DIR/hyprpaper.conf" - hyprpaper & - fi +# Resolve selection via stable index prefix (format: index||label) +SELECTED_INDEX=$(echo "$SELECTED" | cut -d '|' -f1) - echo "$SELECTED_WALLPAPER" > "$HYPR_DIR/.current-wallpaper" - notify-send "󰸉 Wallpaper Changed" "$WALLPAPER_NAME" -t 2000 +if [[ "$SELECTED_INDEX" =~ ^[0-9]+$ ]] && [ "$SELECTED_INDEX" -lt ${#WALLPAPER_LIST[@]} ]; then + set_wallpaper "${WALLPAPER_LIST[$SELECTED_INDEX]}" fi From fb52802bd834e50cceea5d648ac9389a26c4b973 Mon Sep 17 00:00:00 2001 From: Parteek Bindra <45378885+bindrap@users.noreply.github.com> Date: Wed, 26 Nov 2025 12:57:49 -0500 Subject: [PATCH 2/4] Add wallpaper previews and tweak transparency --- .../dotfiles/hypr/scripts/wallpaper-select.sh | 15 +++++++++++++-- cos_nov21/dotfiles/kitty/kitty.conf | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh b/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh index 1a05703..e3fe2a7 100755 --- a/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh +++ b/cos_nov21/dotfiles/hypr/scripts/wallpaper-select.sh @@ -44,9 +44,20 @@ done # Show menu and get selection (prefer rofi, fallback to wofi) if command -v rofi >/dev/null 2>&1; then - SELECTED=$(echo -e "$MENU_ENTRIES" | rofi -dmenu -i -p "󰸉 Select Wallpaper" -theme-str 'window {width: 720px;} listview {lines: 12;}') + # Rofi supports image previews via icon attributes + SELECTED=$(printf "%b" "$MENU_ENTRIES" | while IFS= read -r line; do + idx="${line%%||*}" + label="${line#*||}" + wp_path="${WALLPAPER_LIST[$idx]}" + printf "%s\0icon\x1f%s\n" "$line" "$wp_path" + done | rofi -dmenu -i -p "󰸉 Select Wallpaper" -show-icons -theme-str 'window {width: 780px;} listview {lines: 12;}' ) else - SELECTED=$(echo -e "$MENU_ENTRIES" | wofi --dmenu --prompt "󰸉 Select Wallpaper" --width 720 --height 440) + # Wofi renders inline previews when --allow-images is set and entries start with img: + SELECTED=$(printf "%b" "$MENU_ENTRIES" | while IFS= read -r line; do + idx="${line%%||*}" + wp_path="${WALLPAPER_LIST[$idx]}" + printf "img:%s\t%s\n" "$wp_path" "$line" + done | wofi --dmenu --prompt "󰸉 Select Wallpaper" --width 780 --height 460 --allow-images) fi if [ -z "$SELECTED" ]; then diff --git a/cos_nov21/dotfiles/kitty/kitty.conf b/cos_nov21/dotfiles/kitty/kitty.conf index 28d7ff2..408f5d3 100644 --- a/cos_nov21/dotfiles/kitty/kitty.conf +++ b/cos_nov21/dotfiles/kitty/kitty.conf @@ -11,7 +11,7 @@ font_size 11.0 # Window configuration window_padding_width 8 confirm_os_window_close 0 -background_opacity 0.85 +background_opacity 0.78 dynamic_background_opacity yes # Tab bar From f3ccc9c779439f7a650faac6bbfeb20233ba4960 Mon Sep 17 00:00:00 2001 From: Parteek Bindra <45378885+bindrap@users.noreply.github.com> Date: Wed, 26 Nov 2025 12:57:54 -0500 Subject: [PATCH 3/4] Add audio notifications and device switching menu --- cos_nov21/dotfiles/hypr/hyprland.conf | 6 + cos_nov21/dotfiles/waybar/config | 14 ++- .../dotfiles/waybar/scripts/audio-switcher.sh | 105 ++++++++++++++++++ 3 files changed, 122 insertions(+), 3 deletions(-) create mode 100755 cos_nov21/dotfiles/waybar/scripts/audio-switcher.sh diff --git a/cos_nov21/dotfiles/hypr/hyprland.conf b/cos_nov21/dotfiles/hypr/hyprland.conf index 8e0ff65..f3fe283 100644 --- a/cos_nov21/dotfiles/hypr/hyprland.conf +++ b/cos_nov21/dotfiles/hypr/hyprland.conf @@ -152,6 +152,12 @@ bind = $mod, A, exec, $menu bind = $mod, P, pseudo bind = $mod, J, togglesplit +# Audio controls with notifications +bindle = , XF86AudioRaiseVolume, exec, ~/.config/hypr/scripts/volume-notify.sh up +bindle = , XF86AudioLowerVolume, exec, ~/.config/hypr/scripts/volume-notify.sh down +bind = , XF86AudioMute, exec, ~/.config/hypr/scripts/volume-notify.sh mute +bind = , XF86AudioMicMute, exec, ~/.config/hypr/scripts/mic-notify.sh toggle + # Screenshots bind = , Print, exec, grim -g "$(slurp)" - | wl-copy bind = SHIFT, Print, exec, grim - | wl-copy diff --git a/cos_nov21/dotfiles/waybar/config b/cos_nov21/dotfiles/waybar/config index 788a688..0160fd0 100644 --- a/cos_nov21/dotfiles/waybar/config +++ b/cos_nov21/dotfiles/waybar/config @@ -22,6 +22,7 @@ "memory", "temperature", "backlight", + "custom/audio-switcher", "pulseaudio", "network", "battery", @@ -131,6 +132,13 @@ "tooltip": false }, + "custom/audio-switcher": { + "format": "󰓃", + "tooltip": true, + "tooltip-format": "Switch output / voice routes", + "on-click": "~/.config/waybar/scripts/audio-switcher.sh" + }, + "battery": { "interval": 60, "states": { @@ -172,9 +180,9 @@ "default": ["", "", ""] }, "on-click": "pavucontrol", - "on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle", - "on-scroll-up": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", - "on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-", + "on-click-right": "~/.config/hypr/scripts/volume-notify.sh mute", + "on-scroll-up": "~/.config/hypr/scripts/volume-notify.sh up", + "on-scroll-down": "~/.config/hypr/scripts/volume-notify.sh down", "tooltip-format": "{desc}: {volume}%" }, diff --git a/cos_nov21/dotfiles/waybar/scripts/audio-switcher.sh b/cos_nov21/dotfiles/waybar/scripts/audio-switcher.sh new file mode 100755 index 0000000..f2384c7 --- /dev/null +++ b/cos_nov21/dotfiles/waybar/scripts/audio-switcher.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +set -euo pipefail + +prompt_picker() { + local prompt="$1" + + if command -v wofi >/dev/null 2>&1; then + wofi --show dmenu --prompt "$prompt" --allow-markup + elif command -v rofi >/dev/null 2>&1; then + rofi -dmenu -p "$prompt" -theme-str 'window {width: 46%;}' + else + echo "No wofi/rofi menu found" >&2 + exit 1 + fi +} + +# Build a list of sinks/sources in the format: +# type|id|description|is_default +list_devices() { + local wanted="$1" + local section="" + + wpctl status | while IFS= read -r line; do + case "$line" in + *"Sinks:"*) + section="sink" + continue + ;; + *"Sources:"*) + section="source" + continue + ;; + "") + section="" + continue + ;; + esac + + [[ "$section" == "$wanted" ]] || continue + + if [[ $line =~ ^[[:space:]]*([\*\ ])?[[:space:]]*([0-9]+)\.\s+(.+)$ ]]; then + default_mark="${BASH_REMATCH[1]}" + id="${BASH_REMATCH[2]}" + desc="${BASH_REMATCH[3]}" + printf "%s|%s|%s|%s\n" "$section" "$id" "$desc" "${default_mark// }" + fi + done +} + +select_device() { + local type="$1" role_label="$2" + local prompt="$3" + + mapfile -t choices < <(list_devices "$type") + if [[ ${#choices[@]} -eq 0 ]]; then + notify-send "Audio switcher" "No ${type}s found" -u low + exit 0 + fi + + formatted=() + for entry in "${choices[@]}"; do + IFS='|' read -r ctype cid cdesc cdefault <<<"$entry" + marker="" + [[ "$cdefault" == "*" ]] && marker=" ★" + formatted+=("${cid} | ${cdesc}${marker}") + done + + selection=$(printf "%s\n" "${formatted[@]}" | prompt_picker "$prompt") + [[ -z "$selection" ]] && exit 0 + + chosen_id=$(cut -d'|' -f1 <<<"$selection" | xargs) + chosen_desc=$(cut -d'|' -f2- <<<"$selection" | sed 's/^ //') + + role_args=() + [[ "$role_label" == "Voice" ]] && role_args=(-r voice) + + wpctl set-default "${role_args[@]}" "$chosen_id" + + notify-send "Audio switcher" "${role_label} ${type^} set to:\n${chosen_desc}" -u low +} + +main() { + if [[ $# -ge 2 ]]; then + select_device "$1" "$2" "$3" + exit 0 + fi + + category=$(printf "Volume Output\nVoice Output\nVoice Input" | prompt_picker "Audio Routes") + case "$category" in + "Volume Output") + select_device "sink" "Output" "Output Devices" + ;; + "Voice Output") + select_device "sink" "Voice" "Voice Output" + ;; + "Voice Input") + select_device "source" "Voice" "Voice Input" + ;; + *) + exit 0 + ;; + esac +} + +main "$@" From 76112b529661af41196c4f0864e0221caffcc70b Mon Sep 17 00:00:00 2001 From: Parteek Bindra <45378885+bindrap@users.noreply.github.com> Date: Wed, 26 Nov 2025 13:02:17 -0500 Subject: [PATCH 4/4] Add super launcher bindings with install helper --- cos_nov21/dotfiles/hypr/hyprland.conf | 9 +++ cos_nov21/dotfiles/hypr/scripts/app-launch.sh | 64 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100755 cos_nov21/dotfiles/hypr/scripts/app-launch.sh diff --git a/cos_nov21/dotfiles/hypr/hyprland.conf b/cos_nov21/dotfiles/hypr/hyprland.conf index f3fe283..d67ec90 100644 --- a/cos_nov21/dotfiles/hypr/hyprland.conf +++ b/cos_nov21/dotfiles/hypr/hyprland.conf @@ -25,7 +25,10 @@ source = ~/.config/hypr/colors.conf $terminal = kitty $fileManager = thunar +$browser = firefox +$musicPlayer = ncmpcpp $menu = wofi --show drun +$super = SUPER ################# @@ -175,6 +178,12 @@ bind = $mod CTRL, Left, exec, ~/.config/hypr/scripts/wallpaper-prev.sh # Pre bind = $mod CTRL, Up, exec, ~/.config/hypr/scripts/wallpaper-random.sh # Random wallpaper bind = $mod, H, exec, ~/.config/hypr/scripts/keybinds-hint.sh # Show keybindings +# Super key quick launchers (install on demand) +bind = $super, E, exec, ~/.config/hypr/scripts/app-launch.sh files +bind = $super, N, exec, ~/.config/hypr/scripts/app-launch.sh nvim +bind = $super, B, exec, ~/.config/hypr/scripts/app-launch.sh browser +bind = $super, M, exec, ~/.config/hypr/scripts/app-launch.sh music + # Focus windows bind = $mod, left, movefocus, l bind = $mod, right, movefocus, r diff --git a/cos_nov21/dotfiles/hypr/scripts/app-launch.sh b/cos_nov21/dotfiles/hypr/scripts/app-launch.sh new file mode 100755 index 0000000..eaffd6a --- /dev/null +++ b/cos_nov21/dotfiles/hypr/scripts/app-launch.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Launch common apps, installing them first when missing. + +set -e + +notify_missing() { + local cmd="$1" + local pkg="$2" + notify-send "Missing $cmd" "Attempting to install $pkg" +} + +pick_installer() { + if command -v paru >/dev/null 2>&1; then + echo "paru -S --needed --noconfirm" + elif command -v yay >/dev/null 2>&1; then + echo "yay -S --needed --noconfirm" + elif command -v pacman >/dev/null 2>&1; then + echo "sudo pacman -S --needed" + else + echo "" + fi +} + +run_or_install() { + local cmd="$1" + local pkg="$2" + shift 2 + local args=("$@") + + if command -v "$cmd" >/dev/null 2>&1; then + exec "$cmd" "${args[@]}" + fi + + local installer + installer=$(pick_installer) + + if [ -n "$installer" ]; then + notify_missing "$cmd" "$pkg" + kitty -e bash -lc "$installer $pkg" || notify-send "Install $pkg" "Installer closed or failed" + exec "$cmd" "${args[@]}" + else + notify-send "No installer available" "Install $pkg then retry" + exit 1 + fi +} + +case "$1" in + files) + run_or_install thunar thunar + ;; + nvim) + run_or_install nvim neovim + ;; + browser) + run_or_install firefox firefox + ;; + music) + run_or_install ncmpcpp ncmpcpp + ;; + *) + notify-send "Unknown launcher target" "$1" + exit 1 + ;; +esac