1
0
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:
Rebecca Stambler 2019-09-11 13:13:44 -04:00
parent 4f2ddba30a
commit b13fa046aa
11 changed files with 106 additions and 92 deletions

View File

@ -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(),
} }

View File

@ -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()

View File

@ -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
} }

View File

@ -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

View File

@ -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

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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
}
}

View File

@ -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,
} }

View File

@ -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.

View File

@ -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
} }