diff --git a/gopls/internal/lsp/cache/session.go b/gopls/internal/lsp/cache/session.go index 5931813151..5d40ff6be5 100644 --- a/gopls/internal/lsp/cache/session.go +++ b/gopls/internal/lsp/cache/session.go @@ -13,11 +13,11 @@ import ( "sync" "sync/atomic" + "golang.org/x/tools/gopls/internal/lsp/progress" + "golang.org/x/tools/gopls/internal/lsp/source" "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/imports" - "golang.org/x/tools/gopls/internal/lsp/progress" - "golang.org/x/tools/gopls/internal/lsp/source" "golang.org/x/tools/internal/persistent" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/xcontext" @@ -120,26 +120,31 @@ func (c *closedFile) Version() int32 { return 0 } +// ID returns the unique identifier for this session on this server. func (s *Session) ID() string { return s.id } func (s *Session) String() string { return s.id } +// Options returns a copy of the SessionOptions for this session. func (s *Session) Options() *source.Options { s.optionsMu.Lock() defer s.optionsMu.Unlock() return s.options } +// SetOptions sets the options of this session to new values. func (s *Session) SetOptions(options *source.Options) { s.optionsMu.Lock() defer s.optionsMu.Unlock() s.options = options } +// SetProgressTracker sets the progress tracker for the session. func (s *Session) SetProgressTracker(tracker *progress.Tracker) { // The progress tracker should be set before any view is initialized. s.progress = tracker } +// Shutdown the session and all views it has created. func (s *Session) Shutdown(ctx context.Context) { var views []*View s.viewMu.Lock() @@ -153,10 +158,16 @@ func (s *Session) Shutdown(ctx context.Context) { event.Log(ctx, "Shutdown session", KeyShutdownSession.Of(s)) } -func (s *Session) Cache() interface{} { +// Cache returns the cache that created this session, for debugging only. +func (s *Session) Cache() *Cache { return s.cache } +// NewView creates a new View, returning it and its first snapshot. If a +// non-empty tempWorkspace directory is provided, the View will record a copy +// of its gopls workspace module in that directory, so that client tooling +// can execute in the same main module. On success it also returns a release +// function that must be called when the Snapshot is no longer needed. func (s *Session) NewView(ctx context.Context, name string, folder span.URI, options *source.Options) (source.View, source.Snapshot, func(), error) { s.viewMu.Lock() defer s.viewMu.Unlock() @@ -292,7 +303,7 @@ func (s *Session) createView(ctx context.Context, name string, folder span.URI, return v, snapshot, snapshot.Acquire(), nil } -// View returns the view by name. +// View returns a view with a matching name, if the session has one. func (s *Session) View(name string) source.View { s.viewMu.RLock() defer s.viewMu.RUnlock() @@ -446,6 +457,11 @@ type fileChange struct { isUnchanged bool } +// DidModifyFiles reports a file modification to the session. It returns +// the new snapshots after the modifications have been applied, paired with +// the affected file URIs for those snapshots. +// On success, it returns a release function that +// must be called when the snapshots are no longer needed. func (s *Session) DidModifyFiles(ctx context.Context, changes []source.FileModification) (map[source.Snapshot][]span.URI, func(), error) { s.viewMu.RLock() defer s.viewMu.RUnlock() @@ -556,6 +572,9 @@ func (s *Session) DidModifyFiles(ctx context.Context, changes []source.FileModif return snapshotURIs, release, nil } +// ExpandModificationsToDirectories returns the set of changes with the +// directory changes removed and expanded to include all of the files in +// the directory. func (s *Session) ExpandModificationsToDirectories(ctx context.Context, changes []source.FileModification) []source.FileModification { s.viewMu.RLock() defer s.viewMu.RUnlock() @@ -731,6 +750,7 @@ func (s *Session) updateOverlays(ctx context.Context, changes []source.FileModif return overlays, nil } +// GetFile returns a handle for the specified file. func (s *Session) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) { if overlay := s.readOverlay(uri); overlay != nil { return overlay, nil @@ -749,6 +769,7 @@ func (s *Session) readOverlay(uri span.URI) *overlay { return nil } +// Overlays returns a slice of file overlays for the session. func (s *Session) Overlays() []source.Overlay { s.overlayMu.Lock() defer s.overlayMu.Unlock() @@ -760,6 +781,9 @@ func (s *Session) Overlays() []source.Overlay { return overlays } +// FileWatchingGlobPatterns returns glob patterns to watch every directory +// known by the view. For views within a module, this is the module root, +// any directory in the module root, and any replace targets. func (s *Session) FileWatchingGlobPatterns(ctx context.Context) map[string]struct{} { s.viewMu.RLock() defer s.viewMu.RUnlock() diff --git a/gopls/internal/lsp/debug/serve.go b/gopls/internal/lsp/debug/serve.go index da0d68d41d..248041ed68 100644 --- a/gopls/internal/lsp/debug/serve.go +++ b/gopls/internal/lsp/debug/serve.go @@ -26,6 +26,10 @@ import ( "sync" "time" + "golang.org/x/tools/gopls/internal/lsp/cache" + "golang.org/x/tools/gopls/internal/lsp/debug/log" + "golang.org/x/tools/gopls/internal/lsp/protocol" + "golang.org/x/tools/internal/bug" "golang.org/x/tools/internal/event" "golang.org/x/tools/internal/event/core" "golang.org/x/tools/internal/event/export" @@ -34,12 +38,7 @@ import ( "golang.org/x/tools/internal/event/export/prometheus" "golang.org/x/tools/internal/event/keys" "golang.org/x/tools/internal/event/label" - "golang.org/x/tools/internal/bug" - "golang.org/x/tools/gopls/internal/lsp/cache" - "golang.org/x/tools/gopls/internal/lsp/debug/log" "golang.org/x/tools/internal/event/tag" - "golang.org/x/tools/gopls/internal/lsp/protocol" - "golang.org/x/tools/gopls/internal/lsp/source" ) type contextKeyType int @@ -88,10 +87,7 @@ func (st *State) Caches() []*cache.Cache { var caches []*cache.Cache seen := make(map[string]struct{}) for _, client := range st.Clients() { - cache, ok := client.Session.Cache().(*cache.Cache) - if !ok { - continue - } + cache := client.Session.Cache() if _, found := seen[cache.ID()]; found { continue } @@ -208,7 +204,7 @@ func (st *State) addClient(session *cache.Session) { } // DropClient removes a client from the set being served. -func (st *State) dropClient(session source.Session) { +func (st *State) dropClient(session *cache.Session) { st.mu.Lock() defer st.mu.Unlock() for i, c := range st.clients { diff --git a/gopls/internal/lsp/server.go b/gopls/internal/lsp/server.go index a344b5933e..0d257b26eb 100644 --- a/gopls/internal/lsp/server.go +++ b/gopls/internal/lsp/server.go @@ -10,6 +10,7 @@ import ( "fmt" "sync" + "golang.org/x/tools/gopls/internal/lsp/cache" "golang.org/x/tools/gopls/internal/lsp/progress" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/gopls/internal/lsp/source" @@ -21,7 +22,7 @@ const concurrentAnalyses = 1 // NewServer creates an LSP server and binds it to handle incoming client // messages on on the supplied stream. -func NewServer(session source.Session, client protocol.ClientCloser) *Server { +func NewServer(session *cache.Session, client protocol.ClientCloser) *Server { tracker := progress.NewTracker(client) session.SetProgressTracker(tracker) return &Server{ @@ -70,7 +71,7 @@ type Server struct { // notifications generated before serverInitialized notifications []*protocol.ShowMessageParams - session source.Session + session *cache.Session tempDir string diff --git a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go index 47f463e13b..2565087336 100644 --- a/gopls/internal/lsp/source/view.go +++ b/gopls/internal/lsp/source/view.go @@ -21,7 +21,6 @@ import ( "golang.org/x/mod/module" "golang.org/x/tools/go/analysis" "golang.org/x/tools/go/packages" - "golang.org/x/tools/gopls/internal/lsp/progress" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/imports" @@ -332,68 +331,6 @@ type Metadata interface { ModuleInfo() *packages.Module } -// Session represents a single connection from a client. -// This is the level at which things like open files are maintained on behalf -// of the client. -// A session may have many active views at any given time. -type Session interface { - // ID returns the unique identifier for this session on this server. - ID() string - // NewView creates a new View, returning it and its first snapshot. If a - // non-empty tempWorkspace directory is provided, the View will record a copy - // of its gopls workspace module in that directory, so that client tooling - // can execute in the same main module. On success it also returns a release - // function that must be called when the Snapshot is no longer needed. - NewView(ctx context.Context, name string, folder span.URI, options *Options) (View, Snapshot, func(), error) - - // Cache returns the cache that created this session, for debugging only. - Cache() interface{} - - // View returns a view with a matching name, if the session has one. - View(name string) View - - // ViewOf returns a view corresponding to the given URI. - ViewOf(uri span.URI) (View, error) - - // Views returns the set of active views built by this session. - Views() []View - - // Shutdown the session and all views it has created. - Shutdown(ctx context.Context) - - // GetFile returns a handle for the specified file. - GetFile(ctx context.Context, uri span.URI) (FileHandle, error) - - // DidModifyFile reports a file modification to the session. It returns - // the new snapshots after the modifications have been applied, paired with - // the affected file URIs for those snapshots. - // On success, it returns a release function that - // must be called when the snapshots are no longer needed. - DidModifyFiles(ctx context.Context, changes []FileModification) (map[Snapshot][]span.URI, func(), error) - - // ExpandModificationsToDirectories returns the set of changes with the - // directory changes removed and expanded to include all of the files in - // the directory. - ExpandModificationsToDirectories(ctx context.Context, changes []FileModification) []FileModification - - // Overlays returns a slice of file overlays for the session. - Overlays() []Overlay - - // Options returns a copy of the SessionOptions for this session. - Options() *Options - - // SetOptions sets the options of this session to new values. - SetOptions(*Options) - - // FileWatchingGlobPatterns returns glob patterns to watch every directory - // known by the view. For views within a module, this is the module root, - // any directory in the module root, and any replace targets. - FileWatchingGlobPatterns(ctx context.Context) map[string]struct{} - - // SetProgressTracker sets the progress tracker for the session. - SetProgressTracker(tracker *progress.Tracker) -} - var ErrViewExists = errors.New("view already exists for session") // Overlay is the type for a file held in memory on a session.