refactor: use csync.Map for regex caches (#2187)

Carlos Alexandro Becker created

* refactor: use csync.Map for regex caches

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* fix: lint

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

* ci: golangci-lint 2.9

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

---------

Signed-off-by: Carlos Alexandro Becker <caarlos0@users.noreply.github.com>

Change summary

internal/agent/tools/grep.go | 49 ++++++++++---------------------------
1 file changed, 13 insertions(+), 36 deletions(-)

Detailed changes

internal/agent/tools/grep.go 🔗

@@ -15,64 +15,41 @@ import (
 	"regexp"
 	"sort"
 	"strings"
-	"sync"
 	"time"
 
 	"charm.land/fantasy"
+	"github.com/charmbracelet/crush/internal/csync"
 	"github.com/charmbracelet/crush/internal/fsext"
 )
 
 // regexCache provides thread-safe caching of compiled regex patterns
 type regexCache struct {
-	cache map[string]*regexp.Regexp
-	mu    sync.RWMutex
+	*csync.Map[string, *regexp.Regexp]
 }
 
 // newRegexCache creates a new regex cache
 func newRegexCache() *regexCache {
 	return &regexCache{
-		cache: make(map[string]*regexp.Regexp),
+		Map: csync.NewMap[string, *regexp.Regexp](),
 	}
 }
 
 // get retrieves a compiled regex from cache or compiles and caches it
 func (rc *regexCache) get(pattern string) (*regexp.Regexp, error) {
-	// Try to get from cache first (read lock)
-	rc.mu.RLock()
-	if regex, exists := rc.cache[pattern]; exists {
-		rc.mu.RUnlock()
-		return regex, nil
-	}
-	rc.mu.RUnlock()
-
-	// Compile the regex (write lock)
-	rc.mu.Lock()
-	defer rc.mu.Unlock()
-
-	// Double-check in case another goroutine compiled it while we waited
-	if regex, exists := rc.cache[pattern]; exists {
-		return regex, nil
-	}
-
-	// Compile and cache the regex
-	regex, err := regexp.Compile(pattern)
-	if err != nil {
-		return nil, err
-	}
-
-	rc.cache[pattern] = regex
-	return regex, nil
+	var rerr error
+	return rc.GetOrSet(pattern, func() *regexp.Regexp {
+		regex, err := regexp.Compile(pattern)
+		if err != nil {
+			rerr = err
+		}
+		return regex
+	}), rerr
 }
 
 // ResetCache clears compiled regex caches to prevent unbounded growth across sessions.
 func ResetCache() {
-	searchRegexCache.mu.Lock()
-	clear(searchRegexCache.cache)
-	searchRegexCache.mu.Unlock()
-
-	globRegexCache.mu.Lock()
-	clear(globRegexCache.cache)
-	globRegexCache.mu.Unlock()
+	searchRegexCache.Reset(map[string]*regexp.Regexp{})
+	globRegexCache.Reset(map[string]*regexp.Regexp{})
 }
 
 // Global regex cache instances