diff --git a/cmd/analyze/analyze_test.go b/cmd/analyze/analyze_test.go index d8ddb20..083b2e6 100644 --- a/cmd/analyze/analyze_test.go +++ b/cmd/analyze/analyze_test.go @@ -45,9 +45,10 @@ func TestScanPathConcurrentBasic(t *testing.T) { } var filesScanned, dirsScanned, bytesScanned int64 - current := "" + current := &atomic.Value{} + current.Store("") - result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, ¤t) + result, err := scanPathConcurrent(root, &filesScanned, &dirsScanned, &bytesScanned, current) if err != nil { t.Fatalf("scanPathConcurrent returned error: %v", err) } @@ -361,10 +362,11 @@ func TestScanPathPermissionError(t *testing.T) { }() var files, dirs, bytes int64 - current := "" + current := &atomic.Value{} + current.Store("") // Scanning the locked dir itself should fail. - _, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, ¤t) + _, err := scanPathConcurrent(lockedDir, &files, &dirs, &bytes, current) if err == nil { t.Fatalf("expected error scanning locked directory, got nil") } diff --git a/cmd/analyze/main.go b/cmd/analyze/main.go index 269b493..59fe79a 100644 --- a/cmd/analyze/main.go +++ b/cmd/analyze/main.go @@ -97,7 +97,7 @@ type model struct { filesScanned *int64 dirsScanned *int64 bytesScanned *int64 - currentPath *string + currentPath *atomic.Value showLargeFiles bool isOverview bool deleteConfirm bool @@ -162,7 +162,8 @@ func main() { func newModel(path string, isOverview bool) model { var filesScanned, dirsScanned, bytesScanned int64 - currentPath := "" + currentPath := &atomic.Value{} + currentPath.Store("") var overviewFilesScanned, overviewDirsScanned, overviewBytesScanned int64 overviewCurrentPath := "" @@ -174,7 +175,7 @@ func newModel(path string, isOverview bool) model { filesScanned: &filesScanned, dirsScanned: &dirsScanned, bytesScanned: &bytesScanned, - currentPath: ¤tPath, + currentPath: currentPath, showLargeFiles: false, isOverview: isOverview, cache: make(map[string]historyEntry), @@ -434,7 +435,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { atomic.StoreInt64(m.dirsScanned, 0) atomic.StoreInt64(m.bytesScanned, 0) if m.currentPath != nil { - *m.currentPath = "" + m.currentPath.Store("") } return m, tea.Batch(m.scanCmd(m.path), tickCmd()) } @@ -712,7 +713,7 @@ func (m model) updateKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) { atomic.StoreInt64(m.dirsScanned, 0) atomic.StoreInt64(m.bytesScanned, 0) if m.currentPath != nil { - *m.currentPath = "" + m.currentPath.Store("") } return m, tea.Batch(m.scanCmd(m.path), tickCmd()) case "t", "T": @@ -984,7 +985,7 @@ func (m model) enterSelectedDir() (tea.Model, tea.Cmd) { atomic.StoreInt64(m.dirsScanned, 0) atomic.StoreInt64(m.bytesScanned, 0) if m.currentPath != nil { - *m.currentPath = "" + m.currentPath.Store("") } if cached, ok := m.cache[m.path]; ok && !cached.Dirty { diff --git a/cmd/analyze/scanner.go b/cmd/analyze/scanner.go index 91d07fd..f7c938c 100644 --- a/cmd/analyze/scanner.go +++ b/cmd/analyze/scanner.go @@ -23,7 +23,7 @@ import ( var scanGroup singleflight.Group -func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) (scanResult, error) { +func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) (scanResult, error) { children, err := os.ReadDir(root) if err != nil { return scanResult{}, err @@ -293,7 +293,7 @@ func shouldSkipFileForLargeTracking(path string) bool { } // calculateDirSizeFast performs concurrent dir sizing using os.ReadDir. -func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) int64 { +func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) int64 { var total int64 var wg sync.WaitGroup @@ -312,7 +312,7 @@ func calculateDirSizeFast(root string, filesScanned, dirsScanned, bytesScanned * } if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 { - *currentPath = dirPath + currentPath.Store(dirPath) } entries, err := os.ReadDir(dirPath) @@ -429,7 +429,7 @@ func isInFoldedDir(path string) bool { return false } -func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duSem chan struct{}, filesScanned, dirsScanned, bytesScanned *int64, currentPath *string) int64 { +func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duSem chan struct{}, filesScanned, dirsScanned, bytesScanned *int64, currentPath *atomic.Value) int64 { children, err := os.ReadDir(root) if err != nil { return 0 @@ -507,7 +507,7 @@ func calculateDirSizeConcurrent(root string, largeFileChan chan<- fileEntry, duS // Update current path occasionally to prevent UI jitter. if currentPath != nil && atomic.LoadInt64(filesScanned)%int64(batchUpdateSize) == 0 { - *currentPath = fullPath + currentPath.Store(fullPath) } } diff --git a/cmd/analyze/view.go b/cmd/analyze/view.go index 43263e7..b92678b 100644 --- a/cmd/analyze/view.go +++ b/cmd/analyze/view.go @@ -99,7 +99,7 @@ func (m model) View() string { colorGreen, humanizeBytes(bytesScanned), colorReset) if m.currentPath != nil { - currentPath := *m.currentPath + currentPath := m.currentPath.Load().(string) if currentPath != "" { shortPath := displayPath(currentPath) shortPath = truncateMiddle(shortPath, 50)