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 using var v:T shorthand 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 @param or shorthand syntax (function(a:T) in GMS≥2.3, #args a:T for older versions).
    Return type can be indicated using @returns or 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 @hint or @implements. "Implicit types" can be enabled in linter preferences to auto-derive non-ambiguous types.
  • Global variables
    GMEdit will automatically index global.name and globalvar declarations. Types can be similarly indicated using @is.
  • Macros
    GMEdit is able to expand macros and derive types from code within.
  • self
    Type of self is 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)

Types in GMEdit

Supported types

This is now a separate page because it was taking up half of this one.

X as Y

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*/.

cast X

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*/.

cast X as Y

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.

Examples

Object basics

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 method

After 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.

Local types

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).

@self

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);
}

Interfaces

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..

Notes and limitations:

  • 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 object or type<obj_name>, but just obj_name. With almost all instance_ functions taking either an object or an instance, this can only backfire in instance_create[_depth|_layer] (as you would be able to pass in an instance instead of an object).
  • When using @hint A extends B or constructor inheritance on types with parameters (@template), child's first parameters must match up with parent's parameters.
⚠️ **GitHub.com Fallback** ⚠️