1 module workspaced.com.snippets.plain;
2 
3 import std.regex;
4 
5 import workspaced.api;
6 import workspaced.com.snippets;
7 
8 ///
9 struct PlainSnippet
10 {
11 	/// Grammar scopes in which to complete this snippet
12 	SnippetLevel[] levels;
13 	/// Shortcut to type for this snippet
14 	string shortcut;
15 	/// Label for this snippet.
16 	string title;
17 	/// Text with interactive snippet locations to insert assuming global indentation.
18 	string snippet;
19 	/// Markdown documentation for this snippet
20 	string documentation;
21 	/// Plain text to insert assuming global level indentation. Optional if snippet is a simple string only using plain variables and snippet locations.
22 	string plain;
23 	/// true if this snippet shouldn't be formatted before inserting.
24 	bool unformatted;
25 	/// List of imports that should get imported with this snippet. (e.g. using the `ImporterComponent`)
26 	string[] imports;
27 
28 	/// Creates a resolved snippet based on this plain snippet, filling in plain if neccessary. This drops the levels value.
29 	/// Params:
30 	///     provider = the providerId to fill in
31 	Snippet buildSnippet(string provider) const
32 	{
33 		Snippet built;
34 		built.providerId = provider;
35 		built.title = this.title;
36 		built.shortcut = this.shortcut;
37 		built.documentation = this.documentation;
38 		built.snippet = this.snippet;
39 		built.plain = this.plain.length ? this.plain
40 			: this.snippet.replaceAll(ctRegex!`\$(\d+|[A-Z_]+|\{.*?\})`, "");
41 		built.resolved = true;
42 		built.unformatted = unformatted;
43 		if (imports.length)
44 			built.imports = imports.dup;
45 		return built;
46 	}
47 }
48 
49 //dfmt off
50 static immutable PlainSnippet[] plainSnippets = [
51 
52 	// entry points
53 
54 	PlainSnippet(
55 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
56 		"main",
57 		"void main(string[] args)",
58 		"void main(string[] args) {\n\t$0\n}",
59 		"Normal D entry point main function with arguments and no return value"
60 	),
61 	PlainSnippet(
62 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
63 		"maini",
64 		"int main(string[] args)",
65 		"int main(string[] args) {\n\t${0:return 0;}\n}",
66 		"Normal D entry point main function with arguments and integer status return value"
67 	),
68 	PlainSnippet(
69 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
70 		"mainc",
71 		"-betterC void main(int argc, const(char)** argv)",
72 		"void main(int argc, const(char)** argv) {\n\t$0\n}",
73 		"C entry point when using D with -betterC with no return value"
74 	),
75 	PlainSnippet(
76 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
77 		"mainci",
78 		"-betterC int main(int argc, const(char)** argv)",
79 		"int main(int argc, const(char)** argv) {\n\t${0:return 0;}\n}",
80 		"C entry point when using D with -betterC with integer status return value"
81 	),
82 
83 	// properties
84 
85 	PlainSnippet(
86 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
87 		"refproperty",
88 		"ref property as getter + setter",
89 		"ref ${3:auto} ${1:value}() @property { return ${2:_${1:value}}; }",
90 		"property returning a value as ref for use as getter & setter",
91 		"ref auto value() @property { return _value; }"
92 	),
93 	PlainSnippet(
94 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
95 		"getset",
96 		"getter + setter",
97 		"void ${1:value}(${3:auto} value) @property { ${2:_${1:value}} = value; }\n" ~
98 			"${3:auto} ${1:value}() @property const { return ${2:_${1:value}}; }",
99 		"separate methods for getter and setter",
100 		"void value(auto value) @property { _value = value; }\n" ~
101 			"auto value() @property const { return _value; }"
102 	),
103 	PlainSnippet(
104 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
105 		"get",
106 		"getter property",
107 		"${3:auto} ${1:value}() @property const { return ${2:_${1:value}}; }",
108 		"methods for a getter of any value",
109 		"auto value() @property const { return _value; }"
110 	),
111 	PlainSnippet(
112 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
113 		"set",
114 		"setter property",
115 		"void ${1:value}(${3:auto} value) @property { ${2:_${1:value}} = value; }",
116 		"method for use as setter for any value",
117 		"void value(auto value) @property { _value = value; }"
118 	),
119 
120 	// operator overloading
121 	// todo: automatic generation of types and differences in classes
122 
123 	PlainSnippet(
124 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
125 		"opUnary",
126 		"auto opUnary!(op)()",
127 		"${1:auto} opUnary(string op)() {\n\t$0\n}",
128 		"Unary operators in form of `<op>this` which only work on this object.\n\n"
129 			~ "Overloadable unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
130 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#unary]"
131 	),
132 	PlainSnippet(
133 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
134 		"opIndexUnary",
135 		"auto opIndexUnary!(op)(index)",
136 		"${1:auto} opIndexUnary(string op)(${2:size_t index}) {\n\t$0\n}",
137 		"Unary operators in form of `<op>this[index1, index2...]` which only work on this object.\n\n"
138 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
139 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_unary_operators]"
140 	),
141 	PlainSnippet(
142 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
143 		"opIndexUnarySlice",
144 		"auto opIndexUnary!(op)(slice)",
145 		"${1:auto} opIndexUnary(string op)($2) {\n\t$0\n}",
146 		"Unary operators in form of `<op>this[start .. end]` or `<op>this[]` which only work on this object.\n\n"
147 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
148 			~ "The argument for this function is either empty to act on an entire slice like `<op>this[]` or a "
149 				~ "helper object returned by `opSlice`.\n\n"
150 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_unary_operators]"
151 	),
152 	PlainSnippet(
153 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
154 		"opSliceUnary",
155 		"auto opSliceUnary!(op)(slice)",
156 		"${1:auto} opSliceUnary(string op)(${2:size_t start, size_t end}) {\n\t$0\n}",
157 		"Unary operators in form of `<op>this[start .. end]` or `<op>this[]` which only work on this object.\n\n"
158 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
159 			~ "The argument for this function is either empty to act on an entire slice like `<op>this[]` or "
160 				~ "the start and end indices to operate on.\n\n"
161 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_unary_operators]"
162 	),
163 	PlainSnippet(
164 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
165 		"opCast",
166 		"T opCast!(T)()",
167 		"${1:T} opCast(${1:T})() const {\n\t$0\n}",
168 		"Explicit cast operator in form of `cast(<T>)this` which works on this object.\n\n"
169 			~ "Used when explicitly casting to any type or when implicitly casting to bool.\n\n"
170 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#cast]"
171 	),
172 	PlainSnippet(
173 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
174 		"opCastBool",
175 		"bool opCast!(T : bool)()",
176 		"bool opCast(T : bool)() const {\n\t$0\n}",
177 		"Explicit cast operator in form of `cast(bool)this` or implicit boolean conversion with "
178 			~ "`!!this` or `if (this)` which works on this object.\n\n"
179 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#boolean_operators]"
180 	),
181 	PlainSnippet(
182 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
183 		"opBinary",
184 		"auto opBinary(rhs)",
185 		"${1:auto} opBinary(string op, R)(${2:const R rhs}) const {\n\t$0\n}",
186 		"Binary operators in form of `this <op> rhs` which return a new instance based off this object.\n\n"
187 			~ "Overloadable binary operators: `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, `>>>`, `~`, `in`\n\n"
188 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#binary]"
189 	),
190 	PlainSnippet(
191 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
192 		"opBinaryRight",
193 		"auto opBinaryRight(lhs)",
194 		"${1:auto} opBinaryRight(string op, L)(${2:const L lhs}) const {\n\t$0\n}",
195 		"Binary operators in form of `lhs <op> this` which return a new instance based off this object.\n\n"
196 			~ "Overloadable binary operators: `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, `>>>`, `~`, `in`\n\n"
197 			~ "This overload has the same importance as opBinary. It is an error if both opBinary and opBinaryRight match with "
198 				~ "the same specificity.\n\n"
199 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#binary]"
200 	),
201 	PlainSnippet(
202 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
203 		"opEquals",
204 		"bool opEquals(other) in struct",
205 		"bool opEquals(R)(${1:const R other}) const {\n\t$0\n}",
206 		"Equality operators in form of `this == other` or `other == this` and also used for `!=`.\n\n"
207 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#equals]"
208 	),
209 	PlainSnippet(
210 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
211 		"opEqualsClass",
212 		"bool opEquals(other) in class",
213 		"override bool opEquals(${1:Object other}) {\n\t$0\n}",
214 		"Equality operators in form of `this == other` or `other == this` and also used for `!=`.\n\n"
215 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#equals]"
216 	),
217 	PlainSnippet(
218 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
219 		"toHash",
220 		"size_t toHash() in struct",
221 		"size_t toHash() const @nogc @safe pure nothrow {\n\t$0\n}",
222 		"Hash generation for associative arrays.\n\n"
223 			~ "Reference: [https://dlang.org/spec/hash-map.html#using_struct_as_key]"
224 	),
225 	PlainSnippet(
226 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
227 		"toHashClass",
228 		"size_t toHash() in class",
229 		"override size_t toHash() const @nogc @safe pure nothrow {\n\t$0\n}",
230 		"Hash generation for associative arrays.\n\n"
231 			~ "Reference: [https://dlang.org/spec/hash-map.html#using_classes_as_key]"
232 	),
233 	PlainSnippet(
234 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
235 		"toString",
236 		"string toString() in struct",
237 		"string toString() const @safe pure nothrow {\n\t$0\n}",
238 		"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
239 			~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
240 	),
241 	PlainSnippet(
242 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
243 		"toStringText",
244 		"string toString() in struct using std.conv:text",
245 		"string toString() const @safe {\n\timport std.conv : text;\n\n\treturn text($0);\n}",
246 		"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
247 			~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
248 	),
249 	// these don't get added as they are too error-prone (get silently ignored when there is a compilation error inside of them)
250 	// PlainSnippet(
251 	// 	[SnippetLevel.type, SnippetLevel.mixinTemplate],
252 	// 	"toStringApp",
253 	// 	"toString(ref W w) in struct with appender",
254 	// 	"void toString(W)(ref W w) {\n\t$0\n}",
255 	// 	"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
256 	// 		~ "This overload uses an appender as the first argument which allows the developer to avoid concatenation and GC use.\n\n"
257 	// 		~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
258 	// ),
259 	// PlainSnippet(
260 	// 	[SnippetLevel.type, SnippetLevel.mixinTemplate],
261 	// 	"toStringAppSpec",
262 	// 	"toString(ref W w, FormatSpec) in struct with appender and format spec",
263 	// 	"void toString(W)(ref W w, scope const ref FormatSpec fmt) {\n\t$0\n}",
264 	// 	"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
265 	// 		~ "This overload uses an appender as the first argument which allows the developer to avoid concatenation and GC use.\n\n"
266 	// 		~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
267 	// ),
268 	PlainSnippet(
269 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
270 		"toStringClass",
271 		"string toString() in class",
272 		"override string toString() const @safe pure nothrow {\n\t$0\n}",
273 		"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
274 			~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
275 	),
276 	PlainSnippet(
277 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
278 		"toStringTextClass",
279 		"string toString() in class using std.conv:text",
280 		"override string toString() const @safe {\n\timport std.conv : text;\n\n\treturn text($0);\n}",
281 		"Overriding how objects are serialized to strings with std.conv and writeln.\n\n"
282 			~ "Reference: [https://dlang.org/phobos/std_format_write.html]"
283 	),
284 	PlainSnippet(
285 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
286 		"opCmp",
287 		"int opCmp(other) in struct",
288 		"int opCmp(R)(${1:const R other}) const {\n\t$0\n}",
289 		"Comparision operator in form of `this.opCmp(rhs) < 0` for `<`, `<=`, `>` and `>=`.\n\n"
290 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#compare]"
291 	),
292 	PlainSnippet(
293 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
294 		"opCmpClass",
295 		"int opCmp(other) in class",
296 		"override int opCmp(${1:Object other}) {\n\t$0\n}",
297 		"Comparision operator in form of `this.opCmp(rhs) < 0` for `<`, `<=`, `>` and `>=`.\n\n"
298 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#compare]"
299 	),
300 	PlainSnippet(
301 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
302 		"opCall",
303 		"auto opCall(args)",
304 		"${1:auto} opCall($2) {\n\t$0\n}",
305 		"Calling operator in form of `this(args)`.\n\n"
306 			~ "Note that inside a struct this automatically disables the struct literal syntax. "
307 				~ "You need to declare a constructor which takes priority to avoid this limitation.\n\n"
308 			~ "This operator can be overloaded statically too to mimic constructors as normal calls.\n\n"
309 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#function-call]"
310 	),
311 	PlainSnippet(
312 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
313 		"opAssign",
314 		"auto opAssign(value)",
315 		"auto opAssign(T)(${1:T value}) {\n\t$0\n\treturn this;\n}",
316 		"Assignment operator overload in form of `this = value`.\n\n"
317 			~ "For classes `value` may not be of the same type as `this` (identity assignment). However other values "
318 				~ "are still allowed. For structs no such restriction exists.\n\n"
319 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#assignment]"
320 	),
321 	PlainSnippet(
322 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
323 		"opIndexAssign",
324 		"auto opIndexAssign(value, indices...)",
325 		"auto opIndexAssign(T)(${1:T value}, ${2:size_t index}) {\n\t${0:return value;}\n}",
326 		"Assignment operator overload in form of `this[index1, index2...] = value`.\n\n"
327 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
328 	),
329 	PlainSnippet(
330 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
331 		"opIndexAssignSlice",
332 		"auto opIndexAssign(value, slice)",
333 		"auto opIndexAssign(T)(${1:T value}) {\n\t${0:return value;}\n}",
334 		"Assignment operator overload in form of `this[start .. end] = value` or `this[] = value`.\n\n"
335 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` or a "
336 				~ "helper object returned by `opSlice` after the value to assign.\n\n"
337 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
338 	),
339 	PlainSnippet(
340 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
341 		"opSliceAssign",
342 		"auto opSliceAssign(value, slice)",
343 		"auto opSliceAssign(T)(${1:T value}, ${2:size_t start, size_t end}) {\n\t${0:return value;}\n}",
344 		"Assignment operator overload in form of `this[start .. end] = value` or `this[] = value`.\n\n"
345 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` "
346 				~ "or the start and end indices after the value to assign.\n\n"
347 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
348 	),
349 	PlainSnippet(
350 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
351 		"opOpAssign",
352 		"auto opOpAssign!(op)(value)",
353 		"auto opOpAssign(string op, T)(${1:T value}) {\n\t$0;\n\treturn this;\n}",
354 		"Operator assignment operator overload in form of `this op= value`.\n\n"
355 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
356 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#op-assign]"
357 	),
358 	PlainSnippet(
359 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
360 		"opIndexOpAssign",
361 		"auto opIndexOpAssign!(op)(value, index)",
362 		"auto opIndexOpAssign(string op, T)(${1:T value}, ${2:size_t index}) {\n\t${0:return value;}\n}",
363 		"Operator index assignment operator overload in form of `this[index1, index2...] op= value`.\n\n"
364 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
365 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_op_assignment]"
366 	),
367 	PlainSnippet(
368 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
369 		"opIndexOpAssignSlice",
370 		"auto opIndexOpAssign!(op)(value, slice)",
371 		"auto opIndexOpAssign(string op, T)(${1:T value}) {\n\t${0:return value;}\n}",
372 		"Operator index assignment operator overload in form of `this[start .. end] op= value`.\n\n"
373 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
374 			~ "The argument for this function is either empty to act on an entire slice like `this[] op= value` or a "
375 				~ "helper object returned by `opSlice` after the value to assign.\n\n"
376 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_op_assignment]"
377 	),
378 	PlainSnippet(
379 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
380 		"opSliceOpAssign",
381 		"auto opSliceOpAssign!(op)(value, start, end)",
382 		"auto opSliceOpAssign(string op, T)(${1:T value}, ${2:size_t start, size_t end}) {\n\t${0:return value;}\n}",
383 		"Operator index assignment operator overload in form of `this[start .. end] op= value`.\n\n"
384 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
385 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` "
386 				~ "or the start and end indices after the value to assign.\n\n"
387 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_op_assignment]"
388 	),
389 	PlainSnippet(
390 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
391 		"opIndex",
392 		"auto opIndex(index)",
393 		"${1:ref auto} opIndex(${2:size_t index}) {\n\t$0\n}",
394 		"Array index operator overload in form of `this[index1, index2...]`.\n\n"
395 			~ "Indices may specify any type and may also be the helper objects returned by opSlice.\n\n"
396 			~ "Leaving the index arguments empty means this returns a slice of the whole object. (often a shallow copy)\n\n"
397 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
398 	),
399 	PlainSnippet(
400 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
401 		"opSlice",
402 		"auto opSlice(index)",
403 		"${1:size_t[2]} opSlice(${2:size_t start, size_t end}) {\n\t${0:return [start, end];}\n}",
404 		"Array slice operator overload in form of `this[start .. end]`.\n\n"
405 			~ "`opSlice` returns a helper object which is used in the index methods to operate on. "
406 				~ "It does not return the value of the array slice result, use opIndex for this.\n\n"
407 			~ "This snippet defines an overload for any dimension of the array (any comma count), "
408 				~ "use `opSliceN` for any dimensionality.\n\n"
409 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
410 	),
411 	PlainSnippet(
412 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
413 		"opSliceN",
414 		"auto opSlice!(n)(index)",
415 		"${1:size_t[2]} opSlice(size_t dim : ${2:0})(${3:size_t start, size_t end}) {\n\t${0:return [start, end];}\n}",
416 		"Array slice operator overload in form of `this[start .. end]`.\n\n"
417 			~ "`opSlice` returns a helper object which is used in the index methods to operate on. "
418 				~ "It does not return the value of the array slice result, use opIndex for this.\n\n"
419 			~ "This snippet defines an overload for n-th dimension of the array, meaning this is the "
420 				~ "`n`th value in the comma separated index list, starting at n=0.\n\n"
421 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
422 	),
423 	PlainSnippet(
424 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
425 		"opDollar",
426 		"auto opDollar()",
427 		"${1:size_t} opDollar() {\n\t${0:return length;}\n}",
428 		"Dollar operator overload in form of `this[$]`.\n\n"
429 			~ "`opDollar` returns a the value which the dollar sign in the index call returns. "
430 				~ "Commonly this is the length of the array.\n\n"
431 			~ "This snippet defines an overload for any dimension of the array (any comma count), "
432 				~ "use `opDollarN` for any dimensionality.\n\n"
433 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
434 	),
435 	PlainSnippet(
436 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
437 		"opDollarN",
438 		"auto opDollar!(n)()",
439 		"${1:size_t} opDollar(size_t dim : ${2:0})() {\n\t${0:return length;}\n}",
440 		"Dollar operator overload in form of `this[$]`.\n\n"
441 			~ "`opDollar` returns a the value which the dollar sign in the index call returns. "
442 				~ "Commonly this is the length of the array.\n\n"
443 			~ "This snippet defines an overload for n-th dimension of the array, meaning this is the "
444 				~ "`n`th length in the comma separated index list, starting at n=0.\n\n"
445 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
446 	),
447 	PlainSnippet(
448 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
449 		"opDispatch",
450 		"auto opDispatch!(member)()",
451 		"${1:auto} opDispatch(${2:string member})() {\n\t$0\n}",
452 		"Compile-Time dynamic dispatch operator forwarding unknown member calls and properties in form of `this.member`.\n\n"
453 			~ "`opDispatch` will be executed for any method call or property access not matching another one. This should "
454 				~ "be used on special wrapper types without many other fields to avoid false calls in case of non-matching "
455 				~ "overloads. Defining this operator may also cause issues when trying to use CTFE functions with matching "
456 				~ "names.\n\n"
457 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#dispatch]"
458 	),
459 	PlainSnippet(
460 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
461 		"opApply",
462 		"int opApply(dg)",
463 		"int opApply(scope int delegate(${1:ref Item}) ${2:dg}) {\n"
464 			~ "\tint result = 0;\n"
465 			~ "\n"
466 			~ "\t${3:foreach (item; array)} {\n"
467 			~ "\t\tresult = dg(item);\n"
468 			~ "\t\tif (result)\n"
469 			~ "\t\t\tbreak;\n"
470 			~ "\t}\n"
471 			~ "\n"
472 			~ "\treturn result;\n"
473 			~ "}",
474 		"Explicit foreach overload when calling `foreach (items...; this)`.\n\n"
475 			~ "Note that you can also implement this functionality through a forward range."
476 				~ "`opApply` has higher precedence over range functionality.\n\n"
477 			~ "Reference: [https://dlang.org/spec/statement.html#foreach_over_struct_and_classes]"
478 	),
479 	PlainSnippet(
480 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
481 		"opApplyReverse",
482 		"int opApplyReverse(dg)",
483 		"int opApplyReverse(scope int delegate(${1:ref Item}) ${2:dg}) {\n"
484 			~ "\tint result = 0;\n"
485 			~ "\n"
486 			~ "\t${3:foreach_reverse (item; array)} {\n"
487 			~ "\t\tresult = dg(item);\n"
488 			~ "\t\tif (result)\n"
489 			~ "\t\t\tbreak;\n"
490 			~ "\t}\n"
491 			~ "\n"
492 			~ "\treturn result;\n"
493 			~ "}",
494 		"Explicit foreach overload when calling `foreach_reverse (items...; this)`.\n\n"
495 			~ "Note that you can also implement this functionality through a backward range. "
496 				~ "`opApplyReverse` has higher precedence over range functionality.\n\n"
497 			~ "Reference: [https://dlang.org/spec/statement.html#foreach_over_struct_and_classes]"
498 	),
499 
500 	// Exception snippets
501 
502 	PlainSnippet(
503 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
504 		"Exception",
505 		"class MyException : Exception",
506 		"class ${1:MyException} : ${2:Exception} {\n"
507 			~ "\tthis(${3:string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null}) pure nothrow @nogc @safe {\n"
508 			~ "\t\tsuper(${4:msg, file, line, nextInChain});\n"
509 			~ "\t}\n"
510 			~ "}\n$0",
511 		"Class extending Exception. Use this for recoverable errors that may be catched in the application.\n\n"
512 			~ "Reference: [https://dlang.org/phobos/object.html#.Exception]"
513 	),
514 	PlainSnippet(
515 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
516 		"Error",
517 		"class MyError : Error",
518 		"class ${1:MyError} : ${2:Error} {\n"
519 			~ "\tthis(${3:string msg, Throwable nextInChain = null}) pure nothrow @nogc @safe {\n"
520 			~ "\t\tsuper(${4:msg, nextInChain});\n"
521 			~ "\t}\n"
522 			~ "}\n$0",
523 		"Class extending Error. Use this for unrecoverable errors that applications should not catch.\n\n"
524 			~ "Reference: [https://dlang.org/phobos/object.html#.Exception]"
525 	),
526 
527 	// Block keywords
528 	PlainSnippet(
529 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.mixinTemplate],
530 		"unittest",
531 		"unittest",
532 		"unittest {\n\t$0\n}",
533 		"Defines a unittest block, which is a method that tests a part of the code in isolation. Unittests can be run with DUB using `dub test`. "
534 			~ "Unittests most often contain calls to assert to test results or throw exceptions for code that is not working as expected.\n\n"
535 			~ "Do NOT use inside templates / templated types (classes, structs, etc.) as they will not be run!\n\n"
536 			~ "Reference: [https://dlang.org/spec/unittest.html]"
537 	),
538 	PlainSnippet(
539 		[SnippetLevel.method],
540 		"assert",
541 		"assert",
542 		"assert($0);",
543 		"Enforces that the given expression in the first argument evaluates to `true`. "
544 			~ "If it does not evaluate to `true`, an AssertError will be thrown and an optional second argument may be passed as explanation message what went wrong.\n\n"
545 			~ "Asserts are not emitted at all in DUB release builds. Therefore **expressions in the first argument may not be run**. "
546 			~ "Don't use expressions like ~~`assert(i++)`~~ outside unittests and contracts as they might introduce bugs when building in release mode.\n\n"
547 			~ "```d\n"
548 			~ "assert(complexAlgorithm() == 4, \"an error message\");\n"
549 			~ "```\n\n"
550 			~ "Reference: [https://dlang.org/spec/expression.html#AssertExpression]",
551 		null, true
552 	),
553 
554 	// Builtin Types (keywords)
555 	PlainSnippet(
556 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
557 		"import",
558 		"import module",
559 		"import ${1:std};\n$0",
560 		"Imports a module given a name.\n\nReference: [https://dlang.org/spec/module.html#import-declaration]"
561 	),
562 	PlainSnippet(
563 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
564 		"class",
565 		"class MyClass",
566 		"class ${1:MyClass} {\n\t$0\n}",
567 		"Defines a simple class type.\n\nReference: [https://dlang.org/spec/class.html]"
568 	),
569 	PlainSnippet(
570 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
571 		"interface",
572 		"interface MyInterface",
573 		"interface ${1:MyInterface} {\n\t$0\n}",
574 		"Defines a simple interface type.\n\nReference: [https://dlang.org/spec/interface.html]"
575 	),
576 	PlainSnippet(
577 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
578 		"struct",
579 		"struct MyStruct",
580 		"struct ${1:MyStruct} {\n\t$0\n}",
581 		"Defines a simple struct type.\n\nReference: [https://dlang.org/spec/struct.html]"
582 	),
583 	PlainSnippet(
584 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
585 		"union",
586 		"union MyUnion",
587 		"union ${1:MyUnion} {\n\t$0\n}",
588 		"Defines a simple union type.\n\nReference: [https://dlang.org/spec/struct.html]"
589 	),
590 	PlainSnippet(
591 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
592 		"template",
593 		"template MyTemplate()",
594 		"template ${1:MyTemplate}($2) {\n\t$0\n}",
595 		"Defines a simple union type.\n\nReference: [https://dlang.org/spec/struct.html]"
596 	),
597 	PlainSnippet(
598 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
599 		"enums",
600 		"enum MyEnum { ... }",
601 		"enum ${1:MyEnum} {\n\t${0:init,}\n}",
602 		"Defines a simple enumeration.\n\nReference: [https://dlang.org/spec/enum.html]"
603 	),
604 	PlainSnippet(
605 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
606 		"enumv",
607 		"enum EnumValue = ...",
608 		"enum ${1:EnumValue} = $2;\n$0",
609 		"Defines a simple compile time constant using enum.\n\nReference: [https://dlang.org/spec/enum.html#manifest_constants]"
610 	),
611 	PlainSnippet(
612 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
613 		"alias",
614 		"alias Alias = ...",
615 		"alias ${1:Alias} = $2;\n$0",
616 		"Creates a symbol that is an alias for another type, and can be used anywhere that other type may appear.\n\nReference: [https://dlang.org/spec/declaration.html#alias]"
617 	),
618 
619 	// Types using phobos or some code idioms
620 	PlainSnippet(
621 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
622 		"typedef",
623 		"typedef MyType : BaseType",
624 		"enum ${1:MyType} : ${2:BaseType} {\n\t${0:init = 0}\n}",
625 		"Creates a typesafe alias not allowing implicit casting from base type, but allows implicit conversion to "
626 			~ "the base type in most cases. Therefore the implicit casting works a lot like class/interface inheritance.\n\n"
627 			~ "Reference: (17.1.5) [https://dlang.org/spec/enum.html#named_enums]"
628 	),
629 	PlainSnippet(
630 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method, SnippetLevel.mixinTemplate],
631 		"Proxy",
632 		"struct MyType { mixin Proxy }",
633 		"struct ${1:MyType} {\n\t${2:BaseType} base;\n\tmixin Proxy!(${2:BaseType});\n}",
634 		"Creates a typesafe alias not allowing implicit casting to the base type, but allows implicit conversion "
635 				~ "from the base type in most cases. Basically allows copying any base type with new properties and "
636 				~ "methods as new and separate type. Imports `std.typecons : Proxy`.\n\n"
637 			~ "Reference: [https://dlang.org/phobos/std_typecons.html#Proxy]"
638 	),
639 	PlainSnippet(
640 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
641 		"IUnknown",
642 		"interface COMInterface : IUnknown",
643 		"interface ${1:COMInterface} : IUnknown {\nextern(Windows):\n\t$0\n}",
644 		"Win32 COM interface without implementation to talk to other applications.\n\n"
645 			~ "Reference: [https://wiki.dlang.org/COM_Programming]"
646 	),
647 	PlainSnippet(
648 		[SnippetLevel.global, SnippetLevel.mixinTemplate],
649 		"ComObject",
650 		"class MyObject : ComObject",
651 		"class ${1:MyObject} : ComObject {\nextern(Windows):\n\t$0\n}",
652 		"Win32 COM interface with implementation to serve to other applications.\n\n"
653 			~ "Reference: [https://wiki.dlang.org/COM_Programming]"
654 	),
655 
656 	// range methods
657 
658 	PlainSnippet(
659 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
660 		"InputRange",
661 		"InputRange (popFront, empty, front)",
662 		"${1:auto} front() @property { ${2:return myElement;} }\n"
663 			~ "bool empty() @property const { ${3:return true;} }\n"
664 			~ "void popFront() { $4 }\n$0",
665 		"Implements an input range for iteration support in range functions and foreach.\n\n"
666 			~ "Functions can only iterate over an InputRange exactly one time.\n\n"
667 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isInputRange]"
668 	),
669 	PlainSnippet(
670 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
671 		"OutputRange",
672 		"OutputRange (put)",
673 		"void put(${1:Item} item) {\n\t$2\n}\n$0",
674 		"Implements the put function which allows to put one or more items into this range.\n\n"
675 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isOutputRange]"
676 	),
677 	PlainSnippet(
678 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
679 		"ForwardRange",
680 		"ForwardRange (InputRange, save)",
681 		"${1:auto} front() @property { ${2:return myElement;} }\n"
682 			~ "bool empty() @property const { ${3:return true;} }\n"
683 			~ "void popFront() { $4 }\n"
684 			~ "typeof(this) save() { ${5:return this;} }\n$0",
685 		"Implements a forward range for iteration support in range functions and foreach.\n\n"
686 			~ "As opposed to InputRange this supports iterating over the same range multiple times.\n\n"
687 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isForwardRange]"
688 	),
689 	PlainSnippet(
690 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
691 		"InfiniteRange",
692 		"InfiniteRange (empty = false)",
693 		"enum bool empty = false;\n$0",
694 		"Makes this range appear as infinite by adding `empty` as always `false` enum constant value.\n\n"
695 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isInfinite]"
696 	),
697 	PlainSnippet(
698 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
699 		"BidirectionalRange",
700 		"BidirectionalRange (InputRange, back, popBack)",
701 		"${1:auto} front() @property { ${2:return myElement;} }\n"
702 			~ "${1:auto} back() @property { ${3:return myElement;} }\n"
703 			~ "bool empty() @property const { ${4:return true;} }\n"
704 			~ "void popFront() { $5 }\n"
705 			~ "void popBack() { $6 }\n$0",
706 		"Implements a bidirectional range for iteration support in range functions, foreach and foreach_reverse.\n\n"
707 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
708 	),
709 	PlainSnippet(
710 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
711 		"RandomAccessRange",
712 		"RandomAccessRange (BidirectionalRange, opIndex, length)",
713 		"${1:auto} front() @property { ${2:return myElement;} }\n"
714 			~ "${1:auto} back() @property { ${3:return myElement;} }\n"
715 			~ "bool empty() @property const { ${4:return true;} }\n"
716 			~ "void popFront() { $5 }\n"
717 			~ "void popBack() { $6 }\n"
718 			~ "ref ${1:auto} opIndex(${7:size_t index}) { $8 }\n"
719 			~ "size_t length() { $9 }\n"
720 			~ "alias opDollar = length;$0",
721 		"Implements a bidirectional range with random access indexing support for full array emulation.\n\n"
722 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
723 	),
724 	PlainSnippet(
725 		[SnippetLevel.type, SnippetLevel.mixinTemplate],
726 		"RandomAccessRangeInf",
727 		"RandomAccessRange (InfiniteForwardRange, opIndex)",
728 		"${1:auto} front() @property { ${2:return myElement;} }\n"
729 			~ "enum bool empty = false;\n"
730 			~ "void popFront() { $3 }\n"
731 			~ "${1:auto} opIndex(${4:size_t index}) { $5 }\n$0",
732 		"Implements an infinite forward range with random access indexing support.\n\n"
733 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
734 	),
735 	PlainSnippet(
736 		[SnippetLevel.method],
737 		"debug_writeln",
738 		"debug try-catch writeln",
739 		`debug { import std.stdio : writeln; try { writeln("$1"); } catch (Exception) {} }$0`,
740 		"A `writeln` call in a debug block with try-catch wrapping around it.\n\n"
741 			~ "Useful to do a debug output inside a pure or nothrow function.",
742 		null, true
743 	),
744 	PlainSnippet(
745 		[SnippetLevel.method],
746 		"debug_writefln",
747 		"debug try-catch writefln",
748 		`debug { import std.stdio : writefln; try { writefln!"$1"($2); } catch (Exception) {} }$0`,
749 		"A `writefln` call in a debug block with try-catch wrapping around it.\n\n"
750 			~ "Useful to do a debug output inside a pure or nothrow function.",
751 		null, true
752 	),
753 	PlainSnippet(
754 		[SnippetLevel.method],
755 		"debug_printf",
756 		"debug try-catch printf",
757 		`debug { import core.stdc.stdio : printf; printf("$1\\n"); }$0`,
758 		"A `printf` call in a debug block.\n\n"
759 			~ "Useful to do a debug output inside a pure, nothrow or @nogc function.",
760 		null, true
761 	),
762 
763 	// statements
764 	PlainSnippet(
765 		[SnippetLevel.method],
766 		"switch",
767 		"switch-case",
768 		"switch ($1) {\n$0\ndefault:\n\tbreak;\n}",
769 		"Simple switch statement, with default (required). Use `final switch` "
770 			~ "to match on enums where you know all possible values.\n\n"
771 			~ "Reference: [https://dlang.org/spec/statement.html#switch-statement]"
772 	),
773 	PlainSnippet(
774 		[SnippetLevel.method],
775 		"final switch",
776 		"final switch",
777 		"final switch ($1) {\n$0\n}",
778 		"switch statement that is used when all possible values are tested for"
779 			~ ". (e.g. for enums) Missing cases will result in a compile time "
780 			~ "error, which is useful for future-proofing the code.\n\n"
781 			~ "Reference: [https://dlang.org/spec/statement.html#final-switch-statement]"
782 	),
783 	PlainSnippet(
784 		[SnippetLevel.method],
785 		"if",
786 		"if",
787 		"if ($1) {\n\t$0\n}",
788 		"Basic `if` statement to branch on a condition.\n\n"
789 			~ "Reference: [https://dlang.org/spec/statement.html#if-statement]"
790 	),
791 	PlainSnippet(
792 		[SnippetLevel.method],
793 		"if auto",
794 		"if (auto x = ...)",
795 		"if (auto ${2:x} = $1) {\n\t$0\n}",
796 		"Given an expression, when it evaluates truthy (implicitly converts to "
797 			~ "true), assigns that expression to the variable `x`. The scope of"
798 			~ " x is then extended to the end of the ThenStatement.\n\n"
799 			~ "If the expression does not evaluate truthy, the then-branch is "
800 			~ "not called. This is useful for example to do null-checks and "
801 			~ "then conditionally run code on only non-null values.\n\n"
802 			~ "Example null check inside a JSONValue map: "
803 			~ "`if (auto name = \"name\" in config.object) { ... }`\n\n"
804 			~ "Reference: [https://dlang.org/spec/statement.html#if-statement]"
805 	),
806 	PlainSnippet(
807 		[SnippetLevel.method],
808 		"while",
809 		"while",
810 		"while ($1) {\n\t$0\n}",
811 		"Basic `while` loop.\n\n"
812 			~ "Reference: [https://dlang.org/spec/statement.html#while-statement]"
813 	),
814 	PlainSnippet(
815 		[SnippetLevel.method],
816 		"while auto",
817 		"while (auto x = ...)",
818 		"while (auto ${2:x} = $1) {\n\t$0\n}",
819 		"Similar to `if (auto ...)`, this will loop on the expression and also "
820 			~ "assign that expression to the given variable name every "
821 			~ "iteration.\n\n"
822 			~ "Reference: [https://dlang.org/spec/statement.html#while-statement]"
823 	),
824 	PlainSnippet(
825 		[SnippetLevel.method],
826 		"for",
827 		"for",
828 		"for (int ${1:i} = 0; ${1:i} < $2; ${1:i}++) {\n\t$0\n}",
829 		"Basic `for` loop.\n\n"
830 			~ "Reference: [https://dlang.org/spec/statement.html#for-statement]"
831 	),
832 	PlainSnippet(
833 		[SnippetLevel.method],
834 		"scope guard",
835 		"scope (exit|success|failure)",
836 		"scope(${1|exit,success,failure|}) {\n\t$0\n}",
837 		"Runs code at the end of the scope, when it is left successfully or "
838 			~ "after exceptions are thrown. e.g. after the `}` character.\n\n"
839 			~ "- `failure` will only run the code when an Exception is thrown "
840 				~ "(similar to `catch`)\n"
841 			~ "- `success` will only run the code when the scope exits without "
842 				~ "any thrown Exception\n"
843 			~ "- `exit` will runs always (scope succeeds or throws)\n\n"
844 			~ "Reference: [https://dlang.org/spec/statement.html#scope-guard-statement]"
845 	),
846 	PlainSnippet(
847 		[SnippetLevel.method],
848 		"return",
849 		"return",
850 		"return $1;$0",
851 		"Returns (exits) from the function, possibly returning a value.\n\n"
852 			~ "Reference: [https://dlang.org/spec/statement.html#return-statement]",
853 		null, true
854 	),
855 	PlainSnippet(
856 		[SnippetLevel.method],
857 		"throw",
858 		"throw new Exception",
859 		"throw new ${2:Exception}(\"$1\");$0",
860 		"Throws an Exception or Error (or any Throwable).\n\n"
861 			~ "Reference: [https://dlang.org/spec/expression.html#throw_expression]",
862 		null, true
863 	),
864 	PlainSnippet(
865 		[SnippetLevel.method],
866 		"goto",
867 		"goto Label",
868 		"goto ${1:Label};$0",
869 		"Jumps to a label previously defined or inside a switch-case between "
870 			~ "cases or simply fall-through to the next case.\n\n"
871 			~ "Reference: [https://dlang.org/spec/statement.html#goto-statement]",
872 		null, true
873 	),
874 	PlainSnippet(
875 		[SnippetLevel.method],
876 		"with",
877 		"with",
878 		"with ($1) {\n\t$0\n}",
879 		"A with block simplifies repeated access of the same symbol. You can "
880 			~ "use it for example to repeatedly access the same enum or to "
881 			~ "use an inline-constructed value within a block without giving "
882 			~ "it a name\n\n"
883 			~ "Reference: [https://dlang.org/spec/statement.html#with-statement]"
884 	),
885 ];
886 //dfmt on
887 
888 class PlainSnippetProvider : SnippetProvider
889 {
890 	protected Snippet[][SnippetLevel] prebuilt;
891 
892 	this()
893 	{
894 		foreach (s; plainSnippets)
895 		{
896 			Snippet built = s.buildSnippet(typeid(this).name);
897 
898 			foreach (level; s.levels)
899 				prebuilt[level] ~= built;
900 		}
901 	}
902 
903 	Future!(Snippet[]) provideSnippets(scope const WorkspaceD.Instance instance,
904 			scope const(char)[] file, scope const(char)[] code, int position, const SnippetInfo info)
905 	{
906 		Snippet[] ret;
907 		if (auto p = info.level in prebuilt)
908 			ret = *p;
909 		return typeof(return).fromResult(ret);
910 	}
911 
912 	Future!Snippet resolveSnippet(scope const WorkspaceD.Instance instance,
913 			scope const(char)[] file, scope const(char)[] code, int position,
914 			const SnippetInfo info, Snippet snippet)
915 	{
916 		snippet.resolved = true;
917 		return typeof(return).fromResult(snippet);
918 	}
919 }