Zero-setup VS Code support for Perception.cx's JIT-compiled Enma scripting language.
IntelliSense, type checking, hover docs, signature help, refactors, formatter, multi-file bundler and DAP debugger — covering 100 % of the Perception Enma API and every pre-shipped stdlib addon.
A Perception-flavoured fork of angel-lsp, retargeted from AngelScript to the Enma language.
Quick Start · Features · Snippets · API Coverage · Architecture · Settings · Roadmap · References
The full Perception Enma API + every pre-shipped stdlib addon is bundled directly into the extension. Open a folder of
.emfiles and IntelliSense is active immediately — noem.predefinedrequired, no host scaffolding, no external doc trawling.
- ⚡ JIT-language native — keyword set, primitive types (
aint8/16/32/64,float32,float64,wchar,wstring, …), grammar shapes (defer,match,coroutine,yield,[[packed]], lambdas, annotations) all wired up. - 🧠 Workspace-aware analyzer — multi-file
#include, namespaces, templates, generics, mixins, multiple inheritance, properties, three-way<=>, designated init, all surfaced. - 🎮 Perception-specific —
proc_t,vec3/quat/mat4, render natives, Zydis encoder, Unicorn emulator, GUI sidebar, MCP bridge — every native shows up with parameter hints, hover docs, and go-to-definition. - 📦 Built-in bundler —
Enma: Bundle Scriptcollapses an#include-tree into the single.emPerception expects, with optional comment stripping and circular-include detection. - 🐞 DAP-ready — attach to any Enma DAP server on
localhost:27979straight from VS Code's debug panel. - 🛡 Multi-project mode — define multiple Enma projects in one workspace, each with its own source dir, bundler output, and LSP scope (
fullorsyntaxOnly).
# 1. Download the latest .vsix
curl -L -o enma-lsp-pcx.vsix \
https://github.com/VoidChecksum/enma-lsp-pcx/releases/latest/download/enma-lsp-pcx.vsix
# 2. Install into VS Code
code --install-extension enma-lsp-pcx.vsixOr — VS Code Marketplace:
code --install-extension voidchecksum.enma-lspOpen a folder, then Ctrl+Shift+P → Enma: Initialize Project. You get:
my-script/
├── source/
│ └── main.em
├── output/
│ └── (bundled.em lands here)
└── .vscode/
└── tasks.json ← enma-bundle task wired up
main.em:
import "color";
import "vec";
int64 g_tick;
void my_draw(int64 data) {
g_tick = g_tick + 1;
color white = color(255, 255, 255, 255);
color noeffect = color(0, 0, 0, 0);
string text = "tick=" + cast<string>(g_tick);
draw_text(text, vec2(40.0, 40.0), white, get_font20(), 0, noeffect, 0.0);
}
int64 main() {
g_tick = 0;
register_routine(cast<int64>(my_draw), 0);
return 1;
}Hit Ctrl+Alt+B → bundled .em ready for Perception.
| Capability | Status | Backed by |
|---|---|---|
| Autocomplete | ✅ | server/src/services/completion.ts |
| Hover docs | ✅ | server/src/services/hover.ts · sourced from *.em.predefined |
| Signature help | ✅ | server/src/services/signatureHelp.ts |
| Go to definition | ✅ | server/src/services/definition.ts |
| Go to type / impl | ✅ | resolver in analyzer scope |
| Find references | ✅ | server/src/services/reference.ts |
| Rename symbol | ✅ | project-wide via the references provider |
| Diagnostics | ✅ | parser + analyzer diagnostics, live |
| Semantic tokens | ✅ | full-document, custom keywordControl superType |
| Inlay hints | ✅ | server/src/services/inlayHint.ts |
| Code actions | ✅ | quick-fix infrastructure, named-arg helpers |
| Document symbols | ✅ | outline panel populated |
| Document formatting | ✅ | format on type / range / full doc |
| Document on-type fmt | ✅ | ; / } / newline triggers |
| Workspace symbol srch | ⏳ | best-effort fallback via definitionExtension |
| Capability | Trigger |
|---|---|
| Bundle Script | Ctrl+Alt+B · Enma: Bundle Script |
| Bundle Script (Strip Comments) | Ctrl+Alt+Shift+B |
| Bundle Project… / Bundle All | Quick pick / sequential bundling |
| Initialize Project | Scaffolds source/main.em + tasks.json |
| Status bar quick menu | One-click access to common commands |
| DAP attach | localhost:27979 default; configurable in launch.json |
| Multi-project workspaces | enma.projects[] · per-project LSP mode |
| Prefix | Inserts |
|---|---|
pcx-main |
int64 main() { … return 1; } entry point |
pcx-routine |
register_routine(cast<int64>(cb), 0) callback skeleton |
pcx-draw |
Render routine with color + vec2 + draw_text |
pcx-proc |
Attach to a process via ref_process |
pcx-pattern |
find_code_pattern IDA-style scan |
pcx-http |
http_get(...) with network_access reminder |
pcx-section |
Sidebar section + checkbox |
pcx-emu |
Unicorn cpu_t emulator skeleton |
pcx-zydis |
Zydis encoder skeleton |
defer |
defer { … } |
match |
match (x) { 1 => 10, _ => 0 }; |
coroutine |
coroutine int32 name(...) { while (true) { yield …; } } |
lambda |
[](int32 x) -> int32 { … } |
arrow |
(int32 x) => x * 2 |
new |
T* p = new T(args); |
[[packed]] |
Packed struct |
[[align]] |
Aligned struct |
The bundled perception.em.predefined ships declarations for:
-
All 18 pre-shipped Enma stdlib addons core string arrays maps math math3d simd variant atomic bits time regex thread vec hash_set sorted_map list json
-
All 12 Perception API surfaces lifecycle render proc cpu sound zydis win input unicorn net gui mcp
Every value type (
vec2/3/4,quat,mat4,color,proc_t,cpu_t,http_response_t,ws_t,regex,variant,json_value,mutex,atomic_int*, every GUI widget type, …) appears as an autocompleteable class with full method surface.
Want to add your own shared types? Drop an em.predefined in your project root and the analyzer merges it with the built-in surface automatically.
The language server is a standard stdio LSP — it is not tied to VS Code. The same engine that powers the extension can drive any LSP-capable editor or AI coding agent.
These run VS Code extensions directly — just install the VSIX:
curl -L -o enma-lsp-pcx.vsix \
https://github.com/VoidChecksum/enma-lsp-pcx/releases/latest/download/enma-lsp-pcx.vsix
# Cursor / Antigravity / VSCodium / any VS Code fork:
<editor-cli> --install-extension enma-lsp-pcx.vsixGitHub Copilot / Copilot Chat work alongside the extension inside any of these hosts with no extra setup.
Build once, then point any LSP client at the launcher. It speaks stdio by default (no flag needed):
git clone https://github.com/VoidChecksum/enma-lsp-pcx
cd enma-lsp-pcx && npm install && npm run compile
node bin/enma-language-server.js # stdio LSP, language id: enma, ext: .emOpenCode — add to opencode.json:
{
"lsp": {
"enma": {
"command": ["node", "/abs/path/to/enma-lsp-pcx/bin/enma-language-server.js"],
"extensions": [".em", ".em.predefined"]
}
}
}Neovim (nvim-lspconfig / vim.lsp.start):
vim.lsp.start({
name = 'enma',
cmd = { 'node', '/abs/path/to/enma-lsp-pcx/bin/enma-language-server.js' },
root_dir = vim.fs.dirname(vim.fs.find({ '.git', 'em.predefined' }, { upward = true })[1]),
})Helix (languages.toml):
[language-server.enma]
command = "node"
args = ["/abs/path/to/enma-lsp-pcx/bin/enma-language-server.js"]
[[language]]
name = "enma"
file-types = ["em"]
language-servers = ["enma"]Claude Code / Copilot CLI and other AI agents: launch
node bin/enma-language-server.js as the project's Enma LSP. For agent-native
script validation/execution, Perception also exposes its own MCP tools
(script/get_context, script/validate, script/execute) — see the
Perception Enma docs.
The built-in Perception/Enma API surface is bundled with the server, so IntelliSense, type-checking and diagnostics work the same standalone as in VS Code.
enma-lsp-pcx/
├─ client/ # VS Code extension (TypeScript)
│ └─ src/extension.ts # Activation, commands, status bar, DAP, bundle tasks
├─ server/
│ ├─ src/
│ │ ├─ server.ts # LSP entrypoint, request routing
│ │ ├─ compiler_tokenizer/ # Tokens, reserved words (Enma keywords baked in)
│ │ ├─ compiler_parser/ # Hand-written parser, preprocessor
│ │ ├─ compiler_analyzer/ # Scopes, types, hoisting, perception value-types
│ │ ├─ services/ # completion, hover, definition, references, ...
│ │ ├─ formatter/ # On-type / range / document formatter
│ │ ├─ inspector/ # Incremental workspace indexing
│ │ └─ predefined/
│ │ └─ perception.em.predefined ← bundled API surface
│ └─ test/ # 112 mocha specs (server unit tests)
├─ scripts/
│ ├─ bundler.ts # #include resolver + circular-detection
│ └─ import-docs.ts # merges `enma::extract_documentation()` output into the predefined
├─ assets/ # README diagrams (architecture, coverage)
├─ enma.tmLanguage.json # TextMate grammar
├─ language-configuration.json
└─ snippets.json
| Key | Default | Notes |
|---|---|---|
enma.suppressAnalyzerErrors |
true |
Show analyzer issues as warnings instead of errors |
enma.implicitMutualInclusion |
false |
All .em files in the workspace implicitly see each other |
enma.includePath |
[] |
Extra dirs searched when resolving #include |
enma.forceIncludePredefined |
[] |
Inject additional .em.predefined files globally |
enma.indexExclude |
["output", …] |
Directories skipped during the workspace scan |
enma.hoistEnumParentScope |
false |
Hoist enum members one scope up for completion |
enma.explicitPropertyAccessor |
true |
Require the property keyword for virtual property accessors |
enma.allowUnicodeIdentifiers |
false |
Accept international characters in identifiers |
enma.supportsTypedEnumerations |
true |
Treat enum class X / enum struct X as typed enumerations |
enma.supportsForEach |
true |
Accept for (T v : col) foreach syntax |
enma.supportsDigitSeparators |
true |
Accept 1_000_000, 0xFF_FF, 0b1010_1100 |
enma.formatter.indentSpaces |
4 |
Spaces per indent (used when not tabbed) |
enma.formatter.useTabIndent |
false |
Use tabs instead of spaces |
enma.formatter.maxBlankLines |
1 |
Maximum consecutive blank lines kept |
enma.bundler.sourceDirectory |
"source" |
Default bundler input dir (single-project mode) |
enma.bundler.outputFile |
"output/bundled.em" |
Default bundler output (single-project mode) |
enma.bundler.stripComments |
true |
Strip // and /* */ from bundled output |
enma.projects |
[] |
Multi-project workspaces: per-project sourceDirectory, outputFile, lspMode |
enma.trace.server |
"off" |
LSP wire-protocol tracing: off / messages / verbose |
- Full Enma keyword set in the tokenizer
- Perception Enma API as a bundled
em.predefined - Multi-project workspaces with per-project LSP scope
- DAP attach with default
localhost:27979 - Bundler with
#includeresolver + circular detection - Snippets for every Perception API entry point
- First-class semantic for
defer { … }/match { … }blocks - Statement-level semantic for
coroutine+yield(return-type inference ofcoroutine_tdeferred) - Generic-constraint hover for SDK-side
.requires_iface - Hover-from-source ingestion of
enma::extract_documentation()output vianpm run import-docs
Track and shape the roadmap in Issues and Discussions.
git clone https://github.com/VoidChecksum/enma-lsp-pcx.git
cd enma-lsp-pcx
npm install # also installs client/ + server/ via postinstall
npm run compile # tsc -b + bundle perception.em.predefined into server/out
npx @vscode/vsce package --no-yarn --skip-license -o enma-lsp-pcx.vsix
code --install-extension enma-lsp-pcx.vsixRun the test suite (105 mocha specs):
cd server && npm testPull requests welcome. Quick path:
- Fork → branch → commit on a topic branch.
npm run lint·cd server && npm test· rebuild + sanity-check the VSIX.- Open a PR using the template; link the related issue.
See CONTRIBUTING.md for the full guide, the STYLE section, and CODE_OF_CONDUCT.md.
Find a vulnerability? Please follow SECURITY.md — do not file a public issue.
- 📘 enma-1.gitbook.io/enma — language guide, addons, SDK
- 🧪 LLMS-Language reference — flat, agent-friendly grammar dump
- 📦 Pre-shipped addons: core · string · arrays · maps · math · math3d · simd · variant · atomic · bits · time · regex · thread · vec · hash_set · sorted_map · list · json
- 🌐 perception.cx — the host platform
- 📒 docs.perception.cx/perception/enma — Perception's Enma API
- 🔌 API surfaces: lifecycle · render · proc · cpu · sound · zydis · win · input · unicorn · net · gui · mcp
- 🪶 sashi0034/angel-lsp — original AngelScript LSP this fork is built on
- 🎯 sinnayuh/angel-lsp-pcx — the AngelScript-for-Perception fork that preceded this one
- 🔗 Language Server Protocol · Debug Adapter Protocol
Sole copyright holder: VoidChecksum · 2026.
This program is built on prior MIT-licensed open-source work; per the MIT terms of those projects their notices are preserved in NOTICE. The work as a whole is now licensed under GPLv3.
| Acknowledgement | For |
|---|---|
| angel-lsp | Foundational AngelScript LSP this codebase descends from |
| angel-lsp-pcx | The Perception-specific AngelScript fork that preceded this one |
| Perception.cx | The Enma language, runtime, public documentation, and the brand assets / palette (navy #25486C, steel #6E94BC) used in this repo's visual identity |
| vscode-unreal-angelscript | TextMate grammar baseline adapted into enma.tmLanguage.json |
Copyright (C) 2026 VoidChecksum.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3 as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
Upstream MIT-licensed code reproduced verbatim is governed by the original MIT notices preserved in NOTICE; the redistribution of the work as a whole is GPLv3.
Made for Perception scripters. Not affiliated with Perception.cx — community fork.

