@@ -3,7 +3,6 @@ package watcher
33import (
44 "context"
55 "fmt"
6− "log"
76 "os"
87 "path/filepath"
98 "strings"
@@ -11,11 +10,13 @@ import (
1110 "time"
1211
1312 "github.com/fsnotify/fsnotify"
13+ "github.com/kujtimiihoxha/termai/internal/config"
14+ "github.com/kujtimiihoxha/termai/internal/logging"
1415 "github.com/kujtimiihoxha/termai/internal/lsp"
1516 "github.com/kujtimiihoxha/termai/internal/lsp/protocol"
1617)
1718
18−var debug = false // Force debug logging on
19+var logger = logging.Get()
1920
2021// WorkspaceWatcher manages LSP file watching
2122type WorkspaceWatcher struct {
@@ -43,6 +44,7 @@ func NewWorkspaceWatcher(client *lsp.Client) *WorkspaceWatcher {
4344
4445// AddRegistrations adds file watchers to track
4546func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watchers []protocol.FileSystemWatcher) {
47+ cnf := config.Get()
4648 w.registrationMu.Lock()
4749 defer w.registrationMu.Unlock()
4850
@@ -50,31 +52,35 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
5052 w.registrations = append(w.registrations, watchers...)
5153
5254 // Print detailed registration information for debugging
53− if debug {
54− log.Printf("Added %d file watcher registrations (id: %s), total: %d",
55− len(watchers), id, len(w.registrations))
55+ if cnf.Debug {
56+ logger.Debug("Adding file watcher registrations",
57+ "id", id,
58+ "watchers", len(watchers),
59+ "total", len(w.registrations),
60+ "watchers", watchers,
61+ )
5662
5763 for i, watcher := range watchers {
58− log.Printf("Registration #%d raw data:", i+1)
64+ logger.Debug("Registration", "index", i+1)
5965
6066 // Log the GlobPattern
6167 switch v := watcher.GlobPattern.Value.(type) {
6268 case string:
63− log.Printf(" GlobPattern: string pattern '%s'", v)
69+ logger.Debug("GlobPattern", "pattern", v)
6470 case protocol.RelativePattern:
65− log.Printf(" GlobPattern: RelativePattern with pattern '%s'", v.Pattern)
71+ logger.Debug("GlobPattern", "pattern", v.Pattern)
6672
6773 // Log BaseURI details
6874 switch u := v.BaseURI.Value.(type) {
6975 case string:
70− log.Printf(" BaseURI: string '%s'", u)
76+ logger.Debug("BaseURI", "baseURI", u)
7177 case protocol.DocumentUri:
72− log.Printf(" BaseURI: DocumentUri '%s'", u)
78+ logger.Debug("BaseURI", "baseURI", u)
7379 default:
74− log.Printf(" BaseURI: unknown type %T", u)
80+ logger.Debug("BaseURI", "baseURI", u)
7581 }
7682 default:
77− log.Printf(" GlobPattern: unknown type %T", v)
83+ logger.Debug("GlobPattern", "unknown type", fmt.Sprintf("%T", v))
7884 }
7985
8086 // Log WatchKind
@@ -82,11 +88,8 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
8288 if watcher.Kind != nil {
8389 watchKind = *watcher.Kind
8490 }
85− log.Printf(" WatchKind: %d (Create:%v, Change:%v, Delete:%v)",
86− watchKind,
87− watchKind&protocol.WatchCreate != 0,
88− watchKind&protocol.WatchChange != 0,
89− watchKind&protocol.WatchDelete != 0)
91+
92+ logger.Debug("WatchKind", "kind", watchKind)
9093
9194 // Test match against some example paths
9295 testPaths := []string{
@@ -96,7 +99,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
9699
97100 for _, testPath := range testPaths {
98101 isMatch := w.matchesPattern(testPath, watcher.GlobPattern)
99− log.Printf(" Test path '%s': %v", testPath, isMatch)
102+ logger.Debug("Test path", "path", testPath, "matches", isMatch)
100103 }
101104 }
102105 }
@@ -114,10 +117,9 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
114117
115118 // Skip directories that should be excluded
116119 if d.IsDir() {
117− log.Println(path)
118120 if path != w.workspacePath && shouldExcludeDir(path) {
119− if debug {
120− log.Printf("Skipping excluded directory!!: %s", path)
121+ if cnf.Debug {
122+ logger.Debug("Skipping excluded directory", "path", path)
121123 }
122124 return filepath.SkipDir
123125 }
@@ -136,18 +138,23 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
136138 })
137139
138140 elapsedTime := time.Since(startTime)
139− if debug {
140− log.Printf("Workspace scan complete: processed %d files in %.2f seconds", filesOpened, elapsedTime.Seconds())
141+ if cnf.Debug {
142+ logger.Debug("Workspace scan complete",
143+ "filesOpened", filesOpened,
144+ "elapsedTime", elapsedTime.Seconds(),
145+ "workspacePath", w.workspacePath,
146+ )
141147 }
142148
143− if err != nil && debug {
144− log.Printf("Error scanning workspace for files to open: %v", err)
149+ if err != nil && cnf.Debug {
150+ logger.Debug("Error scanning workspace for files to open", "error", err)
145151 }
146152 }()
147153}
148154
149155// WatchWorkspace sets up file watching for a workspace
150156func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath string) {
157+ cnf := config.Get()
151158 w.workspacePath = workspacePath
152159
153160 // Register handler for file watcher registrations from the server
@@ -157,7 +164,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
157164
158165 watcher, err := fsnotify.NewWatcher()
159166 if err != nil {
160− log.Fatalf("Error creating watcher: %v", err)
167+ logger.Error("Error creating watcher", "error", err)
161168 }
162169 defer watcher.Close()
163170
@@ -170,8 +177,8 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
170177 // Skip excluded directories (except workspace root)
171178 if d.IsDir() && path != workspacePath {
172179 if shouldExcludeDir(path) {
173− if debug {
174− log.Printf("Skipping watching excluded directory: %s", path)
180+ if cnf.Debug {
181+ logger.Debug("Skipping excluded directory", "path", path)
175182 }
176183 return filepath.SkipDir
177184 }
@@ -181,14 +188,14 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
181188 if d.IsDir() {
182189 err = watcher.Add(path)
183190 if err != nil {
184− log.Printf("Error watching path %s: %v", path, err)
191+ logger.Error("Error watching path", "path", path, "error", err)
185192 }
186193 }
187194
188195 return nil
189196 })
190197 if err != nil {
191− log.Fatalf("Error walking workspace: %v", err)
198+ logger.Error("Error walking workspace", "error", err)
192199 }
193200
194201 // Event loop
@@ -210,7 +217,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
210217 // Skip excluded directories
211218 if !shouldExcludeDir(event.Name) {
212219 if err := watcher.Add(event.Name); err != nil {
213− log.Printf("Error watching new directory: %v", err)
220+ logger.Error("Error adding directory to watcher", "path", event.Name, "error", err)
214221 }
215222 }
216223 } else {
@@ -223,10 +230,15 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
223230 }
224231
225232 // Debug logging
226− if debug {
233+ if cnf.Debug {
227234 matched, kind := w.isPathWatched(event.Name)
228− log.Printf("Event: %s, Op: %s, Watched: %v, Kind: %d",
229− event.Name, event.Op.String(), matched, kind)
235+ logger.Debug("File event",
236+ "path", event.Name,
237+ "operation", event.Op.String(),
238+ "watched", matched,
239+ "kind", kind,
240+ )
241+
230242 }
231243
232244 // Check if this path should be watched according to server registrations
@@ -265,7 +277,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
265277 if !ok {
266278 return
267279 }
268− log.Printf("Watcher error: %v\n", err)
280+ logger.Error("Error watching file", "error", err)
269281 }
270282 }
271283}
@@ -390,7 +402,7 @@ func matchesSimpleGlob(pattern, path string) bool {
390402 // Fall back to simple matching for simpler patterns
391403 matched, err := filepath.Match(pattern, path)
392404 if err != nil {
393− log.Printf("Error matching pattern %s: %v", pattern, err)
405+ logger.Error("Error matching pattern", "pattern", pattern, "path", path, "error", err)
394406 return false
395407 }
396408
@@ -401,7 +413,7 @@ func matchesSimpleGlob(pattern, path string) bool {
401413func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPattern) bool {
402414 patternInfo, err := pattern.AsPattern()
403415 if err != nil {
404− log.Printf("Error parsing pattern: %v", err)
416+ logger.Error("Error parsing pattern", "pattern", pattern, "error", err)
405417 return false
406418 }
407419
@@ -426,7 +438,7 @@ func (w *WorkspaceWatcher) matchesPattern(path string, pattern protocol.GlobPatt
426438 // Make path relative to basePath for matching
427439 relPath, err := filepath.Rel(basePath, path)
428440 if err != nil {
429− log.Printf("Error getting relative path for %s: %v", path, err)
441+ logger.Error("Error getting relative path", "path", path, "basePath", basePath, "error", err)
430442 return false
431443 }
432444 relPath = filepath.ToSlash(relPath)
@@ -467,21 +479,25 @@ func (w *WorkspaceWatcher) handleFileEvent(ctx context.Context, uri string, chan
467479 if changeType == protocol.FileChangeType(protocol.Changed) && w.client.IsFileOpen(filePath) {
468480 err := w.client.NotifyChange(ctx, filePath)
469481 if err != nil {
470− log.Printf("Error notifying change: %v", err)
482+ logger.Error("Error notifying change", "error", err)
471483 }
472484 return
473485 }
474486
475487 // Notify LSP server about the file event using didChangeWatchedFiles
476488 if err := w.notifyFileEvent(ctx, uri, changeType); err != nil {
477− log.Printf("Error notifying LSP server about file event: %v", err)
489+ logger.Error("Error notifying LSP server about file event", "error", err)
478490 }
479491}
480492
481493// notifyFileEvent sends a didChangeWatchedFiles notification for a file event
482494func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, changeType protocol.FileChangeType) error {
483− if debug {
484− log.Printf("Notifying file event: %s (type: %d)", uri, changeType)
495+ cnf := config.Get()
496+ if cnf.Debug {
497+ logger.Debug("Notifying file event",
498+ "uri", uri,
499+ "changeType", changeType,
500+ )
485501 }
486502
487503 params := protocol.DidChangeWatchedFilesParams{
@@ -575,7 +591,7 @@ func shouldExcludeDir(dirPath string) bool {
575591// shouldExcludeFile returns true if the file should be excluded from opening
576592func shouldExcludeFile(filePath string) bool {
577593 fileName := filepath.Base(filePath)
578−
594+ cnf := config.Get()
579595 // Skip dot files
580596 if strings.HasPrefix(fileName, ".") {
581597 return true
@@ -601,8 +617,15 @@ func shouldExcludeFile(filePath string) bool {
601617
602618 // Skip large files
603619 if info.Size() > maxFileSize {
604− if debug {
605− log.Printf("Skipping large file: %s (%.2f MB)", filePath, float64(info.Size())/(1024*1024))
620+ if cnf.Debug {
621+ logger.Debug("Skipping large file",
622+ "path", filePath,
623+ "size", info.Size(),
624+ "maxSize", maxFileSize,
625+ "debug", cnf.Debug,
626+ "sizeMB", float64(info.Size())/(1024*1024),
627+ "maxSizeMB", float64(maxFileSize)/(1024*1024),
628+ )
606629 }
607630 return true
608631 }
@@ -612,6 +635,7 @@ func shouldExcludeFile(filePath string) bool {
612635
613636// openMatchingFile opens a file if it matches any of the registered patterns
614637func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
638+ cnf := config.Get()
615639 // Skip directories
616640 info, err := os.Stat(path)
617641 if err != nil || info.IsDir() {
@@ -626,8 +650,8 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
626650 // Check if this path should be watched according to server registrations
627651 if watched, _ := w.isPathWatched(path); watched {
628652 // Don't need to check if it's already open - the client.OpenFile handles that
629− if err := w.client.OpenFile(ctx, path); err != nil && debug {
630− log.Printf("Error opening file %s: %v", path, err)
653+ if err := w.client.OpenFile(ctx, path); err != nil && cnf.Debug {
654+ logger.Error("Error opening file", "path", path, "error", err)
631655 }
632656 }
633657}