| // Copyright 2018 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 source |
| |
| import ( |
| "fmt" |
| "go/token" |
| "sync" |
| |
| "golang.org/x/tools/go/packages" |
| "golang.org/x/tools/internal/lsp/protocol" |
| ) |
| |
| type View struct { |
| Config *packages.Config |
| |
| activeFilesMu sync.Mutex |
| activeFiles map[protocol.DocumentURI][]byte |
| |
| fset *token.FileSet |
| } |
| |
| func NewView() *View { |
| fset := token.NewFileSet() |
| return &View{ |
| Config: &packages.Config{ |
| Mode: packages.LoadSyntax, |
| Fset: fset, |
| Tests: true, |
| }, |
| activeFiles: make(map[protocol.DocumentURI][]byte), |
| fset: fset, |
| } |
| } |
| |
| func (v *View) overlay() map[string][]byte { |
| over := make(map[string][]byte) |
| |
| v.activeFilesMu.Lock() |
| defer v.activeFilesMu.Unlock() |
| |
| for uri, content := range v.activeFiles { |
| filename, err := FromURI(uri) |
| if err == nil { |
| over[filename] = content |
| } |
| } |
| return over |
| } |
| |
| func (v *View) SetActiveFileContent(uri protocol.DocumentURI, content []byte) { |
| v.activeFilesMu.Lock() |
| v.activeFiles[uri] = content |
| v.activeFilesMu.Unlock() |
| } |
| |
| func (v *View) ReadActiveFile(uri protocol.DocumentURI) ([]byte, error) { |
| v.activeFilesMu.Lock() |
| content, ok := v.activeFiles[uri] |
| v.activeFilesMu.Unlock() |
| if !ok { |
| return nil, fmt.Errorf("uri not found: %s", uri) |
| } |
| return content, nil |
| } |
| |
| func (v *View) ClearActiveFile(uri protocol.DocumentURI) { |
| v.activeFilesMu.Lock() |
| delete(v.activeFiles, uri) |
| v.activeFilesMu.Unlock() |
| } |
| |
| // TypeCheck type-checks the package for the given package path. |
| func (v *View) TypeCheck(uri protocol.DocumentURI) (*packages.Package, error) { |
| v.Config.Overlay = v.overlay() |
| path, err := FromURI(uri) |
| if err != nil { |
| return nil, err |
| } |
| pkgs, err := packages.Load(v.Config, fmt.Sprintf("file=%s", path)) |
| if len(pkgs) == 0 { |
| return nil, err |
| } |
| pkg := pkgs[0] |
| return pkg, nil |
| } |