This is a "cheat sheet" for "gml_string" extension by YellowAfterlife.
The extension can be acquired from itch.io or GM:Marketplace
Click on sections to expand/collapse them.
Quick display controls: Categories · Sections · Everything ·

Parsing

Input:

gml_string_parse(codeString, outList)​int

Parses an input string of GML code and pushes the resulting tokens into a ds_list (outList).

The list will not be cleared prior, so you should ds_list_clear it yourself unless you are trying to concatenate results from several parse calls.

Returns the number of tokens added to the list.

Output:

gml_string_parser_lines_found:int

This global variable stores the number of lines found during the last call to gml_string_parse. Note that it does not count for any pre-existing tokens that might have been in your list.

Hinting:

gml_string_hint_locals(tokenList)

This function does a post-process pass on a token list to do a few things:

  • Highlights local variables (var)
  • Highlights global variables (globalvar)
  • Highlights macros (#macro)
  • Highlights enums (enum <name> { ...constructs })
  • Highlights locally defined scripts (#define)

Processing time is usually similar to that of initial parse operation.

tokens = ds_list_create();
gml_string_parse("var i = 1, k = 2; return i + k;", tokens);
gml_string_hint_locals(tokens);
Drawing
gml_string_draw(sx, sy, tokens, colors, ?fonts)

Draws a list of tokens onto screen.

colors is an array of colors per token kind.

fonts (optional) is an array of fonts per token kind.

tokens = ds_list_create();
gml_string_parse("return 1;", tokens);
colors = array_create(gml_string_kind.sizeof, $C0C0C0);
colors[gml_string_kind.keyword] = $71BBFF;

// ...later in Draw event
gml_string_draw(10, 10, tokens, colors);
gml_string_draw_culled(sx, sy, tokens, ytop, ybot, colors, ?fonts)

Like gml_string_draw, but skips drawing tokens outside the ytop..ybot range.

This is handy if you are drawing snippets substantially larger than the viewport, as it'll offer better performance.

var code = string_repeat("// hello!" + chr(13) + chr(10), 100);
tokens = ds_list_create();
gml_string_parse(code, tokens);
colors = array_create(gml_string_kind_sizeof, $C0C0C0);
colors[gml_string_kind.comment] = $5b995b;

// ...later in Draw event
draw_rectangle(0, 50, 200, 150, true);
gml_string_draw_culled(10, 10 - current_time / 100, tokens, 50, 150, colors);
API

The following allow you to customize how parser will deal GML API.

gml_string_api_version:int

Target GML version.
Can be set to 1 for GMS1 or 2 for GMS2.
This affects how strings will be parsed.

gml_string_api_tab_string:string

If you do not want tab characters in tokenized output (e.g. GameMaker cannot draw them via draw_text), you can set this variable to a sequence of spaces to use instead.

gml_string_api_tab_string = "    "; // (4 spaces - default)
gml_string_api_tab_string = undefined; // (keep tab characters)
gml_string_api_ident_map:map<name:string, token_kind>
gml_string_api_enum_map:map<enum_name, map<field_name, any>>

Maps can be assigned into this map to have gml_string know about global enums during hinting pass.

Values inside inner maps do not matter - gml_string will only run ds_map_exists on them.

Note that you should still assign entries into gml_string_api_ident_map.

gml_string_api_ident_map[?"MyEnum"] = gml_string_kind_enum;
var e = ds_map_create();
e[?"A"] = true;
e[?"B"] = true;
gml_string_api_enum_map[?"MyEnum"] = e;
gml_string_api_flow_keyword_map:map<name:string, is_flow:bool>

This ds_map specifies keywords that immediately end processing of local variable declarations (var). You shouldn't have to touch it unless you are using custom keywords and also do not require semicolons.

gml_string_api_load(fnames_path)

Adds entries to gml_string_api_ident_map as per definitions in GameMaker fnames-style format. This can be more convenient than assigning identifiers to gml_string_api_ident_map.

The following will be recognized:

  • variable_name
  • constant_name#
  • function_name(

For example,

gml_string_api_load("custom.txt");

would load API entries from a "custom.txt" file.

gml_string_api_load_from_string(fnames_text)
Tokens

Each token is an array where the first item is token kind and the second item is token text. Trailing items are allowed and will be ignored by the extension's functions.

Kind can be any index so long as your provided color/font arrays include it.

The following are the default token kinds.
They can also be accessed through underscore notation (gml_string_kind_ident instead of gml_string_kind.ident) for convenience and backwards compatibility.

gml_string_kind.none

Not included in the extension's normal output.
This can be used when manually adding tokens (e.g. to have a non-highlighted prefix/suffix).

gml_string_kind.error

Syntactically invalid characters
(e.g. if you were to have var pound_sign = £;, £ would be error-kind)

gml_string_kind.space

Spaces and tabs. Adjacent characters are joined together into single tokens.

gml_string_kind.new_line

"new line" token. These are not present after nesting tokens.

gml_string_kind.comment_line

A single-line comment (// text)

gml_string_kind.comment_block

A block comment (/* text */)

gml_string_kind.header_meta

#define very specifically

gml_string_kind.header_name

Script name following a #define

gml_string_kind.keyword

Keywords, including operator-keywords

gml_string_kind.curly_bracket

Curly brackets (as it is common to style them differently)

gml_string_kind.operator

Actual operators and assisting tokens (;, :, (, )...)

gml_string_kind.ident

Identifiers not recognized as keywords or other structures

gml_string_kind.constant

Constants (such as c_white)

gml_string_kind.variable

Built-in variables (such as x)

gml_string_kind.function_

Built-in functions (such as show_message)

gml_string_kind.script

User-defined scripts

gml_string_kind.local_
gml_string_kind.global_

Variables marked via globalvar

gml_string_kind.macro

GMS2 #macros

gml_string_kind.enum_

Enum names (E for E.A)

gml_string_kind.enum_field

Enum fields (A in E.A)

gml_string_kind.string

String literals

gml_string_kind.number

Numeric literals (1, 1.2, $12, 0x12)

gml_string_kind.sizeof

Number of "built-in" token types.
Custom token types should count up from this.

Helper functions:

gml_string_get_token_kind(token)​token_kind
gml_string_set_token_kind(token, newKind)

Changes the token's kind.

gml_string_get_token_text(token)​string

Returns the token's text (e.g. "4.2" for 4.2).

gml_string_set_token_text(token, newText)

Changes the token's text.

gml_string_kind_is_space(token)​bool

Returns whether a token is a "space" kind of token (spaces, new lines, comments).

gml_string_kind_get_depth_delta(token)​int

Returns bracket depth "delta" (e.g. 1 for ( and -1 for )) for the token.
Supports the three kinds of brackets and begin/end. Returns 0 for non-brackets.

gml_string_kind_get_name(kind)​string
Nesting

If you need to display reasonably big (>1000 lines of code) snippets, you may find that there is a minor cost to drawing tokens closer to the end of the token list simply because the drawing function has to loop over them first to find the first index within the viewport bounds.

These two functions aid with such use cases.

gml_string_nest(tokens, ?lineCount)​array<array<token>>

Converts a list of tokens into an array of lines, where each line is an array of tokens residing on that line.

If the optional lineCount argument is supplied, it will be used instead of iterating over the list to count the lines before allocating an array.
You can retrieve it from Note that supplying an incorrect lineCount may result in either operation taking longer than it should (due to re-allocating the array on out-of-bounds write) or gml_string_draw_nested crashing due to a missing array in an index.

gml_string_draw_nested(sx, sy, bakedArray, ytop, ybot, colors, ?fonts)
JavaScript API

The JS version of the extension exposes a global gml_string object with the following fields mirroring the GML API:

The following are unique to JS API:

renderToHTML(tokens, cssClassPrefix="")​string

Example renderer function.

Takes a list of tokens and a CSS class prefix so

var tks = [];
gml_string.parse("return 1", tks);
console.log(gml_string.renderToHTML(tks, "gml"));

would give you

<span class="gmlKeyword">return</span> <span class="gmlNumber">1</span>

Notes on types:

  • ds_list is replaced with array.
  • ds_map is replaced with a prototype-less (Object.create(null)) JS object.
  • Tokens are replaced by mini-objects with kind and text fields.
Getting started

You are expected to have at least basic knowledge of HTML and how websites work.

1. Create a new directory on your website - called, for example, gml.

2. Upload gml_string.js (from "gml_string (for websites).zip") to that directory.

3. Create a stylesheet file in the same directory - called, for example, gml.css.

This will define how different code bits will look.

For something resembling the syntax highlighting in GameMaker IDE, you can use the following:

.gmlError { color: #f0f }
.gmlCommentLine, .gmlCommentBlock { color: #5B995B }
.gmlMacro, .gmlEnum, .gmlEnumField {
    color: #FF8080;
}
.gmlNumber { color: #FF8080 }
.gmlString { color: #FCF320 }
.gmlKeyword, .gmlCurlyBracket,
.gmlFunction, .gmlScript {
    color: #FFB871;
}
.gmlLocal { color: #FFF899 }
.gmlVariable { color: #58E55A }
.gmlHeaderMeta { color: #A7B }
.gmlHeaderName { color: #77BB5B }

And for light-mode websites, you can use the following (GM8.1-inspired):

.gmlError { color: red }
.gmlCommentLine, .gmlCommentBlock { color: #008000 }
.gmlKeyword, .gmlCurlyBracket {
	color: #00379B;
	font-weight: bold;
}
.gmlNumber, .gmlString { color: #00f }
.gmlLocal { color: #748 }
.gmlHeaderMeta, .gmlHeaderName { color: #0078AA }
.gmlScript { color: #808 }
.gmlFunction, .gmlMacro, .gmlVariable, .gmlEnum, .gmlEnumField {
    color: #990000;
}

4. Create a new JavaScript file in that same directory - called, for example, gml_highlight.js.

This will be the file responsible for loading the API and applying the syntax highlighter.

If you are putting your code in <pre> tags, it can go like this::

gml_string.API.loadFromString(`
is_real(val)
is_numeric(val)
is_string(val)
is_array(val)
// You can paste the entire `fnames` file from the runtime directory in this string
// Find its location via File - Preferences - Runtime Feeds
`);
function highlightCodeBlocks() {
	for (let el of document.querySelectorAll("pre:not(.gml)")) {
		el.classList.add(".gml");
		el.innerHTML = gml_string.renderToHTML(el.innerHTML, "gml");
	}
}
if (document.readyState == "loading") {
	document.addEventListener('DOMContentLoaded', highlightCodeBlocks);
} else highlightCodeBlocks();

5. Include the files in your page template(s).

The easiest would be to put everything inside your <head> tag:

<link rel="stylesheet" href="/gml/gml.css" />
<script src="/gml/gml_string.js"></script>
<script src="/gml/gml_highlight.js"></script>
Haxe API

Haxe API is represented by the gs.* package.

It is what is used to generate GML and JS versions.

Limitations
Default vs nested

As per nesting section, you will generally want to convert your token list to nested format if the line count is too high.

Note on use in code editors

Although it may be very tempting to utilize this extension to create a code editor in GameMaker, you should be aware that there's much more to it than syntax highlighting;

Aside of actual editing, to allow editing particularly large files, you would eventually want to not re-highlight an entire file upon typing, and to do so over multiple frames.

Nested mode in GMS<=2.2

Due to very large 1d arrays not actually being 1d in pre-2.3 versions of GMS, you can only have up to 32000 lines in a nested structure and up to 32000 tokens per such line.

Needless to say, this is far more than realistic use cases need, but if you do need more, you would want to look at the implementation and make a custom version that either writes lengths as prefixes (since arr[32003] accesses arr[1,3]), or structure it to add/remove lists to a list.