diff --git a/bin/analyze-go b/bin/analyze-go index 58f70af..58f06d9 100755 Binary files a/bin/analyze-go and b/bin/analyze-go differ diff --git a/cmd/analyze/main.go b/cmd/analyze/main.go index a448390..5a76783 100644 --- a/cmd/analyze/main.go +++ b/cmd/analyze/main.go @@ -21,8 +21,8 @@ import ( "syscall" "time" - tea "github.com/charmbracelet/bubbletea" "github.com/cespare/xxhash/v2" + tea "github.com/charmbracelet/bubbletea" "golang.org/x/sync/singleflight" ) @@ -51,30 +51,30 @@ var foldDirs = map[string]bool{ ".hg": true, // JavaScript/Node - "node_modules": true, - ".npm": true, - "_npx": true, // ~/.npm/_npx global cache - "_cacache": true, // ~/.npm/_cacache - "_logs": true, // ~/.npm/_logs - "_locks": true, // ~/.npm/_locks - "_quick": true, // Quick install cache - "_libvips": true, // ~/.npm/_libvips - "_prebuilds": true, // ~/.npm/_prebuilds + "node_modules": true, + ".npm": true, + "_npx": true, // ~/.npm/_npx global cache + "_cacache": true, // ~/.npm/_cacache + "_logs": true, // ~/.npm/_logs + "_locks": true, // ~/.npm/_locks + "_quick": true, // Quick install cache + "_libvips": true, // ~/.npm/_libvips + "_prebuilds": true, // ~/.npm/_prebuilds "_update-notifier-last-checked": true, // npm update notifier - ".yarn": true, - ".pnpm-store": true, - ".next": true, - ".nuxt": true, - "bower_components": true, - ".vite": true, - ".turbo": true, - ".parcel-cache": true, - ".nx": true, - ".rush": true, - "tnpm": true, // Taobao npm - ".tnpm": true, // Taobao npm cache - ".bun": true, // Bun cache - ".deno": true, // Deno cache + ".yarn": true, + ".pnpm-store": true, + ".next": true, + ".nuxt": true, + "bower_components": true, + ".vite": true, + ".turbo": true, + ".parcel-cache": true, + ".nx": true, + ".rush": true, + "tnpm": true, // Taobao npm + ".tnpm": true, // Taobao npm cache + ".bun": true, // Bun cache + ".deno": true, // Deno cache // Python "__pycache__": true, @@ -122,27 +122,27 @@ var foldDirs = map[string]bool{ ".fleet": true, // Cache directories - ".cache": true, - "__MACOSX": true, - ".DS_Store": true, - ".Trash": true, - "Caches": true, - ".Spotlight-V100": true, - ".fseventsd": true, + ".cache": true, + "__MACOSX": true, + ".DS_Store": true, + ".Trash": true, + "Caches": true, + ".Spotlight-V100": true, + ".fseventsd": true, ".DocumentRevisions-V100": true, - ".TemporaryItems": true, - "$RECYCLE.BIN": true, - ".temp": true, - ".tmp": true, - "_temp": true, - "_tmp": true, - ".Homebrew": true, // Homebrew cache - ".rustup": true, // Rust toolchain - ".sdkman": true, // SDK manager - ".nvm": true, // Node version manager + ".TemporaryItems": true, + "$RECYCLE.BIN": true, + ".temp": true, + ".tmp": true, + "_temp": true, + "_tmp": true, + ".Homebrew": true, // Homebrew cache + ".rustup": true, // Rust toolchain + ".sdkman": true, // SDK manager + ".nvm": true, // Node version manager // macOS specific - "Application Scripts": true, // macOS sandboxed app scripts (can have many subdirs) + "Application Scripts": true, // macOS sandboxed app scripts (can have many subdirs) "Saved Application State": true, // App state snapshots // iCloud @@ -444,14 +444,41 @@ func createOverviewEntries() []dirEntry { dirEntry{name: "System Library", path: "/Library", isDir: true, size: -1}, ) - // Add Volumes if exists - if _, err := os.Stat("/Volumes"); err == nil { + // Add Volumes shortcut only when it contains real mounted folders (e.g., external disks) + if hasUsefulVolumeMounts("/Volumes") { entries = append(entries, dirEntry{name: "Volumes", path: "/Volumes", isDir: true, size: -1}) } return entries } +func hasUsefulVolumeMounts(path string) bool { + entries, err := os.ReadDir(path) + if err != nil { + return false + } + + for _, entry := range entries { + name := entry.Name() + // Skip hidden control entries for Spotlight/TimeMachine etc. + if strings.HasPrefix(name, ".") { + continue + } + + info, err := os.Lstat(filepath.Join(path, name)) + if err != nil { + continue + } + if info.Mode()&fs.ModeSymlink != 0 { + continue // Ignore the synthetic MacintoshHD link + } + if info.IsDir() { + return true + } + } + return false +} + func (m *model) hydrateOverviewEntries() { m.entries = createOverviewEntries() if m.overviewSizeCache == nil { @@ -1760,7 +1787,7 @@ func truncateMiddle(s string, maxWidth int) string { headIdx := 0 for i, r := range runes { w := runeWidth(r) - if headWidth + w > targetHeadWidth { + if headWidth+w > targetHeadWidth { break } headWidth += w @@ -1772,7 +1799,7 @@ func truncateMiddle(s string, maxWidth int) string { tailIdx := len(runes) for i := len(runes) - 1; i >= 0; i-- { w := runeWidth(runes[i]) - if tailWidth + w > targetTailWidth { + if tailWidth+w > targetTailWidth { break } tailWidth += w diff --git a/mole b/mole index 5e4f419..a3607c2 100755 --- a/mole +++ b/mole @@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/common.sh" # Version info -VERSION="1.9.11" +VERSION="1.9.12" MOLE_TAGLINE="can dig deep to clean your Mac." # Get latest version from remote repository