#!/bin/bash pidof transmission-daemon >/dev/null && exit # Directories containing Git repositories dotfiles_repos="${XDG_DOTFILES_DIR:-${HOME}/.dotfiles}" suckless_repos="${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless" private_repos="$HOME/Private/repos" public_repos="${XDG_PUBLICSHARE_DIR:-${HOME}/Public}/repos" # Icon indicators dotfiles_icon="⚙" suckless_icon="🛠" private_icon="🏠" public_icon="🏢" # Function to parse Git status and format symbols get_git_status_symbols() { git status --porcelain | awk ' { if ($1 == "??") { changes["?"]++ } else if ($1 ~ /^[MADR]$/) { changes[$1]++ } } END { # Print in consistent order: M, A, D, R, ? if (changes["M"] > 0) printf "M%s", changes["M"] if (changes["A"] > 0) printf "A%s", changes["A"] if (changes["D"] > 0) printf "D%s", changes["D"] if (changes["R"] > 0) printf "R%s", changes["R"] if (changes["?"] > 0) printf "?%s", changes["?"] }' } # Function to check for unpushed commits get_unpushed_commits() { git cherry -v 2>/dev/null | wc -l; } # Function to check for unpulled commits get_unpulled_commits() { git rev-list --count HEAD..@{upstream}; } # Function to check Git repository status for multiple repos check_multi_repo_status() { local dir="$1" local icon="$2" local repo_status="" local changed_repos="" while IFS= read -r git_dir; do local repo_dir="${git_dir%/.git}" cd "$repo_dir" || continue changes=$(get_git_status_symbols) unpushed=$(get_unpushed_commits) unpulled=$(get_unpulled_commits) if [ -n "$changes" ] || [ "$unpushed" -gt 0 ] || [ "$unpulled" -gt 0 ]; then [ -n "$repo_status" ] && repo_status+=" " repo_status+="$icon$changes" [ "$unpushed" -gt 0 ] && repo_status+="↑$unpushed" [ "$unpulled" -gt 0 ] && repo_status+="↓$unpulled" changed_repos+="$repo_dir"$'\n' fi done < <(find "$dir" -mindepth 2 -maxdepth 2 -type d -name ".git" 2>/dev/null) printf "%s|%s" "$repo_status" "$changed_repos" } # Function to check Git repository status for a single repository check_single_repo_status() { local dir="$1" local icon="$2" local repo_status="" local changed_repo="" if [ -d "$dir/.git" ]; then cd "$dir" || return changes=$(get_git_status_symbols) unpushed=$(get_unpushed_commits) unpulled=$(get_unpulled_commits) if [ -n "$changes" ] || [ "$unpushed" -gt 0 ] || [ "$unpulled" -gt 0 ]; then repo_status+="$icon$changes" [ "$unpushed" -gt 0 ] && repo_status+="↑$unpushed" [ "$unpulled" -gt 0 ] && repo_status+="↓$unpulled" changed_repo="$dir" fi fi printf "%s|%s" "$repo_status" "$changed_repo" } # Check statuses for repositories dotfiles_result=$(check_single_repo_status "$dotfiles_repos" "$dotfiles_icon") dotfiles_status="${dotfiles_result%%|*}" dotfiles_changes="${dotfiles_result#*|}" suckless_result=$(check_single_repo_status "$suckless_repos" "$suckless_icon") suckless_status="${suckless_result%%|*}" suckless_changes="${suckless_result#*|}" private_result=$(check_multi_repo_status "$private_repos" "$private_icon") private_status="${private_result%%|*}" private_changes="${private_result#*|}" public_result=$(check_multi_repo_status "$public_repos" "$public_icon") public_status="${public_result%%|*}" public_changes="${public_result#*|}" [ -f /tmp/gitsync ] && rm -f /tmp/gitsync # Combine statuses output="" [ -n "$dotfiles_status" ] && output+="$dotfiles_status " [ -n "$suckless_status" ] && output+="$suckless_status " [ -n "$private_status" ] && output+="$private_status " [ -n "$public_status" ] && output+="$public_status " # Trim trailing spaces and display output output="${output% }" [ -n "$output" ] && (cat /tmp/gitsync 2>/dev/null || echo "$output") openrepos() { all_changed_repos="$dotfiles_changes"$'\n'"$suckless_changes"$'\n'"$private_changes"$'\n'"$public_changes" repos_cleaned="$(echo "$all_changed_repos" | grep -v '^$')" if [ -n "$repos_cleaned" ]; then # Build array of repos repos_array=() while IFS= read -r repo; do [ -n "$repo" ] && repos_array+=("$repo") done <<< "$repos_cleaned" # Call opensessions with all repos as separate arguments [ "${#repos_array[@]}" -gt 0 ] && setsid -f "$TERMINAL" -e opensessions "${repos_array[@]}" >/dev/null 2>&1 fi } # Handle button actions case "$BLOCK_BUTTON" in 1) openrepos ;; 3) notify-send " Git module" "\- Shows git repositories changes - Left click opens changed repositories" ;; 6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; # Launch editor for the script esac