1 module served.lsp.protocol; 2 3 import std.conv; 4 import std.json; 5 import std.meta; 6 import std.traits; 7 8 import painlessjson; 9 10 struct Optional(T) 11 { 12 bool isNull = true; 13 T value; 14 15 this(T val) 16 { 17 value = val; 18 isNull = false; 19 } 20 21 this(U)(U val) 22 { 23 value = val; 24 isNull = false; 25 } 26 27 this(typeof(null)) 28 { 29 isNull = true; 30 } 31 32 void opAssign(typeof(null)) 33 { 34 nullify(); 35 } 36 37 void opAssign(T val) 38 { 39 isNull = false; 40 value = val; 41 } 42 43 void opAssign(U)(U val) 44 { 45 isNull = false; 46 value = val; 47 } 48 49 void nullify() 50 { 51 isNull = true; 52 value = T.init; 53 } 54 55 bool opCast(T : bool)() const 56 { 57 return !isNull; 58 } 59 60 string toString() const 61 { 62 if (isNull) 63 return "null(" ~ T.stringof ~ ")"; 64 else 65 return value.to!string; 66 } 67 68 const JSONValue _toJSON() 69 { 70 import painlessjson : toJSON; 71 72 if (isNull) 73 return JSONValue(null); 74 else 75 return value.toJSON; 76 } 77 78 static Optional!T _fromJSON(JSONValue val) 79 { 80 Optional!T ret; 81 ret.isNull = false; 82 ret.value = val.fromJSON!T; 83 return ret; 84 } 85 86 ref inout(T) get() inout 87 { 88 return value; 89 } 90 91 alias value this; 92 } 93 94 mixin template StrictOptionalSerializer() 95 { 96 const JSONValue _toJSON() 97 { 98 JSONValue[string] ret = this.defaultToJSON.object; 99 foreach (member; __traits(allMembers, typeof(this))) 100 static if (is(typeof(__traits(getMember, this, member)) == Optional!T, T)) 101 { 102 static if (hasUDA!(__traits(getMember, this, member), SerializedName)) 103 string name = getUDAs!(__traits(getMember, this, member), SerializedName)[0].to; 104 else static if (hasUDA!(__traits(getMember, this, member), SerializedToName)) 105 string name = getUDAs!(__traits(getMember, this, member), SerializedToName)[0].name; 106 else 107 string name = member; 108 109 if (__traits(getMember, this, member).isNull) 110 ret.remove(name); 111 } 112 return JSONValue(ret); 113 } 114 } 115 116 Optional!T opt(T)(T val) 117 { 118 return Optional!T(val); 119 } 120 121 struct ArrayOrSingle(T) 122 { 123 T[] value; 124 125 this(T val) 126 { 127 value = [val]; 128 } 129 130 this(T[] val) 131 { 132 value = val; 133 } 134 135 void opAssign(T val) 136 { 137 value = [val]; 138 } 139 140 void opAssign(T[] val) 141 { 142 value = val; 143 } 144 145 const JSONValue _toJSON() 146 { 147 if (value.length == 1) 148 return value[0].toJSON; 149 else 150 return value.toJSON; 151 } 152 153 static ArrayOrSingle!T _fromJSON(JSONValue val) 154 { 155 ArrayOrSingle!T ret; 156 if (val.type == JSONType.array) 157 ret.value = val.fromJSON!(T[]); 158 else 159 ret.value = [val.fromJSON!T]; 160 return ret; 161 } 162 163 alias value this; 164 } 165 166 static assert(__traits(compiles, ArrayOrSingle!Location.init._toJSON())); 167 static assert(__traits(compiles, ArrayOrSingle!Location._fromJSON(JSONValue.init))); 168 169 unittest 170 { 171 auto single = ArrayOrSingle!Location(Location("file:///foo.d", TextRange(4, 2, 4, 8))); 172 auto array = ArrayOrSingle!Location([Location("file:///foo.d", TextRange(4, 2, 4, 8)), Location("file:///bar.d", TextRange(14, 1, 14, 9))]); 173 assert(toJSON(single) == JSONValue([ 174 "range": JSONValue([ 175 "start": JSONValue(["line":JSONValue(4), "character":JSONValue(2)]), 176 "end": JSONValue(["line":JSONValue(4), "character":JSONValue(8)]) 177 ]), 178 "uri": JSONValue("file:///foo.d") 179 ])); 180 assert(toJSON(array) == JSONValue([ 181 JSONValue([ 182 "range": JSONValue([ 183 "start": JSONValue(["line":JSONValue(4), "character":JSONValue(2)]), 184 "end": JSONValue(["line":JSONValue(4), "character":JSONValue(8)]) 185 ]), 186 "uri": JSONValue("file:///foo.d") 187 ]), 188 JSONValue([ 189 "range": JSONValue([ 190 "start": JSONValue(["line":JSONValue(14), "character":JSONValue(1)]), 191 "end": JSONValue(["line":JSONValue(14), "character":JSONValue(9)]) 192 ]), 193 "uri": JSONValue("file:///bar.d") 194 ]) 195 ])); 196 assert(fromJSON!(ArrayOrSingle!Location)(toJSON(single)) == single, fromJSON!(ArrayOrSingle!Location)(toJSON(single)).value.to!string); 197 assert(fromJSON!(ArrayOrSingle!Location)(toJSON(array)) == array); 198 } 199 200 struct RequestToken 201 { 202 this(scope const(JSONValue)* val) 203 { 204 if (!val) 205 this(JSONValue.init); 206 else 207 this(*val); 208 } 209 210 this(const(JSONValue) val) 211 { 212 hasData = val != JSONValue.init; 213 if (val.type == JSONType..string) 214 { 215 isString = true; 216 str = val.str; 217 } 218 else if (val.type == JSONType.integer) 219 { 220 isString = false; 221 num = val.integer; 222 } 223 else if (hasData) 224 throw new Exception("Invalid ID"); 225 } 226 227 union 228 { 229 string str; 230 long num; 231 } 232 233 bool hasData, isString; 234 235 JSONValue toJSON() 236 { 237 JSONValue ret = null; 238 if (!hasData) 239 return ret; 240 ret = isString ? JSONValue(str) : JSONValue(num); 241 return ret; 242 } 243 244 JSONValue _toJSON()() 245 { 246 pragma(msg, "Attempted painlesstraits.toJSON on RequestToken"); 247 } 248 249 void _fromJSON()(JSONValue val) 250 { 251 pragma(msg, "Attempted painlesstraits.fromJSON on RequestToken"); 252 } 253 254 string toString() 255 { 256 return hasData ? (isString ? str : num.to!string) : "none"; 257 } 258 259 static RequestToken random() 260 { 261 import std.uuid; 262 263 JSONValue id = JSONValue(randomUUID.toString); 264 return RequestToken(&id); 265 } 266 267 bool opEquals(RequestToken b) const 268 { 269 return isString == b.isString && (isString ? str == b.str : num == b.num); 270 } 271 } 272 273 /// 274 struct RequestMessage 275 { 276 this(JSONValue val) 277 { 278 id = RequestToken("id" in val); 279 method = val["method"].str; 280 auto ptr = "params" in val; 281 if (ptr) 282 params = *ptr; 283 } 284 285 /// 286 RequestToken id; 287 /// 288 string method; 289 /// Optional parameters to this method. Must be either null (omitted), array 290 /// (positional parameters) or object. (named parameters) 291 JSONValue params; 292 293 bool isCancelRequest() 294 { 295 return method == "$/cancelRequest"; 296 } 297 298 /// Converts this message to a JSON-RPC packet 299 JSONValue toJSON() 300 { 301 auto ret = JSONValue([ 302 "jsonrpc": JSONValue("2.0"), 303 "method": JSONValue(method) 304 ]); 305 if (!params.isNull) 306 ret["params"] = params; 307 if (id.hasData) 308 ret["id"] = id.toJSON; 309 return ret; 310 } 311 } 312 313 /// 314 enum ErrorCode 315 { 316 /// Invalid JSON was received by the server. 317 /// An error occurred on the server while parsing the JSON text. 318 parseError = -32700, 319 /// The JSON sent is not a valid Request object. 320 invalidRequest = -32600, 321 /// The method does not exist / is not available. 322 methodNotFound = -32601, 323 /// Invalid method parameter(s). 324 invalidParams = -32602, 325 /// Internal JSON-RPC error. 326 internalError = -32603, 327 /// Range start reserved for implementation-defined server-errors. 328 serverErrorStart = -32099, 329 /// Range end reserved for implementation-defined server-errors. 330 serverErrorEnd = -32000, 331 /// serve-d specific error: received method before server was fully 332 /// initialized. 333 serverNotInitialized = -32002, 334 /// 335 unknownErrorCode = -32001 336 } 337 338 enum MessageType 339 { 340 error = 1, 341 warning, 342 info, 343 log 344 } 345 346 /// 347 struct ResponseError 348 { 349 /// A Number that indicates the error type that occurred. 350 ErrorCode code; 351 /// A String providing a short description of the error. 352 /// The message SHOULD be limited to a concise single sentence. 353 string message; 354 /// A Primitive or Structured value that contains additional information 355 /// about the error. 356 /// This may be omitted. 357 /// The value of this member is defined by the Server (e.g. detailed error 358 /// information, nested errors etc.). 359 JSONValue data; 360 361 this(Throwable t) 362 { 363 code = ErrorCode.unknownErrorCode; 364 message = t.msg; 365 data = JSONValue(t.to!string); 366 } 367 368 this(ErrorCode c) 369 { 370 code = c; 371 message = c.to!string; 372 } 373 374 this(ErrorCode c, string msg) 375 { 376 code = c; 377 message = msg; 378 } 379 } 380 381 class MethodException : Exception 382 { 383 this(ResponseError error, string file = __FILE__, size_t line = __LINE__) pure nothrow @nogc @safe 384 { 385 super(error.message, file, line); 386 this.error = error; 387 } 388 389 ResponseError error; 390 } 391 392 /// 393 struct ResponseMessage 394 { 395 this(RequestToken id, JSONValue result) 396 { 397 this.id = id; 398 this.result = result; 399 } 400 401 this(RequestToken id, ResponseError error) 402 { 403 this.id = id; 404 this.error = error; 405 } 406 407 /// 408 RequestToken id; 409 /// 410 Optional!JSONValue result; 411 /// 412 Optional!ResponseError error; 413 } 414 415 alias DocumentUri = string; 416 417 enum EolType 418 { 419 cr, 420 lf, 421 crlf 422 } 423 424 string toString(EolType eol) 425 { 426 final switch (eol) 427 { 428 case EolType.cr: 429 return "\r"; 430 case EolType.lf: 431 return "\n"; 432 case EolType.crlf: 433 return "\r\n"; 434 } 435 } 436 437 struct Position 438 { 439 /// Zero-based line & character offset (UTF-16 codepoints) 440 uint line, character; 441 442 int opCmp(const Position other) const 443 { 444 if (line < other.line) 445 return -1; 446 if (line > other.line) 447 return 1; 448 if (character < other.character) 449 return -1; 450 if (character > other.character) 451 return 1; 452 return 0; 453 } 454 455 const JSONValue _toJSON() 456 { 457 return JSONValue(["line": JSONValue(line), "character": JSONValue(character)]); 458 } 459 460 static Position _fromJSON(const JSONValue val) 461 { 462 import std.exception : enforce; 463 464 enforce(val.type == JSONType.object); 465 auto line = val.object.get("line", JSONValue.init); 466 auto character = val.object.get("character", JSONValue.init); 467 468 uint iline, icharacter; 469 470 if (line.type == JSONType.integer) 471 iline = cast(uint)line.integer; 472 else if (line.type == JSONType.uinteger) 473 iline = cast(uint)line.uinteger; 474 else 475 throw new JSONException("Position['line'] is not an integer"); 476 477 if (character.type == JSONType.integer) 478 icharacter = cast(uint)character.integer; 479 else if (character.type == JSONType.uinteger) 480 icharacter = cast(uint)character.uinteger; 481 else 482 throw new JSONException("Position['character'] is not an integer"); 483 484 return Position(iline, icharacter); 485 } 486 } 487 488 static assert(__traits(compiles, Position.init._toJSON())); 489 static assert(__traits(compiles, Position._fromJSON(JSONValue.init))); 490 491 struct TextRange 492 { 493 union 494 { 495 struct 496 { 497 Position start; 498 Position end; 499 } 500 501 Position[2] range; 502 } 503 504 enum all = TextRange(0, 0, int.max, int.max); // int.max ought to be enough 505 506 alias range this; 507 508 this(Num)(Num startLine, Num startCol, Num endLine, Num endCol) if (isNumeric!Num) 509 { 510 this(Position(cast(uint) startLine, cast(uint) startCol), 511 Position(cast(uint) endLine, cast(uint) endCol)); 512 } 513 514 this(Position start, Position end) 515 { 516 this.start = start; 517 this.end = end; 518 } 519 520 this(Position[2] range) 521 { 522 this.range = range; 523 } 524 525 this(Position pos) 526 { 527 this.start = pos; 528 this.end = pos; 529 } 530 531 /// Returns: true if this range contains the position or the position is at 532 /// the edges of this range. 533 bool contains(Position position) 534 { 535 int minLine = start.line; 536 int minCol = start.character; 537 int maxLine = end.line; 538 int maxCol = end.character; 539 540 return !(position.line < minLine || position.line > maxLine 541 || (position.line == minLine && position.character < minCol) 542 || (position.line == maxLine && position.character > maxCol)); 543 } 544 545 /// Returns: true if text range `a` and `b` intersect with at least one character. 546 /// This function is commutative (a·b == b·a) 547 bool intersects(const TextRange b) 548 { 549 return start < b.end && end > b.start; 550 } 551 552 /// 553 unittest 554 { 555 bool test(TextRange a, TextRange b) 556 { 557 bool res = a.intersects(b); 558 // test commutativity 559 assert(res == b.intersects(a)); 560 return res; 561 } 562 563 assert(test(TextRange(10, 4, 20, 3), TextRange(20, 2, 30, 1))); 564 assert(!test(TextRange(10, 4, 20, 3), TextRange(20, 3, 30, 1))); 565 assert(test(TextRange(10, 4, 20, 3), TextRange(12, 3, 14, 1))); 566 assert(!test(TextRange(10, 4, 20, 3), TextRange(9, 3, 10, 4))); 567 assert(test(TextRange(10, 4, 20, 3), TextRange(9, 3, 10, 5))); 568 assert(test(TextRange(10, 4, 20, 3), TextRange(10, 4, 20, 3))); 569 assert(test(TextRange(0, 0, 0, 1), TextRange(0, 0, uint.max, uint.max))); 570 assert(!test(TextRange(0, 0, 0, 1), TextRange(uint.max, uint.max, uint.max, uint.max))); 571 } 572 573 const JSONValue _toJSON() 574 { 575 import painlessjson : toJSON; 576 577 return JSONValue([ 578 "start": start.toJSON, 579 "end": end.toJSON 580 ]); 581 } 582 583 static TextRange _fromJSON(const JSONValue val) 584 { 585 import painlessjson : fromJSON; 586 587 return TextRange(val.object["start"].fromJSON!Position, val.object["end"].fromJSON!Position); 588 } 589 } 590 591 static assert(__traits(compiles, TextRange.init._toJSON())); 592 static assert(__traits(compiles, TextRange._fromJSON(JSONValue.init))); 593 594 struct Location 595 { 596 DocumentUri uri; 597 TextRange range; 598 } 599 600 struct Diagnostic 601 { 602 mixin StrictOptionalSerializer; 603 604 TextRange range; 605 Optional!DiagnosticSeverity severity; 606 Optional!JSONValue code; 607 Optional!string source; 608 string message; 609 Optional!(DiagnosticRelatedInformation[]) relatedInformation; 610 Optional!(DiagnosticTag[]) tags; 611 } 612 613 struct DiagnosticRelatedInformation 614 { 615 Location location; 616 string message; 617 } 618 619 enum DiagnosticSeverity 620 { 621 error = 1, 622 warning, 623 information, 624 hint 625 } 626 627 enum DiagnosticTag 628 { 629 unnecessary = 1, 630 deprecated_ 631 } 632 633 struct Command 634 { 635 string title; 636 string command; 637 JSONValue[] arguments; 638 } 639 640 struct TextEdit 641 { 642 TextRange range; 643 string newText; 644 645 this(TextRange range, string newText) 646 { 647 this.range = range; 648 this.newText = newText; 649 } 650 651 this(Position[2] range, string newText) 652 { 653 this.range = TextRange(range); 654 this.newText = newText; 655 } 656 657 const JSONValue _toJSON() 658 { 659 return JSONValue(["range": range._toJSON, "newText": JSONValue(newText)]); 660 } 661 662 static TextEdit _fromJSON(const JSONValue val) 663 { 664 TextEdit ret; 665 ret.range = TextRange._fromJSON(val["range"]); 666 ret.newText = val["newText"].str; 667 return ret; 668 } 669 } 670 671 static assert(__traits(compiles, TextEdit.init._toJSON())); 672 static assert(__traits(compiles, TextEdit._fromJSON(JSONValue.init))); 673 674 unittest 675 { 676 assert(toJSON(TextEdit([Position(0, 0), Position(4, 4)], "hello\nworld!")) == JSONValue([ 677 "range": JSONValue([ 678 "start": JSONValue(["line":JSONValue(0), "character":JSONValue(0)]), 679 "end": JSONValue(["line":JSONValue(4), "character":JSONValue(4)]) 680 ]), 681 "newText": JSONValue("hello\nworld!") 682 ])); 683 assert(fromJSON!TextEdit(toJSON(TextEdit([Position(0, 0), Position(4, 4)], "hello\nworld!"))) == TextEdit([Position(0, 0), Position(4, 4)], "hello\nworld!")); 684 } 685 686 struct CreateFileOptions 687 { 688 mixin StrictOptionalSerializer; 689 690 Optional!bool overwrite; 691 Optional!bool ignoreIfExists; 692 } 693 694 struct CreateFile 695 { 696 mixin StrictOptionalSerializer; 697 698 string uri; 699 Optional!CreateFileOptions options; 700 string kind = "create"; 701 } 702 703 struct RenameFileOptions 704 { 705 mixin StrictOptionalSerializer; 706 707 Optional!bool overwrite; 708 Optional!bool ignoreIfExists; 709 } 710 711 struct RenameFile 712 { 713 mixin StrictOptionalSerializer; 714 715 string oldUri; 716 string newUri; 717 Optional!RenameFileOptions options; 718 string kind = "rename"; 719 } 720 721 struct DeleteFileOptions 722 { 723 mixin StrictOptionalSerializer; 724 725 Optional!bool recursive; 726 Optional!bool ignoreIfNotExists; 727 } 728 729 struct DeleteFile 730 { 731 mixin StrictOptionalSerializer; 732 733 string uri; 734 Optional!DeleteFileOptions options; 735 string kind = "delete"; 736 } 737 738 struct TextDocumentEdit 739 { 740 VersionedTextDocumentIdentifier textDocument; 741 TextEdit[] edits; 742 } 743 744 alias TextEditCollection = TextEdit[]; 745 746 struct WorkspaceEdit 747 { 748 mixin StrictOptionalSerializer; 749 750 TextEditCollection[DocumentUri] changes; 751 752 Optional!JSONValue documentChanges; 753 } 754 755 struct TextDocumentIdentifier 756 { 757 DocumentUri uri; 758 } 759 760 struct VersionedTextDocumentIdentifier 761 { 762 DocumentUri uri; 763 @SerializedName("version") long version_; 764 } 765 766 struct TextDocumentItem 767 { 768 DocumentUri uri; 769 string languageId; 770 @SerializedName("version") long version_; 771 string text; 772 } 773 774 struct TextDocumentPositionParams 775 { 776 TextDocumentIdentifier textDocument; 777 Position position; 778 } 779 780 struct DocumentFilter 781 { 782 mixin StrictOptionalSerializer; 783 784 Optional!string language; 785 Optional!string scheme; 786 Optional!string pattern; 787 } 788 789 alias DocumentSelector = DocumentFilter[]; 790 791 struct InitializeParams 792 { 793 int processId; 794 string rootPath; 795 DocumentUri rootUri; 796 JSONValue initializationOptions; 797 ClientCapabilities capabilities; 798 string trace = "off"; 799 WorkspaceFolder[] workspaceFolders; 800 } 801 802 struct DynamicRegistration 803 { 804 mixin StrictOptionalSerializer; 805 806 Optional!bool dynamicRegistration; 807 } 808 809 enum ResourceOperationKind : string 810 { 811 create = "create", 812 rename = "rename", 813 delete_ = "delete" 814 } 815 816 enum FailureHandlingKind : string 817 { 818 abort = "abort", 819 transactional = "transactional", 820 textOnlyTransactional = "textOnlyTransactional", 821 undo = "undo" 822 } 823 824 struct WorkspaceEditClientCapabilities 825 { 826 mixin StrictOptionalSerializer; 827 828 Optional!bool documentChanges; 829 Optional!(string[]) resourceOperations; 830 Optional!string failureHandling; 831 } 832 833 struct WorkspaceClientCapabilities 834 { 835 mixin StrictOptionalSerializer; 836 837 bool applyEdit; 838 Optional!WorkspaceEditClientCapabilities workspaceEdit; 839 Optional!DynamicRegistration didChangeConfiguration; 840 Optional!DynamicRegistration didChangeWatchedFiles; 841 Optional!DynamicRegistration symbol; 842 Optional!DynamicRegistration executeCommand; 843 Optional!bool workspaceFolders; 844 Optional!bool configuration; 845 } 846 847 struct TextDocumentClientCapabilities 848 { 849 mixin StrictOptionalSerializer; 850 851 struct SyncInfo 852 { 853 mixin StrictOptionalSerializer; 854 855 Optional!bool dynamicRegistration; 856 Optional!bool willSave; 857 Optional!bool willSaveWaitUntil; 858 Optional!bool didSave; 859 } 860 861 struct CompletionInfo 862 { 863 mixin StrictOptionalSerializer; 864 865 struct CompletionItem 866 { 867 mixin StrictOptionalSerializer; 868 869 Optional!bool snippetSupport; 870 Optional!bool commitCharactersSupport; 871 //Optional!(MarkupKind[]) documentationFormat; 872 Optional!bool deprecatedSupport; 873 Optional!bool preselectSupport; 874 Optional!bool insertReplaceSupport; 875 Optional!bool labelDetailsSupport; 876 } 877 878 struct CompletionItemKindSet 879 { 880 mixin StrictOptionalSerializer; 881 882 // CompletionItemKind[] 883 Optional!(int[]) valueSet; 884 } 885 886 Optional!bool dynamicRegistration; 887 Optional!CompletionItem completionItem; 888 Optional!CompletionItemKindSet completionItemKind; 889 Optional!bool contextSupport; 890 } 891 892 struct SignatureHelpInfo 893 { 894 struct SignatureInformationInfo 895 { 896 struct ParameterInformationInfo 897 { 898 mixin StrictOptionalSerializer; 899 900 Optional!bool labelOffsetSupport; 901 } 902 903 mixin StrictOptionalSerializer; 904 905 // MarkupKind[] 906 Optional!(string[]) documentationFormat; 907 Optional!ParameterInformationInfo parameterInformation; 908 } 909 910 mixin StrictOptionalSerializer; 911 912 Optional!bool dynamicRegistration; 913 Optional!SignatureInformationInfo signatureInformation; 914 915 @SerializeIgnore bool supportsLabelOffset() @property 916 { 917 if (signatureInformation.isNull || signatureInformation.parameterInformation.isNull 918 || signatureInformation.parameterInformation.labelOffsetSupport.isNull) 919 return false; 920 return signatureInformation.parameterInformation.labelOffsetSupport.get; 921 } 922 } 923 924 struct DocumentSymbolInfo 925 { 926 mixin StrictOptionalSerializer; 927 928 struct SymbolKindSet 929 { 930 mixin StrictOptionalSerializer; 931 932 // SymbolKind[] 933 Optional!(int[]) valueSet; 934 } 935 936 Optional!bool dynamicRegistration; 937 Optional!SymbolKindSet symbolKind; 938 Optional!bool hierarchicalDocumentSymbolSupport; 939 } 940 941 struct PublishDiagnosticsCap 942 { 943 mixin StrictOptionalSerializer; 944 945 Optional!bool relatedInformation; 946 } 947 948 struct CodeActionClientCapabilities 949 { 950 struct CodeActionLiteralSupport 951 { 952 struct CodeActionKinds 953 { 954 // CodeActionKind[] 955 string[] valueSet; 956 } 957 958 CodeActionKinds codeActionKind; 959 } 960 961 mixin StrictOptionalSerializer; 962 963 Optional!bool dynamicRegistration; 964 Optional!CodeActionLiteralSupport codeActionLiteralSupport; 965 } 966 967 Optional!SyncInfo synchronization; 968 Optional!CompletionInfo completion; 969 Optional!DynamicRegistration hover; 970 Optional!SignatureHelpInfo signatureHelp; 971 Optional!DynamicRegistration references; 972 Optional!DynamicRegistration documentHighlight; 973 Optional!DocumentSymbolInfo documentSymbol; 974 Optional!DynamicRegistration formatting; 975 Optional!DynamicRegistration rangeFormatting; 976 Optional!DynamicRegistration onTypeFormatting; 977 Optional!DynamicRegistration definition; 978 Optional!DynamicRegistration typeDefinition; 979 Optional!DynamicRegistration implementation; 980 Optional!CodeActionClientCapabilities codeAction; 981 Optional!DynamicRegistration codeLens; 982 Optional!DynamicRegistration documentLink; 983 Optional!DynamicRegistration colorProvider; 984 Optional!DynamicRegistration rename; 985 Optional!PublishDiagnosticsCap publishDiagnostics; 986 } 987 988 enum CodeActionKind : string 989 { 990 empty = "", 991 quickfix = "quickfix", 992 refactor = "refactor", 993 refactorExtract = "refactor.extract", 994 refactorInline = "refactor.inline", 995 refactorRewrite = "refactor.rewrite", 996 refactorSource = "source", 997 sourceOrganizeImports = "source.organizeImports", 998 } 999 1000 struct CodeAction 1001 { 1002 mixin StrictOptionalSerializer; 1003 1004 this(Command command) 1005 { 1006 title = command.title; 1007 this.command = command; 1008 } 1009 1010 this(string title, WorkspaceEdit edit) 1011 { 1012 this.title = title; 1013 this.edit = edit; 1014 } 1015 1016 string title; 1017 // CodeActionKind 1018 Optional!string kind; 1019 Optional!(Diagnostic[]) diagnostics; 1020 Optional!bool isPreferred; 1021 Optional!WorkspaceEdit edit; 1022 Optional!Command command; 1023 } 1024 1025 struct ClientCapabilities 1026 { 1027 mixin StrictOptionalSerializer; 1028 1029 Optional!WorkspaceClientCapabilities workspace; 1030 Optional!TextDocumentClientCapabilities textDocument; 1031 JSONValue experimental; 1032 } 1033 1034 unittest 1035 { 1036 string json = q{{ 1037 "workspace": { 1038 "configuration": true 1039 } 1040 }}; 1041 auto caps = json.parseJSON.fromJSON!ClientCapabilities; 1042 assert(caps.workspace.configuration); 1043 } 1044 1045 struct InitializeResult 1046 { 1047 ServerCapabilities capabilities; 1048 } 1049 1050 struct InitializeError 1051 { 1052 bool retry; 1053 } 1054 1055 enum TextDocumentSyncKind 1056 { 1057 none, 1058 full, 1059 incremental 1060 } 1061 1062 struct CompletionOptions 1063 { 1064 mixin StrictOptionalSerializer; 1065 1066 struct CompletionItem 1067 { 1068 mixin StrictOptionalSerializer; 1069 1070 Optional!bool labelDetailsSupport; 1071 } 1072 1073 bool resolveProvider; 1074 string[] triggerCharacters; 1075 Optional!CompletionItem completionItem; 1076 } 1077 1078 struct SignatureHelpOptions 1079 { 1080 string[] triggerCharacters; 1081 } 1082 1083 struct CodeLensOptions 1084 { 1085 bool resolveProvider; 1086 } 1087 1088 struct DocumentOnTypeFormattingOptions 1089 { 1090 mixin StrictOptionalSerializer; 1091 1092 string firstTriggerCharacter; 1093 Optional!(string[]) moreTriggerCharacter; 1094 } 1095 1096 struct DocumentLinkOptions 1097 { 1098 bool resolveProvider; 1099 } 1100 1101 struct ColorProviderOptions 1102 { 1103 } 1104 1105 struct ExecuteCommandOptions 1106 { 1107 string[] commands; 1108 } 1109 1110 struct SaveOptions 1111 { 1112 bool includeText; 1113 } 1114 1115 struct TextDocumentSyncOptions 1116 { 1117 bool openClose; 1118 int change; 1119 bool willSave; 1120 bool willSaveWaitUntil; 1121 SaveOptions save; 1122 } 1123 1124 struct ServerCapabilities 1125 { 1126 mixin StrictOptionalSerializer; 1127 1128 JSONValue textDocumentSync; 1129 bool hoverProvider; 1130 Optional!CompletionOptions completionProvider; 1131 Optional!SignatureHelpOptions signatureHelpProvider; 1132 bool definitionProvider; 1133 Optional!bool typeDefinitionProvider; 1134 Optional!bool implementationProvider; 1135 bool referencesProvider; 1136 bool documentHighlightProvider; 1137 bool documentSymbolProvider; 1138 bool workspaceSymbolProvider; 1139 bool codeActionProvider; 1140 Optional!CodeLensOptions codeLensProvider; 1141 bool documentFormattingProvider; 1142 bool documentRangeFormattingProvider; 1143 Optional!DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; 1144 bool renameProvider; 1145 Optional!DocumentLinkOptions documentLinkProvider; 1146 Optional!ColorProviderOptions colorProvider; 1147 Optional!ExecuteCommandOptions executeCommandProvider; 1148 Optional!ServerWorkspaceCapabilities workspace; 1149 JSONValue experimental; 1150 } 1151 1152 struct ServerWorkspaceCapabilities 1153 { 1154 mixin StrictOptionalSerializer; 1155 1156 struct WorkspaceFolders 1157 { 1158 mixin StrictOptionalSerializer; 1159 1160 Optional!bool supported; 1161 Optional!bool changeNotifications; 1162 } 1163 1164 Optional!WorkspaceFolders workspaceFolders; 1165 } 1166 1167 struct ShowMessageParams 1168 { 1169 MessageType type; 1170 string message; 1171 } 1172 1173 struct ShowMessageRequestParams 1174 { 1175 mixin StrictOptionalSerializer; 1176 1177 MessageType type; 1178 string message; 1179 Optional!(MessageActionItem[]) actions; 1180 } 1181 1182 struct MessageActionItem 1183 { 1184 string title; 1185 } 1186 1187 struct LogMessageParams 1188 { 1189 MessageType type; 1190 string message; 1191 } 1192 1193 struct Registration 1194 { 1195 string id; 1196 string method; 1197 JSONValue registerOptions; 1198 } 1199 1200 struct RegistrationParams 1201 { 1202 Registration[] registrations; 1203 } 1204 1205 struct TextDocumentRegistrationOptions 1206 { 1207 mixin StrictOptionalSerializer; 1208 1209 Optional!DocumentSelector documentSelector; 1210 } 1211 1212 struct Unregistration 1213 { 1214 string id; 1215 string method; 1216 } 1217 1218 struct UnregistrationParams 1219 { 1220 Unregistration[] unregistrations; 1221 } 1222 1223 struct DidChangeConfigurationParams 1224 { 1225 JSONValue settings; 1226 } 1227 1228 struct ConfigurationParams 1229 { 1230 ConfigurationItem[] items; 1231 } 1232 1233 struct ConfigurationItem 1234 { 1235 mixin StrictOptionalSerializer; 1236 1237 Optional!string scopeUri; 1238 Optional!string section; 1239 } 1240 1241 struct DidOpenTextDocumentParams 1242 { 1243 TextDocumentItem textDocument; 1244 } 1245 1246 struct DidChangeTextDocumentParams 1247 { 1248 VersionedTextDocumentIdentifier textDocument; 1249 TextDocumentContentChangeEvent[] contentChanges; 1250 } 1251 1252 struct TextDocumentContentChangeEvent 1253 { 1254 mixin StrictOptionalSerializer; 1255 1256 Optional!TextRange range; 1257 Optional!int rangeLength; 1258 string text; 1259 } 1260 1261 struct TextDocumentChangeRegistrationOptions 1262 { 1263 mixin StrictOptionalSerializer; 1264 1265 Optional!DocumentSelector documentSelector; 1266 TextDocumentSyncKind syncKind; 1267 } 1268 1269 struct WillSaveTextDocumentParams 1270 { 1271 TextDocumentIdentifier textDocument; 1272 TextDocumentSaveReason reason; 1273 } 1274 1275 enum TextDocumentSaveReason 1276 { 1277 manual = 1, 1278 afterDelay, 1279 focusOut 1280 } 1281 1282 struct DidSaveTextDocumentParams 1283 { 1284 mixin StrictOptionalSerializer; 1285 1286 TextDocumentIdentifier textDocument; 1287 Optional!string text; 1288 } 1289 1290 struct TextDocumentSaveRegistrationOptions 1291 { 1292 mixin StrictOptionalSerializer; 1293 1294 Optional!DocumentSelector documentSelector; 1295 bool includeText; 1296 } 1297 1298 struct DidCloseTextDocumentParams 1299 { 1300 TextDocumentIdentifier textDocument; 1301 } 1302 1303 struct FileSystemWatcher 1304 { 1305 mixin StrictOptionalSerializer; 1306 1307 string globPattern; 1308 Optional!WatchKind kind; 1309 } 1310 1311 enum WatchKind 1312 { 1313 create = 1, 1314 change = 2, 1315 delete_ = 4 1316 } 1317 1318 struct DidChangeWatchedFilesParams 1319 { 1320 FileEvent[] changes; 1321 } 1322 1323 struct FileEvent 1324 { 1325 DocumentUri uri; 1326 FileChangeType type; 1327 } 1328 1329 enum FileChangeType 1330 { 1331 created = 1, 1332 changed, 1333 deleted 1334 } 1335 1336 struct PublishDiagnosticsParams 1337 { 1338 DocumentUri uri; 1339 Diagnostic[] diagnostics; 1340 } 1341 1342 struct CompletionList 1343 { 1344 bool isIncomplete; 1345 CompletionItem[] items; 1346 } 1347 1348 enum InsertTextFormat 1349 { 1350 plainText = 1, 1351 snippet 1352 } 1353 1354 struct CompletionItemLabelDetails 1355 { 1356 mixin StrictOptionalSerializer; 1357 1358 /** 1359 * An optional string which is rendered less prominently directly after 1360 * {@link CompletionItemLabel.label label}, without any spacing. Should be 1361 * used for function signatures or type annotations. 1362 */ 1363 Optional!string detail; 1364 1365 /** 1366 * An optional string which is rendered less prominently after 1367 * {@link CompletionItemLabel.detail}. Should be used for fully qualified 1368 * names or file path. 1369 */ 1370 Optional!string description; 1371 } 1372 1373 struct CompletionItem 1374 { 1375 mixin StrictOptionalSerializer; 1376 1377 string label; 1378 Optional!CompletionItemKind kind; 1379 Optional!string detail; 1380 Optional!MarkupContent documentation; 1381 @SerializedName("deprecated") Optional!bool deprecated_; 1382 Optional!bool preselect; 1383 Optional!string sortText; 1384 Optional!string filterText; 1385 Optional!string insertText; 1386 Optional!InsertTextFormat insertTextFormat; 1387 Optional!TextEdit textEdit; 1388 Optional!(TextEdit[]) additionalTextEdits; 1389 Optional!(string[]) commitCharacters; 1390 Optional!Command command; 1391 JSONValue data; 1392 Optional!CompletionItemLabelDetails labelDetails; 1393 1394 string effectiveInsertText() const 1395 { 1396 return insertText.isNull ? label : insertText.get; 1397 } 1398 } 1399 1400 enum CompletionItemKind 1401 { 1402 text = 1, 1403 method, 1404 function_, 1405 constructor, 1406 field, 1407 variable, 1408 class_, 1409 interface_, 1410 module_, 1411 property, 1412 unit, 1413 value, 1414 enum_, 1415 keyword, 1416 snippet, 1417 color, 1418 file, 1419 reference, 1420 folder, 1421 enumMember, 1422 constant, 1423 struct_, 1424 event, 1425 operator, 1426 typeParameter 1427 } 1428 1429 struct CompletionRegistrationOptions 1430 { 1431 mixin StrictOptionalSerializer; 1432 1433 Optional!DocumentSelector documentSelector; 1434 Optional!(string[]) triggerCharacters; 1435 bool resolveProvider; 1436 } 1437 1438 struct Hover 1439 { 1440 mixin StrictOptionalSerializer; 1441 1442 ArrayOrSingle!MarkedString contents; 1443 Optional!TextRange range; 1444 } 1445 1446 struct MarkedString 1447 { 1448 string value; 1449 string language; 1450 1451 const JSONValue _toJSON() 1452 { 1453 if (!language.length) 1454 return JSONValue(value); 1455 else 1456 return JSONValue([ 1457 "value": JSONValue(value), 1458 "language": JSONValue(language) 1459 ]); 1460 } 1461 1462 static MarkedString fromJSON(JSONValue val) 1463 { 1464 MarkedString ret; 1465 if (val.type == JSONType..string) 1466 ret.value = val.str; 1467 else 1468 { 1469 ret.value = val["value"].str; 1470 ret.language = val["language"].str; 1471 } 1472 return ret; 1473 } 1474 } 1475 1476 enum MarkupKind : string 1477 { 1478 plaintext = "plaintext", 1479 markdown = "markdown" 1480 } 1481 1482 struct MarkupContent 1483 { 1484 string kind; 1485 string value; 1486 1487 this(MarkupKind kind, string value) 1488 { 1489 this.kind = kind; 1490 this.value = value; 1491 } 1492 1493 this(string text) 1494 { 1495 kind = MarkupKind.plaintext; 1496 value = text; 1497 } 1498 1499 this(MarkedString[] markup) 1500 { 1501 kind = MarkupKind.markdown; 1502 foreach (block; markup) 1503 { 1504 if (block.language.length) 1505 { 1506 value ~= "```" ~ block.language ~ "\n"; 1507 value ~= block.value; 1508 value ~= "```"; 1509 } 1510 else 1511 value ~= block.value; 1512 value ~= "\n\n"; 1513 } 1514 } 1515 } 1516 1517 struct SignatureHelp 1518 { 1519 mixin StrictOptionalSerializer; 1520 1521 SignatureInformation[] signatures; 1522 Optional!int activeSignature; 1523 Optional!int activeParameter; 1524 1525 this(SignatureInformation[] signatures) 1526 { 1527 this.signatures = signatures; 1528 } 1529 1530 this(SignatureInformation[] signatures, int activeSignature, int activeParameter) 1531 { 1532 this.signatures = signatures; 1533 this.activeSignature = activeSignature; 1534 this.activeParameter = activeParameter; 1535 } 1536 } 1537 1538 struct SignatureInformation 1539 { 1540 mixin StrictOptionalSerializer; 1541 1542 string label; 1543 Optional!MarkupContent documentation; 1544 Optional!(ParameterInformation[]) parameters; 1545 } 1546 1547 struct ParameterInformation 1548 { 1549 mixin StrictOptionalSerializer; 1550 1551 JSONValue label; 1552 Optional!MarkupContent documentation; 1553 } 1554 1555 struct SignatureHelpRegistrationOptions 1556 { 1557 mixin StrictOptionalSerializer; 1558 1559 Optional!DocumentSelector documentSelector; 1560 Optional!(string[]) triggerCharacters; 1561 } 1562 1563 struct ReferenceParams 1564 { 1565 TextDocumentIdentifier textDocument; 1566 Position position; 1567 ReferenceContext context; 1568 } 1569 1570 struct ReferenceContext 1571 { 1572 bool includeDeclaration; 1573 } 1574 1575 struct DocumentHighlightParams 1576 { 1577 TextDocumentIdentifier textDocument; 1578 Position position; 1579 } 1580 1581 struct DocumentHighlight 1582 { 1583 mixin StrictOptionalSerializer; 1584 1585 TextRange range; 1586 Optional!DocumentHighlightKind kind; 1587 } 1588 1589 enum DocumentHighlightKind 1590 { 1591 text = 1, 1592 read, 1593 write 1594 } 1595 1596 struct DocumentSymbolParams 1597 { 1598 TextDocumentIdentifier textDocument; 1599 } 1600 1601 struct SymbolInformation 1602 { 1603 mixin StrictOptionalSerializer; 1604 1605 string name; 1606 SymbolKind kind; 1607 Location location; 1608 Optional!string containerName; 1609 } 1610 1611 struct DocumentSymbol 1612 { 1613 mixin StrictOptionalSerializer; 1614 1615 string name; 1616 Optional!string detail; 1617 SymbolKind kind; 1618 @SerializedName("deprecated") Optional!bool deprecated_; 1619 TextRange range; 1620 TextRange selectionRange; 1621 DocumentSymbol[] children; 1622 @SerializeIgnore string parent; 1623 } 1624 1625 enum SymbolKind 1626 { 1627 file = 1, 1628 module_, 1629 namespace, 1630 package_, 1631 class_, 1632 method, 1633 property, 1634 field, 1635 constructor, 1636 enum_, 1637 interface_, 1638 function_, 1639 variable, 1640 constant, 1641 string, 1642 number, 1643 boolean, 1644 array, 1645 object, 1646 key, 1647 null_, 1648 enumMember, 1649 struct_, 1650 event, 1651 operator, 1652 typeParameter 1653 } 1654 1655 struct WorkspaceSymbolParams 1656 { 1657 string query; 1658 } 1659 1660 struct CodeActionParams 1661 { 1662 TextDocumentIdentifier textDocument; 1663 TextRange range; 1664 CodeActionContext context; 1665 } 1666 1667 struct CodeActionContext 1668 { 1669 Diagnostic[] diagnostics; 1670 } 1671 1672 struct CodeLensParams 1673 { 1674 TextDocumentIdentifier textDocument; 1675 } 1676 1677 struct CodeLens 1678 { 1679 mixin StrictOptionalSerializer; 1680 1681 TextRange range; 1682 Optional!Command command; 1683 JSONValue data; 1684 } 1685 1686 struct CodeLensRegistrationOptions 1687 { 1688 mixin StrictOptionalSerializer; 1689 1690 Optional!DocumentSelector documentSelector; 1691 bool resolveProvider; 1692 } 1693 1694 struct DocumentLinkParams 1695 { 1696 TextDocumentIdentifier textDocument; 1697 } 1698 1699 struct DocumentLink 1700 { 1701 TextRange range; 1702 DocumentUri target; 1703 } 1704 1705 struct DocumentLinkRegistrationOptions 1706 { 1707 mixin StrictOptionalSerializer; 1708 1709 Optional!DocumentSelector documentSelector; 1710 bool resolveProvider; 1711 } 1712 1713 struct DocumentColorParams 1714 { 1715 TextDocumentIdentifier textDocument; 1716 } 1717 1718 struct ColorInformation 1719 { 1720 TextRange range; 1721 Color color; 1722 } 1723 1724 struct Color 1725 { 1726 double red = 0; 1727 double green = 0; 1728 double blue = 0; 1729 double alpha = 1; 1730 } 1731 1732 struct ColorPresentationParams 1733 { 1734 TextDocumentIdentifier textDocument; 1735 Color color; 1736 TextRange range; 1737 } 1738 1739 struct ColorPresentation 1740 { 1741 mixin StrictOptionalSerializer; 1742 1743 string label; 1744 Optional!TextEdit textEdit; 1745 Optional!(TextEdit[]) additionalTextEdits; 1746 } 1747 1748 struct DocumentFormattingParams 1749 { 1750 TextDocumentIdentifier textDocument; 1751 FormattingOptions options; 1752 } 1753 1754 struct FormattingOptions 1755 { 1756 int tabSize; 1757 bool insertSpaces; 1758 JSONValue data; 1759 } 1760 1761 struct DocumentRangeFormattingParams 1762 { 1763 TextDocumentIdentifier textDocument; 1764 TextRange range; 1765 FormattingOptions options; 1766 } 1767 1768 struct DocumentOnTypeFormattingParams 1769 { 1770 TextDocumentIdentifier textDocument; 1771 Position position; 1772 string ch; 1773 FormattingOptions options; 1774 } 1775 1776 struct DocumentOnTypeFormattingRegistrationOptions 1777 { 1778 mixin StrictOptionalSerializer; 1779 1780 Optional!DocumentSelector documentSelector; 1781 string firstTriggerCharacter; 1782 Optional!(string[]) moreTriggerCharacter; 1783 } 1784 1785 struct RenameParams 1786 { 1787 TextDocumentIdentifier textDocument; 1788 Position position; 1789 string newName; 1790 } 1791 1792 struct ExecuteCommandParams 1793 { 1794 mixin StrictOptionalSerializer; 1795 1796 string command; 1797 Optional!(JSONValue[]) arguments; 1798 } 1799 1800 struct ExecuteCommandRegistrationOptions 1801 { 1802 string[] commands; 1803 } 1804 1805 struct ApplyWorkspaceEditParams 1806 { 1807 WorkspaceEdit edit; 1808 } 1809 1810 struct ApplyWorkspaceEditResponse 1811 { 1812 bool applied; 1813 } 1814 1815 struct WorkspaceFolder 1816 { 1817 string uri; 1818 string name; 1819 } 1820 1821 struct DidChangeWorkspaceFoldersParams 1822 { 1823 WorkspaceFoldersChangeEvent event; 1824 } 1825 1826 struct WorkspaceFoldersChangeEvent 1827 { 1828 WorkspaceFolder[] added; 1829 WorkspaceFolder[] removed; 1830 } 1831 1832 struct TraceParams 1833 { 1834 string value; 1835 }