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