1 /** 2 Implements the various LSP type definitions 3 4 Standards: LSP v3.16 https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/ 5 */ 6 module served.lsp.protocol; 7 8 import std.conv; 9 import std.meta; 10 import std.traits; 11 12 import mir.serde; 13 import mir.deser : serdeProxyCast; 14 15 public import mir.algebraic : Variant, isVariant, match, Nullable; 16 17 public import served.lsp.jsonops; 18 19 version (unittest) 20 import std.exception; 21 22 private enum getJsonKey(T, string member) = ({ 23 enum keys = getUDAs!(__traits(getMember, T, member), serdeKeys); 24 static if (keys.length) 25 { 26 static assert(keys.length == 1); 27 assert(keys[0].keys.length == 1); 28 return keys[0].keys[0]; 29 } 30 else 31 { 32 return member; 33 } 34 })(); 35 36 enum getRequiredKeys(T) = ({ 37 import std.algorithm : sort; 38 string[] ret; 39 static foreach (member; serdeFinalProxyDeserializableMembers!T) 40 { 41 static if (!hasUDA!(__traits(getMember, T, member), serdeOptional)) 42 ret ~= getJsonKey!(T, member); 43 } 44 ret.sort!"a<b"; 45 return ret; 46 })(); 47 48 @serdeFallbackStruct 49 @serdeProxy!JsonValue 50 struct StructVariant(AllowedTypes...) 51 if (AllowedTypes.length > 0) 52 { 53 import mir.ion.exception; 54 import mir.ion.value; 55 56 import std.algorithm; 57 import std.array; 58 59 enum isAllowedType(T) = AllowedTypes.length == 0 60 || staticIndexOf!(Unqual!T, AllowedTypes) != -1; 61 62 enum commonKeys = setIntersection(staticMap!(getRequiredKeys, AllowedTypes)).array; 63 64 private static bool valueMatchesType(T)(IonStructWithSymbols struct_) 65 { 66 enum requiredKeys = getRequiredKeys!T; 67 bool[requiredKeys.length] hasRequired; 68 foreach (error, key, value; struct_) 69 { 70 Switch: switch (key) 71 { 72 static foreach (member; serdeFinalProxyDeserializableMembers!T) 73 { 74 case getJsonKey!(T, member): 75 static if (!hasUDA!(__traits(getMember, T, member), serdeOptional)) 76 { 77 enum idx = requiredKeys.countUntil(member); 78 hasRequired[idx] = true; 79 } 80 break Switch; 81 } 82 default: 83 break; 84 } 85 } 86 87 static foreach (i; 0 .. hasRequired.length) 88 if (!hasRequired[i]) 89 return false; 90 return true; 91 } 92 93 static string mismatchMessage(T)(IonStructWithSymbols struct_) 94 { 95 string reasons; 96 enum requiredKeys = getRequiredKeys!T; 97 bool[requiredKeys.length] hasRequired; 98 foreach (error, key, value; struct_) 99 { 100 Switch: switch (key) 101 { 102 static foreach (member; serdeFinalProxyDeserializableMembers!T) 103 { 104 case getJsonKey!(T, member): 105 static if (!hasUDA!(__traits(getMember, T, member), serdeOptional)) 106 { 107 enum idx = requiredKeys.countUntil(member); 108 hasRequired[idx] = true; 109 } 110 break Switch; 111 } 112 default: 113 break; 114 } 115 } 116 117 static foreach (i; 0 .. hasRequired.length) 118 if (!hasRequired[i]) 119 reasons ~= "missing required key " ~ requiredKeys[i] ~ "\n"; 120 return reasons.length ? reasons[0 .. $ - 1] : null; 121 } 122 123 Variant!AllowedTypes value; 124 alias value this; 125 126 this(Variant!AllowedTypes v) 127 { 128 value = v; 129 } 130 131 this(T)(T v) 132 if (isAllowedType!T) 133 { 134 value = v; 135 } 136 137 ref typeof(this) opAssign(T)(T rhs) 138 { 139 static if (is(T : typeof(this))) 140 value = rhs.value; 141 else static if (isAllowedType!T) 142 value = rhs; 143 else 144 static assert(false, "unsupported assignment of type " ~ T.stringof ~ " to " ~ typeof(this).stringof); 145 return this; 146 } 147 148 void serialize(S)(scope ref S serializer) const 149 { 150 import mir.ser : serializeValue; 151 152 serializeValue(serializer, value); 153 } 154 155 /** 156 Returns: error msg if any 157 */ 158 @safe pure scope 159 IonException deserializeFromIon(scope const char[][] symbolTable, IonDescribedValue value) 160 { 161 import mir.deser.ion : deserializeIon; 162 import mir.ion.type_code : IonTypeCode; 163 164 if (value.descriptor.type != IonTypeCode.struct_) 165 return ionException(IonErrorCode.expectedStructValue); 166 167 auto struct_ = value.get!(IonStruct).withSymbols(symbolTable); 168 169 static if (commonKeys.length > 0) 170 { 171 bool[commonKeys.length] hasRequired; 172 173 foreach (error, key, value; struct_) 174 { 175 if (error) 176 return error.ionException; 177 178 Switch: 179 switch (key) 180 { 181 static foreach (i, member; commonKeys) 182 { 183 case member: 184 hasRequired[i] = true; 185 break Switch; 186 } 187 default: 188 break; 189 } 190 } 191 192 foreach (i, has; hasRequired) 193 if (!has) 194 return new IonException({ 195 string reason; 196 foreach (i, has; hasRequired) 197 if (!has) 198 reason ~= "\nrequired common key '" ~ commonKeys[i] ~ "' is missing"; 199 return "ion value is not compatible with StructVariant with types " ~ AllowedTypes.stringof ~ reason; 200 }()); 201 } 202 203 static foreach (T; AllowedTypes) 204 if (valueMatchesType!T(struct_)) 205 { 206 this.value = deserializeIon!T(symbolTable, value); 207 return null; 208 } 209 210 return new IonException({ 211 string reason; 212 static foreach (T; AllowedTypes) 213 reason ~= "\n\t" ~ T.stringof ~ ": " ~ mismatchMessage!T(struct_); 214 return "ion value is not compatible with StructVariant with types " ~ AllowedTypes.stringof ~ ":" ~ reason; 215 }()); 216 } 217 218 bool tryExtract(T)(out T ret) 219 { 220 return value.match!( 221 (T exact) { ret = exact; return true; }, 222 (other) { 223 bool success = true; 224 static foreach (key; __traits(allMembers, T)) 225 { 226 static if (__traits(hasMember, other, key)) 227 __traits(getMember, ret, key) = __traits(getMember, other, key); 228 else 229 success = false; 230 } 231 if (!success) 232 ret = T.init; 233 return success; 234 } 235 ); 236 } 237 238 T extract(T)() const 239 if (isAllowedType!T) 240 { 241 return value.match!( 242 (T exact) => exact, 243 (other) { 244 T ret; 245 static foreach (key; __traits(allMembers, T)) 246 { 247 static if (__traits(hasMember, other, key)) 248 __traits(getMember, ret, key) = __traits(getMember, other, key); 249 else 250 throw new Exception("can't extract " ~ T.stringof ~ " from effective " ~ (Unqual!(typeof(other))).stringof); 251 } 252 return ret; 253 } 254 ); 255 } 256 } 257 258 /// 259 unittest 260 { 261 @serdeIgnoreUnexpectedKeys 262 struct Named 263 { 264 string name; 265 } 266 267 @serdeIgnoreUnexpectedKeys 268 struct Person 269 { 270 string name; 271 int age; 272 } 273 274 @serdeIgnoreUnexpectedKeys 275 struct Place 276 { 277 string name; 278 double lat, lon; 279 } 280 281 StructVariant!(Named, Person, Place) var = Person("Bob", 32); 282 283 assert(var.serializeJson == `{"name":"Bob","age":32}`); 284 285 Named extractedNamed; 286 Person extractedPerson; 287 Place extractedPlace; 288 assert(var.tryExtract!Named(extractedNamed));//, var.mismatchMessage!Named(var.value)); 289 assert(var.tryExtract!Person(extractedPerson));//, var.mismatchMessage!Person(var.value)); 290 assert(!var.tryExtract!Place(extractedPlace));//, var.mismatchMessage!Place(var.value)); 291 292 try 293 { 294 var.extract!Place(); 295 assert(false); 296 } 297 catch (Exception e) 298 { 299 // assert(e.msg == "missing required key lat\nmissing required key lon", e.msg); 300 assert(e.msg == "can't extract Place from effective Person", e.msg); 301 } 302 303 assert(extractedNamed.name == "Bob"); 304 assert(extractedPerson == Person("Bob", 32)); 305 assert(extractedPlace is Place.init); 306 307 var = `{"name":"new name"}`.deserializeJson!(typeof(var)); 308 assert(var.extract!Named.name == "new name"); 309 assert(!var.tryExtract!Person(extractedPerson)); 310 assert(!var.tryExtract!Place(extractedPlace)); 311 312 assert(var.extract!Named.name == "new name"); 313 assertThrown({ 314 var = `{"nam":"name"}`.deserializeJson!(typeof(var)); 315 }()); 316 assert(var.extract!Named.name == "new name"); 317 318 assertThrown({ 319 var = `"hello"`.deserializeJson!(typeof(var)); 320 }()); 321 } 322 323 unittest 324 { 325 @serdeIgnoreUnexpectedKeys 326 struct Person 327 { 328 string name; 329 int age; 330 } 331 332 @serdeIgnoreUnexpectedKeys 333 struct Place 334 { 335 string name; 336 double lat, lon; 337 } 338 339 StructVariant!(Person, Place) var = Person("Bob", 32); 340 341 assert(var.serializeJson == `{"name":"Bob","age":32}`); 342 343 Person extractedPerson; 344 Place extractedPlace; 345 assert(var.tryExtract!Person(extractedPerson));//, var.mismatchMessage!Person(var.value)); 346 assert(!var.tryExtract!Place(extractedPlace));//, var.mismatchMessage!Place(var.value)); 347 348 assert(extractedPerson == Person("Bob", 32)); 349 assert(extractedPlace is Place.init); 350 351 var = `{"name": "new name", "lat": 0, "lon": 1.5}`.deserializeJson!(typeof(var)); 352 353 assert(!var.tryExtract!Person(extractedPerson));//, var.mismatchMessage!Person(var.value)); 354 assert(var.tryExtract!Place(extractedPlace));//, var.mismatchMessage!Place(var.value)); 355 356 assert(extractedPerson is Person.init); 357 assert(extractedPlace == Place("new name", 0, 1.5)); 358 359 assertThrown({ 360 var = `{"name":"broken name"}`.deserializeJson!(typeof(var)); 361 }()); 362 assert(var.extract!Place.name == "new name"); 363 364 var = `{"name":"Alice","age":64}`.deserializeJson!(typeof(var)); 365 assert(var.extract!Person == Person("Alice", 64)); 366 } 367 368 struct AllowedMethods 369 { 370 immutable string[] methods; 371 } 372 373 AllowedMethods allowedMethods(immutable string[] methods...) 374 { 375 return AllowedMethods(methods.idup); 376 } 377 378 alias Optional(T) = Variant!(void, T); 379 alias OptionalJsonValue = Variant!(void, JsonValue); 380 template TypeFromOptional(T) 381 { 382 alias Reduced = T.AllowedTypes; 383 static assert(Reduced.length == 2, "got optional without exactly a single type: " ~ T.AllowedTypes.stringof); 384 static assert(is(Reduced[0] == void), "got non-optional variant: " ~ T.AllowedTypes.stringof); 385 alias TypeFromOptional = Reduced[1]; 386 } 387 388 struct NullableOptional(T) 389 { 390 import mir.ion.exception; 391 import mir.ion.value; 392 393 bool isSet = false; 394 Nullable!T embed; 395 396 this(T value) 397 { 398 isSet = true; 399 embed = value; 400 } 401 402 this(typeof(null)) 403 { 404 isSet = true; 405 embed = null; 406 } 407 408 void unset() 409 { 410 isSet = false; 411 } 412 413 auto opAssign(T value) 414 { 415 isSet = true; 416 embed = value; 417 return this; 418 } 419 420 auto opAssign(typeof(null)) 421 { 422 isSet = true; 423 embed = null; 424 return this; 425 } 426 427 bool serdeIgnoreOut() const @safe 428 { 429 return !isSet; 430 } 431 432 auto get() inout @safe 433 { 434 assert(isSet, "attempted to .get on an unset value"); 435 return embed; 436 } 437 438 // and use custom serializer to serialize as int 439 void serialize(S)(scope ref S serializer) const 440 { 441 import mir.ser : serializeValue; 442 443 assert(isSet, "attempted to serialize unset value"); 444 445 if (embed.isNull) 446 serializer.putValue(null); 447 else 448 serializeValue(serializer, embed.get); 449 } 450 451 @trusted pure scope 452 IonException deserializeFromIon(scope const char[][] symbolTable, IonDescribedValue value) 453 { 454 import mir.deser.ion: deserializeIon; 455 import mir.ion.type_code : IonTypeCode; 456 457 isSet = true; 458 if (value == null) 459 embed = null; 460 else 461 embed = deserializeIon!T(symbolTable, value); 462 return null; 463 } 464 } 465 466 bool isNone(T)(T v) 467 if (isVariant!T) 468 { 469 return v._is!void; 470 } 471 472 /// 473 auto deref(T)(scope return inout T v) 474 if (isVariant!T) 475 { 476 return v.match!( 477 () { 478 throw new Exception("Attempted to get unset " ~ T.stringof); 479 return assert(false); // changes return type to bottom_t 480 }, 481 ret => ret 482 ); 483 } 484 485 /// ditto 486 JsonValue deref(scope return inout OptionalJsonValue v) 487 { 488 if (v._is!void) 489 throw new Exception("Attempted to get unset JsonValue"); 490 return v.get!JsonValue; 491 } 492 493 /// Returns the deref value from this optional or TypeFromOptional!T.init if 494 /// set to none. 495 TypeFromOptional!T orDefault(T)(scope return T v) 496 if (isVariant!T) 497 { 498 if (v._is!void) 499 return TypeFromOptional!T.init; 500 else 501 return v.get!(TypeFromOptional!T); 502 } 503 504 /// 505 unittest 506 { 507 static assert(is(TypeFromOptional!OptionalJsonValue == JsonValue)); 508 OptionalJsonValue someJson; 509 assert(someJson.orDefault == JsonValue.init); 510 someJson = JsonValue(5); 511 assert(someJson.orDefault == JsonValue(5)); 512 513 static assert(is(TypeFromOptional!(Optional!int) == int)); 514 Optional!int someInt; 515 assert(someInt.orDefault == 0); 516 someInt = 5; 517 assert(someInt.orDefault == 5); 518 } 519 520 /// 521 T expect(T, ST)(ST v) 522 if (isVariant!ST) 523 { 524 return v.match!( 525 () { 526 if (false) return T.init; 527 throw new Exception("Attempted to get unset Optional!" ~ T.stringof); 528 }, 529 (T val) => val, 530 (v) { 531 if (false) return T.init; 532 throw new Exception("Attempted to get " ~ T.stringof ~ " from Variant of type " ~ typeof(v).stringof); 533 } 534 ); 535 } 536 537 /// 538 Optional!T opt(T)(T val) 539 { 540 return Optional!T(val); 541 } 542 543 unittest 544 { 545 Optional!int optInt; 546 Optional!string optString1; 547 Optional!string optString2; 548 549 assert(optInt.isNone); 550 assert(optString1.isNone); 551 assert(optString2.isNone); 552 553 optInt = 4; 554 optString1 = null; 555 optString2 = "hello"; 556 557 assert(!optInt.isNone); 558 assert(!optString1.isNone); 559 assert(!optString2.isNone); 560 561 assert(optInt.deref == 4); 562 assert(optString1.deref == null); 563 assert(optString2.deref == "hello"); 564 565 assert(optInt.expect!int == 4); 566 assert(optString1.expect!string == null); 567 assert(optString2.expect!string == "hello"); 568 569 assertThrown(optInt.expect!string); 570 assertThrown(optString1.expect!int); 571 572 optInt = typeof(optInt)._void; 573 optString1 = typeof(optString1)._void; 574 optString2 = typeof(optString2)._void; 575 576 assert(optInt.isNone); 577 assert(optString1.isNone); 578 assert(optString2.isNone); 579 580 assertThrown(optInt.deref); 581 assertThrown(optInt.expect!int); 582 assertThrown(optString1.deref); 583 assertThrown(optString1.expect!string); 584 } 585 586 @serdeIgnoreUnexpectedKeys: 587 588 /// 589 alias ArrayOrSingle(T) = Variant!(T[], T); 590 591 /// 592 @serdeFallbackStruct 593 struct RequiredValueSet(T) 594 { 595 T[] valueSet; 596 } 597 598 /// 599 @serdeFallbackStruct 600 struct OptionalValueSet(T) 601 { 602 @serdeOptional Optional!(T[]) valueSet; 603 } 604 605 unittest 606 { 607 auto single = ArrayOrSingle!Location(Location("file:///foo.d", TextRange(4, 2, 4, 8))); 608 auto array = ArrayOrSingle!Location([Location("file:///foo.d", TextRange(4, 2, 4, 8)), Location("file:///bar.d", TextRange(14, 1, 14, 9))]); 609 610 foreach (v; [single, array]) 611 { 612 assert(deserializeJson!(ArrayOrSingle!Location)(v.serializeJson) == v); 613 } 614 } 615 616 /// 617 @serdeProxy!(typeof(RequestToken.value)) 618 @serdeFallbackStruct 619 struct RequestToken 620 { 621 Variant!(typeof(null), long, string) value; 622 alias value this; 623 624 this(T)(T v) 625 { 626 value = typeof(value)(v); 627 } 628 629 ref typeof(this) opAssign(T)(T rhs) 630 { 631 static if (is(T : typeof(this))) 632 value = rhs.value; 633 else 634 value = rhs; 635 return this; 636 } 637 638 /// Simply counts up using a global counter, wrapping around at int.max. 639 static RequestToken next() 640 { 641 import core.atomic : atomicOp; 642 643 static shared uint counter = 0; 644 645 // uint overflows at 32 bits, we use a bitmask to further narrow this 646 // down to 31 bits, which should be safe to handle by _any_ LSP client. 647 // 648 // no need to represent this in the uint counter, because overflow at 32 649 // bit is basically the same thing we simulate here with the bitmask. 650 uint ourValue = atomicOp!"+="(counter, 1) 651 & 0x7FFF_FFFFu; 652 653 return RequestToken(ourValue); 654 } 655 656 deprecated alias random = randomLong; 657 658 static RequestToken randomLong() 659 { 660 import std.random : uniform; 661 662 // Lua LSP clients (e.g. vim-lspconfig) aren't playing well with large numbers. 663 // we simply don't go over int.max to support any sensible implementation here. 664 enum long maxSafeInt = int.max; 665 666 return RequestToken(uniform(0L, maxSafeInt)); 667 } 668 669 static RequestToken randomString() 670 { 671 version (unittest) 672 char[16] buffer; // make sure uninitialized buffers are caught in tests 673 else 674 char[16] buffer = void; 675 676 randomSerializedString(buffer); 677 return RequestToken(buffer[1 .. $ - 1].idup); 678 } 679 680 deprecated alias randomSerialized = randomSerializedString; 681 682 static void randomSerializedString(char[] buffer) 683 in(buffer.length > 2) 684 { 685 import std.random : uniform; 686 687 static immutable letters = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`; 688 689 buffer[0] = '"'; 690 for (int i = 1; i < buffer.length; i++) 691 buffer[i] = letters[uniform(0, $)]; 692 buffer[$ - 1] = '"'; 693 } 694 695 deprecated alias randomAndSerialized = randomAndSerializedString; 696 697 static RequestToken randomAndSerializedString(char[] buffer) 698 { 699 randomSerializedString(buffer); 700 return RequestToken(buffer[1 .. $ - 1].idup); 701 } 702 } 703 704 unittest 705 { 706 assert(deserializeJson!RequestToken(`"hello"`) == RequestToken("hello")); 707 assert(deserializeJson!RequestToken(`4000`) == RequestToken(4000)); 708 assert(deserializeJson!RequestToken(`null`) == RequestToken(null)); 709 710 assert(`"hello"` == RequestToken("hello").serializeJson); 711 assert(`4000` == RequestToken(4000).serializeJson); 712 assert(`null` == RequestToken(null).serializeJson); 713 714 auto tok = RequestToken.randomString(); 715 auto other = RequestToken.randomString(); 716 assert(tok.value.get!string.length > 10); 717 assert(tok.value.get!string[0 .. 5] != tok.value.get!string[5 .. 10]); 718 assert(tok.value.get!string != other.value.get!string); 719 720 char[16] buf; 721 tok = RequestToken.randomAndSerializedString(buf[]); 722 assert(buf[0] == '"'); 723 assert(buf[$ - 1] == '"'); 724 assert(buf[1 .. $ - 1] == tok.value.get!string); 725 726 other = "hello"; 727 assert(other.get!string == "hello"); 728 729 other = 6; 730 assert(other.get!long == 6); 731 } 732 733 /// 734 struct RequestMessage 735 { 736 /// 737 @serdeOptional Optional!RequestToken id; 738 /// 739 string jsonrpc = "2.0"; 740 /// 741 string method; 742 /// Optional parameters to this method. Must be either null (omitted), array 743 /// (positional parameters) or object. (named parameters) 744 @serdeOptional OptionalJsonValue params; 745 } 746 747 /// 748 struct RequestMessageRaw 749 { 750 /// 751 @serdeOptional Optional!RequestToken id; 752 /// 753 string jsonrpc = "2.0"; 754 /// 755 string method; 756 /// Optional parameters to this method. Must be either empty string 757 /// (omitted), or array (positional parameters) or object JSON string. 758 /// (named parameters) 759 string paramsJson; 760 761 /// Formats this request message into `RequestMessage({method}: {json})` 762 string toString() const @safe pure 763 { 764 return text("RequestMessage(", method, ": ", paramsJson, ")"); 765 } 766 } 767 768 /// 769 @serdeEnumProxy!int 770 enum ErrorCode 771 { 772 /// Invalid JSON was received by the server. 773 /// An error occurred on the server while parsing the JSON text. 774 parseError = -32700, 775 /// The JSON sent is not a valid Request object. 776 invalidRequest = -32600, 777 /// The method does not exist / is not available. 778 methodNotFound = -32601, 779 /// Invalid method parameter(s). 780 invalidParams = -32602, 781 /// Internal JSON-RPC error. 782 internalError = -32603, 783 /// Range start reserved for implementation-defined server-errors. 784 serverErrorStart = -32099, 785 /// Range end reserved for implementation-defined server-errors. 786 serverErrorEnd = -32000, 787 /// serve-d specific error: received method before server was fully 788 /// initialized. 789 serverNotInitialized = -32002, 790 /// 791 unknownErrorCode = -32001 792 } 793 794 795 /// 796 @serdeFallbackStruct 797 struct ResponseError 798 { 799 /// A Number that indicates the error type that occurred. 800 ErrorCode code; 801 /// A String providing a short description of the error. 802 /// The message SHOULD be limited to a concise single sentence. 803 string message; 804 /// A Primitive or Structured value that contains additional information 805 /// about the error. 806 /// This may be omitted. 807 /// The value of this member is defined by the Server (e.g. detailed error 808 /// information, nested errors etc.). 809 @serdeOptional OptionalJsonValue data; 810 811 this(Throwable t) 812 { 813 code = ErrorCode.unknownErrorCode; 814 message = t.msg; 815 data = JsonValue(t.toString); 816 } 817 818 this(ErrorCode c) 819 { 820 code = c; 821 message = c.to!string; 822 } 823 824 this(ErrorCode c, string msg) 825 { 826 code = c; 827 message = msg; 828 } 829 } 830 831 class MethodException : Exception 832 { 833 this(ResponseError error, string file = __FILE__, size_t line = __LINE__) pure nothrow @nogc @safe 834 { 835 super(error.message, file, line); 836 this.error = error; 837 } 838 839 ResponseError error; 840 } 841 842 /// 843 struct ResponseMessage 844 { 845 this(RequestToken id, JsonValue result) 846 { 847 this.id = id; 848 this.result = result; 849 } 850 851 this(RequestToken id, ResponseError error) 852 { 853 this.id = id; 854 this.error = error; 855 } 856 857 this(typeof(null) id, JsonValue result) 858 { 859 this.id = null; 860 this.result = result; 861 } 862 863 this(typeof(null) id, ResponseError error) 864 { 865 this.id = null; 866 this.error = error; 867 } 868 869 /// 870 RequestToken id; 871 /// 872 @serdeOptional OptionalJsonValue result; 873 /// 874 @serdeOptional Optional!ResponseError error; 875 } 876 877 unittest 878 { 879 ResponseMessage res = ResponseMessage(RequestToken("id"), 880 ResponseError(ErrorCode.invalidRequest, "invalid request")); 881 882 string buf; 883 buf ~= `{"jsonrpc":"2.0"`; 884 if (!res.id.isNull) 885 { 886 buf ~= `,"id":`; 887 buf ~= res.id.serializeJson; 888 } 889 890 if (!res.result.isNone) 891 { 892 buf ~= `,"result":`; 893 buf ~= res.result.serializeJson; 894 } 895 896 if (!res.error.isNone) 897 { 898 buf ~= `,"error":`; 899 buf ~= res.error.serializeJson; 900 } 901 902 buf ~= `}`; 903 904 assert(buf == `{"jsonrpc":"2.0","id":"id","error":{"code":-32600,"message":"invalid request"}}`); 905 } 906 907 /// 908 struct ResponseMessageRaw 909 { 910 /// 911 RequestToken id; 912 /// empty string/null if not set, otherwise JSON string of result 913 string resultJson; 914 /// 915 Optional!ResponseError error; 916 917 /// Formats this request message into `ResponseMessage({id}: {json/error})` 918 string toString() const @safe 919 { 920 if (error.isNone) 921 return text("ResponseMessage(", id, ": ", resultJson, ")"); 922 else 923 return text("ResponseMessage(", id, ": ", error.deref, ")"); 924 } 925 926 static ResponseMessageRaw deserialize(scope const(char)[] json) 927 in (json.looksLikeJsonObject) 928 { 929 auto slices = json.parseKeySlices!("id", "result", "error", "method", "params"); 930 931 auto tok = slices.id.deserializeJson!RequestToken; 932 ResponseMessageRaw ret; 933 ret.id = tok; 934 auto res = slices.result; 935 auto err = slices.error; 936 if (res.length) 937 ret.resultJson = res.idup; 938 if (err.length) 939 ret.error = err.deserializeJson!ResponseError; 940 return ret; 941 } 942 } 943 944 alias DocumentUri = string; 945 946 @serdeFallbackStruct 947 @allowedMethods("window/showMessage") 948 struct ShowMessageParams 949 { 950 MessageType type; 951 string message; 952 } 953 954 @serdeEnumProxy!int 955 enum MessageType 956 { 957 error = 1, 958 warning, 959 info, 960 log 961 } 962 963 @serdeFallbackStruct 964 struct ShowMessageRequestClientCapabilities 965 { 966 @serdeFallbackStruct 967 @serdeIgnoreUnexpectedKeys 968 static struct MessageActionItemCapabilities 969 { 970 @serdeOptional Optional!bool additionalPropertiesSupport; 971 } 972 973 @serdeOptional Optional!MessageActionItemCapabilities messageActionItem; 974 } 975 976 @serdeFallbackStruct 977 @allowedMethods("window/showMessageRequest") 978 struct ShowMessageRequestParams 979 { 980 MessageType type; 981 string message; 982 @serdeOptional Optional!(MessageActionItem[]) actions; 983 } 984 985 @serdeFallbackStruct 986 struct MessageActionItem 987 { 988 string title; 989 } 990 991 @serdeFallbackStruct 992 struct ShowDocumentClientCapabilities 993 { 994 bool support; 995 } 996 997 @serdeFallbackStruct 998 @allowedMethods("window/showDocument") 999 struct ShowDocumentParams 1000 { 1001 DocumentUri uri; 1002 @serdeOptional Optional!bool external; 1003 @serdeOptional Optional!bool takeFocus; 1004 @serdeOptional Optional!TextRange selection; 1005 } 1006 1007 @serdeFallbackStruct 1008 struct ShowDocumentResult 1009 { 1010 bool success; 1011 } 1012 1013 @serdeFallbackStruct 1014 @allowedMethods("window/logMessage") 1015 struct LogMessageParams 1016 { 1017 MessageType type; 1018 string message; 1019 } 1020 1021 alias ProgressToken = Variant!(int, string); 1022 1023 @serdeFallbackStruct 1024 @allowedMethods("window/workDoneProgress/create") 1025 struct WorkDoneProgressCreateParams 1026 { 1027 ProgressToken token; 1028 } 1029 1030 @serdeFallbackStruct 1031 @allowedMethods("window/workDoneProgress/cancel") 1032 struct WorkDoneProgressCancelParams 1033 { 1034 ProgressToken token; 1035 } 1036 1037 enum EolType 1038 { 1039 cr, 1040 lf, 1041 crlf 1042 } 1043 1044 string toString(EolType eol) 1045 { 1046 final switch (eol) 1047 { 1048 case EolType.cr: 1049 return "\r"; 1050 case EolType.lf: 1051 return "\n"; 1052 case EolType.crlf: 1053 return "\r\n"; 1054 } 1055 } 1056 1057 @serdeFallbackStruct 1058 struct Position 1059 { 1060 /// Zero-based line & character offset (UTF-16 codepoints) 1061 uint line, character; 1062 1063 int opCmp(const Position other) const 1064 { 1065 if (line < other.line) 1066 return -1; 1067 if (line > other.line) 1068 return 1; 1069 if (character < other.character) 1070 return -1; 1071 if (character > other.character) 1072 return 1; 1073 return 0; 1074 } 1075 } 1076 1077 unittest 1078 { 1079 foreach (v; [ 1080 Position.init, 1081 Position(10), 1082 Position(10, 10), 1083 Position(uint.max - 1) 1084 ]) 1085 assert(deserializeJson!Position(v.serializeJson()) == v); 1086 } 1087 1088 private struct SerializableTextRange 1089 { 1090 Position start; 1091 Position end; 1092 1093 this(Position start, Position end) @safe pure nothrow @nogc 1094 { 1095 this.start = start; 1096 this.end = end; 1097 } 1098 1099 this(TextRange r) @safe pure nothrow @nogc 1100 { 1101 start = r.start; 1102 end = r.end; 1103 } 1104 } 1105 1106 @serdeProxy!SerializableTextRange 1107 @serdeFallbackStruct 1108 struct TextRange 1109 { 1110 union 1111 { 1112 struct 1113 { 1114 Position start; 1115 Position end; 1116 } 1117 1118 Position[2] range; 1119 } 1120 1121 enum all = TextRange(0, 0, int.max, int.max); // int.max ought to be enough 1122 1123 alias range this; 1124 1125 this(Num)(Num startLine, Num startCol, Num endLine, Num endCol) if (isNumeric!Num) 1126 { 1127 this(Position(cast(uint) startLine, cast(uint) startCol), 1128 Position(cast(uint) endLine, cast(uint) endCol)); 1129 } 1130 1131 this(Position start, Position end) 1132 { 1133 this.start = start; 1134 this.end = end; 1135 } 1136 1137 this(Position[2] range) 1138 { 1139 this.range = range; 1140 } 1141 1142 this(Position pos) 1143 { 1144 this.start = pos; 1145 this.end = pos; 1146 } 1147 1148 /// Returns: true if this range contains the position or the position is at 1149 /// the edges of this range. 1150 bool contains(Position position) 1151 { 1152 int minLine = start.line; 1153 int minCol = start.character; 1154 int maxLine = end.line; 1155 int maxCol = end.character; 1156 1157 return !(position.line < minLine || position.line > maxLine 1158 || (position.line == minLine && position.character < minCol) 1159 || (position.line == maxLine && position.character > maxCol)); 1160 } 1161 1162 /// Returns: true if text range `a` and `b` intersect with at least one character. 1163 /// This function is commutative (a·b == b·a) 1164 bool intersects(const TextRange b) 1165 { 1166 return start < b.end && end > b.start; 1167 } 1168 1169 /// 1170 unittest 1171 { 1172 bool test(TextRange a, TextRange b) 1173 { 1174 bool res = a.intersects(b); 1175 // test commutativity 1176 assert(res == b.intersects(a)); 1177 return res; 1178 } 1179 1180 assert(test(TextRange(10, 4, 20, 3), TextRange(20, 2, 30, 1))); 1181 assert(!test(TextRange(10, 4, 20, 3), TextRange(20, 3, 30, 1))); 1182 assert(test(TextRange(10, 4, 20, 3), TextRange(12, 3, 14, 1))); 1183 assert(!test(TextRange(10, 4, 20, 3), TextRange(9, 3, 10, 4))); 1184 assert(test(TextRange(10, 4, 20, 3), TextRange(9, 3, 10, 5))); 1185 assert(test(TextRange(10, 4, 20, 3), TextRange(10, 4, 20, 3))); 1186 assert(test(TextRange(0, 0, 0, 1), TextRange(0, 0, uint.max, uint.max))); 1187 assert(!test(TextRange(0, 0, 0, 1), TextRange(uint.max, uint.max, uint.max, uint.max))); 1188 } 1189 } 1190 1191 unittest 1192 { 1193 foreach (v; [ 1194 TextRange.init, 1195 TextRange(10, 4, 20, 3), 1196 TextRange(20, 2, 30, 1), 1197 TextRange(0, 0, 0, 1), 1198 TextRange(0, 0, uint.max, uint.max), 1199 TextRange(uint.max, uint.max, uint.max, uint.max) 1200 ]) 1201 assert(deserializeJson!TextRange(serializeJson(v)) == v); 1202 } 1203 1204 @serdeFallbackStruct 1205 struct Location 1206 { 1207 DocumentUri uri; 1208 TextRange range; 1209 } 1210 1211 @serdeFallbackStruct 1212 struct LocationLink 1213 { 1214 @serdeOptional Optional!TextRange originSelectionRange; 1215 DocumentUri targetUri; 1216 TextRange targetRange; 1217 TextRange targetSelectionRange; 1218 } 1219 1220 @serdeFallbackStruct 1221 struct Diagnostic 1222 { 1223 TextRange range; 1224 @serdeOptional Optional!DiagnosticSeverity severity; 1225 @serdeOptional OptionalJsonValue code; 1226 @serdeOptional Optional!CodeDescription codeDescription; 1227 @serdeOptional Optional!string source; 1228 string message; 1229 @serdeOptional Optional!(DiagnosticRelatedInformation[]) relatedInformation; 1230 @serdeOptional Optional!(DiagnosticTag[]) tags; 1231 @serdeOptional OptionalJsonValue data; 1232 } 1233 1234 @serdeFallbackStruct 1235 struct CodeDescription 1236 { 1237 string href; 1238 } 1239 1240 @serdeFallbackStruct 1241 struct DiagnosticRelatedInformation 1242 { 1243 Location location; 1244 string message; 1245 } 1246 1247 @serdeEnumProxy!int 1248 enum DiagnosticSeverity 1249 { 1250 error = 1, 1251 warning, 1252 information, 1253 hint 1254 } 1255 1256 @serdeEnumProxy!int 1257 enum DiagnosticTag 1258 { 1259 unnecessary = 1, 1260 deprecated_ 1261 } 1262 1263 @serdeFallbackStruct 1264 struct Command 1265 { 1266 string title; 1267 string command; 1268 JsonValue[] arguments; 1269 } 1270 1271 alias ChangeAnnotationIdentifier = string; 1272 1273 @serdeFallbackStruct 1274 struct TextEdit 1275 { 1276 TextRange range; 1277 string newText; 1278 @serdeOptional Optional!ChangeAnnotationIdentifier annotationId; 1279 1280 this(TextRange range, string newText, ChangeAnnotationIdentifier annotationId = null) 1281 { 1282 this.range = range; 1283 this.newText = newText; 1284 if (annotationId.length) 1285 this.annotationId = annotationId; 1286 } 1287 1288 this(Position[2] range, string newText, ChangeAnnotationIdentifier annotationId = null) 1289 { 1290 this.range = TextRange(range); 1291 this.newText = newText; 1292 if (annotationId.length) 1293 this.annotationId = annotationId; 1294 } 1295 } 1296 1297 unittest 1298 { 1299 foreach (v; [ 1300 TextEdit([Position(0, 0), Position(4, 4)], "hello\nworld!") 1301 ]) 1302 assert(deserializeJson!TextEdit(serializeJson(v)) == v); 1303 } 1304 1305 @serdeFallbackStruct 1306 struct ChangeAnnotation 1307 { 1308 string label; 1309 @serdeOptional Optional!bool needsConfirmation; 1310 @serdeOptional Optional!string description; 1311 } 1312 1313 @serdeFallbackStruct 1314 struct CreateFileOptions 1315 { 1316 @serdeOptional Optional!bool overwrite; 1317 @serdeOptional Optional!bool ignoreIfExists; 1318 } 1319 1320 @serdeFallbackStruct 1321 struct CreateFile 1322 { 1323 string uri; 1324 @serdeOptional Optional!CreateFileOptions options; 1325 @serdeOptional Optional!ChangeAnnotationIdentifier annotationId; 1326 string kind = "create"; 1327 } 1328 1329 @serdeFallbackStruct 1330 struct RenameFileOptions 1331 { 1332 @serdeOptional Optional!bool overwrite; 1333 @serdeOptional Optional!bool ignoreIfExists; 1334 } 1335 1336 @serdeFallbackStruct 1337 struct RenameFile 1338 { 1339 string oldUri; 1340 string newUri; 1341 @serdeOptional Optional!RenameFileOptions options; 1342 @serdeOptional Optional!ChangeAnnotationIdentifier annotationId; 1343 string kind = "rename"; 1344 } 1345 1346 @serdeFallbackStruct 1347 struct DeleteFileOptions 1348 { 1349 @serdeOptional Optional!bool recursive; 1350 @serdeOptional Optional!bool ignoreIfNotExists; 1351 } 1352 1353 @serdeFallbackStruct 1354 struct DeleteFile 1355 { 1356 string uri; 1357 @serdeOptional Optional!DeleteFileOptions options; 1358 @serdeOptional Optional!ChangeAnnotationIdentifier annotationId; 1359 string kind = "delete"; 1360 } 1361 1362 @serdeFallbackStruct 1363 struct TextDocumentEdit 1364 { 1365 VersionedTextDocumentIdentifier textDocument; 1366 TextEdit[] edits; 1367 } 1368 1369 alias TextEditCollection = TextEdit[]; 1370 1371 alias DocumentChange = StructVariant!(TextDocumentEdit, CreateFile, RenameFile, DeleteFile); 1372 1373 @serdeFallbackStruct 1374 struct WorkspaceEdit 1375 { 1376 TextEditCollection[DocumentUri] changes; 1377 1378 @serdeOptional Optional!(DocumentChange[]) documentChanges; 1379 @serdeOptional Optional!(ChangeAnnotation[ChangeAnnotationIdentifier]) changeAnnotations; 1380 } 1381 1382 @serdeFallbackStruct 1383 struct TextDocumentIdentifier 1384 { 1385 DocumentUri uri; 1386 } 1387 1388 @serdeFallbackStruct 1389 struct VersionedTextDocumentIdentifier 1390 { 1391 DocumentUri uri; 1392 @serdeKeys("version") long version_; 1393 } 1394 1395 @serdeFallbackStruct 1396 struct TextDocumentItem 1397 { 1398 DocumentUri uri; 1399 @serdeOptional // not actually optional according to LSP spec, logically fine to be omitted 1400 string languageId; 1401 @serdeOptional // not actually optional according to LSP spec, logically fine to be omitted 1402 @serdeKeys("version") long version_; 1403 string text; 1404 } 1405 1406 @serdeFallbackStruct 1407 struct TextDocumentPositionParams 1408 { 1409 TextDocumentIdentifier textDocument; 1410 Position position; 1411 } 1412 1413 @serdeFallbackStruct 1414 struct DocumentFilter 1415 { 1416 @serdeOptional Optional!string language; 1417 @serdeOptional Optional!string scheme; 1418 @serdeOptional Optional!string pattern; 1419 } 1420 1421 alias DocumentSelector = DocumentFilter[]; 1422 1423 @serdeFallbackStruct 1424 @allowedMethods("initialize") 1425 struct InitializeParams 1426 { 1427 Variant!(typeof(null), int) processId; 1428 @serdeOptional Optional!string rootPath; 1429 DocumentUri rootUri; 1430 @serdeOptional OptionalJsonValue initializationOptions; 1431 ClientCapabilities capabilities; 1432 @serdeOptional Optional!string trace; 1433 @serdeOptional NullableOptional!(WorkspaceFolder[]) workspaceFolders; 1434 @serdeOptional Optional!InitializeParamsClientInfo clientInfo; 1435 @serdeOptional Optional!string locale; 1436 1437 /// Compatibility helper to get workspace folders. Checks these members: 1438 /// 1) If `workspaceFolders` has any entries, it is returned as-is. 1439 /// 2) Otherwise, if `rootUri` is non-empty, it is returned as the only 1440 /// workspace, with `fallbackRootName` as name. 1441 /// 3) Otherwise, if `rootPath` is non-empty, it is converted to a URI and 1442 /// returned as the only workspace, with `fallbackRootName` as name. 1443 /// 4) Otherwise, empty array `[]` is returned. 1444 WorkspaceFolder[] getWorkspaceFolders(string fallbackRootName = "Root") 1445 { 1446 import served.lsp.uri; 1447 1448 if (workspaceFolders.isSet 1449 && !workspaceFolders.get.isNull 1450 && workspaceFolders.get.get.length > 0 1451 ) 1452 return workspaceFolders.get.get; 1453 else if (rootUri.length) 1454 return [WorkspaceFolder(rootUri, fallbackRootName)]; 1455 else if (rootPath.orDefault.length) 1456 return [WorkspaceFolder(rootPath.deref.uriFromFile, fallbackRootName)]; 1457 else 1458 return []; 1459 } 1460 } 1461 1462 unittest 1463 { 1464 InitializeParams p = { 1465 processId: 1234, 1466 rootUri: "file:///root/path", 1467 capabilities: ClientCapabilities.init 1468 }; 1469 assert(p.serializeJson == `{"processId":1234,"rootUri":"file:///root/path","capabilities":{}}`, p.serializeJson); 1470 1471 p = `{ 1472 "processId":29980, 1473 "clientInfo": { 1474 "name":"Code - OSS", 1475 "version":"1.68.0" 1476 }, 1477 "locale":"en-gb", 1478 "rootPath":"/home/webfreak/dev/serve-d", 1479 "rootUri":"file:///home/webfreak/dev/serve-d", 1480 "capabilities":{ 1481 "workspace":{ 1482 "applyEdit":true, 1483 "workspaceEdit":{ 1484 "documentChanges":true, 1485 "resourceOperations":["create","rename","delete"], 1486 "failureHandling":"textOnlyTransactional", 1487 "normalizesLineEndings":true, 1488 "changeAnnotationSupport":{"groupsOnLabel":true} 1489 }, 1490 "didChangeConfiguration":{ 1491 "dynamicRegistration":true 1492 }, 1493 "didChangeWatchedFiles":{ 1494 "dynamicRegistration":true 1495 }, 1496 "symbol":{ 1497 "dynamicRegistration":true, 1498 "symbolKind":{ 1499 "valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26] 1500 }, 1501 "tagSupport":{"valueSet":[1]} 1502 }, 1503 "codeLens":{ 1504 "refreshSupport":true 1505 }, 1506 "executeCommand":{ 1507 "dynamicRegistration":true 1508 }, 1509 "configuration":true, 1510 "workspaceFolders":true, 1511 "semanticTokens":{"refreshSupport":true}, 1512 "fileOperations":{ 1513 "dynamicRegistration":true, 1514 "didCreate":true, 1515 "didRename":true, 1516 "didDelete":true, 1517 "willCreate":true, 1518 "willRename":true, 1519 "willDelete":true 1520 } 1521 }, 1522 "textDocument":{ 1523 "publishDiagnostics":{ 1524 "relatedInformation":true, 1525 "versionSupport":false, 1526 "tagSupport":{"valueSet":[1,2]}, 1527 "codeDescriptionSupport":true, 1528 "dataSupport":true 1529 }, 1530 "synchronization":{ 1531 "dynamicRegistration":true, 1532 "willSave":true, 1533 "willSaveWaitUntil":true, 1534 "didSave":true 1535 }, 1536 "completion":{ 1537 "dynamicRegistration":true, 1538 "contextSupport":true, 1539 "completionItem":{ 1540 "snippetSupport":true, 1541 "commitCharactersSupport":true, 1542 "documentationFormat":["markdown","plaintext"], 1543 "deprecatedSupport":true, 1544 "preselectSupport":true, 1545 "tagSupport":{"valueSet":[1]}, 1546 "insertReplaceSupport":true, 1547 "resolveSupport":{ 1548 "properties":["documentation","detail","additionalTextEdits"] 1549 }, 1550 "insertTextModeSupport":{ 1551 "valueSet":[1,2] 1552 }, 1553 "labelDetailsSupport":true 1554 }, 1555 "insertTextMode":2, 1556 "completionItemKind":{ 1557 "valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25] 1558 } 1559 }, 1560 "hover":{ 1561 "dynamicRegistration":true, 1562 "contentFormat":["markdown","plaintext"] 1563 }, 1564 "signatureHelp":{ 1565 "dynamicRegistration":true, 1566 "signatureInformation":{ 1567 "documentationFormat":["markdown","plaintext"], 1568 "parameterInformation":{"labelOffsetSupport":true}, 1569 "activeParameterSupport":true 1570 }, 1571 "contextSupport":true 1572 }, 1573 "definition":{ 1574 "dynamicRegistration":true, 1575 "linkSupport":true 1576 }, 1577 "references":{ 1578 "dynamicRegistration":true 1579 }, 1580 "documentHighlight":{ 1581 "dynamicRegistration":true 1582 }, 1583 "documentSymbol":{ 1584 "dynamicRegistration":true, 1585 "symbolKind":{"valueSet":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]}, 1586 "hierarchicalDocumentSymbolSupport":true, 1587 "tagSupport":{"valueSet":[1]}, 1588 "labelSupport":true 1589 }, 1590 "codeAction":{ 1591 "dynamicRegistration":true, 1592 "isPreferredSupport":true, 1593 "disabledSupport":true, 1594 "dataSupport":true, 1595 "resolveSupport":{"properties":["edit"]}, 1596 "codeActionLiteralSupport":{ 1597 "codeActionKind":{ 1598 "valueSet":["","quickfix","refactor","refactor.extract","refactor.inline","refactor.rewrite","source","source.organizeImports"] 1599 } 1600 }, 1601 "honorsChangeAnnotations":false 1602 }, 1603 "codeLens":{ 1604 "dynamicRegistration":true 1605 }, 1606 "formatting":{"dynamicRegistration":true}, 1607 "rangeFormatting":{"dynamicRegistration":true}, 1608 "onTypeFormatting":{"dynamicRegistration":true}, 1609 "rename":{ 1610 "dynamicRegistration":true, 1611 "prepareSupport":true, 1612 "prepareSupportDefaultBehavior":1, 1613 "honorsChangeAnnotations":true 1614 }, 1615 "documentLink":{ 1616 "dynamicRegistration":true, 1617 "tooltipSupport":true 1618 }, 1619 "typeDefinition":{ 1620 "dynamicRegistration":true, 1621 "linkSupport":true 1622 }, 1623 "implementation":{ 1624 "dynamicRegistration":true, 1625 "linkSupport":true 1626 }, 1627 "colorProvider":{"dynamicRegistration":true}, 1628 "foldingRange":{"dynamicRegistration":true,"rangeLimit":5000,"lineFoldingOnly":true}, 1629 "declaration":{"dynamicRegistration":true,"linkSupport":true}, 1630 "selectionRange":{"dynamicRegistration":true}, 1631 "callHierarchy":{"dynamicRegistration":true}, 1632 "semanticTokens":{ 1633 "dynamicRegistration":true, 1634 "tokenTypes":["namespace","type","class","enum","interface","struct","typeParameter","parameter","variable","property","enumMember","event","function","method","macro","keyword","modifier","comment","string","number","regexp","operator"], 1635 "tokenModifiers":["declaration","definition","readonly","static","deprecated","abstract","async","modification","documentation","defaultLibrary"], 1636 "formats":["relative"], 1637 "requests":{"range":true,"full":{"delta":true}}, 1638 "multilineTokenSupport":false, 1639 "overlappingTokenSupport":false 1640 }, 1641 "linkedEditingRange":{"dynamicRegistration":true} 1642 }, 1643 "window":{ 1644 "showMessage":{ 1645 "messageActionItem":{"additionalPropertiesSupport":true} 1646 }, 1647 "showDocument":{"support":true}, 1648 "workDoneProgress":true 1649 }, 1650 "general":{ 1651 "staleRequestSupport":{ 1652 "cancel":true, 1653 "retryOnContentModified":["textDocument/semanticTokens/full","textDocument/semanticTokens/range","textDocument/semanticTokens/full/delta"] 1654 }, 1655 "regularExpressions":{"engine":"ECMAScript","version":"ES2020"}, 1656 "markdown":{"parser":"marked","version":"1.1.0"} 1657 } 1658 }, 1659 "trace":"off", 1660 "workspaceFolders":[ 1661 { 1662 "uri":"file:///home/webfreak/dev/serve-d", 1663 "name":"serve-d" 1664 } 1665 ] 1666 }`.deserializeJson!InitializeParams; 1667 1668 assert(p.processId == 29980); 1669 assert(p.clientInfo == InitializeParamsClientInfo("Code - OSS", "1.68.0".opt)); 1670 assert(p.locale == "en-gb"); 1671 assert(p.rootPath == "/home/webfreak/dev/serve-d"); 1672 assert(p.rootUri == "file:///home/webfreak/dev/serve-d"); 1673 assert(p.trace == "off"); 1674 auto folders = p.workspaceFolders.get.get; // double get cuz this one is special because it can be omitted as well as null 1675 assert(folders.length == 1); 1676 assert(folders[0].uri == "file:///home/webfreak/dev/serve-d"); 1677 assert(folders[0].name == "serve-d"); 1678 } 1679 1680 @serdeFallbackStruct 1681 struct InitializeParamsClientInfo 1682 { 1683 string name; 1684 @serdeKeys("version") Optional!string version_; 1685 } 1686 1687 @serdeFallbackStruct 1688 struct DynamicRegistration 1689 { 1690 @serdeOptional Optional!bool dynamicRegistration; 1691 } 1692 1693 @serdeEnumProxy!string 1694 enum ResourceOperationKind : string 1695 { 1696 create = "create", 1697 rename = "rename", 1698 delete_ = "delete" 1699 } 1700 1701 @serdeEnumProxy!string 1702 enum FailureHandlingKind : string 1703 { 1704 abort = "abort", 1705 transactional = "transactional", 1706 textOnlyTransactional = "textOnlyTransactional", 1707 undo = "undo" 1708 } 1709 1710 @serdeFallbackStruct 1711 struct WorkspaceEditClientCapabilities 1712 { 1713 @serdeOptional Optional!bool documentChanges; 1714 @serdeOptional Optional!(ResourceOperationKind[]) resourceOperations; 1715 @serdeOptional Optional!FailureHandlingKind failureHandling; 1716 @serdeOptional Optional!bool normalizesLineEndings; 1717 @serdeOptional Optional!ChangeAnnotationWorkspaceEditClientCapabilities changeAnnotationSupport; 1718 } 1719 1720 unittest 1721 { 1722 WorkspaceEditClientCapabilities cap = { 1723 documentChanges: true, 1724 resourceOperations: [ResourceOperationKind.delete_], 1725 failureHandling: FailureHandlingKind.textOnlyTransactional 1726 }; 1727 1728 assert(cap.serializeJson == `{"documentChanges":true,"resourceOperations":["delete"],"failureHandling":"textOnlyTransactional"}`); 1729 } 1730 1731 @serdeFallbackStruct 1732 struct ChangeAnnotationWorkspaceEditClientCapabilities 1733 { 1734 @serdeOptional Optional!bool groupsOnLabel; 1735 } 1736 1737 @serdeFallbackStruct 1738 struct WorkspaceClientCapabilities 1739 { 1740 @serdeOptional Optional!bool applyEdit; 1741 @serdeOptional Optional!WorkspaceEditClientCapabilities workspaceEdit; 1742 @serdeOptional Optional!DynamicRegistration didChangeConfiguration; 1743 @serdeOptional Optional!DynamicRegistration didChangeWatchedFiles; 1744 @serdeOptional Optional!DynamicRegistration symbol; 1745 @serdeOptional Optional!DynamicRegistration executeCommand; 1746 @serdeOptional Optional!bool workspaceFolders; 1747 @serdeOptional Optional!bool configuration; 1748 @serdeOptional Optional!SemanticTokensWorkspaceClientCapabilities semanticTokens; 1749 @serdeOptional Optional!CodeLensWorkspaceClientCapabilities codeLens; 1750 @serdeOptional Optional!FileOperationsCapabilities fileOperations; 1751 } 1752 1753 @serdeFallbackStruct 1754 struct MonikerClientCapabilities 1755 { 1756 @serdeOptional Optional!bool dynamicRegistration; 1757 } 1758 1759 @serdeFallbackStruct 1760 struct MonikerOptions 1761 { 1762 mixin WorkDoneProgressOptions; 1763 } 1764 1765 @serdeFallbackStruct 1766 struct MonikerRegistrationOptions 1767 { 1768 mixin TextDocumentRegistrationOptions; 1769 mixin WorkDoneProgressOptions; 1770 } 1771 1772 @serdeFallbackStruct 1773 @allowedMethods("textDocument/moniker") 1774 struct MonikerParams 1775 { 1776 TextDocumentIdentifier textDocument; 1777 Position position; 1778 } 1779 1780 @serdeEnumProxy!string 1781 enum UniquenessLevel : string 1782 { 1783 document = "document", 1784 project = "project", 1785 group = "group", 1786 scheme = "scheme", 1787 global = "global" 1788 } 1789 1790 @serdeEnumProxy!string 1791 enum MonikerKind : string 1792 { 1793 import_ = "import", 1794 export_ = "export", 1795 local = "local" 1796 } 1797 1798 @serdeFallbackStruct 1799 struct Moniker 1800 { 1801 string scheme; 1802 string identifier; 1803 UniquenessLevel unique; 1804 @serdeOptional Optional!MonikerKind kind; 1805 } 1806 1807 @serdeFallbackStruct 1808 struct FileOperationsCapabilities 1809 { 1810 @serdeOptional Optional!bool dynamicRegistration; 1811 @serdeOptional Optional!bool didCreate; 1812 @serdeOptional Optional!bool willCreate; 1813 @serdeOptional Optional!bool didRename; 1814 @serdeOptional Optional!bool willRename; 1815 @serdeOptional Optional!bool didDelete; 1816 @serdeOptional Optional!bool willDelete; 1817 } 1818 1819 @serdeFallbackStruct 1820 struct TextDocumentClientCapabilities 1821 { 1822 @serdeOptional Optional!TextDocumentSyncClientCapabilities synchronization; 1823 @serdeOptional Optional!CompletionClientCapabilities completion; 1824 @serdeOptional Optional!HoverClientCapabilities hover; 1825 @serdeOptional Optional!SignatureHelpClientCapabilities signatureHelp; 1826 @serdeOptional Optional!DeclarationClientCapabilities declaration; 1827 @serdeOptional Optional!DefinitionClientCapabilities definition; 1828 @serdeOptional Optional!TypeDefinitionClientCapabilities typeDefinition; 1829 @serdeOptional Optional!ImplementationClientCapabilities implementation; 1830 @serdeOptional Optional!ReferenceClientCapabilities references; 1831 @serdeOptional Optional!DocumentHighlightClientCapabilities documentHighlight; 1832 @serdeOptional Optional!DocumentSymbolClientCapabilities documentSymbol; 1833 @serdeOptional Optional!CodeActionClientCapabilities codeAction; 1834 @serdeOptional Optional!CodeLensClientCapabilities codeLens; 1835 @serdeOptional Optional!DocumentLinkClientCapabilities documentLink; 1836 @serdeOptional Optional!DocumentColorClientCapabilities colorProvider; 1837 @serdeOptional Optional!DocumentFormattingClientCapabilities formatting; 1838 @serdeOptional Optional!DocumentRangeFormattingClientCapabilities rangeFormatting; 1839 @serdeOptional Optional!DocumentOnTypeFormattingClientCapabilities onTypeFormatting; 1840 @serdeOptional Optional!RenameClientCapabilities rename; 1841 @serdeOptional Optional!PublishDiagnosticsClientCapabilities publishDiagnostics; 1842 @serdeOptional Optional!FoldingRangeClientCapabilities foldingRange; 1843 @serdeOptional Optional!SelectionRangeClientCapabilities selectionRange; 1844 @serdeOptional Optional!LinkedEditingRangeClientCapabilities linkedEditingRange; 1845 @serdeOptional Optional!CallHierarchyClientCapabilities callHierarchy; 1846 @serdeOptional Optional!SemanticTokensClientCapabilities semanticTokens; 1847 @serdeOptional Optional!MonikerClientCapabilities moniker; 1848 } 1849 1850 @serdeFallbackStruct 1851 struct ClientCapabilities 1852 { 1853 @serdeOptional Optional!WorkspaceClientCapabilities workspace; 1854 @serdeOptional Optional!TextDocumentClientCapabilities textDocument; 1855 @serdeOptional Optional!WindowClientCapabilities window; 1856 @serdeOptional Optional!GeneralClientCapabilities general; 1857 @serdeOptional OptionalJsonValue experimental; 1858 } 1859 1860 @serdeFallbackStruct 1861 struct WindowClientCapabilities 1862 { 1863 @serdeOptional Optional!bool workDoneProgress; 1864 @serdeOptional Optional!ShowMessageRequestClientCapabilities showMessage; 1865 @serdeOptional Optional!ShowDocumentClientCapabilities showDocument; 1866 } 1867 1868 @serdeFallbackStruct 1869 struct GeneralClientCapabilities 1870 { 1871 @serdeOptional Optional!RegularExpressionsClientCapabilities regularExpressions; 1872 @serdeOptional Optional!MarkdownClientCapabilities markdown; 1873 } 1874 1875 @serdeFallbackStruct 1876 struct RegularExpressionsClientCapabilities 1877 { 1878 string engine; 1879 @serdeKeys("version") @serdeOptional Optional!string version_; 1880 } 1881 1882 unittest 1883 { 1884 string json = q{{ 1885 "workspace": { 1886 "configuration": true 1887 } 1888 }}; 1889 auto caps = json.deserializeJson!ClientCapabilities; 1890 assert(caps.workspace.deref.configuration.deref); 1891 } 1892 1893 @serdeFallbackStruct 1894 struct InitializeResult 1895 { 1896 ServerCapabilities capabilities; 1897 @serdeOptional Optional!ServerInfo serverInfo; 1898 } 1899 1900 // TODO: deserialization broken here because of TextDocumentSync 1901 // (see linters at the very bottom of this file) 1902 version (none) 1903 unittest 1904 { 1905 auto res = `{ 1906 "capabilities":{ 1907 "textDocumentSync":2, 1908 "completionProvider":{ 1909 "resolveProvider":false, 1910 "triggerCharacters":[".","=","/","*","+","-"], 1911 "completionItem":{"labelDetailsSupport":true} 1912 }, 1913 "hoverProvider":true, 1914 "signatureHelpProvider":{ 1915 "triggerCharacters":["(","[",","] 1916 }, 1917 "definitionProvider":true, 1918 "documentHighlightProvider":true, 1919 "documentSymbolProvider":true, 1920 "codeActionProvider":true, 1921 "codeLensProvider":{"resolveProvider":true}, 1922 "colorProvider":{}, 1923 "documentFormattingProvider":true, 1924 "documentRangeFormattingProvider":true, 1925 "workspaceSymbolProvider":true, 1926 "workspace":{ 1927 "workspaceFolders":{ 1928 "supported":true, 1929 "changeNotifications":true 1930 } 1931 } 1932 } 1933 }` 1934 .deserializeJson!InitializeResult; 1935 assert(res.capabilities.textDocumentSync == TextDocumentSyncKind.incremental); 1936 } 1937 1938 @serdeFallbackStruct 1939 struct ServerInfo 1940 { 1941 string name; 1942 @serdeKeys("version") Optional!string version_; 1943 } 1944 1945 @serdeFallbackStruct 1946 struct InitializeError 1947 { 1948 bool retry; 1949 } 1950 1951 @serdeFallbackStruct 1952 struct CompletionClientCapabilities 1953 { 1954 @serdeFallbackStruct 1955 @serdeIgnoreUnexpectedKeys 1956 static struct CompletionItemCapabilities 1957 { 1958 @serdeFallbackStruct 1959 @serdeIgnoreUnexpectedKeys 1960 static struct ResolveSupport 1961 { 1962 string[] properties; 1963 } 1964 1965 @serdeOptional Optional!bool snippetSupport; 1966 @serdeOptional Optional!bool commitCharactersSupport; 1967 @serdeOptional Optional!(MarkupKind[]) documentationFormat; 1968 @serdeOptional Optional!bool deprecatedSupport; 1969 @serdeOptional Optional!bool preselectSupport; 1970 @serdeOptional Optional!(RequiredValueSet!CompletionItemTag) tagSupport; 1971 @serdeOptional Optional!bool insertReplaceSupport; 1972 @serdeOptional Optional!ResolveSupport resolveSupport; 1973 @serdeOptional Optional!(RequiredValueSet!InsertTextMode) insertTextModeSupport; 1974 @serdeOptional Optional!bool labelDetailsSupport; 1975 } 1976 1977 @serdeOptional Optional!bool dynamicRegistration; 1978 @serdeOptional Optional!CompletionItemCapabilities completionItem; 1979 @serdeOptional Optional!(OptionalValueSet!CompletionItemKind) completionItemKind; 1980 @serdeOptional Optional!bool contextSupport; 1981 } 1982 1983 @serdeFallbackStruct 1984 struct CompletionOptions 1985 { 1986 @serdeFallbackStruct 1987 @serdeIgnoreUnexpectedKeys 1988 struct CompletionItem 1989 { 1990 @serdeOptional Optional!bool labelDetailsSupport; 1991 } 1992 1993 @serdeOptional Optional!bool resolveProvider; 1994 @serdeOptional Optional!(string[]) triggerCharacters; 1995 @serdeOptional Optional!(string[]) allCommitCharacters; 1996 @serdeOptional Optional!CompletionItem completionItem; 1997 } 1998 1999 @serdeFallbackStruct 2000 struct SaveOptions 2001 { 2002 @serdeOptional Optional!bool includeText; 2003 } 2004 2005 @serdeFallbackStruct 2006 struct TextDocumentSyncClientCapabilities 2007 { 2008 @serdeOptional Optional!bool dynamicRegistration; 2009 @serdeOptional Optional!bool willSave; 2010 @serdeOptional Optional!bool willSaveWaitUntil; 2011 @serdeOptional Optional!bool didSave; 2012 } 2013 2014 @serdeEnumProxy!int 2015 enum TextDocumentSyncKind 2016 { 2017 none, 2018 full, 2019 incremental 2020 } 2021 2022 @serdeFallbackStruct 2023 struct TextDocumentSyncOptions 2024 { 2025 @serdeOptional Optional!bool openClose; 2026 @serdeOptional Optional!TextDocumentSyncKind change; 2027 @serdeOptional Optional!bool willSave; 2028 @serdeOptional Optional!bool willSaveWaitUntil; 2029 @serdeOptional Variant!(void, bool, SaveOptions) save; 2030 } 2031 2032 @serdeFallbackStruct 2033 struct ServerCapabilities 2034 { 2035 @serdeOptional Variant!(void, TextDocumentSyncKind, TextDocumentSyncOptions) textDocumentSync; 2036 @serdeOptional Variant!(void, CompletionOptions) completionProvider; 2037 @serdeOptional Variant!(void, bool, HoverOptions) hoverProvider; 2038 @serdeOptional Variant!(void, SignatureHelpOptions) signatureHelpProvider; 2039 @serdeOptional Variant!(void, bool, StructVariant!(DeclarationOptions, DeclarationRegistrationOptions)) declarationProvider; 2040 @serdeOptional Variant!(void, bool, DefinitionOptions) definitionProvider; 2041 @serdeOptional Variant!(void, bool, StructVariant!(TypeDefinitionOptions, TypeDefinitionRegistrationOptions)) typeDefinitionProvider; 2042 @serdeOptional Variant!(void, bool, StructVariant!(ImplementationOptions, ImplementationRegistrationOptions)) implementationProvider; 2043 @serdeOptional Variant!(void, bool, ReferenceOptions) referencesProvider; 2044 @serdeOptional Variant!(void, bool, DocumentHighlightOptions) documentHighlightProvider; 2045 @serdeOptional Variant!(void, bool, DocumentSymbolOptions) documentSymbolProvider; 2046 @serdeOptional Variant!(void, bool, CodeActionOptions) codeActionProvider; 2047 @serdeOptional Variant!(void, CodeLensOptions) codeLensProvider; 2048 @serdeOptional Variant!(void, DocumentLinkOptions) documentLinkProvider; 2049 @serdeOptional Variant!(void, bool, StructVariant!(DocumentColorOptions, DocumentColorRegistrationOptions)) colorProvider; 2050 @serdeOptional Variant!(void, bool, DocumentFormattingOptions) documentFormattingProvider; 2051 @serdeOptional Variant!(void, bool, DocumentRangeFormattingOptions) documentRangeFormattingProvider; 2052 @serdeOptional Variant!(void, DocumentOnTypeFormattingOptions) documentOnTypeFormattingProvider; 2053 @serdeOptional Variant!(void, bool, RenameOptions) renameProvider; 2054 @serdeOptional Variant!(void, bool, StructVariant!(FoldingRangeOptions, FoldingRangeRegistrationOptions)) foldingRangeProvider; 2055 @serdeOptional Variant!(void, ExecuteCommandOptions) executeCommandProvider; 2056 @serdeOptional Variant!(void, bool, StructVariant!(SelectionRangeOptions, SelectionRangeRegistrationOptions)) selectionRangeProvider; 2057 @serdeOptional Variant!(void, bool, StructVariant!(LinkedEditingRangeOptions, LinkedEditingRangeRegistrationOptions)) linkedEditingRangeProvider; 2058 @serdeOptional Variant!(void, bool, StructVariant!(CallHierarchyOptions, CallHierarchyRegistrationOptions)) callHierarchyProvider; 2059 @serdeOptional Variant!(void, StructVariant!(SemanticTokensOptions, SemanticTokensRegistrationOptions)) semanticTokensProvider; 2060 @serdeOptional Variant!(void, bool, StructVariant!(MonikerOptions, MonikerRegistrationOptions)) monikerProvider; 2061 @serdeOptional Variant!(void, bool, WorkspaceSymbolOptions) workspaceSymbolProvider; 2062 2063 @serdeOptional Optional!ServerWorkspaceCapabilities workspace; 2064 @serdeOptional OptionalJsonValue experimental; 2065 } 2066 2067 unittest 2068 { 2069 CodeActionOptions cao = { 2070 codeActionKinds: [CodeActionKind.refactor, CodeActionKind.sourceOrganizeImports, cast(CodeActionKind)"CustomKind"] 2071 }; 2072 ServerCapabilities cap = { 2073 textDocumentSync: TextDocumentSyncKind.incremental, 2074 codeActionProvider: cao 2075 }; 2076 assert(cap.serializeJson == `{"textDocumentSync":2,"codeActionProvider":{"codeActionKinds":["refactor","source.organizeImports","CustomKind"]}}`, cap.serializeJson); 2077 } 2078 2079 @serdeFallbackStruct 2080 @allowedMethods("initialized") 2081 struct InitializedParams 2082 { 2083 } 2084 2085 @serdeFallbackStruct 2086 struct ServerWorkspaceCapabilities 2087 { 2088 @serdeOptional Optional!WorkspaceFoldersServerCapabilities workspaceFolders; 2089 @serdeOptional Optional!WorkspaceFileOperationsCapabilities fileOperations; 2090 } 2091 2092 @serdeFallbackStruct 2093 struct WorkspaceFoldersServerCapabilities 2094 { 2095 @serdeOptional Optional!bool supported; 2096 @serdeOptional Variant!(void, bool, string) changeNotifications; 2097 } 2098 2099 @serdeFallbackStruct 2100 struct WorkspaceFileOperationsCapabilities 2101 { 2102 @serdeOptional Optional!FileOperationRegistrationOptions didCreate; 2103 @serdeOptional Optional!FileOperationRegistrationOptions willCreate; 2104 @serdeOptional Optional!FileOperationRegistrationOptions didRename; 2105 @serdeOptional Optional!FileOperationRegistrationOptions willRename; 2106 @serdeOptional Optional!FileOperationRegistrationOptions didDelete; 2107 @serdeOptional Optional!FileOperationRegistrationOptions willDelete; 2108 } 2109 2110 @serdeFallbackStruct 2111 struct FileOperationRegistrationOptions 2112 { 2113 FileOperationFilter[] filters; 2114 } 2115 2116 @serdeEnumProxy!string 2117 enum FileOperationPatternKind : string 2118 { 2119 file = "file", 2120 folder = "folder" 2121 } 2122 2123 @serdeFallbackStruct 2124 struct FileOperationPatternOptions 2125 { 2126 @serdeOptional Optional!bool ignoreCase; 2127 } 2128 2129 @serdeFallbackStruct 2130 struct FileOperationPattern 2131 { 2132 string glob; 2133 @serdeOptional Optional!FileOperationPatternKind matches; 2134 @serdeOptional Optional!FileOperationPatternOptions options; 2135 } 2136 2137 @serdeFallbackStruct 2138 struct FileOperationFilter 2139 { 2140 FileOperationPattern pattern; 2141 @serdeOptional Optional!string scheme; 2142 } 2143 2144 @serdeFallbackStruct 2145 @allowedMethods("workspace/willCreateFiles", "workspace/didCreateFiles") 2146 struct CreateFilesParams 2147 { 2148 FileCreate[] files; 2149 } 2150 2151 @serdeFallbackStruct 2152 struct FileCreate 2153 { 2154 string uri; 2155 } 2156 2157 @serdeFallbackStruct 2158 @allowedMethods("workspace/willRenameFiles", "workspace/didRenameFiles") 2159 struct RenameFilesParams 2160 { 2161 FileRename[] files; 2162 } 2163 2164 @serdeFallbackStruct 2165 struct FileRename 2166 { 2167 string oldUri; 2168 string newUri; 2169 } 2170 2171 @serdeFallbackStruct 2172 @allowedMethods("workspace/willDeleteFiles", "workspace/didDeleteFiles") 2173 struct DeleteFilesParams 2174 { 2175 FileDelete[] files; 2176 } 2177 2178 @serdeFallbackStruct 2179 struct FileDelete 2180 { 2181 string uri; 2182 } 2183 2184 @serdeFallbackStruct 2185 struct Registration 2186 { 2187 string id; 2188 string method; 2189 @serdeOptional OptionalJsonValue registerOptions; 2190 } 2191 2192 @serdeFallbackStruct 2193 @allowedMethods("client/registerCapability") 2194 struct RegistrationParams 2195 { 2196 Registration[] registrations; 2197 } 2198 2199 @serdeFallbackStruct 2200 struct Unregistration 2201 { 2202 string id; 2203 string method; 2204 } 2205 2206 @serdeFallbackStruct 2207 @allowedMethods("client/unregisterCapability") 2208 struct UnregistrationParams 2209 { 2210 Unregistration[] unregistrations; 2211 } 2212 2213 mixin template TextDocumentRegistrationOptions() 2214 { 2215 @serdeOptional Optional!DocumentSelector documentSelector; 2216 } 2217 2218 mixin template WorkDoneProgressOptions() 2219 { 2220 @serdeOptional Optional!bool workDoneProgress; 2221 } 2222 2223 mixin template StaticRegistrationOptions() 2224 { 2225 @serdeOptional Optional!string id; 2226 } 2227 2228 @serdeFallbackStruct 2229 struct DidChangeConfigurationClientCapabilities 2230 { 2231 @serdeOptional Optional!bool dynamicRegistration; 2232 } 2233 2234 /// You might want to use `RootJsonToken` instead of this type if you want to 2235 /// deserialize your custom config types. 2236 @serdeFallbackStruct 2237 @allowedMethods("workspace/didChangeConfiguration") 2238 struct DidChangeConfigurationParams 2239 { 2240 JsonValue settings; 2241 } 2242 2243 @serdeFallbackStruct 2244 @allowedMethods("workspace/configuration") 2245 struct ConfigurationParams 2246 { 2247 ConfigurationItem[] items; 2248 } 2249 2250 @serdeFallbackStruct 2251 struct ConfigurationItem 2252 { 2253 @serdeOptional Optional!string scopeUri; 2254 @serdeOptional Optional!string section; 2255 } 2256 2257 @serdeFallbackStruct 2258 @allowedMethods("textDocument/didOpen") 2259 struct DidOpenTextDocumentParams 2260 { 2261 TextDocumentItem textDocument; 2262 } 2263 2264 @serdeFallbackStruct 2265 @allowedMethods("textDocument/didChange") 2266 struct DidChangeTextDocumentParams 2267 { 2268 VersionedTextDocumentIdentifier textDocument; 2269 TextDocumentContentChangeEvent[] contentChanges; 2270 } 2271 2272 @serdeFallbackStruct 2273 struct TextDocumentContentChangeEvent 2274 { 2275 @serdeOptional Optional!TextRange range; 2276 string text; 2277 } 2278 2279 @serdeFallbackStruct 2280 struct TextDocumentChangeRegistrationOptions 2281 { 2282 mixin TextDocumentRegistrationOptions; 2283 2284 TextDocumentSyncKind syncKind; 2285 } 2286 2287 @serdeFallbackStruct 2288 @allowedMethods("textDocument/willSave", "textDocument/willSaveWaitUntil") 2289 struct WillSaveTextDocumentParams 2290 { 2291 TextDocumentIdentifier textDocument; 2292 TextDocumentSaveReason reason; 2293 } 2294 2295 @serdeEnumProxy!int 2296 enum TextDocumentSaveReason 2297 { 2298 manual = 1, 2299 afterDelay, 2300 focusOut 2301 } 2302 2303 @serdeFallbackStruct 2304 struct TextDocumentSaveRegistrationOptions 2305 { 2306 mixin TextDocumentRegistrationOptions; 2307 2308 @serdeOptional Optional!bool includeText; 2309 } 2310 2311 @serdeFallbackStruct 2312 @allowedMethods("textDocument/didSave") 2313 struct DidSaveTextDocumentParams 2314 { 2315 TextDocumentIdentifier textDocument; 2316 @serdeOptional Optional!string text; 2317 } 2318 2319 @serdeFallbackStruct 2320 @allowedMethods("textDocument/didClose") 2321 struct DidCloseTextDocumentParams 2322 { 2323 TextDocumentIdentifier textDocument; 2324 } 2325 2326 @serdeFallbackStruct 2327 struct FileSystemWatcher 2328 { 2329 string globPattern; 2330 @serdeOptional Optional!WatchKind kind; 2331 } 2332 2333 @serdeEnumProxy!int 2334 enum WatchKind 2335 { 2336 create = 1, 2337 change = 2, 2338 delete_ = 4 2339 } 2340 2341 unittest 2342 { 2343 FileSystemWatcher w = { 2344 globPattern: "**/foo.d", 2345 kind: WatchKind.change | WatchKind.delete_ 2346 }; 2347 assert(w.serializeJson == `{"globPattern":"**/foo.d","kind":6}`); 2348 } 2349 2350 @serdeFallbackStruct 2351 struct DidChangeWatchedFilesClientCapabilities 2352 { 2353 @serdeOptional Optional!bool dynamicRegistration; 2354 } 2355 2356 @serdeFallbackStruct 2357 struct DidChangeWatchedFilesRegistrationOptions 2358 { 2359 FileSystemWatcher[] watchers; 2360 } 2361 2362 @serdeFallbackStruct 2363 @allowedMethods("workspace/didChangeWatchedFiles") 2364 struct DidChangeWatchedFilesParams 2365 { 2366 FileEvent[] changes; 2367 } 2368 2369 @serdeFallbackStruct 2370 struct FileEvent 2371 { 2372 DocumentUri uri; 2373 FileChangeType type; 2374 } 2375 2376 @serdeEnumProxy!int 2377 enum FileChangeType 2378 { 2379 created = 1, 2380 changed, 2381 deleted 2382 } 2383 2384 @serdeFallbackStruct 2385 struct WorkspaceSymbolClientCapabilities 2386 { 2387 @serdeOptional Optional!bool dynamicRegistration; 2388 @serdeOptional Optional!(OptionalValueSet!SymbolKind) symbolKind; 2389 @serdeOptional Optional!(RequiredValueSet!SymbolTag) tagSupport; 2390 } 2391 2392 @serdeFallbackStruct 2393 struct WorkspaceSymbolOptions 2394 { 2395 mixin WorkDoneProgressOptions; 2396 } 2397 2398 @serdeFallbackStruct 2399 struct WorkspaceSymbolRegistrationOptions 2400 { 2401 mixin WorkDoneProgressOptions; 2402 } 2403 2404 @serdeFallbackStruct 2405 @allowedMethods("workspace/symbol") 2406 struct WorkspaceSymbolParams 2407 { 2408 string query; 2409 } 2410 2411 @serdeFallbackStruct 2412 struct PublishDiagnosticsClientCapabilities 2413 { 2414 @serdeOptional Optional!bool relatedInformation; 2415 @serdeOptional Optional!(RequiredValueSet!DiagnosticTag) tagSupport; 2416 @serdeOptional Optional!bool versionSupport; 2417 @serdeOptional Optional!bool codeDescriptionSupport; 2418 @serdeOptional Optional!bool dataSupport; 2419 } 2420 2421 @serdeFallbackStruct 2422 @allowedMethods("textDocument/publishDiagnostics") 2423 struct PublishDiagnosticsParams 2424 { 2425 DocumentUri uri; 2426 Diagnostic[] diagnostics; 2427 @serdeKeys("version") Optional!int version_; 2428 } 2429 2430 @serdeFallbackStruct 2431 struct CompletionRegistrationOptions 2432 { 2433 mixin TextDocumentRegistrationOptions; 2434 2435 @serdeOptional Optional!(string[]) triggerCharacters; 2436 bool resolveProvider; 2437 } 2438 2439 @serdeFallbackStruct 2440 @allowedMethods("textDocument/completion") 2441 struct CompletionParams 2442 { 2443 TextDocumentIdentifier textDocument; 2444 Position position; 2445 @serdeOptional Optional!CompletionContext context; 2446 } 2447 2448 @serdeEnumProxy!int 2449 enum CompletionTriggerKind 2450 { 2451 invoked = 1, 2452 triggerCharacter = 2, 2453 triggerForIncompleteCompletions = 3 2454 } 2455 2456 @serdeFallbackStruct 2457 struct CompletionContext 2458 { 2459 CompletionTriggerKind triggerKind; 2460 @serdeOptional Optional!string triggerCharacter; 2461 } 2462 2463 @serdeFallbackStruct 2464 struct CompletionList 2465 { 2466 bool isIncomplete; 2467 CompletionItem[] items; 2468 } 2469 2470 @serdeEnumProxy!int 2471 enum InsertTextFormat 2472 { 2473 plainText = 1, 2474 snippet 2475 } 2476 2477 @serdeEnumProxy!int 2478 enum CompletionItemTag 2479 { 2480 deprecated_ = 1 2481 } 2482 2483 @serdeFallbackStruct 2484 struct InsertReplaceEdit 2485 { 2486 string newText; 2487 TextRange insert; 2488 TextRange replace; 2489 } 2490 2491 unittest 2492 { 2493 string s = `{"newText":"new text","insert":{"start":{"line":1,"character":2},"end":{"line":3,"character":4}},"replace":{"start":{"line":5,"character":6},"end":{"line":7,"character":8}}}`; 2494 auto v = InsertReplaceEdit( 2495 "new text", 2496 TextRange(1, 2, 3, 4), 2497 TextRange(5, 6, 7, 8) 2498 ); 2499 assert(s.deserializeJson!InsertReplaceEdit == v); 2500 2501 Variant!(void, InsertReplaceEdit) var = v; 2502 assert(s.deserializeJson!(typeof(var)) == var); 2503 2504 Variant!(void, StructVariant!(TextEdit, InsertReplaceEdit)) var2 = v; 2505 assert(s.deserializeJson!(typeof(var2)) == var2); 2506 2507 struct Struct 2508 { 2509 Variant!(void, StructVariant!(TextEdit, InsertReplaceEdit)) edit; 2510 } 2511 2512 Struct str; 2513 str.edit = StructVariant!(TextEdit, InsertReplaceEdit)(v); 2514 auto strS = `{"edit":` ~ s ~ `}`; 2515 assert(str.serializeJson == strS); 2516 assert(strS.deserializeJson!Struct == str, strS.deserializeJson!Struct.to!string ~ " !=\n" ~ str.to!string); 2517 } 2518 2519 @serdeEnumProxy!int 2520 enum InsertTextMode 2521 { 2522 asIs = 1, 2523 adjustIndentation = 2 2524 } 2525 2526 @serdeFallbackStruct 2527 struct CompletionItemLabelDetails 2528 { 2529 /** 2530 * An optional string which is rendered less prominently directly after 2531 * {@link CompletionItemLabel.label label}, without any spacing. Should be 2532 * used for function signatures or type annotations. 2533 */ 2534 @serdeOptional Optional!string detail; 2535 2536 /** 2537 * An optional string which is rendered less prominently after 2538 * {@link CompletionItemLabel.detail}. Should be used for fully qualified 2539 * names or file path. 2540 */ 2541 @serdeOptional Optional!string description; 2542 } 2543 2544 @serdeFallbackStruct 2545 struct CompletionItem 2546 { 2547 string label; 2548 @serdeOptional Optional!CompletionItemLabelDetails labelDetails; 2549 @serdeOptional Optional!CompletionItemKind kind; 2550 @serdeOptional Optional!(CompletionItemTag[]) tags; 2551 @serdeOptional Optional!string detail; 2552 @serdeOptional Variant!(void, string, MarkupContent) documentation; 2553 @serdeOptional Optional!bool preselect; 2554 @serdeOptional Optional!string sortText; 2555 @serdeOptional Optional!string filterText; 2556 @serdeOptional Optional!string insertText; 2557 @serdeOptional Optional!InsertTextFormat insertTextFormat; 2558 @serdeOptional Optional!InsertTextMode insertTextMode; 2559 @serdeOptional Variant!(void, StructVariant!(TextEdit, InsertReplaceEdit)) textEdit; 2560 @serdeOptional Optional!(TextEdit[]) additionalTextEdits; 2561 @serdeOptional Optional!(string[]) commitCharacters; 2562 @serdeOptional Optional!Command command; 2563 @serdeOptional OptionalJsonValue data; 2564 2565 string effectiveInsertText() const 2566 { 2567 return insertText.isNone ? label : insertText.deref; 2568 } 2569 } 2570 2571 unittest 2572 { 2573 CompletionItem[] values = [CompletionItem("hello")]; 2574 CompletionItem b = { 2575 label: "b", 2576 detail: "detail".opt 2577 }; values ~= b; 2578 CompletionItem c = { 2579 label: "c", 2580 documentation: MarkupContent("cool beans") 2581 }; values ~= c; 2582 CompletionItem d = { 2583 label: "d", 2584 textEdit: TextEdit(TextRange(1, 2, 3, 4), "new text") 2585 }; values ~= d; 2586 CompletionItem e = { 2587 label: "e", 2588 textEdit: InsertReplaceEdit("new text", TextRange(1, 2, 3, 4), TextRange(5, 6, 7, 8)) 2589 }; values ~= e; 2590 2591 string[] expected = [ 2592 `{"label":"hello"}`, 2593 `{"label":"b","detail":"detail"}`, 2594 `{"label":"c","documentation":{"kind":"plaintext","value":"cool beans"}}`, 2595 `{"label":"d","textEdit":{"range":{"start":{"line":1,"character":2},"end":{"line":3,"character":4}},"newText":"new text"}}`, 2596 `{"label":"e","textEdit":{"newText":"new text","insert":{"start":{"line":1,"character":2},"end":{"line":3,"character":4}},"replace":{"start":{"line":5,"character":6},"end":{"line":7,"character":8}}}}`, 2597 ]; 2598 2599 foreach (i, v; values) 2600 assert(v.serializeJson == expected[i], v.serializeJson ~ " !=\n" ~ expected[i]); 2601 2602 foreach (v; values) 2603 assert(deserializeJson!CompletionItem(v.serializeJson) == v, v.to!string ~ " !=\n" ~ v.serializeJson.deserializeJson!CompletionItem.to!string); 2604 } 2605 2606 unittest 2607 { 2608 auto str = `{ 2609 "label":"toStringText", 2610 "detail":"string toString() in struct using std.conv:text", 2611 "documentation":{ 2612 "kind":"markdown", 2613 "value":"doc text" 2614 }, 2615 "filterText":"toStringText", 2616 "insertTextFormat":2, 2617 "insertText":"myInsertText", 2618 "kind":15, 2619 "sortText":"2_5_toStringText", 2620 "data":{ 2621 "level":"type", 2622 "column":5, 2623 "format":"dfmt args", 2624 "uri":"file:///home/webfreak/dev/serve-d/source/served/lsp/protoext.d", 2625 "line":305 2626 } 2627 }`; 2628 2629 CompletionItem item = str.deserializeJson!CompletionItem; 2630 assert(item.label == "toStringText"); 2631 assert(item.detail.deref == "string toString() in struct using std.conv:text"); 2632 assert(item.documentation.get!MarkupContent == MarkupContent(MarkupKind.markdown, "doc text")); 2633 assert(item.filterText.deref == "toStringText"); 2634 assert(item.insertTextFormat.deref == InsertTextFormat.snippet); 2635 assert(item.insertText.deref == "myInsertText"); 2636 assert(item.kind.deref == CompletionItemKind.snippet); 2637 assert(item.sortText.deref == "2_5_toStringText"); 2638 auto data = item.data.deref.get!(StringMap!JsonValue); 2639 assert(data["level"].get!string == "type"); 2640 assert(data["column"].get!long == 5); 2641 assert(data["format"].get!string == "dfmt args"); 2642 assert(data["uri"].get!string == "file:///home/webfreak/dev/serve-d/source/served/lsp/protoext.d"); 2643 assert(data["line"].get!long == 305); 2644 } 2645 2646 @serdeEnumProxy!int 2647 enum CompletionItemKind 2648 { 2649 text = 1, 2650 method, 2651 function_, 2652 constructor, 2653 field, 2654 variable, 2655 class_, 2656 interface_, 2657 module_, 2658 property, 2659 unit, 2660 value, 2661 enum_, 2662 keyword, 2663 snippet, 2664 color, 2665 file, 2666 reference, 2667 folder, 2668 enumMember, 2669 constant, 2670 struct_, 2671 event, 2672 operator, 2673 typeParameter 2674 } 2675 2676 @serdeFallbackStruct 2677 struct HoverClientCapabilities 2678 { 2679 @serdeOptional Optional!bool dynamicRegistration; 2680 @serdeOptional Optional!(MarkupKind[]) contentFormat; 2681 } 2682 2683 @serdeFallbackStruct 2684 struct HoverOptions 2685 { 2686 mixin WorkDoneProgressOptions; 2687 } 2688 2689 @serdeFallbackStruct 2690 struct HoverRegistrationOptions 2691 { 2692 mixin TextDocumentRegistrationOptions; 2693 mixin WorkDoneProgressOptions; 2694 } 2695 2696 @serdeFallbackStruct 2697 @allowedMethods("textDocument/hover") 2698 struct HoverParams 2699 { 2700 TextDocumentIdentifier textDocument; 2701 Position position; 2702 } 2703 2704 @serdeFallbackStruct 2705 struct Hover 2706 { 2707 Variant!(StructVariant!(MarkedString, MarkupContent), MarkedString[]) contents; 2708 @serdeOptional Optional!TextRange range; 2709 } 2710 2711 @serdeFallbackStruct 2712 struct MarkedString 2713 { 2714 import mir.ion.exception; 2715 import mir.ion.value; 2716 import mir.deser.ion : deserializeIon; 2717 import mir.ion.type_code : IonTypeCode; 2718 2719 string value; 2720 string language; 2721 2722 private static struct SerializeHelper 2723 { 2724 string value; 2725 string language; 2726 } 2727 2728 void serialize(S)(scope ref S serializer) const 2729 { 2730 import mir.ser : serializeValue; 2731 2732 if (language.length) 2733 { 2734 auto helper = SerializeHelper(value, language); 2735 serializeValue(serializer, helper); 2736 } 2737 else 2738 serializer.putValue(value); 2739 } 2740 2741 /** 2742 Returns: error msg if any 2743 */ 2744 @safe pure scope 2745 IonException deserializeFromIon(scope const char[][] symbolTable, IonDescribedValue value) 2746 { 2747 import mir.deser.ion : deserializeIon; 2748 import mir.ion.type_code : IonTypeCode; 2749 2750 if (value.descriptor.type == IonTypeCode..string) 2751 { 2752 this.value = deserializeIon!string(symbolTable, value); 2753 this.language = null; 2754 } 2755 else if (value.descriptor.type == IonTypeCode.struct_) 2756 { 2757 auto p = deserializeIon!SerializeHelper(symbolTable, value); 2758 this.value = p.value; 2759 this.language = p.language; 2760 } 2761 else 2762 return ionException(IonErrorCode.jsonUnexpectedValue); 2763 return null; 2764 } 2765 } 2766 2767 @serdeEnumProxy!string 2768 enum MarkupKind : string 2769 { 2770 plaintext = "plaintext", 2771 markdown = "markdown" 2772 } 2773 2774 @serdeFallbackStruct 2775 struct MarkupContent 2776 { 2777 string kind; 2778 string value; 2779 2780 this(MarkupKind kind, string value) 2781 { 2782 this.kind = kind; 2783 this.value = value; 2784 } 2785 2786 this(string text) 2787 { 2788 kind = MarkupKind.plaintext; 2789 value = text; 2790 } 2791 2792 this(MarkedString[] markup) 2793 { 2794 kind = MarkupKind.markdown; 2795 foreach (block; markup) 2796 { 2797 if (block.language.length) 2798 { 2799 value ~= "```" ~ block.language ~ "\n"; 2800 value ~= block.value; 2801 value ~= "```"; 2802 } 2803 else 2804 value ~= block.value; 2805 value ~= "\n\n"; 2806 } 2807 } 2808 } 2809 2810 @serdeFallbackStruct 2811 struct MarkdownClientCapabilities 2812 { 2813 string parser; 2814 @serdeKeys("version") Optional!string version_; 2815 } 2816 2817 @serdeFallbackStruct 2818 struct SignatureHelpClientCapabilities 2819 { 2820 @serdeFallbackStruct 2821 @serdeIgnoreUnexpectedKeys 2822 static struct SignatureInformationCapabilities 2823 { 2824 @serdeFallbackStruct 2825 @serdeIgnoreUnexpectedKeys 2826 static struct ParameterInformationSupport 2827 { 2828 @serdeOptional Optional!bool labelOffsetSupport; 2829 } 2830 2831 @serdeOptional Optional!(MarkupKind[]) documentationFormat; 2832 @serdeOptional Optional!ParameterInformationSupport parameterInformation; 2833 @serdeOptional Optional!bool activeParameterSupport; 2834 } 2835 2836 @serdeOptional Optional!bool dynamicRegistration; 2837 @serdeOptional Optional!SignatureInformationCapabilities signatureInformation; 2838 @serdeOptional Optional!bool contextSupport; 2839 } 2840 2841 @serdeFallbackStruct 2842 struct SignatureHelpOptions 2843 { 2844 mixin WorkDoneProgressOptions; 2845 2846 @serdeOptional Optional!(string[]) triggerCharacters; 2847 @serdeOptional Optional!(string[]) retriggerCharacters; 2848 } 2849 2850 @serdeFallbackStruct 2851 struct SignatureHelpRegistrationOptions 2852 { 2853 mixin TextDocumentRegistrationOptions; 2854 mixin WorkDoneProgressOptions; 2855 2856 @serdeOptional Optional!(string[]) triggerCharacters; 2857 @serdeOptional Optional!(string[]) retriggerCharacters; 2858 } 2859 2860 @serdeFallbackStruct 2861 @allowedMethods("textDocument/signatureHelp") 2862 struct SignatureHelpParams 2863 { 2864 TextDocumentIdentifier textDocument; 2865 Position position; 2866 @serdeOptional Optional!SignatureHelpContext context; 2867 } 2868 2869 @serdeEnumProxy!int 2870 enum SignatureHelpTriggerKind 2871 { 2872 invoked = 1, 2873 triggerCharacter, 2874 contentChange 2875 } 2876 2877 @serdeFallbackStruct 2878 struct SignatureHelpContext 2879 { 2880 SignatureHelpTriggerKind triggerKind; 2881 @serdeOptional Optional!string triggerCharacter; 2882 @serdeOptional Optional!bool isRetrigger; 2883 @serdeOptional Optional!SignatureHelp activeSignatureHelp; 2884 } 2885 2886 @serdeFallbackStruct 2887 struct SignatureHelp 2888 { 2889 SignatureInformation[] signatures; 2890 @serdeOptional Optional!uint activeSignature; 2891 @serdeOptional Optional!uint activeParameter; 2892 2893 this(SignatureInformation[] signatures) 2894 { 2895 this.signatures = signatures; 2896 } 2897 2898 this(SignatureInformation[] signatures, int activeSignature, int activeParameter) 2899 { 2900 this.signatures = signatures; 2901 this.activeSignature = activeSignature; 2902 this.activeParameter = activeParameter; 2903 } 2904 2905 this(SignatureInformation[] signatures, uint activeSignature, uint activeParameter) 2906 { 2907 this.signatures = signatures; 2908 this.activeSignature = activeSignature; 2909 this.activeParameter = activeParameter; 2910 } 2911 } 2912 2913 @serdeFallbackStruct 2914 struct SignatureInformation 2915 { 2916 string label; 2917 @serdeOptional Variant!(void, string, MarkupContent) documentation; 2918 @serdeOptional Optional!(ParameterInformation[]) parameters; 2919 @serdeOptional Optional!uint activeParameter; 2920 } 2921 2922 @serdeFallbackStruct 2923 struct ParameterInformation 2924 { 2925 Variant!(string, uint[2]) label; 2926 @serdeOptional Variant!(void, string, MarkupContent) documentation; 2927 } 2928 2929 @serdeFallbackStruct 2930 struct DeclarationClientCapabilities 2931 { 2932 @serdeOptional Optional!bool dynamicRegistration; 2933 @serdeOptional Optional!bool linkSupport; 2934 } 2935 2936 @serdeFallbackStruct 2937 struct DeclarationOptions 2938 { 2939 mixin WorkDoneProgressOptions; 2940 } 2941 2942 @serdeFallbackStruct 2943 struct DeclarationRegistrationOptions 2944 { 2945 mixin WorkDoneProgressOptions; 2946 mixin TextDocumentRegistrationOptions; 2947 mixin StaticRegistrationOptions; 2948 } 2949 2950 @serdeFallbackStruct 2951 @allowedMethods("textDocument/declaration") 2952 struct DeclarationParams 2953 { 2954 TextDocumentIdentifier textDocument; 2955 Position position; 2956 } 2957 2958 @serdeFallbackStruct 2959 struct DefinitionClientCapabilities 2960 { 2961 @serdeOptional Optional!bool dynamicRegistration; 2962 @serdeOptional Optional!bool linkSupport; 2963 } 2964 2965 @serdeFallbackStruct 2966 struct DefinitionOptions 2967 { 2968 mixin WorkDoneProgressOptions; 2969 } 2970 2971 @serdeFallbackStruct 2972 struct DefinitionRegistrationOptions 2973 { 2974 mixin TextDocumentRegistrationOptions; 2975 mixin WorkDoneProgressOptions; 2976 } 2977 2978 @serdeFallbackStruct 2979 @allowedMethods("textDocument/definition") 2980 struct DefinitionParams 2981 { 2982 TextDocumentIdentifier textDocument; 2983 Position position; 2984 } 2985 2986 @serdeFallbackStruct 2987 struct TypeDefinitionClientCapabilities 2988 { 2989 @serdeOptional Optional!bool dynamicRegistration; 2990 @serdeOptional Optional!bool linkSupport; 2991 } 2992 2993 @serdeFallbackStruct 2994 struct TypeDefinitionOptions 2995 { 2996 mixin WorkDoneProgressOptions; 2997 } 2998 2999 @serdeFallbackStruct 3000 struct TypeDefinitionRegistrationOptions 3001 { 3002 mixin TextDocumentRegistrationOptions; 3003 mixin WorkDoneProgressOptions; 3004 mixin StaticRegistrationOptions; 3005 } 3006 3007 @serdeFallbackStruct 3008 @allowedMethods("textDocument/typeDefinition") 3009 struct TypeDefinitionParams 3010 { 3011 TextDocumentIdentifier textDocument; 3012 Position position; 3013 } 3014 3015 @serdeFallbackStruct 3016 struct ImplementationClientCapabilities 3017 { 3018 @serdeOptional Optional!bool dynamicRegistration; 3019 @serdeOptional Optional!bool linkSupport; 3020 } 3021 3022 @serdeFallbackStruct 3023 struct ImplementationOptions 3024 { 3025 mixin WorkDoneProgressOptions; 3026 } 3027 3028 @serdeFallbackStruct 3029 struct ImplementationRegistrationOptions 3030 { 3031 mixin TextDocumentRegistrationOptions; 3032 mixin WorkDoneProgressOptions; 3033 mixin StaticRegistrationOptions; 3034 } 3035 3036 @serdeFallbackStruct 3037 @allowedMethods("textDocument/implementation") 3038 struct ImplementationParams 3039 { 3040 TextDocumentIdentifier textDocument; 3041 Position position; 3042 } 3043 3044 @serdeFallbackStruct 3045 struct ReferenceClientCapabilities 3046 { 3047 @serdeOptional Optional!bool dynamicRegistration; 3048 } 3049 3050 @serdeFallbackStruct 3051 struct ReferenceOptions 3052 { 3053 mixin WorkDoneProgressOptions; 3054 } 3055 3056 @serdeFallbackStruct 3057 struct ReferenceRegistrationOptions 3058 { 3059 mixin TextDocumentRegistrationOptions; 3060 mixin WorkDoneProgressOptions; 3061 } 3062 3063 @serdeFallbackStruct 3064 @allowedMethods("textDocument/references") 3065 struct ReferenceParams 3066 { 3067 TextDocumentIdentifier textDocument; 3068 Position position; 3069 ReferenceContext context; 3070 } 3071 3072 @serdeFallbackStruct 3073 struct ReferenceContext 3074 { 3075 bool includeDeclaration; 3076 } 3077 3078 @serdeFallbackStruct 3079 struct DocumentHighlightClientCapabilities 3080 { 3081 @serdeOptional Optional!bool dynamicRegistration; 3082 } 3083 3084 @serdeFallbackStruct 3085 struct DocumentHighlightOptions 3086 { 3087 mixin WorkDoneProgressOptions; 3088 } 3089 3090 @serdeFallbackStruct 3091 struct DocumentHighlightRegistrationOptions 3092 { 3093 mixin TextDocumentRegistrationOptions; 3094 mixin WorkDoneProgressOptions; 3095 } 3096 3097 @serdeFallbackStruct 3098 @allowedMethods("textDocument/documentHighlight") 3099 struct DocumentHighlightParams 3100 { 3101 TextDocumentIdentifier textDocument; 3102 Position position; 3103 } 3104 3105 @serdeFallbackStruct 3106 struct DocumentHighlight 3107 { 3108 TextRange range; 3109 @serdeOptional Optional!DocumentHighlightKind kind; 3110 } 3111 3112 @serdeEnumProxy!int 3113 enum DocumentHighlightKind 3114 { 3115 text = 1, 3116 read, 3117 write 3118 } 3119 3120 @serdeFallbackStruct 3121 struct DocumentSymbolClientCapabilities 3122 { 3123 @serdeOptional Optional!bool dynamicRegistration; 3124 @serdeOptional Optional!(OptionalValueSet!SymbolKind) symbolKind; 3125 @serdeOptional Optional!bool hierarchicalDocumentSymbolSupport; 3126 @serdeOptional Optional!(RequiredValueSet!SymbolTag) tagSupport; 3127 @serdeOptional Optional!bool labelSupport; 3128 } 3129 3130 @serdeFallbackStruct 3131 struct DocumentSymbolOptions 3132 { 3133 mixin WorkDoneProgressOptions; 3134 3135 @serdeOptional Optional!string label; 3136 } 3137 3138 @serdeFallbackStruct 3139 struct DocumentSymbolRegistrationOptions 3140 { 3141 mixin TextDocumentRegistrationOptions; 3142 mixin WorkDoneProgressOptions; 3143 3144 @serdeOptional Optional!string label; 3145 } 3146 3147 @serdeFallbackStruct 3148 @allowedMethods("textDocument/documentSymbol") 3149 struct DocumentSymbolParams 3150 { 3151 TextDocumentIdentifier textDocument; 3152 } 3153 3154 @serdeEnumProxy!int 3155 enum SymbolKind 3156 { 3157 file = 1, 3158 module_, 3159 namespace, 3160 package_, 3161 class_, 3162 method, 3163 property, 3164 field, 3165 constructor, 3166 enum_, 3167 interface_, 3168 function_, 3169 variable, 3170 constant, 3171 string, 3172 number, 3173 boolean, 3174 array, 3175 object, 3176 key, 3177 null_, 3178 enumMember, 3179 struct_, 3180 event, 3181 operator, 3182 typeParameter 3183 } 3184 3185 @serdeEnumProxy!int 3186 enum SymbolTag 3187 { 3188 deprecated_ = 1 3189 } 3190 3191 @serdeFallbackStruct 3192 struct DocumentSymbol 3193 { 3194 string name; 3195 @serdeOptional Optional!string detail; 3196 SymbolKind kind; 3197 @serdeOptional Optional!(SymbolTag[]) tags; 3198 TextRange range; 3199 TextRange selectionRange; 3200 DocumentSymbol[] children; 3201 } 3202 3203 @serdeFallbackStruct 3204 struct SymbolInformation 3205 { 3206 string name; 3207 SymbolKind kind; 3208 @serdeOptional Optional!(SymbolTag[]) tags; 3209 Location location; 3210 @serdeOptional Optional!string containerName; 3211 } 3212 3213 @serdeFallbackStruct 3214 struct CodeActionClientCapabilities 3215 { 3216 @serdeFallbackStruct 3217 @serdeIgnoreUnexpectedKeys 3218 static struct CodeActionLiteralSupport 3219 { 3220 RequiredValueSet!CodeActionKind codeActionKind; 3221 } 3222 3223 @serdeFallbackStruct 3224 @serdeIgnoreUnexpectedKeys 3225 static struct ResolveSupport 3226 { 3227 string[] properties; 3228 } 3229 3230 3231 @serdeOptional Optional!bool dynamicRegistration; 3232 @serdeOptional Optional!CodeActionLiteralSupport codeActionLiteralSupport; 3233 @serdeOptional Optional!bool isPreferredSupport; 3234 @serdeOptional Optional!bool disabledSupport; 3235 @serdeOptional Optional!bool dataSupport; 3236 @serdeOptional Optional!ResolveSupport resolveSupport; 3237 @serdeOptional Optional!bool honorsChangeAnnotations; 3238 } 3239 3240 @serdeFallbackStruct 3241 struct CodeActionOptions 3242 { 3243 mixin WorkDoneProgressOptions; 3244 3245 @serdeOptional Optional!(CodeActionKind[]) codeActionKinds; 3246 @serdeOptional Optional!bool resolveProvider; 3247 } 3248 3249 @serdeFallbackStruct 3250 struct CodeActionRegistrationOptions 3251 { 3252 mixin TextDocumentRegistrationOptions; 3253 mixin WorkDoneProgressOptions; 3254 3255 @serdeOptional Optional!(CodeActionKind[]) codeActionKinds; 3256 @serdeOptional Optional!bool resolveProvider; 3257 } 3258 3259 @serdeFallbackStruct 3260 @allowedMethods("textDocument/codeAction") 3261 struct CodeActionParams 3262 { 3263 TextDocumentIdentifier textDocument; 3264 TextRange range; 3265 CodeActionContext context; 3266 } 3267 3268 @serdeEnumProxy!string 3269 enum CodeActionKind : string 3270 { 3271 empty = "", 3272 quickfix = "quickfix", 3273 refactor = "refactor", 3274 refactorExtract = "refactor.extract", 3275 refactorInline = "refactor.inline", 3276 refactorRewrite = "refactor.rewrite", 3277 source = "source", 3278 sourceOrganizeImports = "source.organizeImports", 3279 } 3280 3281 @serdeFallbackStruct 3282 struct CodeActionContext 3283 { 3284 Diagnostic[] diagnostics; 3285 @serdeOptional Optional!(CodeActionKind[]) only; 3286 } 3287 3288 @serdeFallbackStruct 3289 struct CodeAction 3290 { 3291 this(Command command) 3292 { 3293 title = command.title; 3294 this.command = command; 3295 } 3296 3297 this(string title, WorkspaceEdit edit) 3298 { 3299 this.title = title; 3300 this.edit = edit; 3301 } 3302 3303 @serdeFallbackStruct 3304 @serdeIgnoreUnexpectedKeys 3305 static struct Disabled 3306 { 3307 string reason; 3308 } 3309 3310 string title; 3311 @serdeOptional Optional!CodeActionKind kind; 3312 @serdeOptional Optional!(Diagnostic[]) diagnostics; 3313 @serdeOptional Optional!bool isPreferred; 3314 @serdeOptional Optional!Disabled disabled; 3315 @serdeOptional Optional!WorkspaceEdit edit; 3316 @serdeOptional Optional!Command command; 3317 @serdeOptional OptionalJsonValue data; 3318 } 3319 3320 @serdeFallbackStruct 3321 struct CodeLensClientCapabilities 3322 { 3323 @serdeOptional Optional!bool dynamicRegistration; 3324 } 3325 3326 @serdeFallbackStruct 3327 struct CodeLensOptions 3328 { 3329 mixin WorkDoneProgressOptions; 3330 3331 @serdeOptional Optional!bool resolveProvider; 3332 } 3333 3334 @serdeFallbackStruct 3335 struct CodeLensRegistrationOptions 3336 { 3337 mixin TextDocumentRegistrationOptions; 3338 mixin WorkDoneProgressOptions; 3339 3340 @serdeOptional Optional!bool resolveProvider; 3341 } 3342 3343 @serdeFallbackStruct 3344 @allowedMethods("textDocument/codeLens") 3345 struct CodeLensParams 3346 { 3347 TextDocumentIdentifier textDocument; 3348 } 3349 3350 @serdeFallbackStruct 3351 struct CodeLens 3352 { 3353 TextRange range; 3354 @serdeOptional Optional!Command command; 3355 @serdeOptional OptionalJsonValue data; 3356 } 3357 3358 @serdeFallbackStruct 3359 struct CodeLensWorkspaceClientCapabilities 3360 { 3361 @serdeOptional Optional!bool refreshSupport; 3362 } 3363 3364 @serdeFallbackStruct 3365 struct DocumentLinkClientCapabilities 3366 { 3367 @serdeOptional Optional!bool dynamicRegistration; 3368 @serdeOptional Optional!bool tooltipSupport; 3369 } 3370 3371 @serdeFallbackStruct 3372 struct DocumentLinkOptions 3373 { 3374 mixin WorkDoneProgressOptions; 3375 3376 bool resolveProvider; 3377 } 3378 3379 @serdeFallbackStruct 3380 struct DocumentLinkRegistrationOptions 3381 { 3382 mixin TextDocumentRegistrationOptions; 3383 mixin WorkDoneProgressOptions; 3384 3385 bool resolveProvider; 3386 } 3387 3388 @serdeFallbackStruct 3389 @allowedMethods("textDocument/documentLink") 3390 struct DocumentLinkParams 3391 { 3392 TextDocumentIdentifier textDocument; 3393 } 3394 3395 @serdeFallbackStruct 3396 struct DocumentLink 3397 { 3398 TextRange range; 3399 @serdeOptional Optional!DocumentUri target; 3400 @serdeOptional Optional!string tooltip; 3401 @serdeOptional OptionalJsonValue data; 3402 } 3403 3404 @serdeFallbackStruct 3405 struct DocumentColorClientCapabilities 3406 { 3407 @serdeOptional Optional!bool dynamicRegistration; 3408 } 3409 3410 @serdeFallbackStruct 3411 struct DocumentColorOptions 3412 { 3413 mixin WorkDoneProgressOptions; 3414 } 3415 3416 @serdeFallbackStruct 3417 struct DocumentColorRegistrationOptions 3418 { 3419 mixin TextDocumentRegistrationOptions; 3420 mixin StaticRegistrationOptions; 3421 mixin WorkDoneProgressOptions; 3422 } 3423 3424 @serdeFallbackStruct 3425 @allowedMethods("textDocument/documentColor") 3426 struct DocumentColorParams 3427 { 3428 TextDocumentIdentifier textDocument; 3429 } 3430 3431 @serdeFallbackStruct 3432 struct ColorInformation 3433 { 3434 TextRange range; 3435 Color color; 3436 } 3437 3438 @serdeFallbackStruct 3439 struct Color 3440 { 3441 double red = 0; 3442 double green = 0; 3443 double blue = 0; 3444 double alpha = 1; 3445 } 3446 3447 @serdeFallbackStruct 3448 @allowedMethods("textDocument/colorPresentation") 3449 struct ColorPresentationParams 3450 { 3451 TextDocumentIdentifier textDocument; 3452 Color color; 3453 TextRange range; 3454 } 3455 3456 @serdeFallbackStruct 3457 struct ColorPresentation 3458 { 3459 string label; 3460 @serdeOptional Optional!TextEdit textEdit; 3461 @serdeOptional Optional!(TextEdit[]) additionalTextEdits; 3462 } 3463 3464 @serdeFallbackStruct 3465 struct DocumentFormattingClientCapabilities 3466 { 3467 @serdeOptional Optional!bool dynamicRegistration; 3468 } 3469 3470 @serdeFallbackStruct 3471 struct DocumentFormattingOptions 3472 { 3473 mixin WorkDoneProgressOptions; 3474 } 3475 3476 @serdeFallbackStruct 3477 struct DocumentFormattingRegistrationOptions 3478 { 3479 mixin TextDocumentRegistrationOptions; 3480 mixin WorkDoneProgressOptions; 3481 } 3482 3483 @serdeFallbackStruct 3484 @allowedMethods("textDocument/formatting") 3485 struct DocumentFormattingParams 3486 { 3487 TextDocumentIdentifier textDocument; 3488 FormattingOptions options; 3489 } 3490 3491 @serdeFallbackStruct 3492 struct FormattingOptions 3493 { 3494 int tabSize; 3495 bool insertSpaces; 3496 @serdeOptional Optional!bool trimTrailingWhitespace; 3497 @serdeOptional Optional!bool insertFinalNewline; 3498 @serdeOptional Optional!bool trimFinalNewlines; 3499 @serdeOptional OptionalJsonValue data; 3500 } 3501 3502 @serdeFallbackStruct 3503 struct DocumentRangeFormattingClientCapabilities 3504 { 3505 @serdeOptional Optional!bool dynamicRegistration; 3506 } 3507 3508 @serdeFallbackStruct 3509 struct DocumentRangeFormattingOptions 3510 { 3511 mixin WorkDoneProgressOptions; 3512 } 3513 3514 @serdeFallbackStruct 3515 struct DocumentRangeFormattingRegistrationOptions 3516 { 3517 mixin TextDocumentRegistrationOptions; 3518 mixin WorkDoneProgressOptions; 3519 } 3520 3521 @serdeFallbackStruct 3522 @allowedMethods("textDocument/rangeFormatting") 3523 struct DocumentRangeFormattingParams 3524 { 3525 TextDocumentIdentifier textDocument; 3526 TextRange range; 3527 FormattingOptions options; 3528 } 3529 3530 @serdeFallbackStruct 3531 struct DocumentOnTypeFormattingClientCapabilities 3532 { 3533 @serdeOptional Optional!bool dynamicRegistration; 3534 } 3535 3536 @serdeFallbackStruct 3537 struct DocumentOnTypeFormattingOptions 3538 { 3539 string firstTriggerCharacter; 3540 @serdeOptional Optional!(string[]) moreTriggerCharacter; 3541 } 3542 3543 @serdeFallbackStruct 3544 struct DocumentOnTypeFormattingRegistrationOptions 3545 { 3546 mixin TextDocumentRegistrationOptions; 3547 3548 string firstTriggerCharacter; 3549 @serdeOptional Optional!(string[]) moreTriggerCharacter; 3550 } 3551 3552 @serdeFallbackStruct 3553 @allowedMethods("textDocument/onTypeFormatting") 3554 struct DocumentOnTypeFormattingParams 3555 { 3556 TextDocumentIdentifier textDocument; 3557 Position position; 3558 string ch; 3559 FormattingOptions options; 3560 } 3561 3562 @serdeEnumProxy!int 3563 enum PrepareSupportDefaultBehavior 3564 { 3565 identifier = 1 3566 } 3567 3568 @serdeFallbackStruct 3569 struct RenameClientCapabilities 3570 { 3571 @serdeOptional Optional!bool dynamicRegistration; 3572 @serdeOptional Optional!bool prepareSupport; 3573 @serdeOptional Optional!PrepareSupportDefaultBehavior prepareSupportDefaultBehavior; 3574 @serdeOptional Optional!bool honorsChangeAnnotations; 3575 } 3576 3577 @serdeFallbackStruct 3578 struct RenameOptions 3579 { 3580 mixin WorkDoneProgressOptions; 3581 3582 @serdeOptional Optional!bool prepareProvider; 3583 } 3584 3585 @serdeFallbackStruct 3586 struct RenameRegistrationOptions 3587 { 3588 mixin TextDocumentRegistrationOptions; 3589 mixin WorkDoneProgressOptions; 3590 3591 @serdeOptional Optional!bool prepareProvider; 3592 } 3593 3594 @serdeFallbackStruct 3595 @allowedMethods("textDocument/rename") 3596 struct RenameParams 3597 { 3598 TextDocumentIdentifier textDocument; 3599 Position position; 3600 string newName; 3601 } 3602 3603 @serdeFallbackStruct 3604 @allowedMethods("textDocument/prepareRename") 3605 struct PrepareRenameParams 3606 { 3607 TextDocumentIdentifier textDocument; 3608 Position position; 3609 } 3610 3611 @serdeFallbackStruct 3612 struct FoldingRangeClientCapabilities 3613 { 3614 @serdeOptional Optional!bool dynamicRegistration; 3615 @serdeOptional Optional!uint rangeLimit; 3616 @serdeOptional Optional!bool lineFoldingOnly; 3617 } 3618 3619 @serdeFallbackStruct 3620 struct FoldingRangeOptions 3621 { 3622 mixin WorkDoneProgressOptions; 3623 } 3624 3625 @serdeFallbackStruct 3626 struct FoldingRangeRegistrationOptions 3627 { 3628 mixin TextDocumentRegistrationOptions; 3629 mixin WorkDoneProgressOptions; 3630 mixin StaticRegistrationOptions; 3631 } 3632 3633 @serdeFallbackStruct 3634 @allowedMethods("textDocument/foldingRange") 3635 struct FoldingRangeParams 3636 { 3637 TextDocumentIdentifier textDocument; 3638 } 3639 3640 @serdeEnumProxy!string 3641 enum FoldingRangeKind : string 3642 { 3643 comment = "comment", 3644 imports = "imports", 3645 region = "region" 3646 } 3647 3648 @serdeFallbackStruct 3649 struct FoldingRange 3650 { 3651 uint startLine; 3652 uint endLine; 3653 @serdeOptional Optional!uint startCharacter; 3654 @serdeOptional Optional!uint endCharacter; 3655 @serdeOptional Optional!string kind; 3656 } 3657 3658 @serdeFallbackStruct 3659 struct SelectionRangeClientCapabilities 3660 { 3661 @serdeOptional Optional!bool dynamicRegistration; 3662 } 3663 3664 @serdeFallbackStruct 3665 struct SelectionRangeOptions 3666 { 3667 mixin WorkDoneProgressOptions; 3668 } 3669 3670 @serdeFallbackStruct 3671 struct SelectionRangeRegistrationOptions 3672 { 3673 mixin WorkDoneProgressOptions; 3674 mixin TextDocumentRegistrationOptions; 3675 mixin StaticRegistrationOptions; 3676 } 3677 3678 @serdeFallbackStruct 3679 @allowedMethods("textDocument/selectionRange") 3680 struct SelectionRangeParams 3681 { 3682 TextDocumentIdentifier textDocument; 3683 Position[] positions; 3684 } 3685 3686 @serdeFallbackStruct 3687 struct SelectionRange 3688 { 3689 TextRange range; 3690 @serdeOptional OptionalJsonValue parent; 3691 } 3692 3693 @serdeFallbackStruct 3694 struct CallHierarchyClientCapabilities 3695 { 3696 @serdeOptional Optional!bool dynamicRegistration; 3697 } 3698 3699 @serdeFallbackStruct 3700 struct CallHierarchyOptions 3701 { 3702 mixin WorkDoneProgressOptions; 3703 } 3704 3705 @serdeFallbackStruct 3706 struct CallHierarchyRegistrationOptions 3707 { 3708 mixin TextDocumentRegistrationOptions; 3709 mixin WorkDoneProgressOptions; 3710 mixin StaticRegistrationOptions; 3711 } 3712 3713 @serdeFallbackStruct 3714 @allowedMethods("textDocument/prepareCallHierarchy") 3715 struct CallHierarchyPrepareParams 3716 { 3717 TextDocumentIdentifier textDocument; 3718 Position position; 3719 } 3720 3721 @serdeFallbackStruct 3722 struct CallHierarchyItem 3723 { 3724 string name; 3725 SymbolKind kind; 3726 @serdeOptional Optional!(SymbolTag[]) tags; 3727 @serdeOptional Optional!string detail; 3728 DocumentUri uri; 3729 TextRange range; 3730 TextRange selectionRange; 3731 @serdeOptional OptionalJsonValue data; 3732 } 3733 3734 @serdeFallbackStruct 3735 @allowedMethods("callHierarchy/incomingCalls") 3736 struct CallHierarchyIncomingCallsParams 3737 { 3738 CallHierarchyItem item; 3739 } 3740 3741 @serdeFallbackStruct 3742 struct CallHierarchyIncomingCall 3743 { 3744 CallHierarchyItem from; 3745 TextRange[] fromRanges; 3746 } 3747 3748 @serdeFallbackStruct 3749 @allowedMethods("callHierarchy/outgoingCalls") 3750 struct CallHierarchyOutgoingCallsParams 3751 { 3752 CallHierarchyItem item; 3753 } 3754 3755 @serdeFallbackStruct 3756 struct CallHierarchyOutgoingCall 3757 { 3758 CallHierarchyItem to; 3759 TextRange[] fromRanges; 3760 } 3761 3762 @serdeEnumProxy!string 3763 enum SemanticTokenTypes : string 3764 { 3765 namespace = "namespace", 3766 type = "type", 3767 class_ = "class", 3768 enum_ = "enum", 3769 interface_ = "interface", 3770 struct_ = "struct", 3771 typeParameter = "typeParameter", 3772 parameter = "parameter", 3773 variable = "variable", 3774 property = "property", 3775 enumMember = "enumMember", 3776 event = "event", 3777 function_ = "function", 3778 method = "method", 3779 macro_ = "macro", 3780 keyword = "keyword", 3781 modifier = "modifier", 3782 comment = "comment", 3783 string = "string", 3784 number = "number", 3785 regexp = "regexp", 3786 operator = "operator" 3787 } 3788 3789 @serdeEnumProxy!string 3790 enum SemanticTokenModifiers : string 3791 { 3792 declaration = "declaration", 3793 definition = "definition", 3794 readonly = "readonly", 3795 static_ = "static", 3796 deprecated_ = "deprecated", 3797 abstract_ = "abstract", 3798 async = "async", 3799 modification = "modification", 3800 documentation = "documentation", 3801 defaultLibrary = "defaultLibrary" 3802 } 3803 3804 @serdeEnumProxy!string 3805 enum TokenFormat : string 3806 { 3807 relative = "relative" 3808 } 3809 3810 @serdeFallbackStruct 3811 struct SemanticTokensLegend 3812 { 3813 string[] tokenTypes; 3814 string[] tokenmodifiers; 3815 } 3816 3817 @serdeFallbackStruct 3818 struct SemanticTokensRange 3819 { 3820 } 3821 3822 @serdeFallbackStruct 3823 struct SemanticTokensFull 3824 { 3825 @serdeOptional Optional!bool delta; 3826 } 3827 3828 3829 @serdeFallbackStruct 3830 struct SemanticTokensClientCapabilities 3831 { 3832 @serdeIgnoreUnexpectedKeys 3833 static struct Requests 3834 { 3835 @serdeOptional Variant!(void, bool, SemanticTokensRange) range; 3836 @serdeOptional Variant!(void, bool, SemanticTokensFull) full; 3837 } 3838 3839 @serdeOptional Optional!bool dynamicRegistration; 3840 Requests requests; 3841 string[] tokenTypes; 3842 string[] tokenModifiers; 3843 TokenFormat[] formats; 3844 @serdeOptional Optional!bool overlappingTokenSupport; 3845 @serdeOptional Optional!bool multilineTokenSupport; 3846 } 3847 3848 @serdeFallbackStruct 3849 struct SemanticTokensOptions 3850 { 3851 mixin WorkDoneProgressOptions; 3852 3853 SemanticTokensLegend legend; 3854 @serdeOptional Variant!(void, bool, SemanticTokensRange) range; 3855 @serdeOptional Variant!(void, bool, SemanticTokensFull) full; 3856 } 3857 3858 @serdeFallbackStruct 3859 struct SemanticTokensRegistrationOptions 3860 { 3861 mixin TextDocumentRegistrationOptions; 3862 mixin WorkDoneProgressOptions; 3863 mixin StaticRegistrationOptions; 3864 3865 SemanticTokensLegend legend; 3866 @serdeOptional Variant!(void, bool, SemanticTokensRange) range; 3867 @serdeOptional Variant!(void, bool, SemanticTokensFull) full; 3868 } 3869 3870 @serdeFallbackStruct 3871 @allowedMethods("textDocument/semanticTokens/full") 3872 struct SemanticTokensParams 3873 { 3874 TextDocumentIdentifier textDocument; 3875 } 3876 3877 @serdeFallbackStruct 3878 struct SemanticTokens 3879 { 3880 @serdeOptional Optional!string resultId; 3881 uint[] data; 3882 } 3883 3884 @serdeFallbackStruct 3885 struct SemanticTokensPartialResult 3886 { 3887 uint[] data; 3888 } 3889 3890 @serdeFallbackStruct 3891 @allowedMethods("textDocument/semanticTokens/full/delta") 3892 struct SemanticTokensDeltaParams 3893 { 3894 TextDocumentIdentifier textDocument; 3895 string previousResultId; 3896 } 3897 3898 @serdeFallbackStruct 3899 struct SemanticTokensDelta 3900 { 3901 string resultId; 3902 SemanticTokensEdit[] edits; 3903 } 3904 3905 @serdeFallbackStruct 3906 struct SemanticTokensEdit 3907 { 3908 uint start; 3909 uint deleteCount; 3910 @serdeOptional Optional!(uint[]) data; 3911 } 3912 3913 @serdeFallbackStruct 3914 struct SemanticTokensDeltaPartialResult 3915 { 3916 SemanticTokensEdit[] edits; 3917 } 3918 3919 @serdeFallbackStruct 3920 @allowedMethods("textDocument/semanticTokens/range") 3921 struct SemanticTokensRangeParams 3922 { 3923 TextDocumentIdentifier textDocument; 3924 TextRange range; 3925 } 3926 3927 @serdeFallbackStruct 3928 struct SemanticTokensWorkspaceClientCapabilities 3929 { 3930 @serdeOptional Optional!bool refreshSupport; 3931 } 3932 3933 3934 @serdeFallbackStruct 3935 struct LinkedEditingRangeClientCapabilities 3936 { 3937 @serdeOptional Optional!bool dynamicRegistration; 3938 } 3939 3940 @serdeFallbackStruct 3941 struct LinkedEditingRangeOptions 3942 { 3943 mixin WorkDoneProgressOptions; 3944 } 3945 3946 @serdeFallbackStruct 3947 struct LinkedEditingRangeRegistrationOptions 3948 { 3949 mixin TextDocumentRegistrationOptions; 3950 mixin WorkDoneProgressOptions; 3951 mixin StaticRegistrationOptions; 3952 } 3953 3954 @serdeFallbackStruct 3955 @allowedMethods("textDocument/linkedEditingRange") 3956 struct LinkedEditingRangeParams 3957 { 3958 TextDocumentIdentifier textDocument; 3959 Position position; 3960 } 3961 3962 @serdeFallbackStruct 3963 struct LinkedEditingRanges 3964 { 3965 TextRange[] ranges; 3966 @serdeOptional Optional!string wordPattern; 3967 } 3968 3969 @serdeFallbackStruct 3970 struct ExecuteCommandClientCapabilities 3971 { 3972 @serdeOptional Optional!bool dynamicRegistration; 3973 } 3974 3975 @serdeFallbackStruct 3976 struct ExecuteCommandOptions 3977 { 3978 string[] commands; 3979 } 3980 3981 @serdeFallbackStruct 3982 struct ExecuteCommandRegistrationOptions 3983 { 3984 string[] commands; 3985 } 3986 3987 @serdeFallbackStruct 3988 @allowedMethods("workspace/executeCommand") 3989 struct ExecuteCommandParams 3990 { 3991 string command; 3992 @serdeOptional Optional!(JsonValue[]) arguments; 3993 } 3994 3995 @serdeFallbackStruct 3996 @allowedMethods("workspace/applyEdit") 3997 struct ApplyWorkspaceEditParams 3998 { 3999 @serdeOptional Optional!string label; 4000 WorkspaceEdit edit; 4001 } 4002 4003 @serdeFallbackStruct 4004 struct ApplyWorkspaceEditResponse 4005 { 4006 bool applied; 4007 @serdeOptional Optional!string failureReason; 4008 @serdeOptional Optional!uint failedChange; 4009 } 4010 4011 @serdeFallbackStruct 4012 struct WorkspaceFolder 4013 { 4014 string uri; 4015 string name; 4016 } 4017 4018 @serdeFallbackStruct 4019 @allowedMethods("workspace/didChangeWorkspaceFolders") 4020 struct DidChangeWorkspaceFoldersParams 4021 { 4022 WorkspaceFoldersChangeEvent event; 4023 } 4024 4025 @serdeFallbackStruct 4026 struct WorkspaceFoldersChangeEvent 4027 { 4028 WorkspaceFolder[] added; 4029 WorkspaceFolder[] removed; 4030 } 4031 4032 @serdeEnumProxy!string 4033 enum TraceValue : string 4034 { 4035 off = "off", 4036 messages = "messages", 4037 verbose = "verbose", 4038 } 4039 4040 @serdeFallbackStruct 4041 @allowedMethods("$/setTrace") 4042 struct SetTraceParams 4043 { 4044 TraceValue value; 4045 } 4046 4047 @serdeFallbackStruct 4048 @allowedMethods("$/logTrace") 4049 struct LogTraceParams 4050 { 4051 string message; 4052 @serdeOptional Optional!string verbose; 4053 } 4054 4055 unittest 4056 { 4057 StringMap!JsonValue s; 4058 assert(serializeJson(s) == `{}`); 4059 s["hello"] = JsonValue("world"); 4060 assert(serializeJson(s) == `{"hello":"world"}`); 4061 } 4062 4063 unittest 4064 { 4065 import std.traits; 4066 import mir.algebraic : Algebraic; 4067 4068 bool hasSerdeEnumProxy(Args...)() 4069 { 4070 bool ret = false; 4071 static foreach (Arg; Args) 4072 { 4073 static if (is(Arg == enum) 4074 && hasUDA!(Arg, serdeProxyCast)) 4075 ret = true; 4076 } 4077 return ret; 4078 } 4079 4080 void LintVariantArgs(string member, Args...)() 4081 { 4082 static if (hasSerdeEnumProxy!Args) 4083 { 4084 static if (Args.length != 2 4085 || !(is(Args[0] == void) || is(Args[0] == typeof(null)))) 4086 { 4087 // https://github.com/libmir/mir-ion/issues/36 4088 pragma(msg, "WARNING: known-broken deserialization on Variant!", Args.stringof, "\n\ton field ", member); 4089 } 4090 } 4091 } 4092 4093 void LintStruct(alias T)() 4094 { 4095 static foreach (member; __traits(allMembers, T)) 4096 {{ 4097 static if (is(__traits(getMember, T, member) == struct)) 4098 { 4099 LintStruct!(__traits(getMember, T, member)); 4100 } 4101 else static if (is(typeof(__traits(getMember, T, member)))) 4102 { 4103 static if (is(typeof(__traits(getMember, T, member)) 4104 : Algebraic!Args, Args...)) 4105 { 4106 LintVariantArgs!(T.stringof ~ "." ~ member, Args); 4107 } 4108 } 4109 }} 4110 } 4111 4112 LintStruct!(served.lsp.protocol); 4113 }