blob: 19400d68e6fa0c28f652d3dba24dcc3df76109b8 [file] [log] [blame]
package lsp
import (
"fmt"
"go/token"
"strings"
"sync"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/lsp/protocol"
)
type view struct {
activeFilesMu sync.Mutex
activeFiles map[protocol.DocumentURI][]byte
config *packages.Config
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 {
over[uriToFilename(uri)] = content
}
return over
}
func (v *view) readActiveFile(uri protocol.DocumentURI) ([]byte, error) {
v.activeFilesMu.Lock()
defer v.activeFilesMu.Unlock()
content, ok := v.activeFiles[uri]
if !ok {
return nil, fmt.Errorf("file 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()
pkgs, err := packages.Load(v.config, fmt.Sprintf("file=%s", uriToFilename(uri)))
if len(pkgs) == 0 {
if err == nil {
err = fmt.Errorf("no packages found for %s", uri)
}
return nil, err
}
pkg := pkgs[0]
return pkg, nil
}
func uriToFilename(uri protocol.DocumentURI) string {
return strings.TrimPrefix(string(uri), "file://")
}
func filenameToURI(filename string) protocol.DocumentURI {
return protocol.DocumentURI("file://" + filename)
}