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