internal/lsp: reduce the api surface of the cache package
The cache now exposes only one symbol, NewView
This is preparing the cache for a re-write
Change-Id: I411c2cd7a7edc2e7c774218c6786f9fd4fcc53cb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/176924
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index fca2804..4a9ec80 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -17,7 +17,7 @@
"golang.org/x/tools/internal/span"
)
-func (v *View) parse(ctx context.Context, f *File) ([]packages.Error, error) {
+func (v *view) parse(ctx context.Context, f *file) ([]packages.Error, error) {
v.mcache.mu.Lock()
defer v.mcache.mu.Unlock()
@@ -61,9 +61,9 @@
return nil, nil
}
-func (v *View) checkMetadata(ctx context.Context, f *File) ([]packages.Error, error) {
+func (v *view) checkMetadata(ctx context.Context, f *file) ([]packages.Error, error) {
if v.reparseImports(ctx, f, f.filename) {
- cfg := v.Config
+ cfg := v.config
cfg.Mode = packages.LoadImports | packages.NeedTypesSizes
pkgs, err := packages.Load(&cfg, fmt.Sprintf("file=%s", f.filename))
if len(pkgs) == 0 {
@@ -92,13 +92,13 @@
// reparseImports reparses a file's import declarations to determine if they
// have changed.
-func (v *View) reparseImports(ctx context.Context, f *File, filename string) bool {
+func (v *view) reparseImports(ctx context.Context, f *file, filename string) bool {
if f.meta == nil {
return true
}
// Get file content in case we don't already have it?
f.read(ctx)
- parsed, _ := parser.ParseFile(v.Config.Fset, filename, f.content, parser.ImportsOnly)
+ parsed, _ := parser.ParseFile(v.config.Fset, filename, f.content, parser.ImportsOnly)
if parsed == nil {
return true
}
@@ -113,7 +113,7 @@
return false
}
-func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
+func (v *view) link(pkgPath string, pkg *packages.Package, parent *metadata) *metadata {
m, ok := v.mcache.packages[pkgPath]
if !ok {
m = &metadata{
@@ -156,7 +156,7 @@
}
type importer struct {
- view *View
+ view *view
// seen maintains the set of previously imported packages.
// If we have seen a package that is already in this map, we have a circular import.
@@ -193,7 +193,7 @@
return e.pkg.types, nil
}
-func (imp *importer) typeCheck(pkgPath string) (*Package, error) {
+func (imp *importer) typeCheck(pkgPath string) (*pkg, error) {
meta, ok := imp.view.mcache.packages[pkgPath]
if !ok {
return nil, fmt.Errorf("no metadata for %v", pkgPath)
@@ -205,11 +205,11 @@
} else {
typ = types.NewPackage(meta.pkgPath, meta.name)
}
- pkg := &Package{
+ pkg := &pkg{
id: meta.id,
pkgPath: meta.pkgPath,
files: meta.files,
- imports: make(map[string]*Package),
+ imports: make(map[string]*pkg),
types: typ,
typesSizes: meta.typesSizes,
typesInfo: &types.Info{
@@ -246,7 +246,7 @@
ctx: imp.ctx,
},
}
- check := types.NewChecker(cfg, imp.view.Config.Fset, pkg.types, pkg.typesInfo)
+ check := types.NewChecker(cfg, imp.view.config.Fset, pkg.types, pkg.typesInfo)
check.Files(pkg.syntax)
// Add every file in this package to our cache.
@@ -255,14 +255,14 @@
return pkg, nil
}
-func (v *View) cachePackage(ctx context.Context, pkg *Package, meta *metadata) {
+func (v *view) cachePackage(ctx context.Context, pkg *pkg, meta *metadata) {
for _, file := range pkg.GetSyntax() {
// TODO: If a file is in multiple packages, which package do we store?
if !file.Pos().IsValid() {
v.Logger().Errorf(ctx, "invalid position for file %v", file.Name)
continue
}
- tok := v.Config.Fset.File(file.Pos())
+ tok := v.config.Fset.File(file.Pos())
if tok == nil {
v.Logger().Errorf(ctx, "no token.File for %v", file.Name)
continue
@@ -302,7 +302,7 @@
}
}
-func (v *View) appendPkgError(pkg *Package, err error) {
+func (v *view) appendPkgError(pkg *pkg, err error) {
if err == nil {
return
}
@@ -325,7 +325,7 @@
}
case types.Error:
errs = append(errs, packages.Error{
- Pos: v.Config.Fset.Position(err.Pos).String(),
+ Pos: v.config.Fset.Position(err.Pos).String(),
Msg: err.Msg,
Kind: packages.TypeError,
})
diff --git a/internal/lsp/cache/file.go b/internal/lsp/cache/file.go
index 0a9b303..1e69dfe 100644
--- a/internal/lsp/cache/file.go
+++ b/internal/lsp/cache/file.go
@@ -16,18 +16,18 @@
"golang.org/x/tools/internal/span"
)
-// File holds all the information we know about a file.
-type File struct {
+// file holds all the information we know about a file.
+type file struct {
uris []span.URI
filename string
basename string
- view *View
+ view *view
active bool
content []byte
ast *ast.File
token *token.File
- pkg *Package
+ pkg *pkg
meta *metadata
imports []*ast.ImportSpec
}
@@ -36,17 +36,17 @@
return strings.ToLower(filepath.Base(filename))
}
-func (f *File) URI() span.URI {
+func (f *file) URI() span.URI {
return f.uris[0]
}
// View returns the view associated with the file.
-func (f *File) View() source.View {
+func (f *file) View() source.View {
return f.view
}
// GetContent returns the contents of the file, reading it from file system if needed.
-func (f *File) GetContent(ctx context.Context) []byte {
+func (f *file) GetContent(ctx context.Context) []byte {
f.view.mu.Lock()
defer f.view.mu.Unlock()
@@ -57,11 +57,11 @@
return f.content
}
-func (f *File) GetFileSet(ctx context.Context) *token.FileSet {
- return f.view.Config.Fset
+func (f *file) GetFileSet(ctx context.Context) *token.FileSet {
+ return f.view.config.Fset
}
-func (f *File) GetToken(ctx context.Context) *token.File {
+func (f *file) GetToken(ctx context.Context) *token.File {
f.view.mu.Lock()
defer f.view.mu.Unlock()
@@ -73,7 +73,7 @@
return f.token
}
-func (f *File) GetAST(ctx context.Context) *ast.File {
+func (f *file) GetAST(ctx context.Context) *ast.File {
f.view.mu.Lock()
defer f.view.mu.Unlock()
@@ -85,7 +85,7 @@
return f.ast
}
-func (f *File) GetPackage(ctx context.Context) source.Package {
+func (f *file) GetPackage(ctx context.Context) source.Package {
f.view.mu.Lock()
defer f.view.mu.Unlock()
@@ -93,7 +93,7 @@
if errs, err := f.view.parse(ctx, f); err != nil {
// Create diagnostics for errors if we are able to.
if len(errs) > 0 {
- return &Package{errors: errs}
+ return &pkg{errors: errs}
}
return nil
}
@@ -103,7 +103,7 @@
// read is the internal part of GetContent. It assumes that the caller is
// holding the mutex of the file's view.
-func (f *File) read(ctx context.Context) {
+func (f *file) read(ctx context.Context) {
if f.content != nil {
if len(f.view.contentChanges) == 0 {
return
@@ -118,7 +118,7 @@
}
}
// We might have the content saved in an overlay.
- if content, ok := f.view.Config.Overlay[f.filename]; ok {
+ if content, ok := f.view.config.Overlay[f.filename]; ok {
f.content = content
return
}
@@ -132,11 +132,11 @@
}
// isPopulated returns true if all of the computed fields of the file are set.
-func (f *File) isPopulated() bool {
+func (f *file) isPopulated() bool {
return f.ast != nil && f.token != nil && f.pkg != nil && f.meta != nil && f.imports != nil
}
-func (f *File) GetActiveReverseDeps(ctx context.Context) []source.File {
+func (f *file) GetActiveReverseDeps(ctx context.Context) []source.File {
pkg := f.GetPackage(ctx)
if pkg == nil {
return nil
@@ -149,7 +149,7 @@
defer f.view.mcache.mu.Unlock()
seen := make(map[string]struct{}) // visited packages
- results := make(map[*File]struct{})
+ results := make(map[*file]struct{})
f.view.reverseDeps(ctx, seen, results, pkg.PkgPath())
files := make([]source.File, 0, len(results))
@@ -166,7 +166,7 @@
return files
}
-func (v *View) reverseDeps(ctx context.Context, seen map[string]struct{}, results map[*File]struct{}, pkgPath string) {
+func (v *view) reverseDeps(ctx context.Context, seen map[string]struct{}, results map[*file]struct{}, pkgPath string) {
if _, ok := seen[pkgPath]; ok {
return
}
diff --git a/internal/lsp/cache/parse.go b/internal/lsp/cache/parse.go
index 29cd001..0cb67e0 100644
--- a/internal/lsp/cache/parse.go
+++ b/internal/lsp/cache/parse.go
@@ -37,9 +37,9 @@
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, filename := range filenames {
- if imp.view.Config.Context.Err() != nil {
+ if imp.view.config.Context.Err() != nil {
parsed[i] = nil
- errors[i] = imp.view.Config.Context.Err()
+ errors[i] = imp.view.config.Context.Err()
continue
}
@@ -63,7 +63,7 @@
// We don't have a cached AST for this file.
var src []byte
// Check for an available overlay.
- for f, contents := range imp.view.Config.Overlay {
+ for f, contents := range imp.view.config.Overlay {
if sameFile(f, filename) {
src = contents
}
@@ -77,11 +77,11 @@
parsed[i], errors[i] = nil, err
} else {
// ParseFile may return both an AST and an error.
- parsed[i], errors[i] = imp.view.Config.ParseFile(imp.view.Config.Fset, filename, src)
+ parsed[i], errors[i] = imp.view.config.ParseFile(imp.view.config.Fset, filename, src)
// Fix any badly parsed parts of the AST.
if file := parsed[i]; file != nil {
- tok := imp.view.Config.Fset.File(file.Pos())
+ tok := imp.view.config.Fset.File(file.Pos())
imp.view.fix(imp.ctx, parsed[i], tok, src)
}
}
@@ -141,7 +141,7 @@
// fix inspects and potentially modifies any *ast.BadStmts or *ast.BadExprs in the AST.
// We attempt to modify the AST such that we can type-check it more effectively.
-func (v *View) fix(ctx context.Context, file *ast.File, tok *token.File, src []byte) {
+func (v *view) fix(ctx context.Context, file *ast.File, tok *token.File, src []byte) {
var parent ast.Node
ast.Inspect(file, func(n ast.Node) bool {
if n == nil {
@@ -167,7 +167,7 @@
// this statement entirely, and we can't use the type information when completing.
// Here, we try to generate a fake *ast.DeferStmt or *ast.GoStmt to put into the AST,
// instead of the *ast.BadStmt.
-func (v *View) parseDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) error {
+func (v *view) parseDeferOrGoStmt(bad *ast.BadStmt, parent ast.Node, tok *token.File, src []byte) error {
// Check if we have a bad statement containing either a "go" or "defer".
s := &scanner.Scanner{}
s.Init(tok, src, nil, 0)
@@ -260,7 +260,7 @@
// offsetPositions applies an offset to the positions in an ast.Node.
// TODO(rstambler): Add more cases here as they become necessary.
-func (v *View) offsetPositions(expr ast.Expr, offset token.Pos) {
+func (v *view) offsetPositions(expr ast.Expr, offset token.Pos) {
ast.Inspect(expr, func(n ast.Node) bool {
switch n := n.(type) {
case *ast.Ident:
diff --git a/internal/lsp/cache/pkg.go b/internal/lsp/cache/pkg.go
index 440b655..6fc6622 100644
--- a/internal/lsp/cache/pkg.go
+++ b/internal/lsp/cache/pkg.go
@@ -16,13 +16,13 @@
"golang.org/x/tools/internal/lsp/source"
)
-// Package contains the type information needed by the source package.
-type Package struct {
+// pkg contains the type information needed by the source package.
+type pkg struct {
id, pkgPath string
files []string
syntax []*ast.File
errors []packages.Error
- imports map[string]*Package
+ imports map[string]*pkg
types *types.Package
typesInfo *types.Info
typesSizes types.Sizes
@@ -41,7 +41,7 @@
*source.Action
}
-func (pkg *Package) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*source.Action, error) {
+func (pkg *pkg) GetActionGraph(ctx context.Context, a *analysis.Analyzer) (*source.Action, error) {
if ctx.Err() != nil {
return nil, ctx.Err()
}
@@ -128,39 +128,39 @@
return e.Action, nil
}
-func (pkg *Package) PkgPath() string {
+func (pkg *pkg) PkgPath() string {
return pkg.pkgPath
}
-func (pkg *Package) GetFilenames() []string {
+func (pkg *pkg) GetFilenames() []string {
return pkg.files
}
-func (pkg *Package) GetSyntax() []*ast.File {
+func (pkg *pkg) GetSyntax() []*ast.File {
return pkg.syntax
}
-func (pkg *Package) GetErrors() []packages.Error {
+func (pkg *pkg) GetErrors() []packages.Error {
return pkg.errors
}
-func (pkg *Package) GetTypes() *types.Package {
+func (pkg *pkg) GetTypes() *types.Package {
return pkg.types
}
-func (pkg *Package) GetTypesInfo() *types.Info {
+func (pkg *pkg) GetTypesInfo() *types.Info {
return pkg.typesInfo
}
-func (pkg *Package) GetTypesSizes() types.Sizes {
+func (pkg *pkg) GetTypesSizes() types.Sizes {
return pkg.typesSizes
}
-func (pkg *Package) IsIllTyped() bool {
+func (pkg *pkg) IsIllTyped() bool {
return pkg.types == nil && pkg.typesInfo == nil
}
-func (pkg *Package) GetImport(pkgPath string) source.Package {
+func (pkg *pkg) GetImport(pkgPath string) source.Package {
imported := pkg.imports[pkgPath]
// Be careful not to return a nil pointer because that still satisfies the
// interface.
diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go
index 6ef8ca8..4329821 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -20,7 +20,7 @@
"golang.org/x/tools/internal/span"
)
-type View struct {
+type view struct {
// mu protects all mutable state of the view.
mu sync.Mutex
@@ -40,19 +40,19 @@
log xlog.Logger
// Name is the user visible name of this view.
- Name string
+ name string
// Folder is the root of this view.
- Folder span.URI
+ folder span.URI
// Config is the configuration used for the view's interaction with the
// go/packages API. It is shared across all views.
- Config packages.Config
+ config packages.Config
// keep track of files by uri and by basename, a single file may be mapped
// to multiple uris, and the same basename may map to multiple files
- filesByURI map[span.URI]*File
- filesByBase map[string][]*File
+ filesByURI map[span.URI]*file
+ filesByBase map[string][]*file
// contentChanges saves the content changes for a given state of the view.
// When type information is requested by the view, all of the dirty changes
@@ -89,24 +89,24 @@
}
type entry struct {
- pkg *Package
+ pkg *pkg
err error
ready chan struct{} // closed to broadcast ready condition
}
-func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI, config *packages.Config) *View {
+func NewView(ctx context.Context, log xlog.Logger, name string, folder span.URI, config *packages.Config) source.View {
backgroundCtx, cancel := context.WithCancel(ctx)
- v := &View{
+ v := &view{
baseCtx: ctx,
backgroundCtx: backgroundCtx,
builtinPkg: builtinPkg(*config),
cancel: cancel,
log: log,
- Config: *config,
- Name: name,
- Folder: folder,
- filesByURI: make(map[span.URI]*File),
- filesByBase: make(map[string][]*File),
+ config: *config,
+ name: name,
+ folder: folder,
+ filesByURI: make(map[span.URI]*file),
+ filesByBase: make(map[string][]*file),
contentChanges: make(map[span.URI]func()),
mcache: &metadataCache{
packages: make(map[string]*metadata),
@@ -118,14 +118,34 @@
return v
}
-func (v *View) BackgroundContext() context.Context {
+// Name returns the user visible name of this view.
+func (v *view) Name() string {
+ return v.name
+}
+
+// Folder returns the root of this view.
+func (v *view) Folder() span.URI {
+ return v.folder
+}
+
+// Config returns the configuration used for the view's interaction with the
+// go/packages API. It is shared across all views.
+func (v *view) Config() packages.Config {
+ return v.config
+}
+
+func (v *view) SetEnv(env []string) {
+ v.config.Env = env
+}
+
+func (v *view) BackgroundContext() context.Context {
v.mu.Lock()
defer v.mu.Unlock()
return v.backgroundCtx
}
-func (v *View) BuiltinPackage() *ast.Package {
+func (v *view) BuiltinPackage() *ast.Package {
return v.builtinPkg
}
@@ -151,12 +171,12 @@
return bpkg
}
-func (v *View) FileSet() *token.FileSet {
- return v.Config.Fset
+func (v *view) FileSet() *token.FileSet {
+ return v.config.Fset
}
// SetContent sets the overlay contents for a file.
-func (v *View) SetContent(ctx context.Context, uri span.URI, content []byte) error {
+func (v *view) SetContent(ctx context.Context, uri span.URI, content []byte) error {
v.mu.Lock()
defer v.mu.Unlock()
@@ -175,7 +195,7 @@
// applyContentChanges applies all of the changed content stored in the view.
// It is assumed that the caller has locked both the view's and the mcache's
// mutexes.
-func (v *View) applyContentChanges(ctx context.Context) error {
+func (v *view) applyContentChanges(ctx context.Context) error {
if ctx.Err() != nil {
return ctx.Err()
}
@@ -193,7 +213,7 @@
// setContent applies a content update for a given file. It assumes that the
// caller is holding the view's mutex.
-func (v *View) applyContentChange(uri span.URI, content []byte) {
+func (v *view) applyContentChange(uri span.URI, content []byte) {
f, err := v.getFile(uri)
if err != nil {
return
@@ -213,19 +233,19 @@
case f.active && content == nil:
// The file was active, so we need to forget its content.
f.active = false
- delete(f.view.Config.Overlay, f.filename)
+ delete(f.view.config.Overlay, f.filename)
f.content = nil
case content != nil:
// This is an active overlay, so we update the map.
f.active = true
- f.view.Config.Overlay[f.filename] = f.content
+ f.view.config.Overlay[f.filename] = f.content
}
}
// remove invalidates a package and its reverse dependencies in the view's
// package cache. It is assumed that the caller has locked both the mutexes
// of both the mcache and the pcache.
-func (v *View) remove(pkgPath string, seen map[string]struct{}) {
+func (v *view) remove(pkgPath string, seen map[string]struct{}) {
if _, ok := seen[pkgPath]; ok {
return
}
@@ -248,7 +268,7 @@
}
// FindFile returns the file if the given URI is already a part of the view.
-func (v *View) FindFile(ctx context.Context, uri span.URI) *File {
+func (v *view) FindFile(ctx context.Context, uri span.URI) *file {
v.mu.Lock()
defer v.mu.Unlock()
f, err := v.findFile(uri)
@@ -260,7 +280,7 @@
// GetFile returns a File for the given URI. It will always succeed because it
// adds the file to the managed set if needed.
-func (v *View) GetFile(ctx context.Context, uri span.URI) (source.File, error) {
+func (v *view) GetFile(ctx context.Context, uri span.URI) (source.File, error) {
v.mu.Lock()
defer v.mu.Unlock()
@@ -272,7 +292,7 @@
}
// getFile is the unlocked internal implementation of GetFile.
-func (v *View) getFile(uri span.URI) (*File, error) {
+func (v *view) getFile(uri span.URI) (*file, error) {
filename, err := uri.Filename()
if err != nil {
return nil, err
@@ -285,7 +305,7 @@
} else if f != nil {
return f, nil
}
- f := &File{
+ f := &file{
view: v,
filename: filename,
}
@@ -295,7 +315,7 @@
// isIgnored checks if the given filename is a file we ignore.
// As of right now, we only ignore files in the "builtin" package.
-func (v *View) isIgnored(filename string) bool {
+func (v *view) isIgnored(filename string) bool {
bpkg := v.BuiltinPackage()
if bpkg != nil {
for builtinFilename := range bpkg.Files {
@@ -311,7 +331,7 @@
//
// An error is only returned for an irreparable failure, for example, if the
// filename in question does not exist.
-func (v *View) findFile(uri span.URI) (*File, error) {
+func (v *view) findFile(uri span.URI) (*file, error) {
if f := v.filesByURI[uri]; f != nil {
// a perfect match
return f, nil
@@ -344,7 +364,7 @@
return nil, nil
}
-func (v *View) mapFile(uri span.URI, f *File) {
+func (v *view) mapFile(uri span.URI, f *file) {
v.filesByURI[uri] = f
f.uris = append(f.uris, uri)
if f.basename == "" {
@@ -353,6 +373,6 @@
}
}
-func (v *View) Logger() xlog.Logger {
+func (v *view) Logger() xlog.Logger {
return v.log
}
diff --git a/internal/lsp/diagnostics.go b/internal/lsp/diagnostics.go
index 2af02da..0312d4e 100644
--- a/internal/lsp/diagnostics.go
+++ b/internal/lsp/diagnostics.go
@@ -7,13 +7,12 @@
import (
"context"
- "golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
)
-func (s *Server) Diagnostics(ctx context.Context, view *cache.View, uri span.URI) {
+func (s *Server) Diagnostics(ctx context.Context, view source.View, uri span.URI) {
if ctx.Err() != nil {
s.log.Errorf(ctx, "canceling diagnostics for %s: %v", uri, ctx.Err())
return
@@ -48,7 +47,7 @@
}
}
-func (s *Server) publishDiagnostics(ctx context.Context, view *cache.View, uri span.URI, diagnostics []source.Diagnostic) error {
+func (s *Server) publishDiagnostics(ctx context.Context, view source.View, uri span.URI, diagnostics []source.Diagnostic) error {
protocolDiagnostics, err := toProtocolDiagnostics(ctx, view, diagnostics)
if err != nil {
return err
diff --git a/internal/lsp/general.go b/internal/lsp/general.go
index 09f0a4e..dbc3703 100644
--- a/internal/lsp/general.go
+++ b/internal/lsp/general.go
@@ -13,8 +13,8 @@
"strings"
"golang.org/x/tools/internal/jsonrpc2"
- "golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
+ "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
)
@@ -128,7 +128,7 @@
for _, view := range s.views {
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
Items: []protocol.ConfigurationItem{{
- ScopeURI: protocol.NewURI(view.Folder),
+ ScopeURI: protocol.NewURI(view.Folder()),
Section: "gopls",
}},
})
@@ -146,7 +146,7 @@
return nil
}
-func (s *Server) processConfig(view *cache.View, config interface{}) error {
+func (s *Server) processConfig(view source.View, config interface{}) error {
// TODO: We should probably store and process more of the config.
if config == nil {
return nil // ignore error if you don't have a config
@@ -162,7 +162,7 @@
return fmt.Errorf("invalid config gopls.env type %T", env)
}
for k, v := range menv {
- view.Config.Env = applyEnv(view.Config.Env, k, v)
+ view.SetEnv(applyEnv(view.Config().Env, k, v))
}
}
// Check if placeholders are enabled.
diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go
index 7c4943b..dd3c9c1 100644
--- a/internal/lsp/lsp_test.go
+++ b/internal/lsp/lsp_test.go
@@ -42,8 +42,8 @@
log := xlog.New(xlog.StdSink{})
r := &runner{
server: &Server{
- views: []*cache.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
- viewMap: make(map[span.URI]*cache.View),
+ views: []source.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(data.Config.Dir), &data.Config)},
+ viewMap: make(map[span.URI]source.View),
undelivered: make(map[span.URI][]source.Diagnostic),
log: log,
},
diff --git a/internal/lsp/server.go b/internal/lsp/server.go
index 047be4e..3ccd7f5 100644
--- a/internal/lsp/server.go
+++ b/internal/lsp/server.go
@@ -11,7 +11,6 @@
"sync"
"golang.org/x/tools/internal/jsonrpc2"
- "golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/lsp/xlog"
@@ -83,8 +82,8 @@
textDocumentSyncKind protocol.TextDocumentSyncKind
viewMu sync.Mutex
- views []*cache.View
- viewMap map[span.URI]*cache.View
+ views []source.View
+ viewMap map[span.URI]source.View
// undelivered is a cache of any diagnostics that the server
// failed to deliver for some reason.
diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go
index 7087430..577d325 100644
--- a/internal/lsp/source/source_test.go
+++ b/internal/lsp/source/source_test.go
@@ -27,7 +27,7 @@
}
type runner struct {
- view *cache.View
+ view source.View
data *tests.Data
}
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index 13e8d74..44796a7 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -22,11 +22,16 @@
// package. The view provides access to files and their contents, so the source
// package does not directly access the file system.
type View interface {
+ Name() string
+ Folder() span.URI
Logger() xlog.Logger
FileSet() *token.FileSet
BuiltinPackage() *ast.Package
GetFile(ctx context.Context, uri span.URI) (File, error)
SetContent(ctx context.Context, uri span.URI, content []byte) error
+ BackgroundContext() context.Context
+ Config() packages.Config
+ SetEnv([]string)
}
// File represents a Go source file that has been type-checked. It is the input
diff --git a/internal/lsp/workspace.go b/internal/lsp/workspace.go
index 1b90473..44674b3 100644
--- a/internal/lsp/workspace.go
+++ b/internal/lsp/workspace.go
@@ -16,6 +16,7 @@
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/cache"
"golang.org/x/tools/internal/lsp/protocol"
+ "golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/span"
)
@@ -59,7 +60,7 @@
Tests: true,
}))
// we always need to drop the view map
- s.viewMap = make(map[span.URI]*cache.View)
+ s.viewMap = make(map[span.URI]source.View)
return nil
}
@@ -67,10 +68,10 @@
s.viewMu.Lock()
defer s.viewMu.Unlock()
// we always need to drop the view map
- s.viewMap = make(map[span.URI]*cache.View)
+ s.viewMap = make(map[span.URI]source.View)
s.log.Infof(ctx, "drop view %v as %v", name, uri)
for i, view := range s.views {
- if view.Name == name {
+ if view.Name() == name {
// delete this view... we don't care about order but we do want to make
// sure we can garbage collect the view
s.views[i] = s.views[len(s.views)-1]
@@ -85,7 +86,7 @@
// findView returns the view corresponding to the given URI.
// If the file is not already associated with a view, pick one using some heuristics.
-func (s *Server) findView(ctx context.Context, uri span.URI) *cache.View {
+func (s *Server) findView(ctx context.Context, uri span.URI) source.View {
s.viewMu.Lock()
defer s.viewMu.Unlock()
@@ -102,14 +103,14 @@
// bestView finds the best view to associate a given URI with.
// viewMu must be held when calling this method.
-func (s *Server) bestView(ctx context.Context, uri span.URI) *cache.View {
+func (s *Server) bestView(ctx context.Context, uri span.URI) source.View {
// we need to find the best view for this file
- var longest *cache.View
+ var longest source.View
for _, view := range s.views {
- if longest != nil && len(longest.Folder) > len(view.Folder) {
+ if longest != nil && len(longest.Folder()) > len(view.Folder()) {
continue
}
- if strings.HasPrefix(string(uri), string(view.Folder)) {
+ if strings.HasPrefix(string(uri), string(view.Folder())) {
longest = view
}
}