← back to Iterm Project Grouper

iterm-map.sh

46 lines

#!/usr/bin/env bash
# iterm-map.sh — accurate "which iTerm2 windows belong to which project" map.
# Reads each session's live shell path (iTerm2 shell-integration `path` variable,
# reliable unlike the OS process cwd), resolves each to its git-repo root, and
# groups windows by project. READ-ONLY: touches nothing, moves nothing.
set -euo pipefail

RAW="$(osascript <<'APPLESCRIPT'
tell application "iTerm2"
  set o to ""
  set wi to 0
  repeat with w in windows
    set wi to wi + 1
    repeat with t in tabs of w
      repeat with s in sessions of t
        set p to ""
        try
          tell s to set p to (get variable named "path")
        end try
        set o to o & wi & "|||" & p & linefeed
      end repeat
    end repeat
  end repeat
  return o
end tell
APPLESCRIPT
)"

# group: project(git-root basename) -> sorted unique window list
printf '%s\n' "$RAW" | while IFS= read -r line; do
  [ -z "$line" ] && continue
  win="${line%%|||*}"; path="${line#*|||}"
  [ "$path" = "$line" ] && path=""   # no delimiter present
  if [ -z "$path" ]; then echo "${win}"$'\t'"(no path / non-shell)"; continue; fi
  root="$(git -C "$path" rev-parse --show-toplevel 2>/dev/null || echo "$path")"
  echo "${win}"$'\t'"$(basename "$root")"
done | sort -t$'\t' -k2 | awk -F'\t' '
{ proj=$2; win="W"$1; if (!(proj in seen) || index(list[proj],win)==0){ list[proj]=list[proj] (list[proj]==""?"":", ") win; cnt[proj]++ } seen[proj]=1 }
END{
  printf "=== iTerm2 windows grouped by project ===\n"
  # print by descending count
  n=0; for(p in cnt){ order[n++]=p }
  for(i=0;i<n;i++) for(j=i+1;j<n;j++) if(cnt[order[j]]>cnt[order[i]]){ t=order[i];order[i]=order[j];order[j]=t }
  for(i=0;i<n;i++){ p=order[i]; printf "%2d window(s)  %-34s %s\n", cnt[p], p, list[p] }
}'