diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index f78dbcdb6e..ee79f742dd 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -519,6 +519,36 @@ func basename(filename string) string { return strings.ToLower(filepath.Base(filename)) } +func (v *View) WorkspaceDirectories(ctx context.Context) ([]string, error) { + // If the view does not have a go.mod file, only the root directory + // is known. In GOPATH mode, we should really watch the entire GOPATH, + // but that's probably too expensive. + // TODO(rstambler): Figure out a better approach in the future. + if v.modURI == "" { + return []string{v.folder.Filename()}, nil + } + // Anything inside of the module root is known. + dirs := []string{filepath.Dir(v.modURI.Filename())} + + // Keep track of any directories mentioned in replace targets. + fh, err := v.session.GetFile(ctx, v.modURI) + if err != nil { + return nil, err + } + pmh, err := v.Snapshot().ParseModHandle(ctx, fh) + if err != nil { + return nil, err + } + parsed, _, _, err := pmh.Parse(ctx) + if err != nil { + return nil, err + } + for _, replace := range parsed.Replace { + dirs = append(dirs, replace.New.Path) + } + return dirs, nil +} + func (v *View) relevantChange(c source.FileModification) bool { // If the file is known to the view, the change is relevant. known := v.knownFile(c.URI) diff --git a/internal/lsp/general.go b/internal/lsp/general.go index c2051ce0ab..16cee522a2 100644 --- a/internal/lsp/general.go +++ b/internal/lsp/general.go @@ -152,25 +152,6 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa ) } - if options.DynamicWatchedFilesSupported { - registrations = append(registrations, protocol.Registration{ - ID: "workspace/didChangeWatchedFiles", - Method: "workspace/didChangeWatchedFiles", - RegisterOptions: protocol.DidChangeWatchedFilesRegistrationOptions{ - Watchers: []protocol.FileSystemWatcher{{ - GlobPattern: "**/*.go", - Kind: float64(protocol.WatchChange + protocol.WatchDelete + protocol.WatchCreate), - }}, - }, - }) - } - - if len(registrations) > 0 { - s.client.RegisterCapability(ctx, &protocol.RegistrationParams{ - Registrations: registrations, - }) - } - // TODO: this event logging may be unnecessary. The version info is included in the initialize response. buf := &bytes.Buffer{} debug.PrintVersionInfo(ctx, buf, true, debug.PlainText) @@ -179,6 +160,31 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa s.addFolders(ctx, s.pendingFolders) s.pendingFolders = nil + if options.DynamicWatchedFilesSupported { + for _, view := range s.session.Views() { + dirs, err := view.WorkspaceDirectories(ctx) + if err != nil { + return err + } + for _, dir := range dirs { + registrations = append(registrations, protocol.Registration{ + ID: "workspace/didChangeWatchedFiles", + Method: "workspace/didChangeWatchedFiles", + RegisterOptions: protocol.DidChangeWatchedFilesRegistrationOptions{ + Watchers: []protocol.FileSystemWatcher{{ + GlobPattern: fmt.Sprintf("%s/**.go", dir), + Kind: float64(protocol.WatchChange + protocol.WatchDelete + protocol.WatchCreate), + }}, + }, + }) + } + } + if len(registrations) > 0 { + s.client.RegisterCapability(ctx, &protocol.RegistrationParams{ + Registrations: registrations, + }) + } + } return nil } diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go index 1854bc8bd4..89bed4b207 100644 --- a/internal/lsp/source/view.go +++ b/internal/lsp/source/view.go @@ -177,6 +177,10 @@ type View interface { // IgnoredFile reports if a file would be ignored by a `go list` of the whole // workspace. IgnoredFile(uri span.URI) bool + + // WorkspaceDirectories returns any directory known by the view. For views + // within a module, this is the module root and any replace targets. + WorkspaceDirectories(ctx context.Context) ([]string, error) } type BuiltinPackage interface {