Smart completion - YellowAfterlife/GMEdit GitHub Wiki
GMEdit can provide contextual syntax completion and syntax highlighting for variables and methods.
In contrast to Feather (which largely tries to figure out types on its own)
An [as of yet] unique feature of GMEdit is in being able to provide contextual syntax completion and syntax highlighting for variables and (2.3) methods.
The premise is as following: if GMEdit knows what a type of an expression is, it can offer you contextual auto-completion (e.g. only showing variables from a specific instance) and better error checking (e.g. warning about assigning a string into a numeric variable or using wrong argument types.
Types and fields are determined as following:
-
Local variables
Local variable types can be indicated usingvar v:Tshorthand syntax. -
Built-in functions and variables
GMEdit comes with type definitions (see/resources/app/api/shared/) for majority of GMS2 functions and most GMS2 functions. -
User scripts and functions
Argument types can be indicated using@paramor shorthand syntax (function(a:T)in GMS≥2.3,#args a:Tfor older versions).
Return type can be indicated using@returnsor shorthand syntax (function(...)->ReturnType) in GMS≥2.3. -
Object and struct variables
GMEdit will automatically pick up variable names declared at top-level (read: not inside{}) within Create events and 2.3 constructors, including inheritance.
Variable types can be specified using@is; additional variables can be indicated using@hintor@implements. "Implicit types" can be enabled in linter preferences to auto-derive non-ambiguous types. -
Global variables
GMEdit will automatically indexglobal.nameandglobalvardeclarations. Types can be similarly indicated using@is. -
Macros
GMEdit is able to expand macros and derive types from code within. -
self
Type ofselfis automatically known in objects and constructors and objects but can be set using@self.
(note: you can summon self-specific completions without self-prefix by typing a period.out-of-context)
This is now a separate page because it was taking up half of this one.
Allows to explicitly cast an expression to a compatible type - such as casting int? to int or picking a specific one of either-types.
For example,
var sn:string|int = ...;
var i:int = is_string(sn) ? real(sn as string) : sn as int;In saved file, this becomes a /*#as T*/.
Allows to explicitly cast an expression to any, bypassing type checks in cases where that might be necessary.
For example,
var s:string = argument0;
if (is_real(s)) s = string_format(cast s, 0, 3); // no warning
// ...In saved file, this becomes a /*#cast*/.
Allows to explicitly cast an expression to a type (including "incompatible" ones). Generally used in parenthesis, so typing
(cast buffer_read(b, buffer_s32) as obj_entity).would show you auto-completion for variables from obj_entity and check for errors accordingly.
Suppose you have obj_enemy with the following Create event:
maxhealth = 10; // @is {number}
my_health = maxhealth; // @is {number}
my_target = noone; // @is {obj_entity}
// attack = function(target) {} // 2.3 methodAfter saving, if you were to type self. anywhere in the object, you would only get the variables defined in Create event and the built-in variables rather than everything that you have in your project.
Similarly, if you were to type obj_enemy. anywhere in the project, you would only get those same variables.
With above setup, if you were to write
var e:obj_enemy = instance_nearest(x, y, obj_enemy);After saving, typing e. would show you only the variables from obj_enemy.
Note: if you are confident that you are writing good code, you can enable "Implicit types for local variables" in Preferences or Project Properties to have types auto-derived for variable declarations with initial values (var v = val).
2.2: Suppose you had scr_enemy_ai that would be called by obj_enemy with the following
/// @self {obj_enemy}
self.my_target = instance_nearest(x, y, obj_player);After saving, typing self. would show you only the variables from obj_enemy.
2.3 version (much the same, but JSDoc tags sit outside the functions now):
/// @self {obj_enemy}
function scr_enemy_ai() {
self.my_target = instance_nearest(x, y, obj_player);
}Suppose you had a pair of functions that represent things that you might assign into constructors/objects:
/// @interface {IHorsable}
function scr_init_horsable() {
neigh = function(magnitude) { throw "not implemented!" }
}
/// @interface
function scr_twovars() {
oneVar = 1;
twoVar = 2;
}(in 2.2, make that two scripts with /// @interface inside the script and replace function(){} by another script)
You would then be able to mark them for inclusion in auto-completion and highlighting by doing the following in Create event of an object:
/// @implements {IHorsable}
scr_twovars(); /// @implements
myVar = "hi!";Or, for constructors,
/// @implements {IHorsable}
function Some() constructor {
// ...
scr_twovars(); /// @implements
myVar = "hi!";
}which would then show you myVar, oneVar, twoVar, and neigh(magnitude) when typing self..
- Like with most GMEdit features, you'll need to save (Ctrl+S) when adding/changing code that specifies types.
- For compatibility purposes, object references are not
objectortype<obj_name>, but justobj_name. With almost allinstance_functions taking either an object or an instance, this can only backfire ininstance_create[_depth|_layer](as you would be able to pass in an instance instead of an object). - When using
@hint A extends Bor constructor inheritance on types with parameters (@template), child's first parameters must match up with parent's parameters.