1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package fake 6 7import ( 8 "context" 9 "fmt" 10 11 "golang.org/x/tools/internal/lsp/protocol" 12) 13 14// ClientHooks are called to handle the corresponding client LSP method. 15type ClientHooks struct { 16 OnLogMessage func(context.Context, *protocol.LogMessageParams) error 17 OnDiagnostics func(context.Context, *protocol.PublishDiagnosticsParams) error 18 OnWorkDoneProgressCreate func(context.Context, *protocol.WorkDoneProgressCreateParams) error 19 OnProgress func(context.Context, *protocol.ProgressParams) error 20 OnShowMessage func(context.Context, *protocol.ShowMessageParams) error 21 OnShowMessageRequest func(context.Context, *protocol.ShowMessageRequestParams) error 22 OnRegistration func(context.Context, *protocol.RegistrationParams) error 23 OnUnregistration func(context.Context, *protocol.UnregistrationParams) error 24} 25 26// Client is an adapter that converts an *Editor into an LSP Client. It mosly 27// delegates functionality to hooks that can be configured by tests. 28type Client struct { 29 editor *Editor 30 hooks ClientHooks 31} 32 33func (c *Client) ShowMessage(ctx context.Context, params *protocol.ShowMessageParams) error { 34 if c.hooks.OnShowMessage != nil { 35 return c.hooks.OnShowMessage(ctx, params) 36 } 37 return nil 38} 39 40func (c *Client) ShowMessageRequest(ctx context.Context, params *protocol.ShowMessageRequestParams) (*protocol.MessageActionItem, error) { 41 if c.hooks.OnShowMessageRequest != nil { 42 if err := c.hooks.OnShowMessageRequest(ctx, params); err != nil { 43 return nil, err 44 } 45 } 46 if len(params.Actions) == 0 || len(params.Actions) > 1 { 47 return nil, fmt.Errorf("fake editor cannot handle multiple action items") 48 } 49 return ¶ms.Actions[0], nil 50} 51 52func (c *Client) LogMessage(ctx context.Context, params *protocol.LogMessageParams) error { 53 if c.hooks.OnLogMessage != nil { 54 return c.hooks.OnLogMessage(ctx, params) 55 } 56 return nil 57} 58 59func (c *Client) Event(ctx context.Context, event *interface{}) error { 60 return nil 61} 62 63func (c *Client) PublishDiagnostics(ctx context.Context, params *protocol.PublishDiagnosticsParams) error { 64 if c.hooks.OnDiagnostics != nil { 65 return c.hooks.OnDiagnostics(ctx, params) 66 } 67 return nil 68} 69 70func (c *Client) WorkspaceFolders(context.Context) ([]protocol.WorkspaceFolder, error) { 71 return []protocol.WorkspaceFolder{}, nil 72} 73 74func (c *Client) Configuration(_ context.Context, p *protocol.ParamConfiguration) ([]interface{}, error) { 75 results := make([]interface{}, len(p.Items)) 76 for i, item := range p.Items { 77 if item.Section != "gopls" { 78 continue 79 } 80 results[i] = c.editor.configuration() 81 } 82 return results, nil 83} 84 85func (c *Client) RegisterCapability(ctx context.Context, params *protocol.RegistrationParams) error { 86 if c.hooks.OnRegistration != nil { 87 return c.hooks.OnRegistration(ctx, params) 88 } 89 return nil 90} 91 92func (c *Client) UnregisterCapability(ctx context.Context, params *protocol.UnregistrationParams) error { 93 if c.hooks.OnUnregistration != nil { 94 return c.hooks.OnUnregistration(ctx, params) 95 } 96 return nil 97} 98 99func (c *Client) Progress(ctx context.Context, params *protocol.ProgressParams) error { 100 if c.hooks.OnProgress != nil { 101 return c.hooks.OnProgress(ctx, params) 102 } 103 return nil 104} 105 106func (c *Client) WorkDoneProgressCreate(ctx context.Context, params *protocol.WorkDoneProgressCreateParams) error { 107 if c.hooks.OnWorkDoneProgressCreate != nil { 108 return c.hooks.OnWorkDoneProgressCreate(ctx, params) 109 } 110 return nil 111} 112 113// ApplyEdit applies edits sent from the server. Note that as of writing gopls 114// doesn't use this feature, so it is untested. 115func (c *Client) ApplyEdit(ctx context.Context, params *protocol.ApplyWorkspaceEditParams) (*protocol.ApplyWorkspaceEditResponse, error) { 116 if len(params.Edit.Changes) != 0 { 117 return &protocol.ApplyWorkspaceEditResponse{FailureReason: "Edit.Changes is unsupported"}, nil 118 } 119 for _, change := range params.Edit.DocumentChanges { 120 path := c.editor.sandbox.Workdir.URIToPath(change.TextDocument.URI) 121 edits := convertEdits(change.Edits) 122 if err := c.editor.EditBuffer(ctx, path, edits); err != nil { 123 return nil, err 124 } 125 } 126 return &protocol.ApplyWorkspaceEditResponse{Applied: true}, nil 127} 128