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 }