mirror of https://github.com/golang/go.git
x/tools/gopls: add support for $/progress functionality
This CL adds support for sending progress notifications through $/progress calls as well as being able to cancel them through window/workDoneProgress/cancel. This feature is only supported in clients running LSP 3.15 and therefore the initialize request will check for client capabilities for its progress support. Updates golang/go#37680 Change-Id: Iff8c016694746a9dd553e5cc49444df7afcc21f5 Reviewed-on: https://go-review.googlesource.com/c/tools/+/222981 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
bd88ce9755
commit
3e76bee198
|
|
@ -387,6 +387,14 @@ func (c *cmdClient) PublishDiagnostics(ctx context.Context, p *protocol.PublishD
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *cmdClient) Progress(context.Context, *protocol.ProgressParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cmdClient) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *cmdClient) getFile(ctx context.Context, uri span.URI) *cmdFile {
|
||||
file, found := c.files[uri]
|
||||
if !found || file.err != nil {
|
||||
|
|
|
|||
|
|
@ -90,6 +90,14 @@ func (c *Client) UnregisterCapability(context.Context, *protocol.UnregistrationP
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Progress(context.Context, *protocol.ProgressParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyEdit applies edits sent from the server. Note that as of writing gopls
|
||||
// doesn't use this feature, so it is untested.
|
||||
func (c *Client) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResponse, error) {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ func (s *Server) initialize(ctx context.Context, params *protocol.ParamInitializ
|
|||
s.state = serverInitializing
|
||||
s.stateMu.Unlock()
|
||||
|
||||
s.supportsWorkDoneProgress = params.Capabilities.Window.WorkDoneProgress
|
||||
s.inProgress = map[string]func(){}
|
||||
|
||||
options := s.session.Options()
|
||||
defer func() { s.session.SetOptions(options) }()
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ type Client interface {
|
|||
LogMessage(context.Context, *LogMessageParams) error
|
||||
Event(context.Context, *interface{}) error
|
||||
PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error
|
||||
Progress(context.Context, *ProgressParams) error
|
||||
WorkspaceFolders(context.Context) ([]WorkspaceFolder /*WorkspaceFolder[] | null*/, error)
|
||||
Configuration(context.Context, *ParamConfiguration) ([]interface{}, error)
|
||||
WorkDoneProgressCreate(context.Context, *WorkDoneProgressCreateParams) error
|
||||
RegisterCapability(context.Context, *RegistrationParams) error
|
||||
UnregisterCapability(context.Context, *UnregistrationParams) error
|
||||
ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem /*MessageActionItem | null*/, error)
|
||||
|
|
@ -79,6 +81,16 @@ func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
|||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "$/progress": // notif
|
||||
var params ProgressParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.client.Progress(ctx, ¶ms); err != nil {
|
||||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "workspace/workspaceFolders": // req
|
||||
if r.Params != nil {
|
||||
r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params"))
|
||||
|
|
@ -100,6 +112,17 @@ func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
|||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "window/workDoneProgress/create": // req
|
||||
var params WorkDoneProgressCreateParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
err := h.client.WorkDoneProgressCreate(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "client/registerCapability": // req
|
||||
var params RegistrationParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
|
|
@ -169,6 +192,10 @@ func (s *clientDispatcher) Event(ctx context.Context, params *interface{}) error
|
|||
func (s *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error {
|
||||
return s.Conn.Notify(ctx, "textDocument/publishDiagnostics", params)
|
||||
}
|
||||
|
||||
func (s *clientDispatcher) Progress(ctx context.Context, params *ProgressParams) error {
|
||||
return s.Conn.Notify(ctx, "$/progress", params)
|
||||
}
|
||||
func (s *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder /*WorkspaceFolder[] | null*/, error) {
|
||||
var result []WorkspaceFolder /*WorkspaceFolder[] | null*/
|
||||
if err := s.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil {
|
||||
|
|
@ -185,6 +212,10 @@ func (s *clientDispatcher) Configuration(ctx context.Context, params *ParamConfi
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *clientDispatcher) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) error {
|
||||
return s.Conn.Call(ctx, "window/workDoneProgress/create", params, nil) // Call, not Notify
|
||||
}
|
||||
|
||||
func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error {
|
||||
return s.Conn.Call(ctx, "client/registerCapability", params, nil) // Call, not Notify
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4060,3 +4060,27 @@ type WorkspaceFoldersGn struct {
|
|||
*/
|
||||
ChangeNotifications string/*string | boolean*/ `json:"changeNotifications,omitempty"`
|
||||
}
|
||||
|
||||
// The following types are defined by
|
||||
// the protocol but are not yet auto generated
|
||||
// TODO: generate progress types from here: https://github.com/microsoft/vscode-languageserver-node/blob/master/protocol/src/protocol.progress.ts
|
||||
|
||||
type WorkDoneProgressBegin struct {
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Cancellable bool `json:"cancellable,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Percentage int `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressReport struct {
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Cancellable bool `json:"cancellable,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Percentage int `json:"percentage,omitempty"`
|
||||
}
|
||||
|
||||
type WorkDoneProgressEnd struct {
|
||||
Kind string `json:"kind,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ type Server interface {
|
|||
DidSave(context.Context, *DidSaveTextDocumentParams) error
|
||||
WillSave(context.Context, *WillSaveTextDocumentParams) error
|
||||
DidChangeWatchedFiles(context.Context, *DidChangeWatchedFilesParams) error
|
||||
Progress(context.Context, *ProgressParams) error
|
||||
SetTraceNotification(context.Context, *SetTraceParams) error
|
||||
LogTraceNotification(context.Context, *LogTraceParams) error
|
||||
Implementation(context.Context, *ImplementationParams) (Definition /*Definition | DefinitionLink[] | null*/, error)
|
||||
|
|
@ -38,7 +37,6 @@ type Server interface {
|
|||
FoldingRange(context.Context, *FoldingRangeParams) ([]FoldingRange /*FoldingRange[] | null*/, error)
|
||||
Declaration(context.Context, *DeclarationParams) (Declaration /*Declaration | DeclarationLink[] | null*/, error)
|
||||
SelectionRange(context.Context, *SelectionRangeParams) ([]SelectionRange /*SelectionRange[] | null*/, error)
|
||||
WorkDoneProgressCreate(context.Context, *WorkDoneProgressCreateParams) error
|
||||
Initialize(context.Context, *ParamInitialize) (*InitializeResult, error)
|
||||
Shutdown(context.Context) error
|
||||
WillSaveWaitUntil(context.Context, *WillSaveTextDocumentParams) ([]TextEdit /*TextEdit[] | null*/, error)
|
||||
|
|
@ -186,16 +184,6 @@ func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
|||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "$/progress": // notif
|
||||
var params ProgressParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
if err := h.server.Progress(ctx, ¶ms); err != nil {
|
||||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "$/setTraceNotification": // notif
|
||||
var params SetTraceParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
|
|
@ -293,17 +281,6 @@ func (h serverHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, deliver
|
|||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "window/workDoneProgress/create": // req
|
||||
var params WorkDoneProgressCreateParams
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
sendParseError(ctx, r, err)
|
||||
return true
|
||||
}
|
||||
err := h.server.WorkDoneProgressCreate(ctx, ¶ms)
|
||||
if err := r.Reply(ctx, nil, err); err != nil {
|
||||
event.Error(ctx, "", err)
|
||||
}
|
||||
return true
|
||||
case "initialize": // req
|
||||
var params ParamInitialize
|
||||
if err := json.Unmarshal(*r.Params, ¶ms); err != nil {
|
||||
|
|
@ -685,10 +662,6 @@ func (s *serverDispatcher) DidChangeWatchedFiles(ctx context.Context, params *Di
|
|||
return s.Conn.Notify(ctx, "workspace/didChangeWatchedFiles", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Progress(ctx context.Context, params *ProgressParams) error {
|
||||
return s.Conn.Notify(ctx, "$/progress", params)
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) SetTraceNotification(ctx context.Context, params *SetTraceParams) error {
|
||||
return s.Conn.Notify(ctx, "$/setTraceNotification", params)
|
||||
}
|
||||
|
|
@ -752,10 +725,6 @@ func (s *serverDispatcher) SelectionRange(ctx context.Context, params *Selection
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) WorkDoneProgressCreate(ctx context.Context, params *WorkDoneProgressCreateParams) error {
|
||||
return s.Conn.Call(ctx, "window/workDoneProgress/create", params, nil) // Call, not Notify
|
||||
}
|
||||
|
||||
func (s *serverDispatcher) Initialize(ctx context.Context, params *ParamInitialize) (*InitializeResult, error) {
|
||||
var result *InitializeResult
|
||||
if err := s.Conn.Call(ctx, "initialize", params, &result); err != nil {
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ function setReceives() {
|
|||
receives.set('workspace/configuration', 'client');
|
||||
receives.set('workspace/applyEdit', 'client');
|
||||
receives.set('textDocument/publishDiagnostics', 'client');
|
||||
receives.set('window/workDoneProgress/create', 'client');
|
||||
receives.set('$/progress', 'client');
|
||||
// a small check
|
||||
receives.forEach((_, k) => {
|
||||
if (!req.get(k) && !not.get(k)) throw new Error(`missing ${k}}`);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/span"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
const concurrentAnalyses = 1
|
||||
|
|
@ -78,6 +79,12 @@ type Server struct {
|
|||
|
||||
// diagnosticsSema limits the concurrency of diagnostics runs, which can be expensive.
|
||||
diagnosticsSema chan struct{}
|
||||
|
||||
// supportsWorkDoneProgress is set in the initializeRequest
|
||||
// to determine if the client can support progress notifications
|
||||
supportsWorkDoneProgress bool
|
||||
inProgressMu sync.Mutex
|
||||
inProgress map[string]func()
|
||||
}
|
||||
|
||||
// sentDiagnostics is used to cache diagnostics that have been sent for a given file.
|
||||
|
|
@ -132,6 +139,21 @@ func (s *Server) nonstandardRequest(ctx context.Context, method string, params i
|
|||
return nil, notImplemented(method)
|
||||
}
|
||||
|
||||
func (s *Server) workDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
|
||||
token, ok := params.Token.(string)
|
||||
if !ok {
|
||||
return errors.Errorf("expected params.Token to be string but got %T", params.Token)
|
||||
}
|
||||
s.inProgressMu.Lock()
|
||||
defer s.inProgressMu.Unlock()
|
||||
cancel, ok := s.inProgress[token]
|
||||
if !ok {
|
||||
return errors.Errorf("token %q not found in progress", token)
|
||||
}
|
||||
cancel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func notImplemented(method string) *jsonrpc2.Error {
|
||||
return jsonrpc2.NewErrorf(jsonrpc2.CodeMethodNotFound, "method %q not yet implemented", method)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,10 +136,6 @@ func (s *Server) PrepareRename(ctx context.Context, params *protocol.PrepareRena
|
|||
return s.prepareRename(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) Progress(context.Context, *protocol.ProgressParams) error {
|
||||
return notImplemented("Progress")
|
||||
}
|
||||
|
||||
func (s *Server) RangeFormatting(context.Context, *protocol.DocumentRangeFormattingParams) ([]protocol.TextEdit, error) {
|
||||
return nil, notImplemented("RangeFormatting")
|
||||
}
|
||||
|
|
@ -208,10 +204,6 @@ func (s *Server) WillSaveWaitUntil(context.Context, *protocol.WillSaveTextDocume
|
|||
return nil, notImplemented("WillSaveWaitUntil")
|
||||
}
|
||||
|
||||
func (s *Server) WorkDoneProgressCancel(context.Context, *protocol.WorkDoneProgressCancelParams) error {
|
||||
return notImplemented("WorkDoneProgressCancel")
|
||||
}
|
||||
|
||||
func (s *Server) WorkDoneProgressCreate(context.Context, *protocol.WorkDoneProgressCreateParams) error {
|
||||
return notImplemented("WorkDoneProgressCreate")
|
||||
func (s *Server) WorkDoneProgressCancel(ctx context.Context, params *protocol.WorkDoneProgressCancelParams) error {
|
||||
return s.workDoneProgressCancel(ctx, params)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue