-
Notifications
You must be signed in to change notification settings - Fork 47
JSDoc tags
GMEdit supports standard and less-standard JSDoc tags for benefit of syntax highlighting, auto-completion, and argument information.
On this page, [text]
inside "syntax" examples means that something is optional.
- @param: function arguments
- @returns: return types
- @interface: declare script as interface
- @implements: implement an interface
-
@self: indicate type of
self
in scripts - @hint: advanced uses (mostly for GMS≥2.3)
- @is: indicate types of instance/struct/global variables
- @template: set up template types and type constraints
- @typedef: set up project-wide type aliases
- @init: mark events as containing variable/function definitions
- @index_redirect: stop/override indexing process for the current file
This tag is pretty consistent with how the base IDE works.
Zero or more of these can be present per function to annotate each argument.
This information is then used in auto-completion, error checking, and argument hints (seen in status bar).
Syntax:
/// @param [{argType}] argName [description]
Types can be provided in curly brackets {}
and are used for smart completion and linter type checks.
Optional parameters can be marked via [argName]
, ?argName
, or argName=value
.
Rest-argument (allowing 0 or more additional arguments to be added at the end) can be marked as ...argName
.
Any additional text after the argument name is considered to be the description and is currently unused.
Examples:
/// @param an_arg
/// @param {int} a_number
/// @param ?optional_arg
/// @param depth=0
/// @param ...rest
Aliases: @arg
, @argument
Marks the return type for a script/function.
Syntax:
/// @returns {returnType} [description]
Similarly used for completion and type checks.
Aliases: @return
Marks a script as an interface, for use with @implements
.
Syntax:
/// @interface [{InterfaceName}]
Top-level (read: not nested inside {} - e.g. name = value
) variable assignments within an interface-script will be considered fields and will show up in syntax highlighting/auto-completion for structures and objects that implement it.
Example (GMS≥2.3, manually named):
/// @interface {IMovable}
function scr_move_init() {
xspeed = 0;
yspeed = 0;
}
Example (GMS≤2.2, automatically named):
/// scr_move_init()
/// @interface
which would later let you /// @implements {IMovable}
and /// @implements {scr_move_init}
accordingly.
Indicates that a constructor or an object implements an interface.
Syntax:
/// @implements {InterfaceName}
scr_name(); /// @implements
As result, syntax highlighting and auto-completion information will include fields from the said interface.
A constructor/object can have any number of interfaces; interfaces themselves may implement other interfaces.
Example (2.3 constructor and a named interface):
/// @implements {IMovable}
function Some() constructor {
// after saving, writing `self.` here would now bring up `xspeed` and `yspeed`.
}
Example (object's Create event and an automatically named interface):
scr_move_init(); /// @implements
// after saving, writing `self.` here would now bring up `xspeed` and `yspeed`.
Indicates what type self
would be for a script
Syntax:
/// @self {InterfaceOrObjectName}
While GMEdit will automatically determine what type self
inside constructors and objects, doing so for arbitrary scripts is a task that varies from hard to impossible, so you may mark the type yourself.
Example (GMS≥2.3, named interface):
/// @self {IMovable}
function scr_move(input_x, input_y) {
// after saving, writing `self.` here would now bring up variables from IMovable
}
Example (GMS≤2.2, objects):
/// scr_move(input_x, input_y)
/// @param input_x
/// @param input_y
/// @self {obj_some}
// after saving, writing `self.` here would now bring up variables from obj_some
Aliases: @this
Hint at variables, functions, constructors, interfaces, or anything else that is not or cannot be automatically inferred from your source code.
Syntax:
/// @hint [new] [Type][.:][field][(...arguments)[->returnType]] [description]
/// @hint TypeName extends ParentTypeName
/// @hint TypeName implements InterfaceName
See the dedicated wiki page for more information.
Specify types of struct, instance, and global variables.
Syntax:
// in Create or inside a constructor
varName = value; /// @is {type}
// anywhere
global.varName = value; /// @is {type}
globalvar varName; /// @is {type}
globalvar varName; varName = value; /// @is {type}
Example:
function Vec2(_x, _y) constructor {
x = _x; /// @is {number}
y = _y; /// @is {number}
}
global.v2 = new Vec2(0, 0); /// @is {Vec2}
globalvar g_vec2; g_vec2 = new Vec2(0, 0); /// @is {Vec2}
#macro m_vec2 global.v2
afterwards, typing global.v2.
, g_vec2.
, or m_vec2.
,
or typing var v:Vec2
, saving, and then typing v.
would show you auto-completion for x
/y
and check types for them when reading/writing.
Specify template types and type constraints for scripts, functions, and constructors.
/// @template T1[,T2,...]
/// @template {ConstraintType} T1[,T2,...]
Example:
If you were to do the following in GMS≤2.2.5 (in a script called select
)
/// @template T
/// @param {int} index
/// @param {T} ...values
/// @returns {T}
return argument[argument[0] + 1];
or the following in GMS≥2.3
/// @template T
/// @param {int} index
/// @param {T} ...values
/// @returns {T}
function select() {
return argument[argument[0] + 1];
}
doing select(i, "a", "b")
would give you a string-typed value and doing select(i, "a", 0)
would give you a warning due to mixing types.
Or, for constraints with local type syntactic sugar
/// @template {obj_entity} E
function find_first_alive_entity(obj:E)->E {
with (obj) if (hp > 0) return self;
return noone;
}
and then typing find_first_alive_entity(obj_player).
would automatically offer you variables from obj_player
;
trying to pass in an object that is not a descendant of obj_entity
will show a warning.
This allows you to define a shorter and/or more descriptive name for a type.
/// @typedef {type} alias
Example: suppose you have a 3d vector type, tuple<x:number, y:number, z:number>
.
That's a bit of text to type every time you use it. So you could make an alias for it via
/// @typedef {tuple<x:number, y:number, z:number>} vec3
and subsequently do var v:vec3
or myVec = [1, 2, 3]; /// @is {vec3}
By default, GMEdit will pick up variables from Create event for syntax highlighting and auto-completion. With this, however, you can mark another event (such as a User Event) as containing variables.
// Create:
event_user(0);
an_int = 1;
User 0:
/// @init
a_string = "hi!";
This way both an_int
and a_string
would show in auto-completion and highlight accordingly.
Tells the indexer to stop processing the current file (and, optionally, to start processing a different file as if it's a continuation of the current one).
/// @index_redirect
/// @index_redirect path
This is handy in a few cases:
- You have code (perhaps auto-generated, or not written by you, or both) that you don't want to see in your auto-completion and generally pretend that it doesn't exist.
- You have code that you want to be processed not in the way it looks - most commonly involving macros.
If the path starts with a /
, it'll be assumed to be relative to the project folder (so that you can do paths like /notes/mynote/mynote.txt
). Otherwise it's assumed to be relative to the current file's location. Omitting a path just stops indexing the current file with no further action.
For example, suppose you decided to make yourself a JS-like setTimeout script that's called like setTimeout(func, delay, arg1, arg2, ...)
. But also you want to get warnings when you mismatch argument types, which isn't something that most editors/programming languages (except C++ and TypeScript) can help you with as template type parameters have to be extracted out of the function type except for the last one (being return type). And if your arguments come before the function, it gets much worse than this. Anyway,
You could create separate variations of the function for different argument counts that in reality are just aliases for the original, like so
/// setTimeout_macros
/// @index_redirect setTimeout_macros.txt
#macro setTimeout_1 setTimeout
#macro setTimeout_2 setTimeout
and then in setTimeout_macros.txt
(created in script's folder)
/// @template A
function setTimeout_1(fn:function<A,void>, delay:number, arg1:A) {}
/// @template A,B
function setTimeout_2(fn:function<A,B,void>, delay:number, arg1:A, arg2:B) {}
consequently, both setTimeout
s would warn about passing arguments with type not matching the function's arguments (provided that those were set) as they would warn about passing the wrong number of arguments. And all of this would come at zero runtime cost because those function definitions in a .txt
file aren't even real code.
- Smart auto-completion
- Types
- JSDoc tags (incl. additional ones)
- @hint tag (mostly 2.3)
- `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)