mirror of
https://github.com/tw93/Mole.git
synced 2026-02-11 12:59:16 +00:00
Reconstruct the structure of go
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -291,7 +292,7 @@ func removeOverviewSnapshot(path string) {
|
||||
|
||||
// prefetchOverviewCache scans overview directories in background
|
||||
// to populate cache for faster overview mode access
|
||||
func prefetchOverviewCache() {
|
||||
func prefetchOverviewCache(ctx context.Context) {
|
||||
entries := createOverviewEntries()
|
||||
|
||||
// Check which entries need refresh
|
||||
@@ -309,8 +310,15 @@ func prefetchOverviewCache() {
|
||||
return
|
||||
}
|
||||
|
||||
// Scan and cache in background
|
||||
// Scan and cache in background with context cancellation support
|
||||
for _, path := range needScan {
|
||||
// Check if context is cancelled
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
size, err := measureOverviewSize(path)
|
||||
if err == nil && size > 0 {
|
||||
_ = storeOverviewSize(path, size)
|
||||
|
||||
@@ -59,17 +59,17 @@ var projectDependencyDirs = map[string]bool{
|
||||
".pnpm-store": true, // pnpm store
|
||||
|
||||
// Python dependencies and outputs
|
||||
"venv": true,
|
||||
".venv": true,
|
||||
"virtualenv": true,
|
||||
"__pycache__": true,
|
||||
".pytest_cache": true,
|
||||
".mypy_cache": true,
|
||||
".ruff_cache": true,
|
||||
".tox": true,
|
||||
".eggs": true,
|
||||
"htmlcov": true, // Coverage reports
|
||||
".ipynb_checkpoints": true, // Jupyter checkpoints
|
||||
"venv": true,
|
||||
".venv": true,
|
||||
"virtualenv": true,
|
||||
"__pycache__": true,
|
||||
".pytest_cache": true,
|
||||
".mypy_cache": true,
|
||||
".ruff_cache": true,
|
||||
".tox": true,
|
||||
".eggs": true,
|
||||
"htmlcov": true, // Coverage reports
|
||||
".ipynb_checkpoints": true, // Jupyter checkpoints
|
||||
|
||||
// Ruby dependencies
|
||||
"vendor": true,
|
||||
@@ -95,10 +95,10 @@ var projectDependencyDirs = map[string]bool{
|
||||
".nyc_output": true, // NYC coverage
|
||||
|
||||
// Frontend framework outputs
|
||||
".angular": true, // Angular CLI cache
|
||||
".svelte-kit": true, // SvelteKit build
|
||||
".astro": true, // Astro cache
|
||||
".docusaurus": true, // Docusaurus build
|
||||
".angular": true, // Angular CLI cache
|
||||
".svelte-kit": true, // SvelteKit build
|
||||
".astro": true, // Astro cache
|
||||
".docusaurus": true, // Docusaurus build
|
||||
|
||||
// iOS/macOS development
|
||||
"DerivedData": true,
|
||||
|
||||
@@ -6,8 +6,8 @@ const (
|
||||
maxEntries = 30
|
||||
maxLargeFiles = 30
|
||||
barWidth = 24
|
||||
minLargeFileSize = 100 << 20 // 100 MB
|
||||
defaultViewport = 12 // Default viewport when terminal height is unknown
|
||||
minLargeFileSize = 100 << 20 // 100 MB
|
||||
defaultViewport = 12 // Default viewport when terminal height is unknown
|
||||
overviewCacheTTL = 7 * 24 * time.Hour // 7 days
|
||||
overviewCacheFile = "overview_sizes.json"
|
||||
duTimeout = 60 * time.Second // Increased for large directories
|
||||
|
||||
@@ -56,14 +56,19 @@ func deletePathWithProgress(root string, counter *int64) (int64, error) {
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return count, err
|
||||
// Track walk error separately
|
||||
if err != nil && firstErr == nil {
|
||||
firstErr = err
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(root); err != nil {
|
||||
return count, err
|
||||
// Try to remove remaining directory structure
|
||||
// Even if this fails, we still report files deleted
|
||||
if removeErr := os.RemoveAll(root); removeErr != nil {
|
||||
if firstErr == nil {
|
||||
firstErr = removeErr
|
||||
}
|
||||
}
|
||||
|
||||
// Return the first error encountered during deletion if any
|
||||
// Always return count (even if there were errors), along with first error
|
||||
return count, firstErr
|
||||
}
|
||||
|
||||
@@ -141,7 +141,10 @@ func main() {
|
||||
}
|
||||
|
||||
// Prefetch overview cache in background (non-blocking)
|
||||
go prefetchOverviewCache()
|
||||
// Use context with timeout to prevent hanging
|
||||
prefetchCtx, prefetchCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer prefetchCancel()
|
||||
go prefetchOverviewCache(prefetchCtx)
|
||||
|
||||
p := tea.NewProgram(newModel(abs, isOverview), tea.WithAltScreen())
|
||||
if err := p.Start(); err != nil {
|
||||
@@ -509,7 +512,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
func (m model) updateKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
// Handle delete confirmation
|
||||
if m.deleteConfirm {
|
||||
if msg.String() == "delete" || msg.String() == "backspace" {
|
||||
switch msg.String() {
|
||||
case "delete", "backspace":
|
||||
// Confirm delete - start async deletion
|
||||
if m.deleteTarget != nil {
|
||||
m.deleteConfirm = false
|
||||
@@ -525,17 +529,14 @@ func (m model) updateKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
|
||||
m.deleteConfirm = false
|
||||
m.deleteTarget = nil
|
||||
return m, nil
|
||||
} else if msg.String() == "esc" || msg.String() == "q" {
|
||||
case "esc", "q":
|
||||
// Cancel delete with ESC or Q
|
||||
m.status = "Cancelled"
|
||||
m.deleteConfirm = false
|
||||
m.deleteTarget = nil
|
||||
return m, nil
|
||||
} else {
|
||||
// Any other key also cancels
|
||||
m.status = "Cancelled"
|
||||
m.deleteConfirm = false
|
||||
m.deleteTarget = nil
|
||||
default:
|
||||
// Ignore other keys - keep showing confirmation
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,10 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
|
||||
atomic.AddInt64(&total, size)
|
||||
|
||||
entryChan <- dirEntry{
|
||||
Name: child.Name() + " →", // Add arrow to indicate symlink
|
||||
Name: child.Name() + " →", // Add arrow to indicate symlink
|
||||
Path: fullPath,
|
||||
Size: size,
|
||||
IsDir: false, // Don't allow navigation into symlinks
|
||||
IsDir: false, // Don't allow navigation into symlinks
|
||||
LastAccess: getLastAccessTimeFromInfo(info),
|
||||
}
|
||||
continue
|
||||
@@ -189,10 +189,14 @@ func scanPathConcurrent(root string, filesScanned, dirsScanned, bytesScanned *in
|
||||
entries = entries[:maxEntries]
|
||||
}
|
||||
|
||||
// Try to use Spotlight for faster large file discovery
|
||||
// Try to use Spotlight (mdfind) for faster large file discovery
|
||||
// This is a performance optimization that gracefully falls back to scan results
|
||||
// if Spotlight is unavailable or fails. The fallback is intentionally silent
|
||||
// because users only care about correct results, not the method used.
|
||||
if spotlightFiles := findLargeFilesWithSpotlight(root, minLargeFileSize); len(spotlightFiles) > 0 {
|
||||
largeFiles = spotlightFiles
|
||||
} else {
|
||||
// Use files collected during scanning (fallback path)
|
||||
// Sort and trim large files collected from scanning
|
||||
sort.Slice(largeFiles, func(i, j int) bool {
|
||||
return largeFiles[i].Size > largeFiles[j].Size
|
||||
|
||||
Reference in New Issue
Block a user