blob: 6e3fadc045f2e33a273fa5d1e273b0be3e464610 [file] [log] [blame]
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00001//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the serialization code for the LSP structs.
11// FIXME: This is extremely repetetive and ugly. Is there a better way?
12//
13//===----------------------------------------------------------------------===//
14
15#include "Protocol.h"
16#include "clang/Basic/LLVM.h"
17#include "llvm/ADT/SmallString.h"
18#include "llvm/Support/Format.h"
19#include "llvm/Support/raw_ostream.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000020#include "llvm/Support/Path.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000021using namespace clang::clangd;
22
Krasimir Georgiev50117372017-04-07 11:03:26 +000023
24URI URI::fromUri(llvm::StringRef uri) {
25 URI Result;
26 Result.uri = uri;
27 uri.consume_front("file://");
28 // For Windows paths e.g. /X:
29 if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':')
30 uri.consume_front("/");
31 // Make sure that file paths are in native separators
32 Result.file = llvm::sys::path::convert_to_slash(uri);
33 return Result;
34}
35
36URI URI::fromFile(llvm::StringRef file) {
37 using namespace llvm::sys;
38 URI Result;
39 Result.file = file;
40 Result.uri = "file://";
41 // For Windows paths e.g. X:
42 if (file.size() > 1 && file[1] == ':')
43 Result.uri += "/";
44 // Make sure that uri paths are with posix separators
45 Result.uri += path::convert_to_slash(file, path::Style::posix);
46 return Result;
47}
48
49URI URI::parse(llvm::yaml::ScalarNode *Param) {
50 llvm::SmallString<10> Storage;
51 return URI::fromUri(Param->getValue(Storage));
52}
53
54std::string URI::unparse(const URI &U) {
55 return U.uri;
56}
57
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000058llvm::Optional<TextDocumentIdentifier>
59TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) {
60 TextDocumentIdentifier Result;
61 for (auto &NextKeyValue : *Params) {
62 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
63 if (!KeyString)
64 return llvm::None;
65
66 llvm::SmallString<10> KeyStorage;
67 StringRef KeyValue = KeyString->getValue(KeyStorage);
68 auto *Value =
69 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
70 if (!Value)
71 return llvm::None;
72
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000073 if (KeyValue == "uri") {
Krasimir Georgiev50117372017-04-07 11:03:26 +000074 Result.uri = URI::parse(Value);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000075 } else if (KeyValue == "version") {
76 // FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
77 } else {
78 return llvm::None;
79 }
80 }
81 return Result;
82}
83
84llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params) {
85 Position Result;
86 for (auto &NextKeyValue : *Params) {
87 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
88 if (!KeyString)
89 return llvm::None;
90
91 llvm::SmallString<10> KeyStorage;
92 StringRef KeyValue = KeyString->getValue(KeyStorage);
93 auto *Value =
94 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
95 if (!Value)
96 return llvm::None;
97
98 llvm::SmallString<10> Storage;
99 if (KeyValue == "line") {
100 long long Val;
101 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
102 return llvm::None;
103 Result.line = Val;
104 } else if (KeyValue == "character") {
105 long long Val;
106 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
107 return llvm::None;
108 Result.character = Val;
109 } else {
110 return llvm::None;
111 }
112 }
113 return Result;
114}
115
116std::string Position::unparse(const Position &P) {
117 std::string Result;
118 llvm::raw_string_ostream(Result)
119 << llvm::format(R"({"line": %d, "character": %d})", P.line, P.character);
120 return Result;
121}
122
123llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params) {
124 Range Result;
125 for (auto &NextKeyValue : *Params) {
126 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
127 if (!KeyString)
128 return llvm::None;
129
130 llvm::SmallString<10> KeyStorage;
131 StringRef KeyValue = KeyString->getValue(KeyStorage);
132 auto *Value =
133 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
134 if (!Value)
135 return llvm::None;
136
137 llvm::SmallString<10> Storage;
138 if (KeyValue == "start") {
139 auto Parsed = Position::parse(Value);
140 if (!Parsed)
141 return llvm::None;
142 Result.start = std::move(*Parsed);
143 } else if (KeyValue == "end") {
144 auto Parsed = Position::parse(Value);
145 if (!Parsed)
146 return llvm::None;
147 Result.end = std::move(*Parsed);
148 } else {
149 return llvm::None;
150 }
151 }
152 return Result;
153}
154
155std::string Range::unparse(const Range &P) {
156 std::string Result;
157 llvm::raw_string_ostream(Result) << llvm::format(
158 R"({"start": %s, "end": %s})", Position::unparse(P.start).c_str(),
159 Position::unparse(P.end).c_str());
160 return Result;
161}
162
163llvm::Optional<TextDocumentItem>
164TextDocumentItem::parse(llvm::yaml::MappingNode *Params) {
165 TextDocumentItem Result;
166 for (auto &NextKeyValue : *Params) {
167 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
168 if (!KeyString)
169 return llvm::None;
170
171 llvm::SmallString<10> KeyStorage;
172 StringRef KeyValue = KeyString->getValue(KeyStorage);
173 auto *Value =
174 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
175 if (!Value)
176 return llvm::None;
177
178 llvm::SmallString<10> Storage;
179 if (KeyValue == "uri") {
Krasimir Georgiev50117372017-04-07 11:03:26 +0000180 Result.uri = URI::parse(Value);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000181 } else if (KeyValue == "languageId") {
182 Result.languageId = Value->getValue(Storage);
183 } else if (KeyValue == "version") {
184 long long Val;
185 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
186 return llvm::None;
187 Result.version = Val;
188 } else if (KeyValue == "text") {
189 Result.text = Value->getValue(Storage);
190 } else {
191 return llvm::None;
192 }
193 }
194 return Result;
195}
196
197llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params) {
198 TextEdit Result;
199 for (auto &NextKeyValue : *Params) {
200 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
201 if (!KeyString)
202 return llvm::None;
203
204 llvm::SmallString<10> KeyStorage;
205 StringRef KeyValue = KeyString->getValue(KeyStorage);
206 auto *Value = NextKeyValue.getValue();
207
208 llvm::SmallString<10> Storage;
209 if (KeyValue == "range") {
210 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
211 if (!Map)
212 return llvm::None;
213 auto Parsed = Range::parse(Map);
214 if (!Parsed)
215 return llvm::None;
216 Result.range = std::move(*Parsed);
217 } else if (KeyValue == "newText") {
218 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
219 if (!Node)
220 return llvm::None;
221 Result.newText = Node->getValue(Storage);
222 } else {
223 return llvm::None;
224 }
225 }
226 return Result;
227}
228
229std::string TextEdit::unparse(const TextEdit &P) {
230 std::string Result;
231 llvm::raw_string_ostream(Result) << llvm::format(
232 R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(),
233 llvm::yaml::escape(P.newText).c_str());
234 return Result;
235}
236
237llvm::Optional<DidOpenTextDocumentParams>
238DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
239 DidOpenTextDocumentParams Result;
240 for (auto &NextKeyValue : *Params) {
241 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
242 if (!KeyString)
243 return llvm::None;
244
245 llvm::SmallString<10> KeyStorage;
246 StringRef KeyValue = KeyString->getValue(KeyStorage);
247 auto *Value =
248 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
249 if (!Value)
250 return llvm::None;
251
252 llvm::SmallString<10> Storage;
253 if (KeyValue == "textDocument") {
254 auto Parsed = TextDocumentItem::parse(Value);
255 if (!Parsed)
256 return llvm::None;
257 Result.textDocument = std::move(*Parsed);
258 } else {
259 return llvm::None;
260 }
261 }
262 return Result;
263}
264
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000265llvm::Optional<DidCloseTextDocumentParams>
266DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
267 DidCloseTextDocumentParams Result;
268 for (auto &NextKeyValue : *Params) {
269 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
270 if (!KeyString)
271 return llvm::None;
272
273 llvm::SmallString<10> KeyStorage;
274 StringRef KeyValue = KeyString->getValue(KeyStorage);
275 auto *Value = NextKeyValue.getValue();
276
277 if (KeyValue == "textDocument") {
278 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
279 if (!Map)
280 return llvm::None;
281 auto Parsed = TextDocumentIdentifier::parse(Map);
282 if (!Parsed)
283 return llvm::None;
284 Result.textDocument = std::move(*Parsed);
285 } else {
286 return llvm::None;
287 }
288 }
289 return Result;
290}
291
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000292llvm::Optional<DidChangeTextDocumentParams>
293DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
294 DidChangeTextDocumentParams Result;
295 for (auto &NextKeyValue : *Params) {
296 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
297 if (!KeyString)
298 return llvm::None;
299
300 llvm::SmallString<10> KeyStorage;
301 StringRef KeyValue = KeyString->getValue(KeyStorage);
302 auto *Value = NextKeyValue.getValue();
303
304 llvm::SmallString<10> Storage;
305 if (KeyValue == "textDocument") {
306 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
307 if (!Map)
308 return llvm::None;
309 auto Parsed = TextDocumentIdentifier::parse(Map);
310 if (!Parsed)
311 return llvm::None;
312 Result.textDocument = std::move(*Parsed);
313 } else if (KeyValue == "contentChanges") {
314 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
315 if (!Seq)
316 return llvm::None;
317 for (auto &Item : *Seq) {
318 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
319 if (!I)
320 return llvm::None;
321 auto Parsed = TextDocumentContentChangeEvent::parse(I);
322 if (!Parsed)
323 return llvm::None;
324 Result.contentChanges.push_back(std::move(*Parsed));
325 }
326 } else {
327 return llvm::None;
328 }
329 }
330 return Result;
331}
332
333llvm::Optional<TextDocumentContentChangeEvent>
334TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) {
335 TextDocumentContentChangeEvent Result;
336 for (auto &NextKeyValue : *Params) {
337 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
338 if (!KeyString)
339 return llvm::None;
340
341 llvm::SmallString<10> KeyStorage;
342 StringRef KeyValue = KeyString->getValue(KeyStorage);
343 auto *Value =
344 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
345 if (!Value)
346 return llvm::None;
347
348 llvm::SmallString<10> Storage;
349 if (KeyValue == "text") {
350 Result.text = Value->getValue(Storage);
351 } else {
352 return llvm::None;
353 }
354 }
355 return Result;
356}
357
358llvm::Optional<FormattingOptions>
359FormattingOptions::parse(llvm::yaml::MappingNode *Params) {
360 FormattingOptions Result;
361 for (auto &NextKeyValue : *Params) {
362 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
363 if (!KeyString)
364 return llvm::None;
365
366 llvm::SmallString<10> KeyStorage;
367 StringRef KeyValue = KeyString->getValue(KeyStorage);
368 auto *Value =
369 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
370 if (!Value)
371 return llvm::None;
372
373 llvm::SmallString<10> Storage;
374 if (KeyValue == "tabSize") {
375 long long Val;
376 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
377 return llvm::None;
378 Result.tabSize = Val;
379 } else if (KeyValue == "insertSpaces") {
380 long long Val;
381 StringRef Str = Value->getValue(Storage);
382 if (llvm::getAsSignedInteger(Str, 0, Val)) {
383 if (Str == "true")
384 Val = 1;
385 else if (Str == "false")
386 Val = 0;
387 else
388 return llvm::None;
389 }
390 Result.insertSpaces = Val;
391 } else {
392 return llvm::None;
393 }
394 }
395 return Result;
396}
397
398std::string FormattingOptions::unparse(const FormattingOptions &P) {
399 std::string Result;
400 llvm::raw_string_ostream(Result) << llvm::format(
401 R"({"tabSize": %d, "insertSpaces": %d})", P.tabSize, P.insertSpaces);
402 return Result;
403}
404
405llvm::Optional<DocumentRangeFormattingParams>
406DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
407 DocumentRangeFormattingParams Result;
408 for (auto &NextKeyValue : *Params) {
409 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
410 if (!KeyString)
411 return llvm::None;
412
413 llvm::SmallString<10> KeyStorage;
414 StringRef KeyValue = KeyString->getValue(KeyStorage);
415 auto *Value =
416 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
417 if (!Value)
418 return llvm::None;
419
420 llvm::SmallString<10> Storage;
421 if (KeyValue == "textDocument") {
422 auto Parsed = TextDocumentIdentifier::parse(Value);
423 if (!Parsed)
424 return llvm::None;
425 Result.textDocument = std::move(*Parsed);
426 } else if (KeyValue == "range") {
427 auto Parsed = Range::parse(Value);
428 if (!Parsed)
429 return llvm::None;
430 Result.range = std::move(*Parsed);
431 } else if (KeyValue == "options") {
432 auto Parsed = FormattingOptions::parse(Value);
433 if (!Parsed)
434 return llvm::None;
435 Result.options = std::move(*Parsed);
436 } else {
437 return llvm::None;
438 }
439 }
440 return Result;
441}
442
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000443llvm::Optional<DocumentOnTypeFormattingParams>
444DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
445 DocumentOnTypeFormattingParams Result;
446 for (auto &NextKeyValue : *Params) {
447 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
448 if (!KeyString)
449 return llvm::None;
450
451 llvm::SmallString<10> KeyStorage;
452 StringRef KeyValue = KeyString->getValue(KeyStorage);
453
454 if (KeyValue == "ch") {
455 auto *ScalarValue =
456 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
457 if (!ScalarValue)
458 return llvm::None;
459 llvm::SmallString<10> Storage;
460 Result.ch = ScalarValue->getValue(Storage);
461 continue;
462 }
463
464 auto *Value =
465 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
466 if (!Value)
467 return llvm::None;
468 if (KeyValue == "textDocument") {
469 auto Parsed = TextDocumentIdentifier::parse(Value);
470 if (!Parsed)
471 return llvm::None;
472 Result.textDocument = std::move(*Parsed);
473 } else if (KeyValue == "position") {
474 auto Parsed = Position::parse(Value);
475 if (!Parsed)
476 return llvm::None;
477 Result.position = std::move(*Parsed);
478 } else if (KeyValue == "options") {
479 auto Parsed = FormattingOptions::parse(Value);
480 if (!Parsed)
481 return llvm::None;
482 Result.options = std::move(*Parsed);
483 } else {
484 return llvm::None;
485 }
486 }
487 return Result;
488}
489
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000490llvm::Optional<DocumentFormattingParams>
491DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) {
492 DocumentFormattingParams Result;
493 for (auto &NextKeyValue : *Params) {
494 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
495 if (!KeyString)
496 return llvm::None;
497
498 llvm::SmallString<10> KeyStorage;
499 StringRef KeyValue = KeyString->getValue(KeyStorage);
500 auto *Value =
501 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
502 if (!Value)
503 return llvm::None;
504
505 llvm::SmallString<10> Storage;
506 if (KeyValue == "textDocument") {
507 auto Parsed = TextDocumentIdentifier::parse(Value);
508 if (!Parsed)
509 return llvm::None;
510 Result.textDocument = std::move(*Parsed);
511 } else if (KeyValue == "options") {
512 auto Parsed = FormattingOptions::parse(Value);
513 if (!Parsed)
514 return llvm::None;
515 Result.options = std::move(*Parsed);
516 } else {
517 return llvm::None;
518 }
519 }
520 return Result;
521}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000522
523llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params) {
524 Diagnostic Result;
525 for (auto &NextKeyValue : *Params) {
526 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
527 if (!KeyString)
528 return llvm::None;
529
530 llvm::SmallString<10> KeyStorage;
531 StringRef KeyValue = KeyString->getValue(KeyStorage);
532
533 llvm::SmallString<10> Storage;
534 if (KeyValue == "range") {
535 auto *Value =
536 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
537 if (!Value)
538 return llvm::None;
539 auto Parsed = Range::parse(Value);
540 if (!Parsed)
541 return llvm::None;
542 Result.range = std::move(*Parsed);
543 } else if (KeyValue == "severity") {
544 auto *Value =
545 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
546 if (!Value)
547 return llvm::None;
548 long long Val;
549 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
550 return llvm::None;
551 Result.severity = Val;
552 } else if (KeyValue == "message") {
553 auto *Value =
554 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
555 if (!Value)
556 return llvm::None;
557 Result.message = Value->getValue(Storage);
558 } else {
559 return llvm::None;
560 }
561 }
562 return Result;
563}
564
565llvm::Optional<CodeActionContext>
566CodeActionContext::parse(llvm::yaml::MappingNode *Params) {
567 CodeActionContext Result;
568 for (auto &NextKeyValue : *Params) {
569 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
570 if (!KeyString)
571 return llvm::None;
572
573 llvm::SmallString<10> KeyStorage;
574 StringRef KeyValue = KeyString->getValue(KeyStorage);
575 auto *Value = NextKeyValue.getValue();
576
577 llvm::SmallString<10> Storage;
578 if (KeyValue == "diagnostics") {
579 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
580 if (!Seq)
581 return llvm::None;
582 for (auto &Item : *Seq) {
583 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
584 if (!I)
585 return llvm::None;
586 auto Parsed = Diagnostic::parse(I);
587 if (!Parsed)
588 return llvm::None;
589 Result.diagnostics.push_back(std::move(*Parsed));
590 }
591 } else {
592 return llvm::None;
593 }
594 }
595 return Result;
596}
597
598llvm::Optional<CodeActionParams>
599CodeActionParams::parse(llvm::yaml::MappingNode *Params) {
600 CodeActionParams Result;
601 for (auto &NextKeyValue : *Params) {
602 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
603 if (!KeyString)
604 return llvm::None;
605
606 llvm::SmallString<10> KeyStorage;
607 StringRef KeyValue = KeyString->getValue(KeyStorage);
608 auto *Value =
609 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
610 if (!Value)
611 return llvm::None;
612
613 llvm::SmallString<10> Storage;
614 if (KeyValue == "textDocument") {
615 auto Parsed = TextDocumentIdentifier::parse(Value);
616 if (!Parsed)
617 return llvm::None;
618 Result.textDocument = std::move(*Parsed);
619 } else if (KeyValue == "range") {
620 auto Parsed = Range::parse(Value);
621 if (!Parsed)
622 return llvm::None;
623 Result.range = std::move(*Parsed);
624 } else if (KeyValue == "context") {
625 auto Parsed = CodeActionContext::parse(Value);
626 if (!Parsed)
627 return llvm::None;
628 Result.context = std::move(*Parsed);
629 } else {
630 return llvm::None;
631 }
632 }
633 return Result;
634}
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000635
636llvm::Optional<TextDocumentPositionParams>
637TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) {
638 TextDocumentPositionParams Result;
639 for (auto &NextKeyValue : *Params) {
640 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
641 if (!KeyString)
642 return llvm::None;
643
644 llvm::SmallString<10> KeyStorage;
645 StringRef KeyValue = KeyString->getValue(KeyStorage);
646 auto *Value =
647 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
648 if (!Value)
649 return llvm::None;
650
651 llvm::SmallString<10> Storage;
652 if (KeyValue == "textDocument") {
653 auto Parsed = TextDocumentIdentifier::parse(Value);
654 if (!Parsed)
655 return llvm::None;
656 Result.textDocument = std::move(*Parsed);
657 } else if (KeyValue == "position") {
658 auto Parsed = Position::parse(Value);
659 if (!Parsed)
660 return llvm::None;
661 Result.position = std::move(*Parsed);
662 } else {
663 return llvm::None;
664 }
665 }
666 return Result;
667}
668
669std::string CompletionItem::unparse(const CompletionItem &CI) {
670 std::string Result = "{";
671 llvm::raw_string_ostream Os(Result);
672 assert(!CI.label.empty() && "completion item label is required");
673 Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
674 if (CI.kind != CompletionItemKind::Missing)
675 Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(",)";
676 if (!CI.detail.empty())
677 Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
678 if (!CI.documentation.empty())
679 Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
680 << R"(",)";
681 if (!CI.sortText.empty())
682 Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
683 if (!CI.filterText.empty())
684 Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
685 if (!CI.insertText.empty())
686 Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
687 if (CI.insertTextFormat != InsertTextFormat::Missing) {
688 Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
689 << R"(",)";
690 }
691 if (CI.textEdit)
692 Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
693 if (!CI.additionalTextEdits.empty()) {
694 Os << R"("additionalTextEdits":[)";
695 for (const auto &Edit : CI.additionalTextEdits)
696 Os << TextEdit::unparse(Edit) << ",";
697 Os.flush();
698 // The list additionalTextEdits is guaranteed nonempty at this point.
699 // Replace the trailing comma with right brace.
700 Result.back() = ']';
701 }
702 Os.flush();
703 // Label is required, so Result is guaranteed to have a trailing comma.
704 Result.back() = '}';
705 return Result;
706}