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