internal/lsp: support multiple views
This uses the workspace folders to build multiple views, and then tries to pick the right view to send each incomming request to. Change-Id: I0cc896dbbc67eb0a88225ddeca6c518f4258bbba Reviewed-on: https://go-review.googlesource.com/c/tools/+/170179 Run-TryBot: Ian Cottrell <iancottrell@google.com> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
bf99c0974b
commit
1bac838f5b
|
@ -209,6 +209,17 @@ func (v *View) remove(pkgPath string) {
|
||||||
delete(v.pcache.packages, pkgPath)
|
delete(v.pcache.packages, pkgPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
v.mu.Lock()
|
||||||
|
defer v.mu.Unlock()
|
||||||
|
f, err := v.findFile(uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
// GetFile returns a File for the given URI. It will always succeed because it
|
// GetFile returns a File for the given URI. It will always succeed because it
|
||||||
// adds the file to the managed set if needed.
|
// 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) {
|
||||||
|
|
|
@ -8,21 +8,23 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/cache"
|
||||||
"golang.org/x/tools/internal/lsp/protocol"
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
"golang.org/x/tools/internal/lsp/source"
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
"golang.org/x/tools/internal/span"
|
"golang.org/x/tools/internal/span"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) cacheAndDiagnose(ctx context.Context, uri span.URI, content string) error {
|
func (s *Server) cacheAndDiagnose(ctx context.Context, uri span.URI, content string) error {
|
||||||
if err := s.view.SetContent(ctx, uri, []byte(content)); err != nil {
|
view := s.findView(ctx, uri)
|
||||||
|
if err := view.SetContent(ctx, uri, []byte(content)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
ctx := s.view.BackgroundContext()
|
ctx := view.BackgroundContext()
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reports, err := source.Diagnostics(ctx, s.view, uri)
|
reports, err := source.Diagnostics(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return // handle error?
|
return // handle error?
|
||||||
}
|
}
|
||||||
|
@ -31,7 +33,7 @@ func (s *Server) cacheAndDiagnose(ctx context.Context, uri span.URI, content str
|
||||||
defer s.undeliveredMu.Unlock()
|
defer s.undeliveredMu.Unlock()
|
||||||
|
|
||||||
for uri, diagnostics := range reports {
|
for uri, diagnostics := range reports {
|
||||||
if err := s.publishDiagnostics(ctx, uri, diagnostics); err != nil {
|
if err := s.publishDiagnostics(ctx, view, uri, diagnostics); err != nil {
|
||||||
if s.undelivered == nil {
|
if s.undelivered == nil {
|
||||||
s.undelivered = make(map[span.URI][]source.Diagnostic)
|
s.undelivered = make(map[span.URI][]source.Diagnostic)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +46,7 @@ func (s *Server) cacheAndDiagnose(ctx context.Context, uri span.URI, content str
|
||||||
// Anytime we compute diagnostics, make sure to also send along any
|
// Anytime we compute diagnostics, make sure to also send along any
|
||||||
// undelivered ones (only for remaining URIs).
|
// undelivered ones (only for remaining URIs).
|
||||||
for uri, diagnostics := range s.undelivered {
|
for uri, diagnostics := range s.undelivered {
|
||||||
s.publishDiagnostics(ctx, uri, diagnostics)
|
s.publishDiagnostics(ctx, view, uri, diagnostics)
|
||||||
|
|
||||||
// If we fail to deliver the same diagnostics twice, just give up.
|
// If we fail to deliver the same diagnostics twice, just give up.
|
||||||
delete(s.undelivered, uri)
|
delete(s.undelivered, uri)
|
||||||
|
@ -53,8 +55,8 @@ func (s *Server) cacheAndDiagnose(ctx context.Context, uri span.URI, content str
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) publishDiagnostics(ctx context.Context, uri span.URI, diagnostics []source.Diagnostic) error {
|
func (s *Server) publishDiagnostics(ctx context.Context, view *cache.View, uri span.URI, diagnostics []source.Diagnostic) error {
|
||||||
protocolDiagnostics, err := toProtocolDiagnostics(ctx, s.view, diagnostics)
|
protocolDiagnostics, err := toProtocolDiagnostics(ctx, view, diagnostics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
|
||||||
log := xlog.New(xlog.StdSink{})
|
log := xlog.New(xlog.StdSink{})
|
||||||
s := &Server{
|
s := &Server{
|
||||||
view: cache.NewView(ctx, log, "lsp_test", span.FileURI(cfg.Dir), &cfg),
|
views: []*cache.View{cache.NewView(ctx, log, "lsp_test", span.FileURI(cfg.Dir), &cfg)},
|
||||||
undelivered: make(map[span.URI][]source.Diagnostic),
|
undelivered: make(map[span.URI][]source.Diagnostic),
|
||||||
}
|
}
|
||||||
// Do a first pass to collect special markers for completion.
|
// Do a first pass to collect special markers for completion.
|
||||||
|
@ -121,7 +121,7 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
||||||
|
|
||||||
t.Run("Diagnostics", func(t *testing.T) {
|
t.Run("Diagnostics", func(t *testing.T) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
diagnosticsCount := expectedDiagnostics.test(t, s.view)
|
diagnosticsCount := expectedDiagnostics.test(t, s.views[0])
|
||||||
if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
|
if goVersion111 { // TODO(rstambler): Remove this when we no longer support Go 1.10.
|
||||||
if diagnosticsCount != expectedDiagnosticsCount {
|
if diagnosticsCount != expectedDiagnosticsCount {
|
||||||
t.Errorf("got %v diagnostics expected %v", diagnosticsCount, expectedDiagnosticsCount)
|
t.Errorf("got %v diagnostics expected %v", diagnosticsCount, expectedDiagnosticsCount)
|
||||||
|
@ -425,7 +425,7 @@ func (f formats) test(t *testing.T, s *Server) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f, m, err := newColumnMap(ctx, s.view, uri)
|
f, m, err := newColumnMap(ctx, s.findView(ctx, uri), uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,7 @@ type Server struct {
|
||||||
|
|
||||||
textDocumentSyncKind protocol.TextDocumentSyncKind
|
textDocumentSyncKind protocol.TextDocumentSyncKind
|
||||||
|
|
||||||
viewMu sync.Mutex
|
views []*cache.View
|
||||||
view *cache.View
|
|
||||||
|
|
||||||
// undelivered is a cache of any diagnostics that the server
|
// undelivered is a cache of any diagnostics that the server
|
||||||
// failed to deliver for some reason.
|
// failed to deliver for some reason.
|
||||||
|
@ -113,15 +112,6 @@ func (s *Server) Initialize(ctx context.Context, params *protocol.InitializePara
|
||||||
}
|
}
|
||||||
s.signatureHelpEnabled = true
|
s.signatureHelpEnabled = true
|
||||||
|
|
||||||
var rootURI span.URI
|
|
||||||
if params.RootURI != "" {
|
|
||||||
rootURI = span.NewURI(params.RootURI)
|
|
||||||
}
|
|
||||||
rootPath, err := rootURI.Filename()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(rstambler): Change this default to protocol.Incremental (or add a
|
// TODO(rstambler): Change this default to protocol.Incremental (or add a
|
||||||
// flag). Disabled for now to simplify debugging.
|
// flag). Disabled for now to simplify debugging.
|
||||||
s.textDocumentSyncKind = protocol.Full
|
s.textDocumentSyncKind = protocol.Full
|
||||||
|
@ -129,19 +119,39 @@ func (s *Server) Initialize(ctx context.Context, params *protocol.InitializePara
|
||||||
//We need a "detached" context so it does not get timeout cancelled.
|
//We need a "detached" context so it does not get timeout cancelled.
|
||||||
//TODO(iancottrell): Do we need to copy any values across?
|
//TODO(iancottrell): Do we need to copy any values across?
|
||||||
viewContext := context.Background()
|
viewContext := context.Background()
|
||||||
//TODO:use workspace folders
|
folders := params.WorkspaceFolders
|
||||||
s.view = cache.NewView(viewContext, s.log, path.Base(string(rootURI)), rootURI, &packages.Config{
|
if len(folders) == 0 {
|
||||||
Context: ctx,
|
if params.RootURI != "" {
|
||||||
Dir: rootPath,
|
folders = []protocol.WorkspaceFolder{{
|
||||||
Env: os.Environ(),
|
URI: params.RootURI,
|
||||||
Mode: packages.LoadImports,
|
Name: path.Base(params.RootURI),
|
||||||
Fset: token.NewFileSet(),
|
}}
|
||||||
Overlay: make(map[string][]byte),
|
} else {
|
||||||
ParseFile: func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
|
// no folders and no root, single file mode
|
||||||
return parser.ParseFile(fset, filename, src, parser.AllErrors|parser.ParseComments)
|
//TODO(iancottrell): not sure how to do single file mode yet
|
||||||
},
|
//issue: golang.org/issue/31168
|
||||||
Tests: true,
|
return nil, fmt.Errorf("single file mode not supported yet")
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
for _, folder := range folders {
|
||||||
|
uri := span.NewURI(folder.URI)
|
||||||
|
folderPath, err := uri.Filename()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s.views = append(s.views, cache.NewView(viewContext, s.log, folder.Name, uri, &packages.Config{
|
||||||
|
Context: ctx,
|
||||||
|
Dir: folderPath,
|
||||||
|
Env: os.Environ(),
|
||||||
|
Mode: packages.LoadImports,
|
||||||
|
Fset: token.NewFileSet(),
|
||||||
|
Overlay: make(map[string][]byte),
|
||||||
|
ParseFile: func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
|
||||||
|
return parser.ParseFile(fset, filename, src, parser.AllErrors|parser.ParseComments)
|
||||||
|
},
|
||||||
|
Tests: true,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
return &protocol.InitializeResult{
|
return &protocol.InitializeResult{
|
||||||
Capabilities: protocol.ServerCapabilities{
|
Capabilities: protocol.ServerCapabilities{
|
||||||
|
@ -178,17 +188,19 @@ func (s *Server) Initialized(ctx context.Context, params *protocol.InitializedPa
|
||||||
Method: "workspace/didChangeConfiguration",
|
Method: "workspace/didChangeConfiguration",
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
|
for _, view := range s.views {
|
||||||
Items: []protocol.ConfigurationItem{{
|
config, err := s.client.Configuration(ctx, &protocol.ConfigurationParams{
|
||||||
ScopeURI: protocol.NewURI(s.view.Folder),
|
Items: []protocol.ConfigurationItem{{
|
||||||
Section: "gopls",
|
ScopeURI: protocol.NewURI(view.Folder),
|
||||||
}},
|
Section: "gopls",
|
||||||
})
|
}},
|
||||||
if err != nil {
|
})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
if err := s.processConfig(config[0]); err != nil {
|
}
|
||||||
return err
|
if err := s.processConfig(view, config[0]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -245,7 +257,9 @@ func (s *Server) applyChanges(ctx context.Context, params *protocol.DidChangeTex
|
||||||
return change.Text, nil
|
return change.Text, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
file, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
file, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "file not found")
|
return "", jsonrpc2.NewErrorf(jsonrpc2.CodeInternalError, "file not found")
|
||||||
}
|
}
|
||||||
|
@ -308,14 +322,15 @@ func (s *Server) DidSave(context.Context, *protocol.DidSaveTextDocumentParams) e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DidClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
|
func (s *Server) DidClose(ctx context.Context, params *protocol.DidCloseTextDocumentParams) error {
|
||||||
if err := s.view.SetContent(ctx, span.NewURI(params.TextDocument.URI), nil); err != nil {
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
return err
|
view := s.findView(ctx, uri)
|
||||||
}
|
return view.SetContent(ctx, uri, nil)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
|
func (s *Server) Completion(ctx context.Context, params *protocol.CompletionParams) (*protocol.CompletionList, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -342,7 +357,9 @@ func (s *Server) CompletionResolve(context.Context, *protocol.CompletionItem) (*
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Hover(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.Hover, error) {
|
func (s *Server) Hover(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.Hover, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -354,7 +371,7 @@ func (s *Server) Hover(ctx context.Context, params *protocol.TextDocumentPositio
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ident, err := source.Identifier(ctx, s.view, f, identRange.Start)
|
ident, err := source.Identifier(ctx, view, f, identRange.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -381,7 +398,9 @@ func (s *Server) Hover(ctx context.Context, params *protocol.TextDocumentPositio
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SignatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
func (s *Server) SignatureHelp(ctx context.Context, params *protocol.TextDocumentPositionParams) (*protocol.SignatureHelp, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -401,7 +420,9 @@ func (s *Server) SignatureHelp(ctx context.Context, params *protocol.TextDocumen
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
func (s *Server) Definition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -413,7 +434,7 @@ func (s *Server) Definition(ctx context.Context, params *protocol.TextDocumentPo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ident, err := source.Identifier(ctx, s.view, f, rng.Start)
|
ident, err := source.Identifier(ctx, view, f, rng.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -421,7 +442,7 @@ func (s *Server) Definition(ctx context.Context, params *protocol.TextDocumentPo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, decM, err := newColumnMap(ctx, s.view, decSpan.URI())
|
_, decM, err := newColumnMap(ctx, view, decSpan.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -433,7 +454,9 @@ func (s *Server) Definition(ctx context.Context, params *protocol.TextDocumentPo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) TypeDefinition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
func (s *Server) TypeDefinition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -445,7 +468,7 @@ func (s *Server) TypeDefinition(ctx context.Context, params *protocol.TextDocume
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ident, err := source.Identifier(ctx, s.view, f, rng.Start)
|
ident, err := source.Identifier(ctx, view, f, rng.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -453,7 +476,7 @@ func (s *Server) TypeDefinition(ctx context.Context, params *protocol.TextDocume
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, identM, err := newColumnMap(ctx, s.view, identSpan.URI())
|
_, identM, err := newColumnMap(ctx, view, identSpan.URI())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -473,7 +496,9 @@ func (s *Server) References(context.Context, *protocol.ReferenceParams) ([]proto
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DocumentHighlight(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
func (s *Server) DocumentHighlight(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.DocumentHighlight, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -493,7 +518,9 @@ func (s *Server) DocumentHighlight(ctx context.Context, params *protocol.TextDoc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
func (s *Server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
||||||
f, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -502,7 +529,9 @@ func (s *Server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) CodeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
func (s *Server) CodeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
||||||
_, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
_, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -510,7 +539,7 @@ func (s *Server) CodeAction(ctx context.Context, params *protocol.CodeActionPara
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
edits, err := organizeImports(ctx, s.view, spn)
|
edits, err := organizeImports(ctx, view, spn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -552,12 +581,16 @@ func (s *Server) ColorPresentation(context.Context, *protocol.ColorPresentationP
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
|
func (s *Server) Formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
|
||||||
spn := span.New(span.URI(params.TextDocument.URI), span.Point{}, span.Point{})
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
return formatRange(ctx, s.view, spn)
|
view := s.findView(ctx, uri)
|
||||||
|
spn := span.New(uri, span.Point{}, span.Point{})
|
||||||
|
return formatRange(ctx, view, spn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RangeFormatting(ctx context.Context, params *protocol.DocumentRangeFormattingParams) ([]protocol.TextEdit, error) {
|
func (s *Server) RangeFormatting(ctx context.Context, params *protocol.DocumentRangeFormattingParams) ([]protocol.TextEdit, error) {
|
||||||
_, m, err := newColumnMap(ctx, s.view, span.NewURI(params.TextDocument.URI))
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
_, m, err := newColumnMap(ctx, view, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -565,7 +598,7 @@ func (s *Server) RangeFormatting(ctx context.Context, params *protocol.DocumentR
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return formatRange(ctx, s.view, spn)
|
return formatRange(ctx, view, spn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeFormattingParams) ([]protocol.TextEdit, error) {
|
func (s *Server) OnTypeFormatting(context.Context, *protocol.DocumentOnTypeFormattingParams) ([]protocol.TextEdit, error) {
|
||||||
|
@ -580,7 +613,7 @@ func (s *Server) FoldingRanges(context.Context, *protocol.FoldingRangeParams) ([
|
||||||
return nil, notImplemented("FoldingRanges")
|
return nil, notImplemented("FoldingRanges")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) processConfig(config interface{}) error {
|
func (s *Server) processConfig(view *cache.View, config interface{}) error {
|
||||||
//TODO: we should probably store and process more of the config
|
//TODO: we should probably store and process more of the config
|
||||||
c, ok := config.(map[string]interface{})
|
c, ok := config.(map[string]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -595,7 +628,7 @@ func (s *Server) processConfig(config interface{}) error {
|
||||||
return fmt.Errorf("Invalid config gopls.env type %T", env)
|
return fmt.Errorf("Invalid config gopls.env type %T", env)
|
||||||
}
|
}
|
||||||
for k, v := range menv {
|
for k, v := range menv {
|
||||||
s.view.Config.Env = applyEnv(s.view.Config.Env, k, v)
|
view.Config.Env = applyEnv(view.Config.Env, k, v)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -615,3 +648,26 @@ func applyEnv(env []string, k string, v interface{}) []string {
|
||||||
func notImplemented(method string) *jsonrpc2.Error {
|
func notImplemented(method string) *jsonrpc2.Error {
|
||||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not yet implemented", method)
|
return jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not yet implemented", method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) findView(ctx context.Context, uri span.URI) *cache.View {
|
||||||
|
// first see if a view already has this file
|
||||||
|
for _, view := range s.views {
|
||||||
|
if view.FindFile(ctx, uri) != nil {
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var longest *cache.View
|
||||||
|
for _, view := range s.views {
|
||||||
|
if longest != nil && len(longest.Folder) > len(view.Folder) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(string(uri), string(view.Folder)) {
|
||||||
|
longest = view
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if longest != nil {
|
||||||
|
return longest
|
||||||
|
}
|
||||||
|
//TODO: are there any more heuristics we can use?
|
||||||
|
return s.views[0]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue