| 1 | #!/usr/bin/env bash |
| 2 | # JetBrains menu for Waybar |
| 3 | # Left click shows IDEs from .desktop files (Toolbox, Flatpak, distro installs) |
| 4 | # Right click (configured in Waybar) opens jetbrains-toolbox |
| 5 | |
| 6 | set -euo pipefail |
| 7 | |
| 8 | # Pick a menu program |
| 9 | if command -v wofi >/dev/null 2>&1; then |
| 10 | MENU_CMD=(wofi --dmenu -i -p "JetBrains") |
| 11 | elif command -v rofi >/dev/null 2>&1; then |
| 12 | MENU_CMD=(rofi -dmenu -i -p "JetBrains") |
| 13 | else |
| 14 | command -v notify-send >/dev/null 2>&1 && notify-send "JetBrains" "Install wofi or rofi for the menu." |
| 15 | exit 1 |
| 16 | fi |
| 17 | |
| 18 | # Directories where .desktop files commonly live |
| 19 | dirs=( |
| 20 | "$HOME/.local/share/applications" |
| 21 | "$HOME/.local/share/flatpak/exports/share/applications" |
| 22 | "/var/lib/flatpak/exports/share/applications" |
| 23 | "/usr/share/applications" |
| 24 | ) |
| 25 | |
| 26 | # Gather JetBrains desktop entries (Toolbox uses jetbrains-*.desktop, Flatpak uses com.jetbrains.*) |
| 27 | mapfile -t files < <( |
| 28 | for d in "${dirs[@]}"; do |
| 29 | [[ -d "$d" ]] || continue |
| 30 | find "$d" -maxdepth 1 -type f \( -name 'jetbrains-*.desktop' -o -name 'com.jetbrains*.desktop' \) -print |
| 31 | done | awk '!seen[$0]++' |
| 32 | ) |
| 33 | |
| 34 | if (( ${#files[@]} == 0 )); then |
| 35 | if command -v jetbrains-toolbox >/dev/null 2>&1; then |
| 36 | command -v notify-send >/dev/null 2>&1 && notify-send "JetBrains" "No IDE entries found. Opening Toolbox…" |
| 37 | nohup jetbrains-toolbox >/dev/null 2>&1 & |
| 38 | exit 0 |
| 39 | else |
| 40 | command -v notify-send >/dev/null 2>&1 && notify-send "JetBrains" "No JetBrains IDEs detected." |
| 41 | exit 0 |
| 42 | fi |
| 43 | fi |
| 44 | |
| 45 | # Build "Name|||desktop-id" lines so we can sort but keep mapping |
| 46 | mapfile -t lines < <( |
| 47 | for f in "${files[@]}"; do |
| 48 | id="$(basename "$f" .desktop)" |
| 49 | name="$(grep -m1 '^Name=' "$f" | cut -d= -f2-)" |
| 50 | [[ -n "$name" ]] || name="$id" |
| 51 | printf '%s|||%s\n' "$name" "$id" |
| 52 | done | sort -f |
| 53 | ) |
| 54 | |
| 55 | # Show menu of just the names |
| 56 | selection="$(printf '%s\n' "${lines[@]}" | sed 's/|||.*//' | "${MENU_CMD[@]}")" |
| 57 | [[ -n "$selection" ]] || exit 0 |
| 58 | |
| 59 | id="$(printf '%s\n' "${lines[@]}" | awk -F'\|\|\|' -v sel="$selection" '$1==sel{print $2; exit}')" |
| 60 | |
| 61 | # Launch via gtk-launch (preferred), else fall back to Exec= line |
| 62 | if command -v gtk-launch >/dev/null 2>&1; then |
| 63 | setsid gtk-launch "$id" >/dev/null 2>&1 & |
| 64 | exit 0 |
| 65 | fi |
| 66 | |
| 67 | # Fallback: run the Exec= command from the .desktop file |
| 68 | desktop_file="" |
| 69 | for d in "${dirs[@]}"; do |
| 70 | [[ -f "$d/$id.desktop" ]] && desktop_file="$d/$id.desktop" && break |
| 71 | done |
| 72 | [[ -z "$desktop_file" ]] && exit 1 |
| 73 | |
| 74 | exec_line="$(grep -m1 '^Exec=' "$desktop_file" | cut -d= -f2-)" |
| 75 | # Strip desktop placeholders like %f %u etc. |
| 76 | exec_line="${exec_line//%[fFuUdDnNickvm]/}" |
| 77 | nohup bash -lc "$exec_line" >/dev/null 2>&1 & |