on main help sign in
refactor: remove weird context value usage (#153)

* refactor: remove weird context value usage * fix: improvements * fix: more cleanup * fix: diff

commitfb21333164037023f626bbfb60d6e9d07210e494 authorCarlos Alexandro Becker <caarlos0@users.noreply.github.com> dateFri 11 Jul 2025, 16:09 (1 year ago) parent3e820ec
2 files changed+56−102
internal/app/lsp.go+1−4 internal/lsp/watcher/watcher.go+55−98
internal/app/lsp.go+1−4
@@ -59,11 +59,8 @@ func (app *App) createAndStartLSPClient(ctx context.Context, name string, comman
5959 // Create a child context that can be canceled when the app is shutting down
6060 watchCtx, cancelFunc := context.WithCancel(ctx)
6161
62− // Create a context with the server name for better identification
63− watchCtx = context.WithValue(watchCtx, "serverName", name)
64−
6562 // Create the workspace watcher
66− workspaceWatcher := watcher.NewWorkspaceWatcher(lspClient)
63+ workspaceWatcher := watcher.NewWorkspaceWatcher(name, lspClient)
6764
6865 // Store the cancel function to be called during cleanup
6966 app.cancelFuncsMutex.Lock()
internal/lsp/watcher/watcher.go+55−98
@@ -21,6 +21,7 @@ import (
2121// WorkspaceWatcher manages LSP file watching
2222type WorkspaceWatcher struct {
2323 client *lsp.Client
24+ name string
2425 workspacePath string
2526
2627 debounceTime time.Duration
@@ -33,8 +34,9 @@ type WorkspaceWatcher struct {
3334}
3435
3536// NewWorkspaceWatcher creates a new workspace watcher
36−func NewWorkspaceWatcher(client *lsp.Client) *WorkspaceWatcher {
37+func NewWorkspaceWatcher(name string, client *lsp.Client) *WorkspaceWatcher {
3738 return &WorkspaceWatcher{
39+ name: name,
3840 client: client,
3941 debounceTime: 300 * time.Millisecond,
4042 debounceMap: make(map[string]*time.Timer),
@@ -95,7 +97,7 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
9597 }
9698
9799 // Determine server type for specialized handling
98− serverName := getServerNameFromContext(ctx)
100+ serverName := w.name
99101 slog.Debug("Server type detected", "serverName", serverName)
100102
101103 // Check if this server has sent file watchers
@@ -325,17 +327,7 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
325327 cfg := config.Get()
326328 w.workspacePath = workspacePath
327329
328− // Store the watcher in the context for later use
329− ctx = context.WithValue(ctx, "workspaceWatcher", w)
330−
331− // If the server name isn't already in the context, try to detect it
332− if _, ok := ctx.Value("serverName").(string); !ok {
333− serverName := getServerNameFromContext(ctx)
334− ctx = context.WithValue(ctx, "serverName", serverName)
335− }
336−
337− serverName := getServerNameFromContext(ctx)
338− slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", serverName)
330+ slog.Debug("Starting workspace watcher", "workspacePath", workspacePath, "serverName", w.name)
339331
340332 // Register handler for file watcher registrations from the server
341333 lsp.RegisterFileWatchHandler(func(id string, watchers []protocol.FileSystemWatcher) {
@@ -697,40 +689,6 @@ func (w *WorkspaceWatcher) notifyFileEvent(ctx context.Context, uri string, chan
697689 return w.client.DidChangeWatchedFiles(ctx, params)
698690}
699691
700−// getServerNameFromContext extracts the server name from the context
701−// This is a best-effort function that tries to identify which LSP server we're dealing with
702−func getServerNameFromContext(ctx context.Context) string {
703− // First check if the server name is directly stored in the context
704− if serverName, ok := ctx.Value("serverName").(string); ok && serverName != "" {
705− return strings.ToLower(serverName)
706− }
707−
708− // Otherwise, try to extract server name from the client command path
709− if w, ok := ctx.Value("workspaceWatcher").(*WorkspaceWatcher); ok && w != nil && w.client != nil && w.client.Cmd != nil {
710− path := strings.ToLower(w.client.Cmd.Path)
711−
712− // Extract server name from path
713− if strings.Contains(path, "typescript") || strings.Contains(path, "tsserver") || strings.Contains(path, "vtsls") {
714− return "typescript"
715− } else if strings.Contains(path, "gopls") {
716− return "gopls"
717− } else if strings.Contains(path, "rust-analyzer") {
718− return "rust-analyzer"
719− } else if strings.Contains(path, "pyright") || strings.Contains(path, "pylsp") || strings.Contains(path, "python") {
720− return "python"
721− } else if strings.Contains(path, "clangd") {
722− return "clangd"
723− } else if strings.Contains(path, "jdtls") || strings.Contains(path, "java") {
724− return "java"
725− }
726−
727− // Return the base name as fallback
728− return filepath.Base(path)
729− }
730−
731− return "unknown"
732−}
733−
734692// shouldPreloadFiles determines if we should preload files for a specific language server
735693// Some servers work better with preloaded files, others don't need it
736694func shouldPreloadFiles(serverName string) bool {
@@ -884,64 +842,63 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
884842 }
885843
886844 // Check if this path should be watched according to server registrations
887− if watched, _ := w.isPathWatched(path); watched {
888− // Get server name for specialized handling
889− serverName := getServerNameFromContext(ctx)
845+ if watched, _ := w.isPathWatched(path); !watched {
846+ return
847+ }
890848
891− // Check if the file is a high-priority file that should be opened immediately
892− // This helps with project initialization for certain language servers
893− if isHighPriorityFile(path, serverName) {
894− if cfg.Options.DebugLSP {
895− slog.Debug("Opening high-priority file", "path", path, "serverName", serverName)
896− }
897− if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
898− slog.Error("Error opening high-priority file", "path", path, "error", err)
899− }
900− return
901− }
849+ serverName := w.name
902850
903− // For non-high-priority files, we'll use different strategies based on server type
904− if shouldPreloadFiles(serverName) {
905− // For servers that benefit from preloading, open files but with limits
851+ // Get server name for specialized handling
852+ // Check if the file is a high-priority file that should be opened immediately
853+ // This helps with project initialization for certain language servers
854+ if isHighPriorityFile(path, serverName) {
855+ if cfg.Options.DebugLSP {
856+ slog.Debug("Opening high-priority file", "path", path, "serverName", serverName)
857+ }
858+ if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
859+ slog.Error("Error opening high-priority file", "path", path, "error", err)
860+ }
861+ return
862+ }
906863
907− // Check file size - for preloading we're more conservative
908− if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files
909− if cfg.Options.DebugLSP {
910− slog.Debug("Skipping large file for preloading", "path", path, "size", info.Size())
911− }
912− return
913− }
864+ // For non-high-priority files, we'll use different strategies based on server type
865+ if !shouldPreloadFiles(serverName) {
866+ return
867+ }
868+ // For servers that benefit from preloading, open files but with limits
914869
915− // Check file extension for common source files
916− ext := strings.ToLower(filepath.Ext(path))
870+ // Check file size - for preloading we're more conservative
871+ if info.Size() > (1 * 1024 * 1024) { // 1MB limit for preloaded files
872+ if cfg.Options.DebugLSP {
873+ slog.Debug("Skipping large file for preloading", "path", path, "size", info.Size())
874+ }
875+ return
876+ }
917877
918− // Only preload source files for the specific language
919− shouldOpen := false
878+ // Check file extension for common source files
879+ ext := strings.ToLower(filepath.Ext(path))
920880
921− switch serverName {
922− case "typescript", "typescript-language-server", "tsserver", "vtsls":
923− shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx"
924− case "gopls":
925− shouldOpen = ext == ".go"
926− case "rust-analyzer":
927− shouldOpen = ext == ".rs"
928− case "python", "pyright", "pylsp":
929− shouldOpen = ext == ".py"
930− case "clangd":
931− shouldOpen = ext == ".c" || ext == ".cpp" || ext == ".h" || ext == ".hpp"
932− case "java", "jdtls":
933− shouldOpen = ext == ".java"
934− default:
935− // For unknown servers, be conservative
936− shouldOpen = false
937− }
881+ // Only preload source files for the specific language
882+ var shouldOpen bool
883+ switch serverName {
884+ case "typescript", "typescript-language-server", "tsserver", "vtsls":
885+ shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx"
886+ case "gopls":
887+ shouldOpen = ext == ".go"
888+ case "rust-analyzer":
889+ shouldOpen = ext == ".rs"
890+ case "python", "pyright", "pylsp":
891+ shouldOpen = ext == ".py"
892+ case "clangd":
893+ shouldOpen = ext == ".c" || ext == ".cpp" || ext == ".h" || ext == ".hpp"
894+ case "java", "jdtls":
895+ shouldOpen = ext == ".java"
896+ }
938897
939− if shouldOpen {
940− // Don't need to check if it's already open - the client.OpenFile handles that
941− if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
942− slog.Error("Error opening file", "path", path, "error", err)
943− }
944− }
898+ if shouldOpen {
899+ // Don't need to check if it's already open - the client.OpenFile handles that
900+ if err := w.client.OpenFile(ctx, path); err != nil && cfg.Options.DebugLSP {
901+ slog.Error("Error opening file", "path", path, "error", err)
945902 }
946903 }
947904}