1
0
mirror of https://github.com/golang/go synced 2024-11-19 03:14:42 -07:00
go/internal/lsp/cache/overlay.go
Rebecca Stambler ca0407e66b internal/lsp: return snapshots from text modifications
Eliminate the file watcher, since it led to a lot of confusion and
difficulty reasoning about the flow of a file action. This change splits
a file invalidation into the two logical steps - 1) things that affect
the overlay, and 2) things that affect the view. It is based on top of
CL 211757, so the diffs will look better once that CL is merged.

Change-Id: I277475569b61f3c80feaa6b6fe457b4bace82e35
Reviewed-on: https://go-review.googlesource.com/c/tools/+/211777
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
2019-12-18 22:53:40 +00:00

154 lines
3.5 KiB
Go

// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cache
import (
"bytes"
"context"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
errors "golang.org/x/xerrors"
)
type overlay struct {
session *session
uri span.URI
data []byte
hash string
version float64
kind source.FileKind
// sameContentOnDisk is true if a file has been saved on disk,
// and therefore does not need to be part of the overlay sent to go/packages.
sameContentOnDisk bool
}
func (o *overlay) FileSystem() source.FileSystem {
return o.session
}
func (o *overlay) Identity() source.FileIdentity {
return source.FileIdentity{
URI: o.uri,
Identifier: o.hash,
Version: o.version,
Kind: o.kind,
}
}
func (o *overlay) Read(ctx context.Context) ([]byte, string, error) {
return o.data, o.hash, nil
}
func (s *session) setOverlay(uri span.URI, version float64, data []byte) error {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
o, ok := s.overlays[uri]
if !ok {
return errors.Errorf("setting overlay for unopened file %s", uri)
}
s.overlays[uri] = &overlay{
session: s,
uri: uri,
kind: o.kind,
data: data,
hash: hashContents(data),
version: version,
}
return nil
}
func (s *session) closeOverlay(uri span.URI) error {
s.openFiles.Delete(uri)
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
_, ok := s.overlays[uri]
if !ok {
return errors.Errorf("closing unopened overlay %s", uri)
}
delete(s.overlays, uri)
return nil
}
func (s *session) openOverlay(ctx context.Context, uri span.URI, languageID string, version float64, data []byte) error {
kind := source.DetectLanguage(languageID, uri.Filename())
if kind == source.UnknownKind {
return errors.Errorf("openOverlay: unknown file kind for %s", uri)
}
s.openFiles.Store(uri, true)
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
s.overlays[uri] = &overlay{
session: s,
uri: uri,
kind: kind,
data: data,
hash: hashContents(data),
version: version,
}
// If the file is on disk, check if its content is the same as the overlay.
if _, hash, err := s.cache.GetFile(uri, kind).Read(ctx); err == nil {
if hash == s.overlays[uri].hash {
s.overlays[uri].sameContentOnDisk = true
}
}
return nil
}
func (s *session) saveOverlay(uri span.URI, version float64, data []byte) error {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
o, ok := s.overlays[uri]
if !ok {
return errors.Errorf("saveOverlay: unopened overlay %s", uri)
}
if o.version != version {
return errors.Errorf("saveOverlay: saving %s at version %v, currently at %v", uri, version, o.version)
}
if data != nil {
if !bytes.Equal(o.data, data) {
return errors.Errorf("saveOverlay: overlay %s changed on save", uri)
}
o.data = data
}
o.sameContentOnDisk = true
o.version = version
return nil
}
func (s *session) readOverlay(uri span.URI) *overlay {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
// We might have the content saved in an overlay.
if overlay, ok := s.overlays[uri]; ok {
return overlay
}
return nil
}
func (s *session) buildOverlay() map[string][]byte {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
overlays := make(map[string][]byte)
for uri, overlay := range s.overlays {
// TODO(rstambler): Make sure not to send overlays outside of the current view.
if overlay.sameContentOnDisk {
continue
}
overlays[uri.Filename()] = overlay.data
}
return overlays
}