@@ -11,7 +11,7 @@ import (
1111
1212 "github.com/bmatcuk/doublestar/v4"
1313 "github.com/charmbracelet/crush/internal/config"
14− "github.com/charmbracelet/crush/internal/logging"
14+ "log/slog"
1515 "github.com/charmbracelet/crush/internal/lsp"
1616 "github.com/charmbracelet/crush/internal/lsp/protocol"
1717 "github.com/fsnotify/fsnotify"
@@ -45,7 +45,7 @@ func NewWorkspaceWatcher(client *lsp.Client) *WorkspaceWatcher {
4545func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watchers []protocol.FileSystemWatcher) {
4646 cfg := config.Get()
4747
48− logging.Debug("Adding file watcher registrations")
48+ slog.Debug("Adding file watcher registrations")
4949 w.registrationMu.Lock()
5050 defer w.registrationMu.Unlock()
5151
@@ -54,33 +54,33 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
5454
5555 // Print detailed registration information for debugging
5656 if cfg.Options.DebugLSP {
57− logging.Debug("Adding file watcher registrations",
57+ slog.Debug("Adding file watcher registrations",
5858 "id", id,
5959 "watchers", len(watchers),
6060 "total", len(w.registrations),
6161 )
6262
6363 for i, watcher := range watchers {
64− logging.Debug("Registration", "index", i+1)
64+ slog.Debug("Registration", "index", i+1)
6565
6666 // Log the GlobPattern
6767 switch v := watcher.GlobPattern.Value.(type) {
6868 case string:
69− logging.Debug("GlobPattern", "pattern", v)
69+ slog.Debug("GlobPattern", "pattern", v)
7070 case protocol.RelativePattern:
71− logging.Debug("GlobPattern", "pattern", v.Pattern)
71+ slog.Debug("GlobPattern", "pattern", v.Pattern)
7272
7373 // Log BaseURI details
7474 switch u := v.BaseURI.Value.(type) {
7575 case string:
76− logging.Debug("BaseURI", "baseURI", u)
76+ slog.Debug("BaseURI", "baseURI", u)
7777 case protocol.DocumentUri:
78− logging.Debug("BaseURI", "baseURI", u)
78+ slog.Debug("BaseURI", "baseURI", u)
7979 default:
80− logging.Debug("BaseURI", "baseURI", u)
80+ slog.Debug("BaseURI", "baseURI", u)
8181 }
8282 default:
83− logging.Debug("GlobPattern", "unknown type", fmt.Sprintf("%T", v))
83+ slog.Debug("GlobPattern", "unknown type", fmt.Sprintf("%T", v))
8484 }
8585
8686 // Log WatchKind
@@ -89,13 +89,13 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
8989 watchKind = *watcher.Kind
9090 }
9191
92− logging.Debug("WatchKind", "kind", watchKind)
92+ slog.Debug("WatchKind", "kind", watchKind)
9393 }
9494 }
9595
9696 // Determine server type for specialized handling
9797 serverName := getServerNameFromContext(ctx)
98− logging.Debug("Server type detected", "serverName", serverName)
98+ slog.Debug("Server type detected", "serverName", serverName)
9999
100100 // Check if this server has sent file watchers
101101 hasFileWatchers := len(watchers) > 0
@@ -123,7 +123,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
123123 filesOpened += highPriorityFilesOpened
124124
125125 if cfg.Options.DebugLSP {
126− logging.Debug("Opened high-priority files",
126+ slog.Debug("Opened high-priority files",
127127 "count", highPriorityFilesOpened,
128128 "serverName", serverName)
129129 }
@@ -131,7 +131,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
131131 // If we've already opened enough high-priority files, we might not need more
132132 if filesOpened >= maxFilesToOpen {
133133 if cfg.Options.DebugLSP {
134− logging.Debug("Reached file limit with high-priority files",
134+ slog.Debug("Reached file limit with high-priority files",
135135 "filesOpened", filesOpened,
136136 "maxFiles", maxFilesToOpen)
137137 }
@@ -149,7 +149,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
149149 if d.IsDir() {
150150 if path != w.workspacePath && shouldExcludeDir(path) {
151151 if cfg.Options.DebugLSP {
152− logging.Debug("Skipping excluded directory", "path", path)
152+ slog.Debug("Skipping excluded directory", "path", path)
153153 }
154154 return filepath.SkipDir
155155 }
@@ -177,7 +177,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
177177
178178 elapsedTime := time.Since(startTime)
179179 if cfg.Options.DebugLSP {
180− logging.Debug("Limited workspace scan complete",
180+ slog.Debug("Limited workspace scan complete",
181181 "filesOpened", filesOpened,
182182 "maxFiles", maxFilesToOpen,
183183 "elapsedTime", elapsedTime.Seconds(),
@@ -186,11 +186,11 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
186186 }
187187
188188 if err != nil && cfg.Options.DebugLSP {
189− logging.Debug("Error scanning workspace for files to open", "error", err)
189+ slog.Debug("Error scanning workspace for files to open", "error", err)
190190 }
191191 }()
192192 } else if cfg.Options.DebugLSP {
193− logging.Debug("Using on-demand file loading for server", "server", serverName)
193+ slog.Debug("Using on-demand file loading for server", "server", serverName)
194194 }
195195}
196196
@@ -266,7 +266,7 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
266266 matches, err := doublestar.Glob(os.DirFS(w.workspacePath), pattern)
267267 if err != nil {
268268 if cfg.Options.DebugLSP {
269− logging.Debug("Error finding high-priority files", "pattern", pattern, "error", err)
269+ slog.Debug("Error finding high-priority files", "pattern", pattern, "error", err)
270270 }
271271 continue
272272 }
@@ -300,12 +300,12 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
300300 fullPath := filesToOpen[j]
301301 if err := w.client.OpenFile(ctx, fullPath); err != nil {
302302 if cfg.Options.DebugLSP {
303− logging.Debug("Error opening high-priority file", "path", fullPath, "error", err)
303+ slog.Debug("Error opening high-priority file", "path", fullPath, "error", err)
304304 }
305305 } else {
306306 filesOpened++
307307 if cfg.Options.DebugLSP {
308− logging.Debug("Opened high-priority file", "path", fullPath)
308+ slog.Debug("Opened high-priority file", "path", fullPath)
309309 }
310310 }
311311 }
@@ -334,7 +334,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
334334 }
335335
336336 serverName := getServerNameFromContext(ctx)
337− logging.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName)
337+ slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName)
338338
339339 // Register handler for file watcher registrations from the server
340340 lsp.RegisterFileWatchHandler(func(id string, watchers []protocol.FileSystemWatcher) {
@@ -343,7 +343,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
343343
344344 watcher, err := fsnotify.NewWatcher()
345345 if err != nil {
346− logging.Error("Error creating watcher", "error", err)
346+ slog.Error("Error creating watcher", "error", err)
347347 }
348348 defer watcher.Close()
349349
@@ -357,7 +357,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
357357 if d.IsDir() && path != workspacePath {
358358 if shouldExcludeDir(path) {
359359 if cfg.Options.DebugLSP {
360− logging.Debug("Skipping excluded directory", "path", path)
360+ slog.Debug("Skipping excluded directory", "path", path)
361361 }
362362 return filepath.SkipDir
363363 }
@@ -367,14 +367,14 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
367367 if d.IsDir() {
368368 err = watcher.Add(path)
369369 if err != nil {
370− logging.Error("Error watching path", "path", path, "error", err)
370+ slog.Error("Error watching path", "path", path, "error", err)
371371 }
372372 }
373373
374374 return nil
375375 })
376376 if err != nil {
377− logging.Error("Error walking workspace", "error", err)
377+ slog.Error("Error walking workspace", "error", err)
378378 }
379379
380380 // Event loop
@@ -396,7 +396,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
396396 // Skip excluded directories
397397 if !shouldExcludeDir(event.Name) {
398398 if err := watcher.Add(event.Name); err != nil {
399− logging.Error("Error adding directory to watcher", "path", event.Name, "error", err)
399+ slog.Error("Error adding directory to watcher", "path", event.Name, "error", err)
400400 }
401401 }
402402 } else {
@@ -411,7 +411,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
411411 // Debug logging
412412 if cfg.Options.DebugLSP {
413413 matched, kind := w.isPathWatched(event.Name)
414− logging.Debug("File event",
414+ slog.Debug("File event",
415415 "path", event.Name,
416416 "operation", event.Op.String(),
417417 "watched", matched,
@@ -431,7 +431,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
431431 // Just send the notification if needed
432432 info, err := os.Stat(event.Name)
433433 if err != nil {
434− logging.Error("Error getting file info", "path", event.Name, "error", err)
434+ slog.Error("Error getting file info", "path", event.Name, "error", err)
435435 return
436436 }
437437 if !info.IsDir() && watchKind&protocol.WatchCreate != 0 {
@@ -459,7 +459,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
459459 if !ok {
460460 return
461461 }
462− logging.Error("Error watching file", "error", err)
462+ slog.Error("Error watching file", "error", err)
463463 }
464464 }
465465}
@@ -584,7 +584,7 @@ func matchesSimpleGlob(pattern, path string) bool {
584584 // Fall back to simple matching for simpler patterns
585585 matched, err := filepath.Match(pattern, path)
586586 if err != nil {
587− logging.Error("Error matching pattern", "pattern", pattern, "path", path, "error", err)
587+ slog.Error("Error matching pattern", "pattern", pattern, "path", path, "error", err)
588588 return false
589589 }
590590
@@ -595,7 +595,7 @@ func matchesSimpleGlob(pattern, path string) bool {
595595func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPattern) bool {
596596 patternInfo, err := pattern.AsPattern()
597597 if err != nil {
598− logging.Error("Error parsing pattern", "pattern", pattern, "error", err)
598+ slog.Error("Error parsing pattern", "pattern", pattern, "error", err)
599599 return false
600600 }
601601
@@ -620,7 +620,7 @@ func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPatt
620620 // Make path relative to basePath for matching
621621 relPath, err := filepath.Rel(basePath, path)
622622 if err != nil {
623− logging.Error("Error getting relative path", "path", path, "basePath", basePath, "error", err)
623+ slog.Error("Error getting relative path", "path", path, "basePath", basePath, "error", err)
624624 return false
625625 }
626626 relPath = filepath.ToSlash(relPath)
@@ -663,14 +663,14 @@ func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, chan
663663 } else if changeType == protocol.FileChangeType(protocol.Changed) && w.client.IsFileOpen(filePath) {
664664 err := w.client.NotifyChange(ctx, filePath)
665665 if err != nil {
666− logging.Error("Error notifying change", "error", err)
666+ slog.Error("Error notifying change", "error", err)
667667 }
668668 return
669669 }
670670
671671 // Notify LSP server about the file event using didChangeWatchedFiles
672672 if err := w.notifyFileEvent(ctx, uri, changeType); err != nil {
673− logging.Error("Error notifying LSP server about file event", "error", err)
673+ slog.Error("Error notifying LSP server about file event", "error", err)
674674 }
675675}
676676
@@ -678,7 +678,7 @@ func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, chan
678678func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, changeType protocol.FileChangeType) error {
679679 cfg := config.Get()
680680 if cfg.Options.DebugLSP {
681− logging.Debug("Notifying file event",
681+ slog.Debug("Notifying file event",
682682 "uri", uri,
683683 "changeType", changeType,
684684 )
@@ -853,7 +853,7 @@ func shouldExcludeFile(filePath string) bool {
853853 // Skip large files
854854 if info.Size() > maxFileSize {
855855 if cfg.Options.DebugLSP {
856− logging.Debug("Skipping large file",
856+ slog.Debug("Skipping large file",
857857 "path", filePath,
858858 "size", info.Size(),
859859 "maxSize", maxFileSize,
@@ -891,10 +891,10 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
891891 // This helps with project initialization for certain language servers
892892 if isHighPriorityFile(path, serverName) {
893893 if cfg.Options.DebugLSP {
894− logging.Debug("Opening high-priority file", "path", path, "serverName", serverName)
894+ slog.Debug("Opening high-priority file", "path", path, "serverName", serverName)
895895 }
896896 if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
897− logging.Error("Error opening high-priority file", "path", path, "error", err)
897+ slog.Error("Error opening high-priority file", "path", path, "error", err)
898898 }
899899 return
900900 }
@@ -906,7 +906,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
906906 // Check file size - for preloading we're more conservative
907907 if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files
908908 if cfg.Options.DebugLSP {
909− logging.Debug("Skipping large file for preloading", "path", path, "size", info.Size())
909+ slog.Debug("Skipping large file for preloading", "path", path, "size", info.Size())
910910 }
911911 return
912912 }
@@ -938,7 +938,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
938938 if shouldOpen {
939939 // Don't need to check if it's already open - the client.OpenFile handles that
940940 if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
941− logging.Error("Error opening file", "path", path, "error", err)
941+ slog.Error("Error opening file", "path", path, "error", err)
942942 }
943943 }
944944 }