golang.org/x/tools/gopls@v0.15.3/internal/server/workspace.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package server 6 7 import ( 8 "context" 9 "fmt" 10 "reflect" 11 "sync" 12 13 "golang.org/x/tools/gopls/internal/cache" 14 "golang.org/x/tools/gopls/internal/protocol" 15 "golang.org/x/tools/gopls/internal/settings" 16 "golang.org/x/tools/internal/event" 17 ) 18 19 func (s *server) DidChangeWorkspaceFolders(ctx context.Context, params *protocol.DidChangeWorkspaceFoldersParams) error { 20 for _, folder := range params.Event.Removed { 21 dir, err := protocol.ParseDocumentURI(folder.URI) 22 if err != nil { 23 return fmt.Errorf("invalid folder %q: %v", folder.URI, err) 24 } 25 if !s.session.RemoveView(dir) { 26 return fmt.Errorf("view %q for %v not found", folder.Name, folder.URI) 27 } 28 } 29 s.addFolders(ctx, params.Event.Added) 30 return nil 31 } 32 33 // addView returns a Snapshot and a release function that must be 34 // called when it is no longer needed. 35 func (s *server) addView(ctx context.Context, name string, dir protocol.DocumentURI) (*cache.Snapshot, func(), error) { 36 s.stateMu.Lock() 37 state := s.state 38 s.stateMu.Unlock() 39 if state < serverInitialized { 40 return nil, nil, fmt.Errorf("addView called before server initialized") 41 } 42 opts, err := s.fetchFolderOptions(ctx, dir) 43 if err != nil { 44 return nil, nil, err 45 } 46 folder, err := s.newFolder(ctx, dir, name, opts) 47 if err != nil { 48 return nil, nil, err 49 } 50 _, snapshot, release, err := s.session.NewView(ctx, folder) 51 return snapshot, release, err 52 } 53 54 func (s *server) DidChangeConfiguration(ctx context.Context, _ *protocol.DidChangeConfigurationParams) error { 55 ctx, done := event.Start(ctx, "lsp.Server.didChangeConfiguration") 56 defer done() 57 58 var wg sync.WaitGroup 59 wg.Add(1) 60 defer wg.Done() 61 if s.Options().VerboseWorkDoneProgress { 62 work := s.progress.Start(ctx, DiagnosticWorkTitle(FromDidChangeConfiguration), "Calculating diagnostics...", nil, nil) 63 go func() { 64 wg.Wait() 65 work.End(ctx, "Done.") 66 }() 67 } 68 69 // Apply any changes to the session-level settings. 70 options, err := s.fetchFolderOptions(ctx, "") 71 if err != nil { 72 return err 73 } 74 s.SetOptions(options) 75 76 // Collect options for all workspace folders. 77 // If none have changed, this is a no op. 78 folderOpts := make(map[protocol.DocumentURI]*settings.Options) 79 changed := false 80 // The set of views is implicitly guarded by the fact that gopls processes 81 // didChange notifications synchronously. 82 // 83 // TODO(rfindley): investigate this assumption: perhaps we should hold viewMu 84 // here. 85 views := s.session.Views() 86 for _, view := range views { 87 folder := view.Folder() 88 if folderOpts[folder.Dir] != nil { 89 continue 90 } 91 opts, err := s.fetchFolderOptions(ctx, folder.Dir) 92 if err != nil { 93 return err 94 } 95 96 // Ignore hooks for the purposes of equality. 97 sameOptions := reflect.DeepEqual(folder.Options.ClientOptions, opts.ClientOptions) && 98 reflect.DeepEqual(folder.Options.ServerOptions, opts.ServerOptions) && 99 reflect.DeepEqual(folder.Options.UserOptions, opts.UserOptions) && 100 reflect.DeepEqual(folder.Options.InternalOptions, opts.InternalOptions) 101 102 if !sameOptions { 103 changed = true 104 } 105 folderOpts[folder.Dir] = opts 106 } 107 if !changed { 108 return nil 109 } 110 111 var newFolders []*cache.Folder 112 for _, view := range views { 113 folder := view.Folder() 114 opts := folderOpts[folder.Dir] 115 newFolder, err := s.newFolder(ctx, folder.Dir, folder.Name, opts) 116 if err != nil { 117 return err 118 } 119 newFolders = append(newFolders, newFolder) 120 } 121 s.session.UpdateFolders(ctx, newFolders) 122 123 // The view set may have been updated above. 124 viewsToDiagnose := make(map[*cache.View][]protocol.DocumentURI) 125 for _, view := range s.session.Views() { 126 viewsToDiagnose[view] = nil 127 } 128 129 modCtx, modID := s.needsDiagnosis(ctx, viewsToDiagnose) 130 wg.Add(1) 131 go func() { 132 s.diagnoseChangedViews(modCtx, modID, viewsToDiagnose, FromDidChangeConfiguration) 133 wg.Done() 134 }() 135 136 // An options change may have affected the detected Go version. 137 s.checkViewGoVersions() 138 139 return nil 140 }