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 }