Syntax highlighting
Since: 0.2.0
This document owns the optional presentation API. Highlighting is tolerant lexical classification, not source validation or a replacement for Compiler diagnostics. It never executes source. Runtime, Compiler and native Bridges do not depend on it.
Grammar and matching
The canonical GES and GESA TextMate JSON grammars under tools/editors/TextMate
are the sole rule source. The Classic plist grammars represent the same rules.
scripts/sync-highlighter-grammars.py embeds immutable tables into C# and Swift;
consumer builds need neither the generator nor grammar files on disk.
The bundled evaluator supports ordered match and begin/end rules, numbered
named captures, name, contentName, local includes, embedded GES and
applyEndPatternLast. The earliest match wins; rule order breaks ties. A current
region’s end wins an equal-position tie unless applyEndPatternLast is enabled.
Strings use that exception so doubled delimiters remain escapes. Captures append
scopes from the outermost range inward. Zero-width ends may close a region without
consuming the next token, as used by GESA source blocks.
This is not a general-purpose TextMate/Oniguruma engine. C# uses BCL Regex; Swift uses Foundation NSRegularExpression. Changes to the bundled grammar must work in both engines and pass the shared highlighting corpus. Unsupported structural features fail generation instead of silently disappearing. No separate keyword list is maintained by the CLI or highlighter.
Input, spans and categories
A reusable highlighter selects GES or GESA. Highlight/highlight processes a
whole document. HighlightLine/highlightLine processes exactly one physical
line with an optional final LF, CR or CRLF. Interior line endings are an API error.
An empty document or line is valid. Input is never normalized or expanded.
Only CR, LF and CRLF delimit physical lines. Regex line anchors and dot matching
must not treat U+0085, U+2028, U+2029, vertical tab or form feed as additional line
boundaries. These characters remain content, including inside comments and
strings in GESA source annotations.
A complete result supplies ordered, nonoverlapping, positive-length spans covering
all input, including whitespace and line endings. Empty input has no spans.
Start/start and Length/length count UTF-16 code units relative to the supplied
document or line; they are directly usable as .NET string offsets and NSRange.
Spans carry an immutable outer-to-inner TextMate scope stack, including the root
language scope, plus a theme-independent category. Editors may theme either the
category or the complete scope stack. No colors or UI objects occur in spans.
Categories are Plain, Keyword, Builtin, Identifier, Message, Type, Tag, Constant, Number, String, Comment, Symbol, Function, Module, Label and Register. The innermost recognized scope determines the category. String escapes belong to String; Boolean literals and word operators belong to Keyword. Unknown/unclassified text belongs to Plain. Declaration keywords retain their keyword category even when the declared name is on the next line or has not been entered yet. Contextual declaration rules take precedence when their complete pattern matches. Classification does not prove that text is valid GES.
Incremental editing
Every complete result supplies an immutable, equatable continuation state after
its final processed line. An initial state starts outside any region. Open strings
and embedded GES regions survive line boundaries; line terminators retain the
scope active after matching the line’s content. A GESA .source-line annotation
is limited to that line, including unfinished strings; source blocks retain normal
multiline GES strings.
States are opaque, belong to one language and may be used by another highlighter instance of the same library version and language. They are not a persistence format. Passing a GES state to a GESA highlighter, or vice versa, is an API error.
An editor caches each line’s text, spans and exit state. After an edit, start with the preceding line’s state and reprocess subsequent lines until both the unchanged text and exit state converge. Shift line-relative spans by the document line start when applying styles. Including original line terminators permits exact comparison with whole-document highlighting. The state is for the next line, not for appending another chunk to the same line.
Resource bounds and failure
Each call accepts at most a configurable positive UTF-16 length, default 262144. The evaluator limits nesting to 128 regions and uses a cooperative 1000 ms matching budget. C# additionally uses a 100 ms timeout per regex; Swift observes the budget through Foundation progress callbacks. These are responsiveness safeguards, not hard real-time guarantees or cross-platform performance requirements.
Exceeding a bound returns IsComplete == false / isComplete == false, no spans
and no continuation state. The caller displays unchanged plain text and must not
cache that result as a successful lexical state. Large documents should use the
line API. An unfinished source construct alone is not failure.
ANSI presentation
The optional ANSI renderer accepts the unchanged source and its spans, preserving
every character. It supports a default category palette and an optional callback
returning a basic/bright foreground SGR code (30–37, 39, 90–97) or no color.
It validates range order, bounds and UTF-16 surrogate boundaries, coalesces adjacent
same-color spans and resets color after painted text. Invalid ranges or colors
are API errors. Terminal detection, NO_COLOR, redirection, tab expansion and
whether coloring is enabled belong to the embedding, not this library.
Mapping and verification
- C#:
GameEventScript.SyntaxHighlighterpackage and namespace, .NET Standard 2.1, no third-party or other GES library dependency. - Swift:
GameEventScriptSyntaxHighlighterSwiftPM product; Foundation supplies regex and embedded grammar decoding. No AppKit, UIKit, Runtime or Compiler dependency. Foundation is also available on supported non-Apple Swift platforms; platform availability is verified separately from the API contract.
Both implementations expose GameEventScriptSyntaxHighlighter,
GameEventScriptSyntaxLanguage, GameEventScriptSyntaxKind,
GameEventScriptHighlightSpan, GameEventScriptHighlightResult,
GameEventScriptHighlightState and GameEventScriptAnsiRenderer.
Swift reports invalid API input through GameEventScriptHighlightingError.
The shared executable examples live in
conformance/highlighting/SyntaxHighlighting.md.
Native package adapters run those Markdown cases without Runtime or Compiler and
verify categories, scope stacks, Unicode offsets, whole-document/line equivalence
and ANSI text preservation. They are presentation conformance, separate from the
VM capability corpus; optional highlighting does not add a Runtime dependency.
Combined pipeline selectors
The selector vocabulary includes cartesian, lockstep, zip, union,
intersect, difference and foreach. Colon-prefixed selector steps use the
existing builtin scope both in separate brackets and in compact chains. The
GESA opcode vocabulary includes Cartesian. Qualified extension names follow
the contiguous spelling specified in Language.md.