mirror of
https://github.com/golang/go
synced 2024-11-18 18:54:42 -07:00
internal/lsp: merge session and view options into one
This fixes the issue of config options not being applied. Also, handle config errors and deprecation by showing a message to the user. Change-Id: I850d5303a7a1e301c97324060a87929710ee6700 Reviewed-on: https://go-review.googlesource.com/c/tools/+/194682 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
4f2ddba30a
commit
b13fa046aa
2
internal/lsp/cache/cache.go
vendored
2
internal/lsp/cache/cache.go
vendored
@ -76,7 +76,7 @@ func (c *cache) NewSession(ctx context.Context) source.Session {
|
|||||||
s := &session{
|
s := &session{
|
||||||
cache: c,
|
cache: c,
|
||||||
id: strconv.FormatInt(index, 10),
|
id: strconv.FormatInt(index, 10),
|
||||||
options: source.DefaultSessionOptions,
|
options: source.DefaultOptions,
|
||||||
overlays: make(map[span.URI]*overlay),
|
overlays: make(map[span.URI]*overlay),
|
||||||
filesWatchMap: NewWatchMap(),
|
filesWatchMap: NewWatchMap(),
|
||||||
}
|
}
|
||||||
|
8
internal/lsp/cache/session.go
vendored
8
internal/lsp/cache/session.go
vendored
@ -28,7 +28,7 @@ type session struct {
|
|||||||
cache *cache
|
cache *cache
|
||||||
id string
|
id string
|
||||||
|
|
||||||
options source.SessionOptions
|
options source.Options
|
||||||
|
|
||||||
viewMu sync.Mutex
|
viewMu sync.Mutex
|
||||||
views []*view
|
views []*view
|
||||||
@ -56,11 +56,11 @@ type overlay struct {
|
|||||||
unchanged bool
|
unchanged bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) Options() source.SessionOptions {
|
func (s *session) Options() source.Options {
|
||||||
return s.options
|
return s.options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) SetOptions(options source.SessionOptions) {
|
func (s *session) SetOptions(options source.Options) {
|
||||||
s.options = options
|
s.options = options
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ func (s *session) Cache() source.Cache {
|
|||||||
return s.cache
|
return s.cache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *session) NewView(ctx context.Context, name string, folder span.URI, options source.ViewOptions) source.View {
|
func (s *session) NewView(ctx context.Context, name string, folder span.URI, options source.Options) source.View {
|
||||||
index := atomic.AddInt64(&viewIndex, 1)
|
index := atomic.AddInt64(&viewIndex, 1)
|
||||||
s.viewMu.Lock()
|
s.viewMu.Lock()
|
||||||
defer s.viewMu.Unlock()
|
defer s.viewMu.Unlock()
|
||||||
|
4
internal/lsp/cache/view.go
vendored
4
internal/lsp/cache/view.go
vendored
@ -30,7 +30,7 @@ type view struct {
|
|||||||
session *session
|
session *session
|
||||||
id string
|
id string
|
||||||
|
|
||||||
options source.ViewOptions
|
options source.Options
|
||||||
|
|
||||||
// mu protects all mutable state of the view.
|
// mu protects all mutable state of the view.
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
@ -113,7 +113,7 @@ func (v *view) Folder() span.URI {
|
|||||||
return v.folder
|
return v.folder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *view) Options() source.ViewOptions {
|
func (v *view) Options() source.Options {
|
||||||
return v.options
|
return v.options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,8 +298,7 @@ func (c *cmdClient) Configuration(ctx context.Context, p *protocol.ParamConfig)
|
|||||||
env[l[0]] = l[1]
|
env[l[0]] = l[1]
|
||||||
}
|
}
|
||||||
results[i] = map[string]interface{}{
|
results[i] = map[string]interface{}{
|
||||||
"env": env,
|
"env": env,
|
||||||
"noDocsOnHover": true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
|
@ -51,7 +51,7 @@ func (s *Server) completion(ctx context.Context, params *protocol.CompletionPara
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.Range, options source.SessionOptions) []protocol.CompletionItem {
|
func (s *Server) toProtocolCompletionItems(candidates []source.CompletionItem, rng protocol.Range, options source.Options) []protocol.CompletionItem {
|
||||||
var (
|
var (
|
||||||
items = make([]protocol.CompletionItem, 0, len(candidates))
|
items = make([]protocol.CompletionItem, 0, len(candidates))
|
||||||
numDeepCompletionsSeen int
|
numDeepCompletionsSeen int
|
||||||
|
@ -7,6 +7,7 @@ package lsp
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitia) (
|
|||||||
options := s.session.Options()
|
options := s.session.Options()
|
||||||
defer func() { s.session.SetOptions(options) }()
|
defer func() { s.session.SetOptions(options) }()
|
||||||
|
|
||||||
//TODO: handle the options results
|
// TODO: Handle results here.
|
||||||
source.SetOptions(&options, params.InitializationOptions)
|
source.SetOptions(&options, params.InitializationOptions)
|
||||||
options.ForClientCapabilities(params.Capabilities)
|
options.ForClientCapabilities(params.Capabilities)
|
||||||
|
|
||||||
@ -172,7 +173,7 @@ func (s *Server) initialized(ctx context.Context, params *protocol.InitializedPa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, vo *source.ViewOptions) error {
|
func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI, o *source.Options) error {
|
||||||
if !s.session.Options().ConfigurationSupported {
|
if !s.session.Options().ConfigurationSupported {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -193,8 +194,31 @@ func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, config := range configs {
|
for _, config := range configs {
|
||||||
//TODO: handle the options results
|
results := source.SetOptions(o, config)
|
||||||
source.SetOptions(vo, config)
|
for _, result := range results {
|
||||||
|
if result.Error != nil {
|
||||||
|
s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
|
||||||
|
Type: protocol.Error,
|
||||||
|
Message: result.Error.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
switch result.State {
|
||||||
|
case source.OptionUnexpected:
|
||||||
|
s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
|
||||||
|
Type: protocol.Error,
|
||||||
|
Message: fmt.Sprintf("unexpected config %s", result.Name),
|
||||||
|
})
|
||||||
|
case source.OptionDeprecated:
|
||||||
|
msg := fmt.Sprintf("config %s is deprecated", result.Name)
|
||||||
|
if result.Replacement != "" {
|
||||||
|
msg = fmt.Sprintf("%s, use %s instead", msg, result.Replacement)
|
||||||
|
}
|
||||||
|
s.client.ShowMessage(ctx, &protocol.ShowMessageParams{
|
||||||
|
Type: protocol.Warning,
|
||||||
|
Message: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,8 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
}
|
}
|
||||||
options.HoverKind = source.SynopsisDocumentation
|
options.HoverKind = source.SynopsisDocumentation
|
||||||
session.SetOptions(options)
|
session.SetOptions(options)
|
||||||
vo := options.DefaultViewOptions
|
options.Env = data.Config.Env
|
||||||
vo.Env = data.Config.Env
|
session.NewView(ctx, viewName, span.FileURI(data.Config.Dir), options)
|
||||||
session.NewView(ctx, viewName, span.FileURI(data.Config.Dir), vo)
|
|
||||||
for filename, content := range data.Config.Overlay {
|
for filename, content := range data.Config.Overlay {
|
||||||
session.SetOverlay(span.FileURI(filename), content)
|
session.SetOverlay(span.FileURI(filename), content)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultSessionOptions = SessionOptions{
|
DefaultOptions = Options{
|
||||||
|
Env: os.Environ(),
|
||||||
TextDocumentSyncKind: protocol.Incremental,
|
TextDocumentSyncKind: protocol.Incremental,
|
||||||
HoverKind: SynopsisDocumentation,
|
HoverKind: SynopsisDocumentation,
|
||||||
InsertTextFormat: protocol.PlainTextTextFormat,
|
InsertTextFormat: protocol.PlainTextTextFormat,
|
||||||
@ -32,15 +33,17 @@ var (
|
|||||||
Deep: false,
|
Deep: false,
|
||||||
FuzzyMatching: false,
|
FuzzyMatching: false,
|
||||||
},
|
},
|
||||||
DefaultViewOptions: ViewOptions{
|
|
||||||
Env: os.Environ(),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type SessionOptions struct {
|
type Options struct {
|
||||||
Env []string
|
|
||||||
BuildFlags []string
|
// Env is the current set of environment overrides on this view.
|
||||||
|
Env []string
|
||||||
|
|
||||||
|
// BuildFlags is used to adjust the build flags applied to the view.
|
||||||
|
BuildFlags []string
|
||||||
|
|
||||||
HoverKind HoverKind
|
HoverKind HoverKind
|
||||||
DisabledAnalyses map[string]struct{}
|
DisabledAnalyses map[string]struct{}
|
||||||
|
|
||||||
@ -58,16 +61,6 @@ type SessionOptions struct {
|
|||||||
TextDocumentSyncKind protocol.TextDocumentSyncKind
|
TextDocumentSyncKind protocol.TextDocumentSyncKind
|
||||||
|
|
||||||
Completion CompletionOptions
|
Completion CompletionOptions
|
||||||
|
|
||||||
DefaultViewOptions ViewOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
type ViewOptions struct {
|
|
||||||
// Env is the current set of environment overrides on this view.
|
|
||||||
Env []string
|
|
||||||
|
|
||||||
// BuildFlags is used to adjust the build flags applied to the view.
|
|
||||||
BuildFlags []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompletionOptions struct {
|
type CompletionOptions struct {
|
||||||
@ -81,10 +74,6 @@ type CompletionOptions struct {
|
|||||||
|
|
||||||
type HoverKind int
|
type HoverKind int
|
||||||
|
|
||||||
type Options interface {
|
|
||||||
set(name string, value interface{}) OptionResult
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SingleLine = HoverKind(iota)
|
SingleLine = HoverKind(iota)
|
||||||
NoDocumentation
|
NoDocumentation
|
||||||
@ -104,8 +93,10 @@ type OptionResults []OptionResult
|
|||||||
type OptionResult struct {
|
type OptionResult struct {
|
||||||
Name string
|
Name string
|
||||||
Value interface{}
|
Value interface{}
|
||||||
State OptionState
|
|
||||||
Error error
|
Error error
|
||||||
|
|
||||||
|
State OptionState
|
||||||
|
Replacement string
|
||||||
}
|
}
|
||||||
|
|
||||||
type OptionState int
|
type OptionState int
|
||||||
@ -116,7 +107,7 @@ const (
|
|||||||
OptionUnexpected
|
OptionUnexpected
|
||||||
)
|
)
|
||||||
|
|
||||||
func SetOptions(options Options, opts interface{}) OptionResults {
|
func SetOptions(options *Options, opts interface{}) OptionResults {
|
||||||
var results OptionResults
|
var results OptionResults
|
||||||
switch opts := opts.(type) {
|
switch opts := opts.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
@ -133,7 +124,7 @@ func SetOptions(options Options, opts interface{}) OptionResults {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *SessionOptions) ForClientCapabilities(caps protocol.ClientCapabilities) {
|
func (o *Options) ForClientCapabilities(caps protocol.ClientCapabilities) {
|
||||||
// Check if the client supports snippets in completion items.
|
// Check if the client supports snippets in completion items.
|
||||||
if caps.TextDocument.Completion.CompletionItem != nil &&
|
if caps.TextDocument.Completion.CompletionItem != nil &&
|
||||||
caps.TextDocument.Completion.CompletionItem.SnippetSupport {
|
caps.TextDocument.Completion.CompletionItem.SnippetSupport {
|
||||||
@ -152,24 +143,46 @@ func (o *SessionOptions) ForClientCapabilities(caps protocol.ClientCapabilities)
|
|||||||
o.LineFoldingOnly = caps.TextDocument.FoldingRange.LineFoldingOnly
|
o.LineFoldingOnly = caps.TextDocument.FoldingRange.LineFoldingOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *SessionOptions) set(name string, value interface{}) OptionResult {
|
func (o *Options) set(name string, value interface{}) OptionResult {
|
||||||
result := OptionResult{Name: name, Value: value}
|
result := OptionResult{Name: name, Value: value}
|
||||||
switch name {
|
switch name {
|
||||||
|
case "env":
|
||||||
|
menv, ok := value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
result.errorf("invalid config gopls.env type %T", value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for k, v := range menv {
|
||||||
|
o.Env = append(o.Env, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
case "buildFlags":
|
||||||
|
iflags, ok := value.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
result.errorf("invalid config gopls.buildFlags type %T", value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
flags := make([]string, 0, len(iflags))
|
||||||
|
for _, flag := range iflags {
|
||||||
|
flags = append(flags, fmt.Sprintf("%s", flag))
|
||||||
|
}
|
||||||
|
o.BuildFlags = flags
|
||||||
|
|
||||||
case "noIncrementalSync":
|
case "noIncrementalSync":
|
||||||
if v, ok := result.asBool(); ok && v {
|
if v, ok := result.asBool(); ok && v {
|
||||||
o.TextDocumentSyncKind = protocol.Full
|
o.TextDocumentSyncKind = protocol.Full
|
||||||
}
|
}
|
||||||
case "watchFileChanges":
|
case "watchFileChanges":
|
||||||
result.setBool(&o.WatchFileChanges)
|
result.setBool(&o.WatchFileChanges)
|
||||||
case "wantCompletionDocumentation":
|
case "completionDocumentation":
|
||||||
result.setBool(&o.Completion.Documentation)
|
result.setBool(&o.Completion.Documentation)
|
||||||
case "usePlaceholders":
|
case "usePlaceholders":
|
||||||
result.setBool(&o.Completion.Placeholders)
|
result.setBool(&o.Completion.Placeholders)
|
||||||
case "disableDeepCompletion":
|
case "deepCompletion":
|
||||||
result.setNotBool(&o.Completion.Deep)
|
result.setBool(&o.Completion.Deep)
|
||||||
case "disableFuzzyMatching":
|
case "fuzzyMatching":
|
||||||
result.setNotBool(&o.Completion.FuzzyMatching)
|
result.setBool(&o.Completion.FuzzyMatching)
|
||||||
case "wantUnimportedCompletions":
|
case "completeUnimported":
|
||||||
result.setBool(&o.Completion.Unimported)
|
result.setBool(&o.Completion.Unimported)
|
||||||
|
|
||||||
case "hoverKind":
|
case "hoverKind":
|
||||||
@ -204,39 +217,25 @@ func (o *SessionOptions) set(name string, value interface{}) OptionResult {
|
|||||||
o.DisabledAnalyses[fmt.Sprint(a)] = struct{}{}
|
o.DisabledAnalyses[fmt.Sprint(a)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated settings.
|
||||||
case "wantSuggestedFixes":
|
case "wantSuggestedFixes":
|
||||||
result.State = OptionDeprecated
|
result.State = OptionDeprecated
|
||||||
|
|
||||||
default:
|
case "disableDeepCompletion":
|
||||||
return o.DefaultViewOptions.set(name, value)
|
result.State = OptionDeprecated
|
||||||
}
|
result.Replacement = "deepCompletion"
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ViewOptions) set(name string, value interface{}) OptionResult {
|
case "disableFuzzyMatching":
|
||||||
result := OptionResult{Name: name, Value: value}
|
result.State = OptionDeprecated
|
||||||
switch name {
|
result.Replacement = "fuzzyMatching"
|
||||||
case "env":
|
|
||||||
menv, ok := value.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
result.errorf("invalid config gopls.env type %T", value)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
for k, v := range menv {
|
|
||||||
o.Env = append(o.Env, fmt.Sprintf("%s=%s", k, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
case "buildFlags":
|
case "wantCompletionDocumentation":
|
||||||
iflags, ok := value.([]interface{})
|
result.State = OptionDeprecated
|
||||||
if !ok {
|
result.Replacement = "completionDocumentation"
|
||||||
result.errorf("invalid config gopls.buildFlags type %T", value)
|
|
||||||
break
|
case "wantUnimportedCompletions":
|
||||||
}
|
result.State = OptionDeprecated
|
||||||
flags := make([]string, 0, len(iflags))
|
result.Replacement = "completeUnimported"
|
||||||
for _, flag := range iflags {
|
|
||||||
flags = append(flags, fmt.Sprintf("%s", flag))
|
|
||||||
}
|
|
||||||
o.BuildFlags = flags
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result.State = OptionUnexpected
|
result.State = OptionUnexpected
|
||||||
@ -262,9 +261,3 @@ func (r *OptionResult) setBool(b *bool) {
|
|||||||
*b = v
|
*b = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OptionResult) setNotBool(b *bool) {
|
|
||||||
if v, ok := r.asBool(); ok {
|
|
||||||
*b = !v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -49,10 +49,9 @@ func testSource(t *testing.T, exporter packagestest.Exporter) {
|
|||||||
cache := cache.New()
|
cache := cache.New()
|
||||||
session := cache.NewSession(ctx)
|
session := cache.NewSession(ctx)
|
||||||
options := session.Options()
|
options := session.Options()
|
||||||
vo := options.DefaultViewOptions
|
options.Env = data.Config.Env
|
||||||
vo.Env = data.Config.Env
|
|
||||||
r := &runner{
|
r := &runner{
|
||||||
view: session.NewView(ctx, "source_test", span.FileURI(data.Config.Dir), vo),
|
view: session.NewView(ctx, "source_test", span.FileURI(data.Config.Dir), options),
|
||||||
data: data,
|
data: data,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ type Cache interface {
|
|||||||
// A session may have many active views at any given time.
|
// A session may have many active views at any given time.
|
||||||
type Session interface {
|
type Session interface {
|
||||||
// NewView creates a new View and returns it.
|
// NewView creates a new View and returns it.
|
||||||
NewView(ctx context.Context, name string, folder span.URI, options ViewOptions) View
|
NewView(ctx context.Context, name string, folder span.URI, options Options) View
|
||||||
|
|
||||||
// Cache returns the cache that created this session.
|
// Cache returns the cache that created this session.
|
||||||
Cache() Cache
|
Cache() Cache
|
||||||
@ -196,10 +196,10 @@ type Session interface {
|
|||||||
DidChangeOutOfBand(ctx context.Context, f GoFile, change protocol.FileChangeType)
|
DidChangeOutOfBand(ctx context.Context, f GoFile, change protocol.FileChangeType)
|
||||||
|
|
||||||
// Options returns a copy of the SessionOptions for this session.
|
// Options returns a copy of the SessionOptions for this session.
|
||||||
Options() SessionOptions
|
Options() Options
|
||||||
|
|
||||||
// SetOptions sets the options of this session to new values.
|
// SetOptions sets the options of this session to new values.
|
||||||
SetOptions(SessionOptions)
|
SetOptions(Options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// View represents a single workspace.
|
// View represents a single workspace.
|
||||||
@ -246,7 +246,7 @@ type View interface {
|
|||||||
RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error, opts *imports.Options) error
|
RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error, opts *imports.Options) error
|
||||||
|
|
||||||
// Options returns a copy of the ViewOptions for this view.
|
// Options returns a copy of the ViewOptions for this view.
|
||||||
Options() ViewOptions
|
Options() Options
|
||||||
}
|
}
|
||||||
|
|
||||||
// File represents a source file of any type.
|
// File represents a source file of any type.
|
||||||
|
@ -38,8 +38,8 @@ func (s *Server) addView(ctx context.Context, name string, uri span.URI) error {
|
|||||||
return errors.Errorf("addView called before server initialized")
|
return errors.Errorf("addView called before server initialized")
|
||||||
}
|
}
|
||||||
|
|
||||||
viewOptions := s.session.Options().DefaultViewOptions
|
options := s.session.Options()
|
||||||
s.fetchConfig(ctx, name, uri, &viewOptions)
|
s.fetchConfig(ctx, name, uri, &options)
|
||||||
s.session.NewView(ctx, name, uri, viewOptions)
|
s.session.NewView(ctx, name, uri, options)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user