1// Copyright 2019 The Go Authors. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package protocol 16 17import ( 18 "context" 19 "encoding/json" 20 "log" 21 22 "github.com/KhronosGroup/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2" 23) 24 25type Client interface { 26 ShowMessage(context.Context, *ShowMessageParams) error 27 LogMessage(context.Context, *LogMessageParams) error 28 Event(context.Context, *interface{}) error 29 PublishDiagnostics(context.Context, *PublishDiagnosticsParams) error 30 WorkspaceFolders(context.Context) ([]WorkspaceFolder, error) 31 Configuration(context.Context, *ParamConfig) ([]interface{}, error) 32 RegisterCapability(context.Context, *RegistrationParams) error 33 UnregisterCapability(context.Context, *UnregistrationParams) error 34 ShowMessageRequest(context.Context, *ShowMessageRequestParams) (*MessageActionItem, error) 35 ApplyEdit(context.Context, *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error) 36} 37 38func (h clientHandler) Deliver(ctx context.Context, r *jsonrpc2.Request, delivered bool) bool { 39 if delivered { 40 return false 41 } 42 if ctx.Err() != nil { 43 r.Reply(ctx, nil, jsonrpc2.NewErrorf(RequestCancelledError, "")) 44 return true 45 } 46 switch r.Method { 47 case "window/showMessage": // notif 48 var params ShowMessageParams 49 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 50 sendParseError(ctx, r, err) 51 return true 52 } 53 if err := h.client.ShowMessage(ctx, ¶ms); err != nil { 54 log.Printf("%v", err) 55 } 56 return true 57 case "window/logMessage": // notif 58 var params LogMessageParams 59 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 60 sendParseError(ctx, r, err) 61 return true 62 } 63 if err := h.client.LogMessage(ctx, ¶ms); err != nil { 64 log.Printf("%v", err) 65 } 66 return true 67 case "telemetry/event": // notif 68 var params interface{} 69 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 70 sendParseError(ctx, r, err) 71 return true 72 } 73 if err := h.client.Event(ctx, ¶ms); err != nil { 74 log.Printf("%v", err) 75 } 76 return true 77 case "textDocument/publishDiagnostics": // notif 78 var params PublishDiagnosticsParams 79 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 80 sendParseError(ctx, r, err) 81 return true 82 } 83 if err := h.client.PublishDiagnostics(ctx, ¶ms); err != nil { 84 log.Printf("%v", err) 85 } 86 return true 87 case "workspace/workspaceFolders": // req 88 if r.Params != nil { 89 r.Reply(ctx, nil, jsonrpc2.NewErrorf(jsonrpc2.CodeInvalidParams, "Expected no params")) 90 return true 91 } 92 resp, err := h.client.WorkspaceFolders(ctx) 93 if err := r.Reply(ctx, resp, err); err != nil { 94 log.Printf("%v", err) 95 } 96 return true 97 case "workspace/configuration": // req 98 var params ParamConfig 99 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 100 sendParseError(ctx, r, err) 101 return true 102 } 103 resp, err := h.client.Configuration(ctx, ¶ms) 104 if err := r.Reply(ctx, resp, err); err != nil { 105 log.Printf("%v", err) 106 } 107 return true 108 case "client/registerCapability": // req 109 var params RegistrationParams 110 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 111 sendParseError(ctx, r, err) 112 return true 113 } 114 err := h.client.RegisterCapability(ctx, ¶ms) 115 if err := r.Reply(ctx, nil, err); err != nil { 116 log.Printf("%v", err) 117 } 118 return true 119 case "client/unregisterCapability": // req 120 var params UnregistrationParams 121 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 122 sendParseError(ctx, r, err) 123 return true 124 } 125 err := h.client.UnregisterCapability(ctx, ¶ms) 126 if err := r.Reply(ctx, nil, err); err != nil { 127 log.Printf("%v", err) 128 } 129 return true 130 case "window/showMessageRequest": // req 131 var params ShowMessageRequestParams 132 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 133 sendParseError(ctx, r, err) 134 return true 135 } 136 resp, err := h.client.ShowMessageRequest(ctx, ¶ms) 137 if err := r.Reply(ctx, resp, err); err != nil { 138 log.Printf("%v", err) 139 } 140 return true 141 case "workspace/applyEdit": // req 142 var params ApplyWorkspaceEditParams 143 if err := json.Unmarshal(*r.Params, ¶ms); err != nil { 144 sendParseError(ctx, r, err) 145 return true 146 } 147 resp, err := h.client.ApplyEdit(ctx, ¶ms) 148 if err := r.Reply(ctx, resp, err); err != nil { 149 log.Printf("%v", err) 150 } 151 return true 152 153 default: 154 return false 155 } 156} 157 158type clientDispatcher struct { 159 *jsonrpc2.Conn 160} 161 162func (s *clientDispatcher) ShowMessage(ctx context.Context, params *ShowMessageParams) error { 163 return s.Conn.Notify(ctx, "window/showMessage", params) 164} 165 166func (s *clientDispatcher) LogMessage(ctx context.Context, params *LogMessageParams) error { 167 return s.Conn.Notify(ctx, "window/logMessage", params) 168} 169 170func (s *clientDispatcher) Event(ctx context.Context, params *interface{}) error { 171 return s.Conn.Notify(ctx, "telemetry/event", params) 172} 173 174func (s *clientDispatcher) PublishDiagnostics(ctx context.Context, params *PublishDiagnosticsParams) error { 175 return s.Conn.Notify(ctx, "textDocument/publishDiagnostics", params) 176} 177func (s *clientDispatcher) WorkspaceFolders(ctx context.Context) ([]WorkspaceFolder, error) { 178 var result []WorkspaceFolder 179 if err := s.Conn.Call(ctx, "workspace/workspaceFolders", nil, &result); err != nil { 180 return nil, err 181 } 182 return result, nil 183} 184 185func (s *clientDispatcher) Configuration(ctx context.Context, params *ParamConfig) ([]interface{}, error) { 186 var result []interface{} 187 if err := s.Conn.Call(ctx, "workspace/configuration", params, &result); err != nil { 188 return nil, err 189 } 190 return result, nil 191} 192 193func (s *clientDispatcher) RegisterCapability(ctx context.Context, params *RegistrationParams) error { 194 return s.Conn.Call(ctx, "client/registerCapability", params, nil) // Call, not Notify 195} 196 197func (s *clientDispatcher) UnregisterCapability(ctx context.Context, params *UnregistrationParams) error { 198 return s.Conn.Call(ctx, "client/unregisterCapability", params, nil) // Call, not Notify 199} 200 201func (s *clientDispatcher) ShowMessageRequest(ctx context.Context, params *ShowMessageRequestParams) (*MessageActionItem, error) { 202 var result MessageActionItem 203 if err := s.Conn.Call(ctx, "window/showMessageRequest", params, &result); err != nil { 204 return nil, err 205 } 206 return &result, nil 207} 208 209func (s *clientDispatcher) ApplyEdit(ctx context.Context, params *ApplyWorkspaceEditParams) (*ApplyWorkspaceEditResponse, error) { 210 var result ApplyWorkspaceEditResponse 211 if err := s.Conn.Call(ctx, "workspace/applyEdit", params, &result); err != nil { 212 return nil, err 213 } 214 return &result, nil 215} 216 217// Types constructed to avoid structs as formal argument types 218type ParamConfig struct { 219 ConfigurationParams 220 PartialResultParams 221} 222