Tools & ecosystem

Language server

zy lsp starts the local stdio language server. Editors exchange Content-Length-framed JSON-RPC messages on stdin/stdout; startup text and script output never enter the protocol stream. This is an initial LSP 3.17 implementation with diagnostics, formatting, and lexical editor features.

Available features

FeatureBehavior
Unsaved sourceFull-document open/change/close synchronization for local file URIs, including files not yet saved
DiagnosticsSame lexer/parser/module/known-contract rules as the CLI, including unsaved imported-file overlays
Dependency updatesRecheck all open roots after edits, saves, closes, and client-reported watched-file changes
Error locationsZero-based UTF-16 ranges and stable Zy category codes; dependency errors appear on their source file
FormattingLossless spacing/block layout using core.FormatSource; no disk writes
HoverLexical declarations, parameters, loop variables, function signatures, built-ins, and library members
CompletionVisible names, keywords, libraries, imported exports, and annotated record fields/enum variants
ReferencesReferences to a lexical binding within the current document
RenamePrivate local binding rename; rejects exported APIs and conflicting existing names
DefinitionLocal declarations and imported exported declarations, including unsaved dependencies
CancellationSuperseded validation snapshots are canceled; canceled editor requests receive -32800
Version handlingOlder document changes are ignored; stale editor results receive -32801
LifecycleInitialize, shutdown, and exit; unsupported requests return method-not-found

Diagnostics are produced without evaluating code. The checker validates known annotations and typed boundaries; dynamic names, collection elements, and host results still require execution. It reports the first error for each open root, deduplicates shared dependency errors, and clears obsolete publications. Formatting always uses the same four-space style as the CLI, regardless of editor tab preferences.

VS Code setup

  1. Build the executable with go build -o bin/zy.exe . on Windows, or go build -o bin/zy . on Linux/macOS.
  2. From the language repository root, run ./editors/vscode/install.ps1 to test, bundle, package, and install the local extension.
  3. Reload VS Code and open any application folder containing .zy files. Source development windows require npm run build first.
  4. Set the user-level Zy: Server Path to the absolute executable path, or put zy on PATH.
  5. In a trusted workspace, run Zy: Start Language Server. Use Format Document on a Zy file to format its current text. Zy: Stop Language Server disposes the client and watcher.

For automatic startup after opting in, set zy.languageServer.enabled to true. It defaults to false. A configuration change restarts an enabled server. The client passes the executable and lsp as separate arguments and does not launch a command shell. Relative executable paths and command strings are rejected. The server never executes Zy programs, but launching any configured host executable still requires a trusted workspace.

Syntax support works without a Zy binary. The installed VSIX bundles its language client; applications do not install npm dependencies. Building the extension from source requires npm, while using an existing VSIX does not. Go is not needed to run a prebuilt Zy server executable.

For another LSP-capable editor, configure the executable with arguments ["lsp"], stdio transport, language identifier zy, and .zy file association. Do not configure incremental changes: the advertised synchronization kind is full-document. The server is local-only and opens no listening port.

Bounds and lifecycle details

  • Local file: URIs only; untitled:, remote hosts/UNC paths, virtual documents, URI query strings, and URI fragments are unsupported. Unsaved text associated with a normal local filename is supported.
  • At most 64 open documents; source larger than 1 MiB receives a diagnostic. The retained oversized snapshot is capped just above that limit. Existing module count/depth/combined-source limits still apply.
  • Protocol headers are limited to 8 KiB and message bodies to 8 MiB. Malformed framing closes the transport. Invalid JSON and requests receive JSON-RPC errors when framing permits a response.
  • One validation worker processes immutable snapshots with a single latest-pending slot. Superseded results cannot overwrite a newer processed generation. All roots are rechecked for correctness; large workspaces may need a dependency index in a later version.
  • Up to eight formatting/semantic operations can be in flight. Cancellation suppresses results immediately but cannot interrupt a parser call already running. Module traversal checks cancellation; synchronous host file I/O is not forcibly interruptible.
  • Closing an overlay restores disk content for remaining importers. If no open root needs a previous error, the server publishes an empty diagnostic list. Duplicate physical-file overlays with conflicting content are rejected.
  • The CLI JSON diagnostic API uses one-based Unicode code points; LSP converts to zero-based UTF-16. Consumers must not mix these coordinate systems.
  • A proper client sends shutdown, waits for its response, then sends exit. Exit before shutdown is unsuccessful. Embedders canceling lsp.Run must also close their input stream to unblock an outstanding read.

Lexical editor behavior

Use Go to Definition (F12), Show Hover (Ctrl+K, Ctrl+I), and Trigger Suggest (Ctrl+Space) in VS Code. A dot triggers namespace/export completion automatically. Names from a nested block, function parameter, or loop stay within that scope. A let initializer resolves an existing outer binding before the new binding is declared. Imported namespaces expose only explicit export declarations; private bindings stay private. Open dependency text takes priority over disk.

The index does not execute scripts or infer dynamic runtime types. It uses explicit record annotations for field completion and typed signatures for hover. References and private-binding rename stay within one document; exported APIs and field names cannot be renamed. Rename rejects any conflicting binding and limits new names to 256 UTF-8 bytes. Definitions assigned later through a captured environment, computed members, collection methods, module aliases, and workspace-wide search remain unsupported. Local indexing requires parseable source; completion repairs a member name at a dot cursor, but unrelated syntax errors can limit results to the built-in catalog. No suggestions are returned inside comments or strings. VS Code may independently offer word-based suggestions; disable editor.wordBasedSuggestions to view only provider/snippet results.

Semantic requests use immutable document snapshots, share the eight-request limit with formatting, support cancellation, and return -32801 if an open document or dependency generation changes before their result is delivered. Disk-backed export lookup reads only the explicitly selected local .zy dependency, checks regular-file status, and enforces the 1 MiB source limit. It does not crawl arbitrary workspace files.

Validation and remaining scope

Go tests cover scope boundaries, shadowing, initializer binding, parameters, imported exports, unsaved overlays, protocol requests, UTF-16, stale dependency generations, comments/strings, lifecycle, framing, and limits. python tools/smoke_lsp.py bin/zy.exe also checks hover, completion, and definition against the compiled executable. Archive smoke tests run the same protocol checks.

Real VS Code extension-host tests exercise providers through editor commands, including unsaved dependency navigation, private export filtering, formatting edits, diagnostics, and shutdown. Run npm run test:integration in editors/vscode with ZY_EXECUTABLE set to an absolute compiled executable path; it uses an isolated temporary profile and workspace. The test runner defaults to VS Code 1.85.2; VSCODE_EXECUTABLE_PATH can select an existing installation. See the engineering review for visual observations and the remaining human trial gate.

Found something to improve?Edit this page on GitHub ↗
Search guides, language features, and APIs ↵ to open first result