mirror of https://github.com/golang/go.git
internal/lsp: recreate the view when needed
If the initial workspace load fails (due to a lack of a go.mod file or an invalid go.mod file), we should try to re-load as changes to the go.mod come in. Rather than retrying within the view, we just drop the view entirely and try to recreate it. This shouldn't lead to any noticeable lag, as anything that has been cached can still be reused. Fixes golang/go#36531 Change-Id: I6e157075e8b3665f0ceef35e051e56ac3c29f286 Reviewed-on: https://go-review.googlesource.com/c/tools/+/216037 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
e873952e15
commit
59ae353e8e
|
|
@ -180,6 +180,11 @@ func (v *view) SetOptions(ctx context.Context, options source.Options) (source.V
|
|||
return newView, err
|
||||
}
|
||||
|
||||
func (v *view) Rebuild(ctx context.Context) (source.Snapshot, error) {
|
||||
_, snapshot, err := v.session.updateView(ctx, v, v.options)
|
||||
return snapshot, err
|
||||
}
|
||||
|
||||
func (v *view) LookupBuiltin(ctx context.Context, name string) (*ast.Object, error) {
|
||||
if err := v.awaitInitialized(ctx); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -565,6 +570,11 @@ func (v *view) initialize(ctx context.Context, s *snapshot) {
|
|||
})
|
||||
}
|
||||
|
||||
func (v *view) Initialized(ctx context.Context) bool {
|
||||
err := v.awaitInitialized(ctx)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (v *view) awaitInitialized(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
|
|
|||
|
|
@ -130,6 +130,12 @@ type View interface {
|
|||
|
||||
// Snapshot returns the current snapshot for the view.
|
||||
Snapshot() Snapshot
|
||||
|
||||
// Initialized returns true if the view has been initialized without errors.
|
||||
Initialized(ctx context.Context) bool
|
||||
|
||||
// Rebuild rebuilds the current view, replacing the original view in its session.
|
||||
Rebuild(ctx context.Context) (Snapshot, error)
|
||||
}
|
||||
|
||||
// Session represents a single connection from a client.
|
||||
|
|
@ -164,6 +170,7 @@ type Session interface {
|
|||
IsOpen(uri span.URI) bool
|
||||
|
||||
// DidModifyFile reports a file modification to the session.
|
||||
// It returns the resulting snapshots, a guaranteed one per view.
|
||||
DidModifyFiles(ctx context.Context, changes []FileModification) ([]Snapshot, error)
|
||||
|
||||
// Options returns a copy of the SessionOptions for this session.
|
||||
|
|
|
|||
|
|
@ -112,13 +112,13 @@ func (s *Server) didModifyFiles(ctx context.Context, modifications []source.File
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uris := make(map[span.URI]source.Snapshot)
|
||||
snapshotByURI := make(map[span.URI]source.Snapshot)
|
||||
for _, c := range modifications {
|
||||
uris[c.URI] = nil
|
||||
snapshotByURI[c.URI] = nil
|
||||
}
|
||||
// Avoid diagnosing the same snapshot twice.
|
||||
snapshotSet := make(map[source.Snapshot]struct{})
|
||||
for uri := range uris {
|
||||
snapshotSet := make(map[source.Snapshot][]span.URI)
|
||||
for uri := range snapshotByURI {
|
||||
view, err := s.session.ViewOf(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -132,13 +132,35 @@ func (s *Server) didModifyFiles(ctx context.Context, modifications []source.File
|
|||
snapshot = s
|
||||
}
|
||||
}
|
||||
uris[uri] = snapshot
|
||||
snapshotSet[snapshot] = struct{}{}
|
||||
if snapshot == nil {
|
||||
return nil, errors.Errorf("no snapshot for %s", uri)
|
||||
}
|
||||
snapshotByURI[uri] = snapshot
|
||||
snapshotSet[snapshot] = append(snapshotSet[snapshot], uri)
|
||||
}
|
||||
for snapshot := range snapshotSet {
|
||||
for snapshot, uris := range snapshotSet {
|
||||
for _, uri := range uris {
|
||||
fh, err := snapshot.GetFile(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If a modification comes in for a go.mod file,
|
||||
// and the view was never properly initialized,
|
||||
// try to recreate the associated view.
|
||||
switch fh.Identity().Kind {
|
||||
case source.Mod:
|
||||
newSnapshot, err := snapshot.View().Rebuild(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Update the snapshot to the rebuilt one.
|
||||
snapshot = newSnapshot
|
||||
snapshotByURI[uri] = snapshot
|
||||
}
|
||||
}
|
||||
go s.diagnoseSnapshot(snapshot)
|
||||
}
|
||||
return uris, nil
|
||||
return snapshotByURI, nil
|
||||
}
|
||||
|
||||
func (s *Server) wasFirstChange(uri span.URI) bool {
|
||||
|
|
|
|||
Loading…
Reference in New Issue