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 
24 	/// Creates a resolved snippet based on this plain snippet, filling in plain if neccessary. This drops the levels value.
25 	/// Params:
26 	///     provider = the providerId to fill in
27 	Snippet buildSnippet(string provider) const
28 	{
29 		Snippet built;
30 		built.providerId = provider;
31 		built.title = this.title;
32 		built.shortcut = this.shortcut;
33 		built.documentation = this.documentation;
34 		built.snippet = this.snippet;
35 		built.plain = this.plain.length ? this.plain
36 			: this.snippet.replaceAll(ctRegex!`\$(\d+|[A-Z_]+|\{.*?\})`, "");
37 		built.resolved = true;
38 		return built;
39 	}
40 }
41 
42 //dfmt off
43 static immutable PlainSnippet[] plainSnippets = [
44 
45 	// entry points
46 
47 	PlainSnippet(
48 		[SnippetLevel.global],
49 		"main",
50 		"void main(string[] args)",
51 		"void main(string[] args) {\n\t$0\n}",
52 		"Normal D entry point main function with arguments and no return value"
53 	),
54 	PlainSnippet(
55 		[SnippetLevel.global],
56 		"maini",
57 		"int main(string[] args)",
58 		"int main(string[] args) {\n\t${0:return 0;}\n}",
59 		"Normal D entry point main function with arguments and integer status return value"
60 	),
61 	PlainSnippet(
62 		[SnippetLevel.global],
63 		"mainc",
64 		"-betterC void main(int argc, const(char)** argv)",
65 		"void main(int argc, const(char)** argv) {\n\t$0\n}",
66 		"C entry point when using D with -betterC with no return value"
67 	),
68 	PlainSnippet(
69 		[SnippetLevel.global],
70 		"mainci",
71 		"-betterC int main(int argc, const(char)** argv)",
72 		"int main(int argc, const(char)** argv) {\n\t${0:return 0;}\n}",
73 		"C entry point when using D with -betterC with integer status return value"
74 	),
75 
76 	// properties
77 
78 	PlainSnippet(
79 		[SnippetLevel.global, SnippetLevel.type],
80 		"refproperty",
81 		"ref property as getter + setter",
82 		"ref ${3:auto} ${1:value}() @property { return ${2:_${1:value}}; }",
83 		"property returning a value as ref for use as getter & setter",
84 		"ref auto value() @property { return _value; }"
85 	),
86 	PlainSnippet(
87 		[SnippetLevel.global, SnippetLevel.type],
88 		"getset",
89 		"getter + setter",
90 		"void ${1:value}(${3:auto} value) @property { ${2:_${1:value}} = value; }\n" ~
91 			"${3:auto} ${1:value}() @property const { return ${2:_${1:value}}; }",
92 		"separate methods for getter and setter",
93 		"void value(auto value) @property { _value = value; }\n" ~
94 			"auto value() @property const { return _value; }"
95 	),
96 	PlainSnippet(
97 		[SnippetLevel.global, SnippetLevel.type],
98 		"get",
99 		"getter property",
100 		"${3:auto} ${1:value}() @property const { return ${2:_${1:value}}; }",
101 		"methods for a getter of any value",
102 		"auto value() @property const { return _value; }"
103 	),
104 	PlainSnippet(
105 		[SnippetLevel.global, SnippetLevel.type],
106 		"set",
107 		"setter property",
108 		"void ${1:value}(${3:auto} value) @property { ${2:_${1:value}} = value; }",
109 		"method for use as setter for any value",
110 		"void value(auto value) @property { _value = value; }"
111 	),
112 
113 	// operator overloading
114 	// todo: automatic generation of types and differences in classes
115 
116 	PlainSnippet(
117 		[SnippetLevel.type],
118 		"opUnary",
119 		"auto opUnary!(op)()",
120 		"${1:auto} opUnary(string op)() {\n\t$0\n}",
121 		"Unary operators in form of `<op>this` which only work on this object.\n\n"
122 			~ "Overloadable unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
123 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#unary]"
124 	),
125 	PlainSnippet(
126 		[SnippetLevel.type],
127 		"opIndexUnary",
128 		"auto opIndexUnary!(op)(index)",
129 		"${1:auto} opIndexUnary(string op)(${2:size_t index}) {\n\t$0\n}",
130 		"Unary operators in form of `<op>this[index1, index2...]` which only work on this object.\n\n"
131 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
132 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_unary_operators]"
133 	),
134 	PlainSnippet(
135 		[SnippetLevel.type],
136 		"opIndexUnarySlice",
137 		"auto opIndexUnary!(op)(slice)",
138 		"${1:auto} opIndexUnary(string op)($2) {\n\t$0\n}",
139 		"Unary operators in form of `<op>this[start .. end]` or `<op>this[]` which only work on this object.\n\n"
140 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
141 			~ "The argument for this function is either empty to act on an entire slice like `<op>this[]` or a "
142 				~ "helper object returned by `opSlice`.\n\n"
143 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_unary_operators]"
144 	),
145 	PlainSnippet(
146 		[SnippetLevel.type],
147 		"opSliceUnary",
148 		"auto opSliceUnary!(op)(slice)",
149 		"${1:auto} opSliceUnary(string op)(${2:size_t start, size_t end}) {\n\t$0\n}",
150 		"Unary operators in form of `<op>this[start .. end]` or `<op>this[]` which only work on this object.\n\n"
151 			~ "Valid unary operators: `-`, `+`, `~`, `*`, `++` (pre-increment), `--` (pre-decrement)\n\n"
152 			~ "The argument for this function is either empty to act on an entire slice like `<op>this[]` or "
153 				~ "the start and end indices to operate on.\n\n"
154 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_unary_operators]"
155 	),
156 	PlainSnippet(
157 		[SnippetLevel.type],
158 		"opCast",
159 		"T opCast!(T)()",
160 		"${1:T} opCast(${1:T})() const {\n\t$0\n}",
161 		"Explicit cast operator in form of `cast(<T>)this` which works on this object.\n\n"
162 			~ "Used when explicitly casting to any type or when implicitly casting to bool.\n\n"
163 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#cast]"
164 	),
165 	PlainSnippet(
166 		[SnippetLevel.type],
167 		"opCastBool",
168 		"bool opCast!(T : bool)()",
169 		"bool opCast(T : bool)() const {\n\t$0\n}",
170 		"Explicit cast operator in form of `cast(bool)this` or implicit boolean conversion with "
171 			~ "`!!this` or `if (this)` which works on this object.\n\n"
172 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#boolean_operators]"
173 	),
174 	PlainSnippet(
175 		[SnippetLevel.type],
176 		"opBinary",
177 		"auto opBinary(rhs)",
178 		"${1:auto} opBinary(string op, R)(${2:const R rhs}) const {\n\t$0\n}",
179 		"Binary operators in form of `this <op> rhs` which return a new instance based off this object.\n\n"
180 			~ "Overloadable binary operators: `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, `>>>`, `~`, `in`\n\n"
181 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#binary]"
182 	),
183 	PlainSnippet(
184 		[SnippetLevel.type],
185 		"opBinaryRight",
186 		"auto opBinaryRight(lhs)",
187 		"${1:auto} opBinaryRight(string op, L)(${2:const L lhs}) const {\n\t$0\n}",
188 		"Binary operators in form of `lhs <op> this` which return a new instance based off this object.\n\n"
189 			~ "Overloadable binary operators: `+`, `-`, `*`, `/`, `%`, `^^`, `&`, `|`, `^`, `<<`, `>>`, `>>>`, `~`, `in`\n\n"
190 			~ "This overload has the same importance as opBinary. It is an error if both opBinary and opBinaryRight match with "
191 				~ "the same specificity.\n\n"
192 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#binary]"
193 	),
194 	PlainSnippet(
195 		[SnippetLevel.type],
196 		"opEquals",
197 		"bool opEquals(other) in struct",
198 		"bool opEquals(R)(${1:const R other}) const {\n\t$0\n}",
199 		"Equality operators in form of `this == other` or `other == this` and also used for `!=`.\n\n"
200 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#equals]"
201 	),
202 	PlainSnippet(
203 		[SnippetLevel.type],
204 		"opEqualsClass",
205 		"bool opEquals(other) in class",
206 		"override bool opEquals(${1:Object other}) {\n\t$0\n}",
207 		"Equality operators in form of `this == other` or `other == this` and also used for `!=`.\n\n"
208 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#equals]"
209 	),
210 	PlainSnippet(
211 		[SnippetLevel.type],
212 		"toHash",
213 		"size_t toHash() in struct",
214 		"size_t toHash() const @safe pure nothrow {\n\t$0\n}",
215 		"Hash generation for associative arrays.\n\n"
216 			~ "Reference: [https://dlang.org/spec/hash-map.html#using_classes_as_key]"
217 	),
218 	PlainSnippet(
219 		[SnippetLevel.type],
220 		"toHashClass",
221 		"size_t toHash() in class",
222 		"override size_t toHash() @safe nothrow {\n\t$0\n}",
223 		"Hash generation for associative arrays.\n\n"
224 			~ "Reference: [https://dlang.org/spec/hash-map.html#using_struct_as_key]"
225 	),
226 	PlainSnippet(
227 		[SnippetLevel.type],
228 		"opCmp",
229 		"int opCmp(other) in struct",
230 		"int opCmp(R)(${1:const R other}) const {\n\t$0\n}",
231 		"Comparision operator in form of `this.opCmp(rhs) < 0` for `<`, `<=`, `>` and `>=`.\n\n"
232 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#compare]"
233 	),
234 	PlainSnippet(
235 		[SnippetLevel.type],
236 		"opCmpClass",
237 		"int opCmp(other) in class",
238 		"override int opCmp(${1:Object other}) {\n\t$0\n}",
239 		"Comparision operator in form of `this.opCmp(rhs) < 0` for `<`, `<=`, `>` and `>=`.\n\n"
240 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#compare]"
241 	),
242 	PlainSnippet(
243 		[SnippetLevel.type],
244 		"opCall",
245 		"auto opCall(args)",
246 		"${1:auto} opCall($2) {\n\t$0\n}",
247 		"Calling operator in form of `this(args)`.\n\n"
248 			~ "Note that inside a struct this automatically disables the struct literal syntax. "
249 				~ "You need to declare a constructor which takes priority to avoid this limitation.\n\n"
250 			~ "This operator can be overloaded statically too to mimic constructors as normal calls.\n\n"
251 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#function-call]"
252 	),
253 	PlainSnippet(
254 		[SnippetLevel.type],
255 		"opAssign",
256 		"auto opAssign(value)",
257 		"auto opAssign(T)(${1:T value}) {\n\t$0\n\treturn this;\n}",
258 		"Assignment operator overload in form of `this = value`.\n\n"
259 			~ "For classes `value` may not be of the same type as `this` (identity assignment). However other values "
260 				~ "are still allowed. For structs no such restriction exists.\n\n"
261 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#assignment]"
262 	),
263 	PlainSnippet(
264 		[SnippetLevel.type],
265 		"opIndexAssign",
266 		"auto opIndexAssign(value, indices...)",
267 		"auto opIndexAssign(T)(${1:T value}, ${2:size_t index}) {\n\t${0:return value;}\n}",
268 		"Assignment operator overload in form of `this[index1, index2...] = value`.\n\n"
269 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
270 	),
271 	PlainSnippet(
272 		[SnippetLevel.type],
273 		"opIndexAssignSlice",
274 		"auto opIndexAssign(value, slice)",
275 		"auto opIndexAssign(T)(${1:T value}) {\n\t${0:return value;}\n}",
276 		"Assignment operator overload in form of `this[start .. end] = value` or `this[] = value`.\n\n"
277 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` or a "
278 				~ "helper object returned by `opSlice` after the value to assign.\n\n"
279 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
280 	),
281 	PlainSnippet(
282 		[SnippetLevel.type],
283 		"opSliceAssign",
284 		"auto opSliceAssign(value, slice)",
285 		"auto opSliceAssign(T)(${1:T value}, ${2:size_t start, size_t end}) {\n\t${0:return value;}\n}",
286 		"Assignment operator overload in form of `this[start .. end] = value` or `this[] = value`.\n\n"
287 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` "
288 				~ "or the start and end indices after the value to assign.\n\n"
289 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_assignment_operator]"
290 	),
291 	PlainSnippet(
292 		[SnippetLevel.type],
293 		"opOpAssign",
294 		"auto opOpAssign!(op)(value)",
295 		"auto opOpAssign(string op, T)(${1:T value}) {\n\t$0;\n\treturn this;\n}",
296 		"Operator assignment operator overload in form of `this op= value`.\n\n"
297 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
298 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#op-assign]"
299 	),
300 	PlainSnippet(
301 		[SnippetLevel.type],
302 		"opIndexOpAssign",
303 		"auto opIndexOpAssign!(op)(value, index)",
304 		"auto opIndexOpAssign(string op, T)(${1:T value}, ${2:size_t index}) {\n\t${0:return value;}\n}",
305 		"Operator index assignment operator overload in form of `this[index1, index2...] op= value`.\n\n"
306 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
307 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#index_op_assignment]"
308 	),
309 	PlainSnippet(
310 		[SnippetLevel.type],
311 		"opIndexOpAssignSlice",
312 		"auto opIndexOpAssign!(op)(value, slice)",
313 		"auto opIndexOpAssign(string op, T)(${1:T value}) {\n\t${0:return value;}\n}",
314 		"Operator index assignment operator overload in form of `this[start .. end] op= value`.\n\n"
315 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
316 			~ "The argument for this function is either empty to act on an entire slice like `this[] op= value` or a "
317 				~ "helper object returned by `opSlice` after the value to assign.\n\n"
318 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_op_assignment]"
319 	),
320 	PlainSnippet(
321 		[SnippetLevel.type],
322 		"opSliceOpAssign",
323 		"auto opSliceOpAssign!(op)(value, start, end)",
324 		"auto opSliceOpAssign(string op, T)(${1:T value}, ${2:size_t start, size_t end}) {\n\t${0:return value;}\n}",
325 		"Operator index assignment operator overload in form of `this[start .. end] op= value`.\n\n"
326 			~ "Overloadable operators: `+=`, `-=`, `*=`, `/=`, `%=`, `^^=`, `&=`, `|=`, `^=`, `<<=`, `>>=`, `>>>=`, `~=`\n\n"
327 			~ "The argument for this function is either empty to act on an entire slice like `this[] = value` "
328 				~ "or the start and end indices after the value to assign.\n\n"
329 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#slice_op_assignment]"
330 	),
331 	PlainSnippet(
332 		[SnippetLevel.type],
333 		"opIndex",
334 		"auto opIndex(index)",
335 		"${1:ref auto} opIndex(${2:size_t index}) {\n\t$0\n}",
336 		"Array index operator overload in form of `this[index1, index2...]`.\n\n"
337 			~ "Indices may specify any type and may also be the helper objects returned by opSlice.\n\n"
338 			~ "Leaving the index arguments empty means this returns a slice of the whole object. (often a shallow copy)\n\n"
339 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
340 	),
341 	PlainSnippet(
342 		[SnippetLevel.type],
343 		"opSlice",
344 		"auto opSlice(index)",
345 		"${1:size_t[2]} opSlice(${2:size_t start, size_t end}) {\n\t${0:return [start, end];}\n}",
346 		"Array slice operator overload in form of `this[start .. end]`.\n\n"
347 			~ "`opSlice` returns a helper object which is used in the index methods to operate on. "
348 				~ "It does not return the value of the array slice result, use opIndex for this.\n\n"
349 			~ "This snippet defines an overload for any dimension of the array (any comma count), "
350 				~ "use `opSliceN` for any dimensionality.\n\n"
351 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
352 	),
353 	PlainSnippet(
354 		[SnippetLevel.type],
355 		"opSliceN",
356 		"auto opSlice!(n)(index)",
357 		"${1:size_t[2]} opSlice(size_t dim : ${2:0})(${3:size_t start, size_t end}) {\n\t${0:return [start, end];}\n}",
358 		"Array slice operator overload in form of `this[start .. end]`.\n\n"
359 			~ "`opSlice` returns a helper object which is used in the index methods to operate on. "
360 				~ "It does not return the value of the array slice result, use opIndex for this.\n\n"
361 			~ "This snippet defines an overload for n-th dimension of the array, meaning this is the "
362 				~ "`n`th value in the comma separated index list, starting at n=0.\n\n"
363 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
364 	),
365 	PlainSnippet(
366 		[SnippetLevel.type],
367 		"opDollar",
368 		"auto opDollar()",
369 		"${1:size_t} opDollar() {\n\t${0:return length;}\n}",
370 		"Dollar operator overload in form of `this[$]`.\n\n"
371 			~ "`opDollar` returns a the value which the dollar sign in the index call returns. "
372 				~ "Commonly this is the length of the array.\n\n"
373 			~ "This snippet defines an overload for any dimension of the array (any comma count), "
374 				~ "use `opDollarN` for any dimensionality.\n\n"
375 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
376 	),
377 	PlainSnippet(
378 		[SnippetLevel.type],
379 		"opDollarN",
380 		"auto opDollar!(n)()",
381 		"${1:size_t} opDollar(size_t dim : ${2:0})() {\n\t${0:return length;}\n}",
382 		"Dollar operator overload in form of `this[$]`.\n\n"
383 			~ "`opDollar` returns a the value which the dollar sign in the index call returns. "
384 				~ "Commonly this is the length of the array.\n\n"
385 			~ "This snippet defines an overload for n-th dimension of the array, meaning this is the "
386 				~ "`n`th length in the comma separated index list, starting at n=0.\n\n"
387 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#array-ops]"
388 	),
389 	PlainSnippet(
390 		[SnippetLevel.type],
391 		"opDispatch",
392 		"auto opDispatch!(member)()",
393 		"${1:auto} opDispatch(${2:string member})() {\n\t$0\n}",
394 		"Compile-Time dynamic dispatch operator forwarding unknown member calls and properties in form of `this.member`.\n\n"
395 			~ "`opDispatch` will be executed for any method call or property access not matching another one. This should "
396 				~ "be used on special wrapper types without many other fields to avoid false calls in case of non-matching "
397 				~ "overloads. Defining this operator may also cause issues when trying to use CTFE functions with matching "
398 				~ "names.\n\n"
399 			~ "Reference: [https://dlang.org/spec/operatoroverloading.html#dispatch]"
400 	),
401 	PlainSnippet(
402 		[SnippetLevel.type],
403 		"opApply",
404 		"int opApply(dg)",
405 		"int opApply(scope int delegate(${1:ref Item}) ${2:dg}) {\n"
406 			~ "\tint result = 0;\n"
407 			~ "\n"
408 			~ "\t${3:foreach (item; array)} {\n"
409 			~ "\t\tresult = dg(item);\n"
410 			~ "\t\tif (result)\n"
411 			~ "\t\t\tbreak;\n"
412 			~ "\t}\n"
413 			~ "\n"
414 			~ "\treturn result;\n"
415 			~ "}",
416 		"Explicit foreach overload when calling `foreach (items...; this)`.\n\n"
417 			~ "Note that you can also implement this functionality through a forward range."
418 				~ "`opApply` has higher precedence over range functionality.\n\n"
419 			~ "Reference: [https://dlang.org/spec/statement.html#foreach_over_struct_and_classes]"
420 	),
421 	PlainSnippet(
422 		[SnippetLevel.type],
423 		"opApplyReverse",
424 		"int opApplyReverse(dg)",
425 		"int opApplyReverse(scope int delegate(${1:ref Item}) ${2:dg}) {\n"
426 			~ "\tint result = 0;\n"
427 			~ "\n"
428 			~ "\t${3:foreach_reverse (item; array)} {\n"
429 			~ "\t\tresult = dg(item);\n"
430 			~ "\t\tif (result)\n"
431 			~ "\t\t\tbreak;\n"
432 			~ "\t}\n"
433 			~ "\n"
434 			~ "\treturn result;\n"
435 			~ "}",
436 		"Explicit foreach overload when calling `foreach_reverse (items...; this)`.\n\n"
437 			~ "Note that you can also implement this functionality through a backward range. "
438 				~ "`opApplyReverse` has higher precedence over range functionality.\n\n"
439 			~ "Reference: [https://dlang.org/spec/statement.html#foreach_over_struct_and_classes]"
440 	),
441 
442 	// Exception snippets
443 
444 	PlainSnippet(
445 		[SnippetLevel.global, SnippetLevel.type],
446 		"Exception",
447 		"class MyException : Exception",
448 		"class ${1:MyException} : ${2:Exception} {\n"
449 			~ "\tthis(${3:string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null}) pure nothrow @nogc @safe {\n"
450 			~ "\t\tsuper(${4:msg, file, line, nextInChain});\n"
451 			~ "\t}\n"
452 			~ "}\n$0",
453 		"Class extending Exception. Use this for recoverable errors that may be catched in the application.\n\n"
454 			~ "Reference: [https://dlang.org/phobos/object.html#.Exception]"
455 	),
456 	PlainSnippet(
457 		[SnippetLevel.global, SnippetLevel.type],
458 		"Error",
459 		"class MyError : Error",
460 		"class ${1:MyError} : ${2:Error} {\n"
461 			~ "\tthis(${3:string msg, Throwable nextInChain = null}) pure nothrow @nogc @safe {\n"
462 			~ "\t\tsuper(${4:msg, nextInChain});\n"
463 			~ "\t}\n"
464 			~ "}\n$0",
465 		"Class extending Error. Use this for unrecoverable errors that applications should not catch.\n\n"
466 			~ "Reference: [https://dlang.org/phobos/object.html#.Exception]"
467 	),
468 
469 	// Builtin Types (keywords)
470 	PlainSnippet(
471 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
472 		"import",
473 		"import module",
474 		"import ${1:std};\n$0",
475 		"Imports a module given a name.\n\nReference: [https://dlang.org/spec/module.html#import-declaration]"
476 	),
477 	PlainSnippet(
478 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
479 		"class",
480 		"class MyClass",
481 		"class ${1:MyClass} {\n\t$0\n}",
482 		"Defines a simple class type.\n\nReference: [https://dlang.org/spec/class.html]"
483 	),
484 	PlainSnippet(
485 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
486 		"interface",
487 		"interface MyInterface",
488 		"interface ${1:MyInterface} {\n\t$0\n}",
489 		"Defines a simple interface type.\n\nReference: [https://dlang.org/spec/interface.html]"
490 	),
491 	PlainSnippet(
492 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
493 		"struct",
494 		"struct MyStruct",
495 		"struct ${1:MyStruct} {\n\t$0\n}",
496 		"Defines a simple struct type.\n\nReference: [https://dlang.org/spec/struct.html]"
497 	),
498 	PlainSnippet(
499 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
500 		"union",
501 		"union MyUnion",
502 		"union ${1:MyUnion} {\n\t$0\n}",
503 		"Defines a simple union type.\n\nReference: [https://dlang.org/spec/struct.html]"
504 	),
505 	PlainSnippet(
506 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
507 		"template",
508 		"template MyTemplate()",
509 		"template ${1:MyTemplate}($2) {\n\t$0\n}",
510 		"Defines a simple union type.\n\nReference: [https://dlang.org/spec/struct.html]"
511 	),
512 	PlainSnippet(
513 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
514 		"enums",
515 		"enum MyEnum { ... }",
516 		"enum ${1:MyEnum} {\n\t${0:init,}\n}",
517 		"Defines a simple enumeration.\n\nReference: [https://dlang.org/spec/enum.html]"
518 	),
519 	PlainSnippet(
520 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
521 		"enumv",
522 		"enum EnumValue = ...",
523 		"enum ${1:EnumValue} = $2;\n$0",
524 		"Defines a simple compile time constant using enum.\n\nReference: [https://dlang.org/spec/enum.html#manifest_constants]"
525 	),
526 
527 	// Types using phobos or some code idioms
528 	PlainSnippet(
529 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
530 		"typedef",
531 		"typedef MyType : BaseType",
532 		"enum ${1:MyType} : ${2:BaseType} {\n\t${0:init = 0}\n}",
533 		"Creates a typesafe alias not allowing implicit casting from base type, but allows implicit conversion to "
534 			~ "the base type in most cases. Therefore the implicit casting works a lot like class/interface inheritance.\n\n"
535 			~ "Reference: (17.1.5) [https://dlang.org/spec/enum.html#named_enums]"
536 	),
537 	PlainSnippet(
538 		[SnippetLevel.global, SnippetLevel.type, SnippetLevel.method],
539 		"Proxy",
540 		"struct MyType { mixin Proxy }",
541 		"struct ${1:MyType} {\n\t${2:BaseType} base;\n\tmixin Proxy!(${2:BaseType});\n}",
542 		"Creates a typesafe alias not allowing implicit casting to the base type, but allows implicit conversion "
543 				~ "from the base type in most cases. Basically allows copying any base type with new properties and "
544 				~ "methods as new and separate type. Imports `std.typecons : Proxy`.\n\n"
545 			~ "Reference: [https://dlang.org/phobos/std_typecons.html#Proxy]"
546 	),
547 	PlainSnippet(
548 		[SnippetLevel.global],
549 		"IUnknown",
550 		"interface COMInterface : IUnknown",
551 		"interface ${1:COMInterface} : IUnknown {\nextern(Windows):\n\t$0\n}",
552 		"Win32 COM interface without implementation to talk to other applications.\n\n"
553 			~ "Reference: [https://wiki.dlang.org/COM_Programming]"
554 	),
555 	PlainSnippet(
556 		[SnippetLevel.global],
557 		"ComObject",
558 		"class MyObject : ComObject",
559 		"class ${1:MyObject} : ComObject {\nextern(Windows):\n\t$0\n}",
560 		"Win32 COM interface with implementation to serve to other applications.\n\n"
561 			~ "Reference: [https://wiki.dlang.org/COM_Programming]"
562 	),
563 
564 	// range methods
565 
566 	PlainSnippet(
567 		[SnippetLevel.type],
568 		"InputRange",
569 		"InputRange (popFront, empty, front)",
570 		"${1:auto} front() @property { ${2:return myElement;} }\n"
571 			~ "bool empty() @property const { ${3:return true;} }\n"
572 			~ "void popFront() { $4 }\n$0",
573 		"Implements an input range for iteration support in range functions and foreach.\n\n"
574 			~ "Functions can only iterate over an InputRange exactly one time.\n\n"
575 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isInputRange]"
576 	),
577 	PlainSnippet(
578 		[SnippetLevel.type],
579 		"OutputRange",
580 		"OutputRange (put)",
581 		"void put(${1:Item} item) {\n\t$2\n}\n$0",
582 		"Implements the put function which allows to put one or more items into this range.\n\n"
583 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isOutputRange]"
584 	),
585 	PlainSnippet(
586 		[SnippetLevel.type],
587 		"ForwardRange",
588 		"ForwardRange (InputRange, save)",
589 		"${1:auto} front() @property { ${2:return myElement;} }\n"
590 			~ "bool empty() @property const { ${3:return true;} }\n"
591 			~ "void popFront() { $4 }\n"
592 			~ "typeof(this) save() { ${5:return this;} }\n$0",
593 		"Implements a forward range for iteration support in range functions and foreach.\n\n"
594 			~ "As opposed to InputRange this supports iterating over the same range multiple times.\n\n"
595 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isForwardRange]"
596 	),
597 	PlainSnippet(
598 		[SnippetLevel.type],
599 		"InfiniteRange",
600 		"InfiniteRange (empty = false)",
601 		"enum bool empty = false;\n$0",
602 		"Makes this range appear as infinite by adding `empty` as always `false` enum constant value.\n\n"
603 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isInfinite]"
604 	),
605 	PlainSnippet(
606 		[SnippetLevel.type],
607 		"BidirectionalRange",
608 		"BidirectionalRange (InputRange, back, popBack)",
609 		"${1:auto} front() @property { ${2:return myElement;} }\n"
610 			~ "${1:auto} back() @property { ${3:return myElement;} }\n"
611 			~ "bool empty() @property const { ${4:return true;} }\n"
612 			~ "void popFront() { $5 }\n"
613 			~ "void popBack() { $6 }\n$0",
614 		"Implements a bidirectional range for iteration support in range functions, foreach and foreach_reverse.\n\n"
615 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
616 	),
617 	PlainSnippet(
618 		[SnippetLevel.type],
619 		"RandomAccessRange",
620 		"RandomAccessRange (BidirectionalRange, opIndex, length)",
621 		"${1:auto} front() @property { ${2:return myElement;} }\n"
622 			~ "${1:auto} back() @property { ${3:return myElement;} }\n"
623 			~ "bool empty() @property const { ${4:return true;} }\n"
624 			~ "void popFront() { $5 }\n"
625 			~ "void popBack() { $6 }\n"
626 			~ "ref ${1:auto} opIndex(${7:size_t index}) { $8 }\n"
627 			~ "size_t length() { $9 }\n"
628 			~ "alias opDollar = length;$0",
629 		"Implements a bidirectional range with random access indexing support for full array emulation.\n\n"
630 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
631 	),
632 	PlainSnippet(
633 		[SnippetLevel.type],
634 		"RandomAccessRangeInf",
635 		"RandomAccessRange (InfiniteForwardRange, opIndex)",
636 		"${1:auto} front() @property { ${2:return myElement;} }\n"
637 			~ "enum bool empty = false;\n"
638 			~ "void popFront() { $3 }\n"
639 			~ "${1:auto} opIndex(${4:size_t index}) { $5 }\n$0",
640 		"Implements an infinite forward range with random access indexing support.\n\n"
641 			~ "Reference: [https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange]"
642 	),
643 ];
644 //dfmt on
645 
646 class PlainSnippetProvider : SnippetProvider
647 {
648 	protected Snippet[][SnippetLevel] prebuilt;
649 
650 	this()
651 	{
652 		foreach (s; plainSnippets)
653 		{
654 			Snippet built = s.buildSnippet(typeid(this).name);
655 
656 			foreach (level; s.levels)
657 				prebuilt[level] ~= built;
658 		}
659 	}
660 
661 	Future!(Snippet[]) provideSnippets(scope const WorkspaceD.Instance instance,
662 			scope const(char)[] file, scope const(char)[] code, int position, const SnippetInfo info)
663 	{
664 		Snippet[] ret;
665 		if (auto p = info.level in prebuilt)
666 			ret = *p;
667 		return Future!(Snippet[]).fromResult(ret);
668 	}
669 
670 	Future!Snippet resolveSnippet(scope const WorkspaceD.Instance instance,
671 			scope const(char)[] file, scope const(char)[] code, int position,
672 			const SnippetInfo info, Snippet snippet)
673 	{
674 		snippet.resolved = true;
675 		return Future!Snippet.fromResult(snippet);
676 	}
677 }