1 #pragma once
2
3 #include "config.h"
4 #include "method.h"
5 #include "serializer.h"
6 #include "utils.h"
7
8 #include <iosfwd>
9 #include <unordered_map>
10
11 /////////////////////////////////////////////////////////////////////////////
12 /////////////////////////////////////////////////////////////////////////////
13 /////////////////////////////////////////////////////////////////////////////
14 ///////////////////////////// OUTGOING MESSAGES /////////////////////////////
15 /////////////////////////////////////////////////////////////////////////////
16 /////////////////////////////////////////////////////////////////////////////
17 /////////////////////////////////////////////////////////////////////////////
18
19 /////////////////////////////////////////////////////////////////////////////
20 /////////////////////////////////////////////////////////////////////////////
21 /////////////////////////////////////////////////////////////////////////////
22 ///////////////////////////// INCOMING MESSAGES /////////////////////////////
23 /////////////////////////////////////////////////////////////////////////////
24 /////////////////////////////////////////////////////////////////////////////
25 /////////////////////////////////////////////////////////////////////////////
26
27 #define REGISTER_IN_MESSAGE(type) \
28 static MessageRegistryRegister<type> type##message_handler_instance_;
29
30 struct MessageRegistry {
31 static MessageRegistry* instance_;
32 static MessageRegistry* instance();
33
34 using Allocator =
35 std::function<void(Reader& visitor, std::unique_ptr<InMessage>*)>;
36 std::unordered_map<std::string, Allocator> allocators;
37
38 optional<std::string> ReadMessageFromStdin(
39 std::unique_ptr<InMessage>* message);
40 optional<std::string> Parse(Reader& visitor,
41 std::unique_ptr<InMessage>* message);
42 };
43
44 template <typename T>
45 struct MessageRegistryRegister {
MessageRegistryRegisterMessageRegistryRegister46 MessageRegistryRegister() {
47 T dummy;
48 std::string method_name = dummy.GetMethodType();
49 MessageRegistry::instance()->allocators[method_name] =
50 [](Reader& visitor, std::unique_ptr<InMessage>* message) {
51 *message = std::make_unique<T>();
52 // Reflect may throw and *message will be partially deserialized.
53 Reflect(visitor, static_cast<T&>(**message));
54 };
55 }
56 };
57
58 struct lsBaseOutMessage {
59 virtual ~lsBaseOutMessage();
60 virtual void ReflectWriter(Writer&) = 0;
61
62 // Send the message to the language client by writing it to stdout.
63 void Write(std::ostream& out);
64 };
65
66 template <typename TDerived>
67 struct lsOutMessage : lsBaseOutMessage {
68 // All derived types need to reflect on the |jsonrpc| member.
69 std::string jsonrpc = "2.0";
70
ReflectWriterlsOutMessage71 void ReflectWriter(Writer& writer) override {
72 Reflect(writer, static_cast<TDerived&>(*this));
73 }
74 };
75
76 struct lsResponseError {
77 enum class lsErrorCodes : int {
78 ParseError = -32700,
79 InvalidRequest = -32600,
80 MethodNotFound = -32601,
81 InvalidParams = -32602,
82 InternalError = -32603,
83 serverErrorStart = -32099,
84 serverErrorEnd = -32000,
85 ServerNotInitialized = -32002,
86 UnknownErrorCode = -32001,
87 RequestCancelled = -32800,
88 };
89
90 lsErrorCodes code;
91 // Short description.
92 std::string message;
93
94 void Write(Writer& visitor);
95 };
96
97 /////////////////////////////////////////////////////////////////////////////
98 /////////////////////////////////////////////////////////////////////////////
99 /////////////////////////////////////////////////////////////////////////////
100 ////////////////////////////// PRIMITIVE TYPES //////////////////////////////
101 /////////////////////////////////////////////////////////////////////////////
102 /////////////////////////////////////////////////////////////////////////////
103 /////////////////////////////////////////////////////////////////////////////
104
105 struct lsDocumentUri {
106 static lsDocumentUri FromPath(const AbsolutePath& path);
107
108 lsDocumentUri();
109 bool operator==(const lsDocumentUri& other) const;
110
111 void SetPath(const AbsolutePath& path);
112 std::string GetRawPath() const;
113 AbsolutePath GetAbsolutePath() const;
114
115 std::string raw_uri_;
116 };
117 MAKE_HASHABLE(lsDocumentUri, t.raw_uri_);
118
119 void Reflect(Writer& visitor, lsDocumentUri& value);
120 void Reflect(Reader& visitor, lsDocumentUri& value);
121
122 struct lsPosition {
123 lsPosition();
124 lsPosition(int line, int character);
125
126 bool operator==(const lsPosition& other) const;
127 bool operator<(const lsPosition& other) const;
128
129 std::string ToString() const;
130
131 // Note: these are 0-based.
132 int line = 0;
133 int character = 0;
134 static const lsPosition kZeroPosition;
135 };
136 MAKE_HASHABLE(lsPosition, t.line, t.character);
137 MAKE_REFLECT_STRUCT(lsPosition, line, character);
138
139 struct lsRange {
140 lsRange();
141 lsRange(lsPosition start, lsPosition end);
142
143 bool operator==(const lsRange& other) const;
144 bool operator<(const lsRange& other) const;
145
146 lsPosition start;
147 lsPosition end;
148 };
149 MAKE_HASHABLE(lsRange, t.start, t.end);
150 MAKE_REFLECT_STRUCT(lsRange, start, end);
151
152 struct lsLocation {
153 lsLocation();
154 lsLocation(lsDocumentUri uri, lsRange range);
155
156 bool operator==(const lsLocation& other) const;
157 bool operator<(const lsLocation& o) const;
158
159 lsDocumentUri uri;
160 lsRange range;
161 };
162 MAKE_HASHABLE(lsLocation, t.uri, t.range);
163 MAKE_REFLECT_STRUCT(lsLocation, uri, range);
164
165 enum class lsSymbolKind : uint8_t {
166 Unknown = 0,
167
168 File = 1,
169 Module = 2,
170 Namespace = 3,
171 Package = 4,
172 Class = 5,
173 Method = 6,
174 Property = 7,
175 Field = 8,
176 Constructor = 9,
177 Enum = 10,
178 Interface = 11,
179 Function = 12,
180 Variable = 13,
181 Constant = 14,
182 String = 15,
183 Number = 16,
184 Boolean = 17,
185 Array = 18,
186 Object = 19,
187 Key = 20,
188 Null = 21,
189 EnumMember = 22,
190 Struct = 23,
191 Event = 24,
192 Operator = 25,
193
194 // For C++, this is interpreted as "template parameter" (including
195 // non-type template parameters).
196 TypeParameter = 26,
197
198 // cquery extensions
199 // See also https://github.com/Microsoft/language-server-protocol/issues/344
200 // for new SymbolKind clang/Index/IndexSymbol.h clang::index::SymbolKind
201 TypeAlias = 252,
202 Parameter = 253,
203 StaticMethod = 254,
204 Macro = 255,
205 };
206 MAKE_REFLECT_TYPE_PROXY(lsSymbolKind);
207
208 template <typename T>
209 struct lsCommand {
210 // Title of the command (ie, 'save')
211 std::string title;
212 // Actual command identifier.
213 std::string command;
214 // Arguments to run the command with.
215 // **NOTE** This must be serialized as an array. Use
216 // MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
217 T arguments;
218 };
219 template <typename TVisitor, typename T>
Reflect(TVisitor & visitor,lsCommand<T> & value)220 void Reflect(TVisitor& visitor, lsCommand<T>& value) {
221 REFLECT_MEMBER_START();
222 REFLECT_MEMBER(title);
223 REFLECT_MEMBER(command);
224 REFLECT_MEMBER(arguments);
225 REFLECT_MEMBER_END();
226 }
227
228 template <typename TData, typename TCommandArguments>
229 struct lsCodeLens {
230 // The range in which this code lens is valid. Should only span a single line.
231 lsRange range;
232 // The command this code lens represents.
233 optional<lsCommand<TCommandArguments>> command;
234 // A data entry field that is preserved on a code lens item between
235 // a code lens and a code lens resolve request.
236 TData data;
237 };
238 template <typename TVisitor, typename TData, typename TCommandArguments>
Reflect(TVisitor & visitor,lsCodeLens<TData,TCommandArguments> & value)239 void Reflect(TVisitor& visitor, lsCodeLens<TData, TCommandArguments>& value) {
240 REFLECT_MEMBER_START();
241 REFLECT_MEMBER(range);
242 REFLECT_MEMBER(command);
243 REFLECT_MEMBER(data);
244 REFLECT_MEMBER_END();
245 }
246
247 struct lsTextDocumentIdentifier {
248 lsDocumentUri uri;
249 };
250 MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
251
252 struct lsVersionedTextDocumentIdentifier {
253 lsDocumentUri uri;
254 // The version number of this document. number | null
255 optional<int> version;
256
257 lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
258 };
259 MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version);
260
261 struct lsTextDocumentPositionParams {
262 // The text document.
263 lsTextDocumentIdentifier textDocument;
264
265 // The position inside the text document.
266 lsPosition position;
267 };
268 MAKE_REFLECT_STRUCT(lsTextDocumentPositionParams, textDocument, position);
269
270 struct lsTextEdit {
271 // The range of the text document to be manipulated. To insert
272 // text into a document create a range where start === end.
273 lsRange range;
274
275 // The string to be inserted. For delete operations use an
276 // empty string.
277 std::string newText;
278
279 bool operator==(const lsTextEdit& that);
280 };
281 MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
282
283 struct lsTextDocumentItem {
284 // The text document's URI.
285 lsDocumentUri uri;
286
287 // The text document's language identifier.
288 std::string languageId;
289
290 // The version number of this document (it will strictly increase after each
291 // change, including undo/redo).
292 int version;
293
294 // The content of the opened text document.
295 std::string text;
296 };
297 MAKE_REFLECT_STRUCT(lsTextDocumentItem, uri, languageId, version, text);
298
299 struct lsTextDocumentEdit {
300 // The text document to change.
301 lsVersionedTextDocumentIdentifier textDocument;
302
303 // The edits to be applied.
304 std::vector<lsTextEdit> edits;
305 };
306 MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
307
308 struct lsWorkspaceEdit {
309 // Holds changes to existing resources.
310 // changes ? : { [uri:string]: TextEdit[]; };
311 // std::unordered_map<lsDocumentUri, std::vector<lsTextEdit>> changes;
312
313 // An array of `TextDocumentEdit`s to express changes to specific a specific
314 // version of a text document. Whether a client supports versioned document
315 // edits is expressed via `WorkspaceClientCapabilites.versionedWorkspaceEdit`.
316 std::vector<lsTextDocumentEdit> documentChanges;
317 };
318 MAKE_REFLECT_STRUCT(lsWorkspaceEdit, documentChanges);
319
320 struct lsFormattingOptions {
321 // Size of a tab in spaces.
322 int tabSize;
323 // Prefer spaces over tabs.
324 bool insertSpaces;
325 };
326 MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
327
328 // MarkedString can be used to render human readable text. It is either a
329 // markdown string or a code-block that provides a language and a code snippet.
330 // The language identifier is sematically equal to the optional language
331 // identifier in fenced code blocks in GitHub issues. See
332 // https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
333 //
334 // The pair of a language and a value is an equivalent to markdown:
335 // ```${language}
336 // ${value}
337 // ```
338 //
339 // Note that markdown strings will be sanitized - that means html will be
340 // escaped.
341 struct lsMarkedString {
342 optional<std::string> language;
343 std::string value;
344 };
345 void Reflect(Writer& visitor, lsMarkedString& value);
346
347 struct lsTextDocumentContentChangeEvent {
348 // The range of the document that changed.
349 optional<lsRange> range;
350 // The length of the range that got replaced.
351 optional<int> rangeLength;
352 // The new text of the range/document.
353 std::string text;
354 };
355 MAKE_REFLECT_STRUCT(lsTextDocumentContentChangeEvent, range, rangeLength, text);
356
357 struct lsTextDocumentDidChangeParams {
358 lsVersionedTextDocumentIdentifier textDocument;
359 std::vector<lsTextDocumentContentChangeEvent> contentChanges;
360 };
361 MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams,
362 textDocument,
363 contentChanges);
364
365 // Show a message to the user.
366 enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
367 MAKE_REFLECT_TYPE_PROXY(lsMessageType)
368 struct Out_ShowLogMessageParams {
369 lsMessageType type = lsMessageType::Error;
370 std::string message;
371 };
372 MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message);
373 struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
374 enum class DisplayType { Show, Log };
375 DisplayType display_type = DisplayType::Show;
376
377 std::string method();
378 Out_ShowLogMessageParams params;
379 };
380 template <typename TVisitor>
Reflect(TVisitor & visitor,Out_ShowLogMessage & value)381 void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
382 REFLECT_MEMBER_START();
383 REFLECT_MEMBER(jsonrpc);
384 std::string method = value.method();
385 REFLECT_MEMBER2("method", method);
386 REFLECT_MEMBER(params);
387 REFLECT_MEMBER_END();
388 }
389
390 struct Out_LocationList : public lsOutMessage<Out_LocationList> {
391 lsRequestId id;
392 std::vector<lsLocation> result;
393 };
394 MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);
395