@@ -11,7 +11,7 @@ import (
12 "github.com/bmatcuk/doublestar/v4"
12 "github.com/bmatcuk/doublestar/v4"
13 "github.com/charmbracelet/crush/internal/config"
13 "github.com/charmbracelet/crush/internal/config"
14− "github.com/charmbracelet/crush/internal/logging"
14+ "log/slog"
15 "github.com/charmbracelet/crush/internal/lsp"
15 "github.com/charmbracelet/crush/internal/lsp"
16 "github.com/charmbracelet/crush/internal/lsp/protocol"
16 "github.com/charmbracelet/crush/internal/lsp/protocol"
17 "github.com/fsnotify/fsnotify"
17 "github.com/fsnotify/fsnotify"
@@ -45,7 +45,7 @@ func NewWorkspaceWatcher(client *lsp.Client) *WorkspaceWatcher {
45func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watchers []protocol.FileSystemWatcher) {
45func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watchers []protocol.FileSystemWatcher) {
46 cfg := config.Get()
46 cfg := config.Get()
48− logging.Debug("Adding file watcher registrations")
48+ slog.Debug("Adding file watcher registrations")
49 w.registrationMu.Lock()
49 w.registrationMu.Lock()
50 defer w.registrationMu.Unlock()
50 defer w.registrationMu.Unlock()
@@ -54,33 +54,33 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
55 // Print detailed registration information for debugging
55 // Print detailed registration information for debugging
56 if cfg.Options.DebugLSP {
56 if cfg.Options.DebugLSP {
57− logging.Debug("Adding file watcher registrations",
57+ slog.Debug("Adding file watcher registrations",
59 "watchers", len(watchers),
59 "watchers", len(watchers),
60 "total", len(w.registrations),
60 "total", len(w.registrations),
63 for i, watcher := range watchers {
63 for i, watcher := range watchers {
64− logging.Debug("Registration", "index", i+1)
64+ slog.Debug("Registration", "index", i+1)
66 // Log the GlobPattern
66 // Log the GlobPattern
67 switch v := watcher.GlobPattern.Value.(type) {
67 switch v := watcher.GlobPattern.Value.(type) {
68 case string:
68 case string:
69− logging.Debug("GlobPattern", "pattern", v)
69+ slog.Debug("GlobPattern", "pattern", v)
70 case protocol.RelativePattern:
70 case protocol.RelativePattern:
71− logging.Debug("GlobPattern", "pattern", v.Pattern)
71+ slog.Debug("GlobPattern", "pattern", v.Pattern)
73 // Log BaseURI details
73 // Log BaseURI details
74 switch u := v.BaseURI.Value.(type) {
74 switch u := v.BaseURI.Value.(type) {
75 case string:
75 case string:
76− logging.Debug("BaseURI", "baseURI", u)
76+ slog.Debug("BaseURI", "baseURI", u)
77 case protocol.DocumentUri:
77 case protocol.DocumentUri:
78− logging.Debug("BaseURI", "baseURI", u)
78+ slog.Debug("BaseURI", "baseURI", u)
80− logging.Debug("BaseURI", "baseURI", u)
80+ slog.Debug("BaseURI", "baseURI", u)
83− logging.Debug("GlobPattern", "unknown type", fmt.Sprintf("%T", v))
83+ slog.Debug("GlobPattern", "unknown type", fmt.Sprintf("%T", v))
86 // Log WatchKind
86 // Log WatchKind
@@ -89,13 +89,13 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
89 watchKind = *watcher.Kind
89 watchKind = *watcher.Kind
92− logging.Debug("WatchKind", "kind", watchKind)
92+ slog.Debug("WatchKind", "kind", watchKind)
96 // Determine server type for specialized handling
96 // Determine server type for specialized handling
97 serverName := getServerNameFromContext(ctx)
97 serverName := getServerNameFromContext(ctx)
98− logging.Debug("Server type detected", "serverName", serverName)
98+ slog.Debug("Server type detected", "serverName", serverName)
100 // Check if this server has sent file watchers
100 // Check if this server has sent file watchers
101 hasFileWatchers := len(watchers) > 0
101 hasFileWatchers := len(watchers) > 0
@@ -123,7 +123,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
123 filesOpened += highPriorityFilesOpened
123 filesOpened += highPriorityFilesOpened
125 if cfg.Options.DebugLSP {
125 if cfg.Options.DebugLSP {
126− logging.Debug("Opened high-priority files",
126+ slog.Debug("Opened high-priority files",
127 "count", highPriorityFilesOpened,
127 "count", highPriorityFilesOpened,
128 "serverName", serverName)
128 "serverName", serverName)
@@ -131,7 +131,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
131 // If we've already opened enough high-priority files, we might not need more
131 // If we've already opened enough high-priority files, we might not need more
132 if filesOpened >= maxFilesToOpen {
132 if filesOpened >= maxFilesToOpen {
133 if cfg.Options.DebugLSP {
133 if cfg.Options.DebugLSP {
134− logging.Debug("Reached file limit with high-priority files",
134+ slog.Debug("Reached file limit with high-priority files",
135 "filesOpened", filesOpened,
135 "filesOpened", filesOpened,
136 "maxFiles", maxFilesToOpen)
136 "maxFiles", maxFilesToOpen)
@@ -149,7 +149,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
149 if d.IsDir() {
149 if d.IsDir() {
150 if path != w.workspacePath && shouldExcludeDir(path) {
150 if path != w.workspacePath && shouldExcludeDir(path) {
151 if cfg.Options.DebugLSP {
151 if cfg.Options.DebugLSP {
152− logging.Debug("Skipping excluded directory", "path", path)
152+ slog.Debug("Skipping excluded directory", "path", path)
154 return filepath.SkipDir
154 return filepath.SkipDir
@@ -177,7 +177,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
178 elapsedTime := time.Since(startTime)
178 elapsedTime := time.Since(startTime)
179 if cfg.Options.DebugLSP {
179 if cfg.Options.DebugLSP {
180− logging.Debug("Limited workspace scan complete",
180+ slog.Debug("Limited workspace scan complete",
181 "filesOpened", filesOpened,
181 "filesOpened", filesOpened,
182 "maxFiles", maxFilesToOpen,
182 "maxFiles", maxFilesToOpen,
183 "elapsedTime", elapsedTime.Seconds(),
183 "elapsedTime", elapsedTime.Seconds(),
@@ -186,11 +186,11 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
188 if err != nil && cfg.Options.DebugLSP {
188 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)
192 } else if cfg.Options.DebugLSP {
192 } 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)
@@ -266,7 +266,7 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
266 matches, err := doublestar.Glob(os.DirFS(w.workspacePath), pattern)
266 matches, err := doublestar.Glob(os.DirFS(w.workspacePath), pattern)
267 if err != nil {
267 if err != nil {
268 if cfg.Options.DebugLSP {
268 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)
@@ -300,12 +300,12 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
300 fullPath := filesToOpen[j]
300 fullPath := filesToOpen[j]
301 if err := w.client.OpenFile(ctx, fullPath); err != nil {
301 if err := w.client.OpenFile(ctx, fullPath); err != nil {
302 if cfg.Options.DebugLSP {
302 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)
306 filesOpened++
306 filesOpened++
307 if cfg.Options.DebugLSP {
307 if cfg.Options.DebugLSP {
308− logging.Debug("Opened high-priority file", "path", fullPath)
308+ slog.Debug("Opened high-priority file", "path", fullPath)
@@ -334,7 +334,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
336 serverName := getServerNameFromContext(ctx)
336 serverName := getServerNameFromContext(ctx)
337− logging.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName)
337+ slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName)
339 // Register handler for file watcher registrations from the server
339 // Register handler for file watcher registrations from the server
340 lsp.RegisterFileWatchHandler(func(id string, watchers []protocol.FileSystemWatcher) {
340 lsp.RegisterFileWatchHandler(func(id string, watchers []protocol.FileSystemWatcher) {
@@ -343,7 +343,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
344 watcher, err := fsnotify.NewWatcher()
344 watcher, err := fsnotify.NewWatcher()
345 if err != nil {
345 if err != nil {
346− logging.Error("Error creating watcher", "error", err)
346+ slog.Error("Error creating watcher", "error", err)
348 defer watcher.Close()
348 defer watcher.Close()
@@ -357,7 +357,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
357 if d.IsDir() && path != workspacePath {
357 if d.IsDir() && path != workspacePath {
358 if shouldExcludeDir(path) {
358 if shouldExcludeDir(path) {
359 if cfg.Options.DebugLSP {
359 if cfg.Options.DebugLSP {
360− logging.Debug("Skipping excluded directory", "path", path)
360+ slog.Debug("Skipping excluded directory", "path", path)
362 return filepath.SkipDir
362 return filepath.SkipDir
@@ -367,14 +367,14 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
367 if d.IsDir() {
367 if d.IsDir() {
368 err = watcher.Add(path)
368 err = watcher.Add(path)
369 if err != nil {
369 if err != nil {
370− logging.Error("Error watching path", "path", path, "error", err)
370+ slog.Error("Error watching path", "path", path, "error", err)
374 return nil
374 return nil
376 if err != nil {
376 if err != nil {
377− logging.Error("Error walking workspace", "error", err)
377+ slog.Error("Error walking workspace", "error", err)
380 // Event loop
380 // Event loop
@@ -396,7 +396,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
396 // Skip excluded directories
396 // Skip excluded directories
397 if !shouldExcludeDir(event.Name) {
397 if !shouldExcludeDir(event.Name) {
398 if err := watcher.Add(event.Name); err != nil {
398 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)
@@ -411,7 +411,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
411 // Debug logging
411 // Debug logging
412 if cfg.Options.DebugLSP {
412 if cfg.Options.DebugLSP {
413 matched, kind := w.isPathWatched(event.Name)
413 matched, kind := w.isPathWatched(event.Name)
414− logging.Debug("File event",
414+ slog.Debug("File event",
415 "path", event.Name,
415 "path", event.Name,
416 "operation", event.Op.String(),
416 "operation", event.Op.String(),
417 "watched", matched,
417 "watched", matched,
@@ -431,7 +431,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
431 // Just send the notification if needed
431 // Just send the notification if needed
432 info, err := os.Stat(event.Name)
432 info, err := os.Stat(event.Name)
433 if err != nil {
433 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)
437 if !info.IsDir() && watchKind&protocol.WatchCreate != 0 {
437 if !info.IsDir() && watchKind&protocol.WatchCreate != 0 {
@@ -459,7 +459,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
462− logging.Error("Error watching file", "error", err)
462+ slog.Error("Error watching file", "error", err)
@@ -584,7 +584,7 @@ func matchesSimpleGlob(pattern, path string) bool {
584 // Fall back to simple matching for simpler patterns
584 // Fall back to simple matching for simpler patterns
585 matched, err := filepath.Match(pattern, path)
585 matched, err := filepath.Match(pattern, path)
586 if err != nil {
586 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)
588 return false
588 return false
@@ -595,7 +595,7 @@ func matchesSimpleGlob(pattern, path string) bool {
595func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPattern) bool {
595func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPattern) bool {
596 patternInfo, err := pattern.AsPattern()
596 patternInfo, err := pattern.AsPattern()
597 if err != nil {
597 if err != nil {
598− logging.Error("Error parsing pattern", "pattern", pattern, "error", err)
598+ slog.Error("Error parsing pattern", "pattern", pattern, "error", err)
599 return false
599 return false
@@ -620,7 +620,7 @@ func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPatt
620 // Make path relative to basePath for matching
620 // Make path relative to basePath for matching
621 relPath, err := filepath.Rel(basePath, path)
621 relPath, err := filepath.Rel(basePath, path)
622 if err != nil {
622 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)
624 return false
624 return false
626 relPath = filepath.ToSlash(relPath)
626 relPath = filepath.ToSlash(relPath)
@@ -663,14 +663,14 @@ func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, chan
663 } else if changeType == protocol.FileChangeType(protocol.Changed) && w.client.IsFileOpen(filePath) {
663 } else if changeType == protocol.FileChangeType(protocol.Changed) && w.client.IsFileOpen(filePath) {
664 err := w.client.NotifyChange(ctx, filePath)
664 err := w.client.NotifyChange(ctx, filePath)
665 if err != nil {
665 if err != nil {
666− logging.Error("Error notifying change", "error", err)
666+ slog.Error("Error notifying change", "error", err)
671 // Notify LSP server about the file event using didChangeWatchedFiles
671 // Notify LSP server about the file event using didChangeWatchedFiles
672 if err := w.notifyFileEvent(ctx, uri, changeType); err != nil {
672 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)
@@ -678,7 +678,7 @@ func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, chan
678func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, changeType protocol.FileChangeType) error {
678func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, changeType protocol.FileChangeType) error {
679 cfg := config.Get()
679 cfg := config.Get()
680 if cfg.Options.DebugLSP {
680 if cfg.Options.DebugLSP {
681− logging.Debug("Notifying file event",
681+ slog.Debug("Notifying file event",
682 "uri", uri,
682 "uri", uri,
683 "changeType", changeType,
683 "changeType", changeType,
@@ -853,7 +853,7 @@ func shouldExcludeFile(filePath string) bool {
853 // Skip large files
853 // Skip large files
854 if info.Size() > maxFileSize {
854 if info.Size() > maxFileSize {
855 if cfg.Options.DebugLSP {
855 if cfg.Options.DebugLSP {
856− logging.Debug("Skipping large file",
856+ slog.Debug("Skipping large file",
857 "path", filePath,
857 "path", filePath,
858 "size", info.Size(),
858 "size", info.Size(),
859 "maxSize", maxFileSize,
859 "maxSize", maxFileSize,
@@ -891,10 +891,10 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
891 // This helps with project initialization for certain language servers
891 // This helps with project initialization for certain language servers
892 if isHighPriorityFile(path, serverName) {
892 if isHighPriorityFile(path, serverName) {
893 if cfg.Options.DebugLSP {
893 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)
896 if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
896 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)
@@ -906,7 +906,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
906 // Check file size - for preloading we're more conservative
906 // Check file size - for preloading we're more conservative
907 if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files
907 if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files
908 if cfg.Options.DebugLSP {
908 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())
@@ -938,7 +938,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
938 if shouldOpen {
938 if shouldOpen {
939 // Don't need to check if it's already open - the client.OpenFile handles that
939 // Don't need to check if it's already open - the client.OpenFile handles that
940 if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
940 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)