1 module served.protocol; 2 3 import std.conv; 4 import std.json; 5 import std.traits; 6 7 import painlessjson; 8 9 struct Optional(T) 10 { 11 bool isNull = true; 12 T value; 13 14 this(T val) 15 { 16 value = val; 17 isNull = false; 18 } 19 20 this(U)(U val) 21 { 22 value = val; 23 isNull = false; 24 } 25 26 this(typeof(null)) 27 { 28 isNull = true; 29 } 30 31 void opAssign(typeof(null)) 32 { 33 nullify(); 34 } 35 36 void opAssign(T val) 37 { 38 isNull = false; 39 value = val; 40 } 41 42 void opAssign(U)(U val) 43 { 44 isNull = false; 45 value = val; 46 } 47 48 void nullify() 49 { 50 isNull = true; 51 } 52 53 string toString() const 54 { 55 if (isNull) 56 return "null(" ~ T.stringof ~ ")"; 57 else 58 return value.to!string; 59 } 60 61 const JSONValue _toJSON() 62 { 63 if (isNull) 64 return JSONValue(null); 65 else 66 return value.toJSON; 67 } 68 69 static Optional!T _fromJSON(JSONValue val) 70 { 71 Optional!T ret; 72 ret.isNull = false; 73 ret.value = val.fromJSON!T; 74 return ret; 75 } 76 77 ref T get() 78 { 79 return value; 80 } 81 82 alias value this; 83 } 84 85 Optional!T opt(T)(T val) 86 { 87 return Optional!T(val); 88 } 89 90 struct ArrayOrSingle(T) 91 { 92 T[] value; 93 94 this(T val) 95 { 96 value = [val]; 97 } 98 99 this(T[] val) 100 { 101 value = val; 102 } 103 104 void opAssign(T val) 105 { 106 value = [val]; 107 } 108 109 void opAssign(T[] val) 110 { 111 value = val; 112 } 113 114 const JSONValue _toJSON() 115 { 116 if (value.length == 1) 117 return value[0].toJSON; 118 else 119 return value.toJSON; 120 } 121 122 static ArrayOrSingle!T fromJSON(JSONValue val) 123 { 124 ArrayOrSingle!T ret; 125 if (val.type == JSON_TYPE.ARRAY) 126 ret.value = val.fromJSON!(T[]); 127 else 128 ret.value = [val.fromJSON!T]; 129 return ret; 130 } 131 132 alias value this; 133 } 134 135 struct RequestToken 136 { 137 this(const(JSONValue)* val) 138 { 139 if (!val) 140 { 141 hasData = false; 142 return; 143 } 144 hasData = true; 145 if (val.type == JSON_TYPE.STRING) 146 { 147 isString = true; 148 str = val.str; 149 } 150 else if (val.type == JSON_TYPE.INTEGER) 151 { 152 isString = false; 153 num = val.integer; 154 } 155 else 156 throw new Exception("Invalid ID"); 157 } 158 159 union 160 { 161 string str; 162 long num; 163 } 164 165 bool hasData, isString; 166 167 JSONValue toJSON() 168 { 169 JSONValue ret = null; 170 if (!hasData) 171 return ret; 172 ret = isString ? JSONValue(str) : JSONValue(num); 173 return ret; 174 } 175 176 JSONValue _toJSON()() 177 { 178 pragma(msg, "Attempted painlesstraits.toJSON on RequestToken"); 179 } 180 181 void _fromJSON()(JSONValue val) 182 { 183 pragma(msg, "Attempted painlesstraits.fromJSON on RequestToken"); 184 } 185 186 string toString() 187 { 188 return hasData ? (isString ? str : num.to!string) : "none"; 189 } 190 191 static RequestToken random() 192 { 193 import std.uuid; 194 195 JSONValue id = JSONValue(randomUUID.toString); 196 return RequestToken(&id); 197 } 198 199 bool opEquals(RequestToken b) const 200 { 201 return isString == b.isString && (isString ? str == b.str : num == b.num); 202 } 203 } 204 205 struct RequestMessage 206 { 207 this(JSONValue val) 208 { 209 id = RequestToken("id" in val); 210 method = val["method"].str; 211 auto ptr = "params" in val; 212 if (ptr) 213 params = *ptr; 214 } 215 216 RequestToken id; 217 string method; 218 JSONValue params; 219 220 bool isCancelRequest() 221 { 222 return method == "$/cancelRequest"; 223 } 224 225 JSONValue toJSON() 226 { 227 auto ret = JSONValue(["jsonrpc" : JSONValue("2.0"), "method" : JSONValue(method)]); 228 if (!params.isNull) 229 ret["params"] = params; 230 if (id.hasData) 231 ret["id"] = id.toJSON; 232 return ret; 233 } 234 } 235 236 enum ErrorCode 237 { 238 parseError = -32700, 239 invalidRequest = -32600, 240 methodNotFound = -32601, 241 invalidParams = -32602, 242 internalError = -32603, 243 serverErrorStart = -32099, 244 serverErrorEnd = -32000, 245 serverNotInitialized = -32002, 246 unknownErrorCode = -32001 247 } 248 249 enum MessageType 250 { 251 error = 1, 252 warning, 253 info, 254 log 255 } 256 257 struct ResponseError 258 { 259 ErrorCode code; 260 string message; 261 JSONValue data; 262 263 this(Throwable t) 264 { 265 code = ErrorCode.unknownErrorCode; 266 message = t.msg; 267 data = JSONValue(t.to!string); 268 } 269 270 this(ErrorCode c) 271 { 272 code = c; 273 message = c.to!string; 274 } 275 276 this(ErrorCode c, string msg) 277 { 278 code = c; 279 message = msg; 280 } 281 } 282 283 class MethodException : Exception 284 { 285 this(ResponseError error, string file = __FILE__, size_t line = __LINE__) pure nothrow @nogc @safe 286 { 287 super(error.message, file, line); 288 this.error = error; 289 } 290 291 ResponseError error; 292 } 293 294 struct ResponseMessage 295 { 296 this(RequestToken id, JSONValue result) 297 { 298 this.id = id; 299 this.result = result; 300 } 301 302 this(RequestToken id, ResponseError error) 303 { 304 this.id = id; 305 this.error = error; 306 } 307 308 RequestToken id; 309 JSONValue result; 310 Optional!ResponseError error; 311 } 312 313 alias DocumentUri = string; 314 315 enum EolType 316 { 317 cr, 318 lf, 319 crlf 320 } 321 322 string toString(EolType eol) 323 { 324 final switch (eol) 325 { 326 case EolType.cr: 327 return "\r"; 328 case EolType.lf: 329 return "\n"; 330 case EolType.crlf: 331 return "\r\n"; 332 } 333 } 334 335 struct Position 336 { 337 uint line, character; 338 } 339 340 struct TextRange 341 { 342 union 343 { 344 struct 345 { 346 Position start; 347 Position end; 348 } 349 350 Position[2] range; 351 } 352 353 alias range this; 354 355 this(Num)(Num startLine, Num startCol, Num endLine, Num endCol) if (isNumeric!Num) 356 { 357 this(Position(cast(uint) startLine, cast(uint) startCol), 358 Position(cast(uint) endLine, cast(uint) endCol)); 359 } 360 361 this(Position start, Position end) 362 { 363 this.start = start; 364 this.end = end; 365 } 366 367 this(Position[2] range) 368 { 369 this.range = range; 370 } 371 372 this(Position pos) 373 { 374 this.start = pos; 375 this.end = pos; 376 } 377 } 378 379 struct Location 380 { 381 DocumentUri uri; 382 TextRange range; 383 } 384 385 struct Diagnostic 386 { 387 TextRange range; 388 DiagnosticSeverity severity; 389 JSONValue code; 390 string source; 391 string message; 392 } 393 394 enum DiagnosticSeverity 395 { 396 error = 1, 397 warning, 398 information, 399 hint 400 } 401 402 struct Command 403 { 404 string title; 405 string command; 406 JSONValue[] arguments; 407 } 408 409 struct TextEdit 410 { 411 TextRange range; 412 string newText; 413 } 414 415 alias TextEditCollection = TextEdit[]; 416 417 struct WorkspaceEdit 418 { 419 TextEditCollection[DocumentUri] changes; 420 } 421 422 struct TextDocumentIdentifier 423 { 424 DocumentUri uri; 425 } 426 427 struct VersionedTextDocumentIdentifier 428 { 429 DocumentUri uri; 430 @SerializedName("version") long version_; 431 } 432 433 struct TextDocumentItem 434 { 435 DocumentUri uri; 436 string languageId; 437 @SerializedName("version") long version_; 438 string text; 439 } 440 441 struct TextDocumentPositionParams 442 { 443 TextDocumentIdentifier textDocument; 444 Position position; 445 } 446 447 struct DocumentFilter 448 { 449 Optional!string language; 450 Optional!string scheme; 451 Optional!string pattern; 452 } 453 454 alias DocumentSelector = DocumentFilter[]; 455 456 struct InitializeParams 457 { 458 int processId; 459 string rootPath; 460 DocumentUri rootUri; 461 JSONValue initializationOptions; 462 ClientCapabilities capabilities; 463 string trace = "off"; 464 WorkspaceFolder[] workspaceFolders; 465 } 466 467 struct DynamicRegistration 468 { 469 Optional!bool dynamicRegistration; 470 } 471 472 struct WorkspaceClientCapabilities 473 { 474 bool applyEdit; 475 Optional!DynamicRegistration didChangeConfiguration; 476 Optional!DynamicRegistration didChangeWatchedFiles; 477 Optional!DynamicRegistration symbol; 478 Optional!DynamicRegistration executeCommand; 479 Optional!bool workspaceFolders; 480 Optional!bool configuration; 481 } 482 483 struct TextDocumentClientCapabilities 484 { 485 struct SyncInfo 486 { 487 Optional!bool dynamicRegistration; 488 bool willSave; 489 bool willSaveWaitUntil; 490 bool didSave; 491 } 492 493 struct CompletionInfo 494 { 495 struct CompletionItem 496 { 497 bool snippetSupport; 498 } 499 500 CompletionItem completionItem; 501 } 502 503 struct PublishDiagnosticsCap 504 { 505 Optional!bool relatedInformation; 506 } 507 508 Optional!SyncInfo synchronization; 509 Optional!CompletionInfo completion; 510 Optional!DynamicRegistration hover; 511 Optional!DynamicRegistration signatureHelp; 512 Optional!DynamicRegistration references; 513 Optional!DynamicRegistration documentHighlight; 514 Optional!DynamicRegistration documentSymbol; 515 Optional!DynamicRegistration formatting; 516 Optional!DynamicRegistration rangeFormatting; 517 Optional!DynamicRegistration onTypeFormatting; 518 Optional!DynamicRegistration definition; 519 Optional!DynamicRegistration typeDefinition; 520 Optional!DynamicRegistration implementation; 521 Optional!DynamicRegistration codeAction; 522 Optional!DynamicRegistration codeLens; 523 Optional!DynamicRegistration documentLink; 524 Optional!DynamicRegistration colorProvider; 525 Optional!DynamicRegistration rename; 526 Optional!PublishDiagnosticsCap publishDiagnostics; 527 } 528 529 struct ClientCapabilities 530 { 531 Optional!WorkspaceClientCapabilities workspace; 532 Optional!TextDocumentClientCapabilities textDocument; 533 JSONValue experimental; 534 } 535 536 unittest 537 { 538 string json = q{{ 539 "workspace": { 540 "configuration": true 541 } 542 }}; 543 auto caps = json.parseJSON.fromJSON!ClientCapabilities; 544 assert(caps.workspace.configuration); 545 } 546 547 struct InitializeResult 548 { 549 ServerCapabilities capabilities; 550 } 551 552 struct InitializeError 553 { 554 bool retry; 555 } 556 557 enum TextDocumentSyncKind 558 { 559 none, 560 full, 561 incremental 562 } 563 564 struct CompletionOptions 565 { 566 bool resolveProvider; 567 string[] triggerCharacters; 568 } 569 570 struct SignatureHelpOptions 571 { 572 string[] triggerCharacters; 573 } 574 575 struct CodeLensOptions 576 { 577 bool resolveProvider; 578 } 579 580 struct DocumentOnTypeFormattingOptions 581 { 582 string firstTriggerCharacter; 583 Optional!(string[]) moreTriggerCharacter; 584 } 585 586 struct DocumentLinkOptions 587 { 588 bool resolveProvider; 589 } 590 591 struct ColorProviderOptions 592 { 593 } 594 595 struct ExecuteCommandOptions 596 { 597 string[] commands; 598 } 599 600 struct SaveOptions 601 { 602 bool includeText; 603 } 604 605 struct TextDocumentSyncOptions 606 { 607 bool openClose; 608 int change; 609 bool willSave; 610 bool willSaveWaitUntil; 611 SaveOptions save; 612 } 613 614 struct ServerCapabilities 615 { 616 JSONValue textDocumentSync; 617 bool hoverProvider; 618 Optional!CompletionOptions completionProvider; 619 Optional!SignatureHelpOptions signatureHelpProvider; 620 bool definitionProvider; 621 Optional!bool typeDefinitionProvider; 622 Optional!bool implementationProvider; 623 bool referencesProvider; 624 bool documentHighlightProvider; 625 bool documentSymbolProvider; 626 bool workspaceSymbolProvider; 627 bool codeActionProvider; 628 Optional!CodeLensOptions codeLensProvider; 629 bool documentFormattingProvider; 630 bool documentRangeFormattingProvider; 631 Optional!DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider; 632 bool renameProvider; 633 Optional!DocumentLinkOptions documentLinkProvider; 634 Optional!ColorProviderOptions colorProvider; 635 Optional!ExecuteCommandOptions executeCommandProvider; 636 Optional!ServerWorkspaceCapabilities workspace; 637 JSONValue experimental; 638 } 639 640 struct ServerWorkspaceCapabilities 641 { 642 struct WorkspaceFolders 643 { 644 Optional!bool supported; 645 Optional!bool changeNotifications; 646 } 647 648 Optional!WorkspaceFolders workspaceFolders; 649 } 650 651 struct ShowMessageParams 652 { 653 MessageType type; 654 string message; 655 } 656 657 struct ShowMessageRequestParams 658 { 659 MessageType type; 660 string message; 661 Optional!(MessageActionItem[]) actions; 662 } 663 664 struct MessageActionItem 665 { 666 string title; 667 } 668 669 struct LogMessageParams 670 { 671 MessageType type; 672 string message; 673 } 674 675 struct Registration 676 { 677 string id; 678 string method; 679 JSONValue registerOptions; 680 } 681 682 struct RegistrationParams 683 { 684 Registration[] registrations; 685 } 686 687 struct TextDocumentRegistrationOptions 688 { 689 Optional!DocumentSelector documentSelector; 690 } 691 692 struct Unregistration 693 { 694 string id; 695 string method; 696 } 697 698 struct UnregistrationParams 699 { 700 Unregistration[] unregistrations; 701 } 702 703 struct DidChangeConfigurationParams 704 { 705 JSONValue settings; 706 } 707 708 struct ConfigurationParams 709 { 710 ConfigurationItem[] items; 711 } 712 713 struct ConfigurationItem 714 { 715 Optional!string scopeUri; 716 Optional!string section; 717 } 718 719 struct DidOpenTextDocumentParams 720 { 721 TextDocumentItem textDocument; 722 } 723 724 struct DidChangeTextDocumentParams 725 { 726 VersionedTextDocumentIdentifier textDocument; 727 TextDocumentContentChangeEvent[] contentChanges; 728 } 729 730 struct TextDocumentContentChangeEvent 731 { 732 Optional!TextRange range; 733 Optional!int rangeLength; 734 string text; 735 } 736 737 struct TextDocumentChangeRegistrationOptions 738 { 739 Optional!DocumentSelector documentSelector; 740 TextDocumentSyncKind syncKind; 741 } 742 743 struct WillSaveTextDocumentParams 744 { 745 TextDocumentIdentifier textDocument; 746 TextDocumentSaveReason reason; 747 } 748 749 enum TextDocumentSaveReason 750 { 751 manual = 1, 752 afterDelay, 753 focusOut 754 } 755 756 struct DidSaveTextDocumentParams 757 { 758 TextDocumentIdentifier textDocument; 759 Optional!string text; 760 } 761 762 struct TextDocumentSaveRegistrationOptions 763 { 764 Optional!DocumentSelector documentSelector; 765 bool includeText; 766 } 767 768 struct DidCloseTextDocumentParams 769 { 770 TextDocumentIdentifier textDocument; 771 } 772 773 struct DidChangeWatchedFilesParams 774 { 775 FileEvent[] changes; 776 } 777 778 struct FileEvent 779 { 780 DocumentUri uri; 781 FileChangeType type; 782 } 783 784 enum FileChangeType 785 { 786 created = 1, 787 changed, 788 deleted 789 } 790 791 struct PublishDiagnosticsParams 792 { 793 DocumentUri uri; 794 Diagnostic[] diagnostics; 795 } 796 797 struct CompletionList 798 { 799 bool isIncomplete; 800 CompletionItem[] items; 801 } 802 803 enum InsertTextFormat 804 { 805 plainText = 1, 806 snippet 807 } 808 809 struct CompletionItem 810 { 811 string label; 812 Optional!CompletionItemKind kind; 813 Optional!string detail; 814 Optional!MarkupContent documentation; 815 Optional!string sortText; 816 Optional!string filterText; 817 Optional!string insertText; 818 Optional!InsertTextFormat insertTextFormat; 819 Optional!TextEdit textEdit; 820 Optional!(TextEdit[]) additionalTextEdits; 821 Optional!Command command; 822 JSONValue data; 823 } 824 825 enum CompletionItemKind 826 { 827 text = 1, 828 method, 829 function_, 830 constructor, 831 field, 832 variable, 833 class_, 834 interface_, 835 module_, 836 property, 837 unit, 838 value, 839 enum_, 840 keyword, 841 snippet, 842 color, 843 file, 844 reference 845 } 846 847 struct CompletionRegistrationOptions 848 { 849 Optional!DocumentSelector documentSelector; 850 Optional!(string[]) triggerCharacters; 851 bool resolveProvider; 852 } 853 854 struct Hover 855 { 856 ArrayOrSingle!MarkedString contents; 857 Optional!TextRange range; 858 } 859 860 struct MarkedString 861 { 862 string value; 863 string language; 864 865 const JSONValue _toJSON() 866 { 867 if (!language.length) 868 return JSONValue(value); 869 else 870 return JSONValue(["value" : JSONValue(value), "language" : JSONValue(language)]); 871 } 872 873 static MarkedString fromJSON(JSONValue val) 874 { 875 MarkedString ret; 876 if (val.type == JSON_TYPE.STRING) 877 ret.value = val.str; 878 else 879 { 880 ret.value = val["value"].str; 881 ret.language = val["language"].str; 882 } 883 return ret; 884 } 885 } 886 887 enum MarkupKind : string 888 { 889 plaintext = "plaintext", 890 markdown = "markdown" 891 } 892 893 struct MarkupContent 894 { 895 MarkupKind kind; 896 string value; 897 898 this(string text) 899 { 900 kind = MarkupKind.plaintext; 901 value = text; 902 } 903 904 this(MarkedString[] markup) 905 { 906 kind = MarkupKind.markdown; 907 foreach (block; markup) 908 { 909 if (block.language.length) 910 { 911 value ~= "```" ~ block.language ~ "\n"; 912 value ~= block.value; 913 value ~= "```"; 914 } 915 else 916 value ~= block.value; 917 value ~= "\n\n"; 918 } 919 } 920 } 921 922 struct SignatureHelp 923 { 924 SignatureInformation[] signatures; 925 Optional!int activeSignature; 926 Optional!int activeParameter; 927 928 this(SignatureInformation[] signatures) 929 { 930 this.signatures = signatures; 931 } 932 933 this(SignatureInformation[] signatures, int activeSignature, int activeParameter) 934 { 935 this.signatures = signatures; 936 this.activeSignature = activeSignature; 937 this.activeParameter = activeParameter; 938 } 939 } 940 941 struct SignatureInformation 942 { 943 string label; 944 Optional!MarkupContent documentation; 945 Optional!(ParameterInformation[]) parameters; 946 } 947 948 struct ParameterInformation 949 { 950 string label; 951 Optional!MarkupContent documentation; 952 } 953 954 struct SignatureHelpRegistrationOptions 955 { 956 Optional!DocumentSelector documentSelector; 957 Optional!(string[]) triggerCharacters; 958 } 959 960 struct ReferenceParams 961 { 962 TextDocumentIdentifier textDocument; 963 Position position; 964 ReferenceContext context; 965 } 966 967 struct ReferenceContext 968 { 969 bool includeDeclaration; 970 } 971 972 struct DocumentHighlight 973 { 974 TextRange range; 975 Optional!DocumentHighlightKind kind; 976 } 977 978 enum DocumentHighlightKind 979 { 980 text = 1, 981 read, 982 write 983 } 984 985 struct DocumentSymbolParams 986 { 987 TextDocumentIdentifier textDocument; 988 } 989 990 struct SymbolInformation 991 { 992 string name; 993 SymbolKind kind; 994 Location location; 995 Optional!string containerName; 996 } 997 998 enum SymbolKind 999 { 1000 file = 1, 1001 module_, 1002 namespace, 1003 package_, 1004 class_, 1005 method, 1006 property, 1007 field, 1008 constructor, 1009 enum_, 1010 interface_, 1011 function_, 1012 variable, 1013 constant, 1014 string, 1015 number, 1016 boolean, 1017 array 1018 } 1019 1020 struct WorkspaceSymbolParams 1021 { 1022 string query; 1023 } 1024 1025 struct CodeActionParams 1026 { 1027 TextDocumentIdentifier textDocument; 1028 TextRange range; 1029 CodeActionContext context; 1030 } 1031 1032 struct CodeActionContext 1033 { 1034 Diagnostic[] diagnostics; 1035 } 1036 1037 struct CodeLensParams 1038 { 1039 TextDocumentIdentifier textDocument; 1040 } 1041 1042 struct CodeLens 1043 { 1044 TextRange range; 1045 Optional!Command command; 1046 JSONValue data; 1047 } 1048 1049 struct CodeLensRegistrationOptions 1050 { 1051 Optional!DocumentSelector documentSelector; 1052 bool resolveProvider; 1053 } 1054 1055 struct DocumentLinkParams 1056 { 1057 TextDocumentIdentifier textDocument; 1058 } 1059 1060 struct DocumentLink 1061 { 1062 TextRange range; 1063 DocumentUri target; 1064 } 1065 1066 struct DocumentLinkRegistrationOptions 1067 { 1068 Optional!DocumentSelector documentSelector; 1069 bool resolveProvider; 1070 } 1071 1072 struct DocumentFormattingParams 1073 { 1074 TextDocumentIdentifier textDocument; 1075 FormattingOptions options; 1076 } 1077 1078 struct FormattingOptions 1079 { 1080 int tabSize; 1081 bool insertSpaces; 1082 JSONValue data; 1083 } 1084 1085 struct DocumentRangeFormattingParams 1086 { 1087 TextDocumentIdentifier textDocument; 1088 TextRange range; 1089 FormattingOptions options; 1090 } 1091 1092 struct DocumentOnTypeFormattingParams 1093 { 1094 TextDocumentIdentifier textDocument; 1095 Position position; 1096 string ch; 1097 FormattingOptions options; 1098 } 1099 1100 struct DocumentOnTypeFormattingRegistrationOptions 1101 { 1102 Optional!DocumentSelector documentSelector; 1103 string firstTriggerCharacter; 1104 Optional!(string[]) moreTriggerCharacter; 1105 } 1106 1107 struct RenameParams 1108 { 1109 TextDocumentIdentifier textDocument; 1110 Position position; 1111 string newName; 1112 } 1113 1114 struct ExecuteCommandParams 1115 { 1116 string command; 1117 Optional!(JSONValue[]) arguments; 1118 } 1119 1120 struct ExecuteCommandRegistrationOptions 1121 { 1122 string[] commands; 1123 } 1124 1125 struct ApplyWorkspaceEditParams 1126 { 1127 WorkspaceEdit edit; 1128 } 1129 1130 struct ApplyWorkspaceEditResponse 1131 { 1132 bool applied; 1133 } 1134 1135 struct WorkspaceFolder 1136 { 1137 string uri; 1138 string name; 1139 } 1140 1141 struct DidChangeWorkspaceFoldersParams 1142 { 1143 WorkspaceFoldersChangeEvent event; 1144 } 1145 1146 struct WorkspaceFoldersChangeEvent 1147 { 1148 WorkspaceFolder[] added; 1149 WorkspaceFolder[] removed; 1150 }