mirror of
https://github.com/golang/go
synced 2024-11-19 01:34:40 -07:00
86d412b4c6
This is the beginning of the CLs to refactor the file watching code with the normal text synchronization code. This hasn't yet been tested other than with some minimal local testing, so follow-up CLs will be needed. Updates golang/go#31553 Change-Id: Id081ecc59dd2903057164171bd95f0dc07baa5f1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/214277 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
134 lines
3.3 KiB
Go
134 lines
3.3 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 (
|
|
"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
|
|
text []byte
|
|
hash string
|
|
version float64
|
|
kind source.FileKind
|
|
|
|
// saved 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.
|
|
saved 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.text, o.hash, nil
|
|
}
|
|
|
|
func (s *session) updateOverlay(ctx context.Context, c source.FileModification) (source.FileKind, error) {
|
|
// Make sure that the file was not changed on disk.
|
|
if c.OnDisk {
|
|
return source.UnknownKind, errors.Errorf("updateOverlay called for an on-disk change: %s", c.URI)
|
|
}
|
|
|
|
s.overlayMu.Lock()
|
|
defer s.overlayMu.Unlock()
|
|
|
|
o, ok := s.overlays[c.URI]
|
|
|
|
// Determine the file kind on open, otherwise, assume it has been cached.
|
|
var kind source.FileKind
|
|
switch c.Action {
|
|
case source.Open:
|
|
kind = source.DetectLanguage(c.LanguageID, c.URI.Filename())
|
|
default:
|
|
if !ok {
|
|
return -1, errors.Errorf("updateOverlay: modifying unopened overlay %v", c.URI)
|
|
}
|
|
kind = o.kind
|
|
}
|
|
if kind == source.UnknownKind {
|
|
return -1, errors.Errorf("updateOverlay: unknown file kind for %s", c.URI)
|
|
}
|
|
|
|
// Closing a file just deletes its overlay.
|
|
if c.Action == source.Close {
|
|
delete(s.overlays, c.URI)
|
|
return kind, nil
|
|
}
|
|
|
|
// If the file is on disk, check if its content is the same as the overlay.
|
|
text := c.Text
|
|
if text == nil {
|
|
text = o.text
|
|
}
|
|
hash := hashContents(text)
|
|
var sameContentOnDisk bool
|
|
switch c.Action {
|
|
case source.Open:
|
|
_, h, err := s.cache.GetFile(c.URI).Read(ctx)
|
|
sameContentOnDisk = (err == nil && h == hash)
|
|
case source.Save:
|
|
// Make sure the version and content (if present) is the same.
|
|
if o.version != c.Version {
|
|
return -1, errors.Errorf("updateOverlay: saving %s at version %v, currently at %v", c.URI, c.Version, o.version)
|
|
}
|
|
if c.Text != nil && o.hash != hash {
|
|
return -1, errors.Errorf("updateOverlay: overlay %s changed on save", c.URI)
|
|
}
|
|
sameContentOnDisk = true
|
|
}
|
|
s.overlays[c.URI] = &overlay{
|
|
session: s,
|
|
uri: c.URI,
|
|
version: c.Version,
|
|
text: text,
|
|
kind: kind,
|
|
hash: hash,
|
|
saved: sameContentOnDisk,
|
|
}
|
|
return kind, 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.saved {
|
|
continue
|
|
}
|
|
overlays[uri.Filename()] = overlay.text
|
|
}
|
|
return overlays
|
|
}
|