Skip to content
Vadym Diachenko edited this page Oct 31, 2024 · 11 revisions

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.

Better workflow:

Syntax extensions:

  • `vals: $v1 $v2` (template strings)
  • #args (pre-2.3 named arguments)
  • ??= (for pre-GM2022 optional arguments)
  • ?? ?. ?[ (pre-GM2022 null-conditional operators)
  • #lambda (pre-2.3 function literals)
  • => (2.3+ function shorthands)
  • #import (namespaces and aliases)
  • v:Type (local variable types)
  • #mfunc (macros with arguments)
  • #gmcr (coroutines)

Customization:

User-created:

Other:

Clone this wiki locally