OxL Справочник OxL
РусскийEnglish

The OxL language server (oxl lsp)

Standard [С ч. III.3], TZ requirements И3 (formatter in the editor) and И4 (LSP, "M": basic features). Decisions: D-2800..D-2810 in docs/decisions.md.

oxl lsp speaks the Language Server Protocol 3.17 (JSON-RPC 2.0, Content-Length framing) on stdin/stdout. It runs the same front end as oxl check (lexer, parser with error recovery, sema), so the editor shows the compiler's own diagnostics and types. Clients: the VS Code extension in tools/vscode (see its README), or any LSP client; editors built on tree-sitter can use the grammar in tools/tree-sitter-oxl for highlighting without the server (JetBrains is not targeted, answer 10 of the stage 5 plan):

sh
oxl lsp [--stdio] [--debounce-ms N] [--std-dir DIR] [--log]

--stdio is accepted and ignored (stdio is the only transport). --log (or OXL_LSP_LOG=1) traces requests, timings and analyses to stderr. Environment: OXL_STD_DIR (standard library sources), OXL_DIAG_DOCS (base of the diagnostic page links). initializationOptions: { "debounceMs": 150, "diagnosticDocsBase": "file:///…/docs/diagnostics/" }; workspace/didChangeConfiguration accepts settings.oxl.debounceMs.

Features#

Request / notificationWhat it does
textDocument/publishDiagnosticsErrors and lint warnings with code, codeDescription.href (the page in docs/diagnostics), notes as relatedInformation, Unnecessary / Deprecated tags, fix-its in data. While the package has syntax errors only syntax diagnostics are sent.
textDocument/hoverSignature (functions with effects, data / enum bodies, interfaces, aliases, variants, consts, locals with their inferred type, fields) and the /// doc comment.
textDocument/definition, typeDefinitionLocals, parameters, functions, methods, types, fields, variants, modules and imported names, across the files of the package and into the standard library.
textDocument/references, documentHighlightAll uses in the package (declaration optional); highlights in the current file.
textDocument/prepareRename, renameSymbols defined in the main package; shorthand struct fields (P{ x }) keep their meaning.
textDocument/documentSymbolHierarchical outline (types with fields / variants, impls with methods, actors, services, tests, consts). Works while the file has syntax errors.
textDocument/completionScope names (locals, fields / methods of the implicit self, module items, imports, prelude, keywords); members after . / ?.; variants, constants and static functions after Type.; module items after std.; type names after -> / as; field names (name: ) inside the braces of a struct literal. Triggers: . and :.
textDocument/signatureHelpParameters of the function or method being called, active parameter by comma count. Triggers: ( and ,.
textDocument/formatting, rangeFormatting, onTypeFormattingThe canonical formatter (oxl fmt) as minimal line edits; on type after } and \n. Files with syntax errors are left alone.
textDocument/codeActionQuick fixes from the fix-its of diagnostics (incl. "extract to constant" of magic-literal), and from the analysis: handle all errors of the chain (a !> E => panic("TODO…") link per pending error), add @internal / add a policy rule (missing-policy), generate mock for S (in a test body, on the name of a service: mock S { m(_) => panic("TODO…") }), move step to role r / run step on the node of the previous step (pipeline steps, kind refactor.rewrite).
textDocument/semanticTokens/full, …/rangeTokens classified by what the names resolve to (namespace, type, struct, enum, interface (services too), class (actors), enumMember, function, method, parameter, variable, property, typeParameter) with the modifiers declaration, readonly, static, defaultLibrary, async (suspending); keywords, contextual keywords where they do not name anything (on, durable, within, role, serves, effects …), attributes (decorator), literals, comments. Multi-line comments and strings are split per line.
textDocument/inlayHint: T after let names without a type; ! E1 | E2 after the head / each link of a -> chain that brings errors; the inferred effects of a function without a written effect list; on caller / on <role> (, durable) after a pipeline step without on; call markers at calls of rpcs and sharded actors: in process, over network → <roles>, in process on a, over network from b → a, by key → <roles>, scatter-gather (from the call graph and the placement, К14). Categories (data.category) can be switched off with initializationOptions.inlayHints / settings.oxl.inlayHints (types, chainErrors, effects, pipelineRoles, callMarkers).
workspace/symbolDeclarations (items, members of types, services, actors) of every package below the workspace folders (rootUri / workspaceFolders) and of the workspaces of the open documents; open buffers win over the disk; fuzzy match, at most 1000.
workspace/didChangeWatchedFilesRe-reads sources changed on disk by other tools.

Hover over an rpc (its call S.m(…), client.m(…), the contract or the impl method) adds the rpc section: path and kind, schema version and tag from oxl.schema.lock, callers per role (call graph), policy mode with @public / @internal / @allow and the allow / deny rules of the service's policy, every attribute with its final value (@timeout(T) → 2s, cluster default when none) and the constants it mentions resolved (T = BASE, BASE = 2s).

Rename also follows mock S { m(_) => … }, S.calls(.m) and names inside attributes such as @retry(max: LIMIT) (D-7793).

Rename covers, besides the package: an rpc is one symbol across its contract, the impl method, the rules of the service's policy, every call (S.m, client.m) and the mock functions; and a pub(api) item or an rpc renamed in a workspace member is also renamed in the other members that depend on it (each is analysed for the rename, D-6775).

Packages and files#

A document below the src/ directory of a directory that contains oxl.toml is analysed together with its package; the unsaved text of every open document replaces the file on disk. Any other file is analysed alone (it need not exist on disk). The standard library is resolved as the compiler does (OXL_STD_DIR, then the directory the compiler was built with). *_test.oxl files take part in the analysis.

Positions and text#

Documents are UTF-8, line ends are normalized to LF. Positions are UTF-16 code units (the LSP default); if the client offers utf-8 in general.positionEncodings the server selects it. Incremental text synchronization is used (textDocumentSync.change = 2).

Responsiveness#

Analyses run on a background thread after a quiet period (150 ms by default) following the last edit. Requests are answered as follows:

  • completion and signature help use the newest finished analysis plus the text just typed, so they never wait (about 1 ms for the lookup, 25-45 ms including the lexing of a 2000-line buffer on a Debug build);
  • hover, definition, references, rename need an analysis of exactly the current text: if the text changed they trigger the analysis at once and answer when it finishes (a re-analysis of a 2000-line file takes 100-200 ms on a Debug build); $/cancelRequest aborts the wait; after 10 s the request is answered with null;
  • symbols and formatting parse the text on their own.
  • semantic tokens and inlay hints need the current analysis like hover (about 50 ms / 2 ms for a 2000-line file on a Debug build once it is there); workspace symbols parse the files of the workspace (cached by modification time); code actions use the analysis only when it is current and never wait for one.

Target (TZ 3.2): completion / hover p95 < 100 ms, checked by tests/lsp/perf_test.py (D-2809); the same script checks semantic tokens and inlay hints against 5x that budget.

Testing#

sh
ctest --test-dir build -R lsp             # test_lsp (gtest), lsp_scenarios, lsp_latency
./build/tests/unit/test_lsp               # unit tests: JSON, framing, positions, sync, queries, server, stdio, fuzz
OXL_LSP_FUZZ_ITERS=3000 ./build/tests/unit/test_lsp --gtest_filter='LspFuzz*'   # long mutation run
python3 tests/lsp/run_scenarios.py --oxl build/tools/oxl/oxl -v                  # protocol scenarios against the real binary
python3 tests/lsp/perf_test.py --oxl build/tools/oxl/oxl                         # latency
(cd tools/vscode && npm install && npm test)                                     # extension + grammar
python3 tools/tree-sitter-oxl/scripts/check.py -v                                # tree-sitter grammar (D-6780)

Protocol scenarios (tests/lsp/*.json, format in tests/lsp/README.md) start oxl lsp, replay a session (initialize, didOpen, didChange, requests) and compare each response with a partial expectation.

Code map#

FileWhat
compiler/src/lsp/Json.cpp, Transport.cppJSON value / parser / serializer; Content-Length framing, fd reader.
Text.cpp, TextDiff.cppDocuments, LineIndex (UTF-8 / 16 / 32 positions), incremental sync, URIs, EditWindow (offset mapping between text versions), line diff.
Analysis.cppSnapshot: one analysis of a package or file with the editor buffers laid over the disk.
AstNodes.cppChild enumeration of all AST node kinds, pathAt(offset).
Queries.cppIdentifier resolution, references, locals in scope, hover text, completion candidates, signatures.
ServerCore.cppDispatch, document store, analysis scheduling, diagnostics, stdio loop.
ServerFeatures.cppRequest handlers.
Insights.cppStage 5 (D-6770..D-6779): semantic tokens, inlay hints, call markers, rpc hover section, workspace-symbol extraction, snapshot quick fixes.
ServerTools.cppTheir request handlers, workspace symbols, rename in the other workspace members.
tools/oxl/cmd_lsp.cppThe oxl lsp command.

Driver hooks used by the server (both additive, off by default): BuildOptions::overlay and BuildOptions::semaDespiteSyntaxErrors.

Исходник: docs/lsp.md

OxL 1.0.0-beta · Версия документации 1.0.0-beta© OxwaldLink · сгенерировано из Стандарта, исходников std и руководства