Skip to main content

lex_extension/
lib.rs

1//! Public surface for Lex extensions.
2//!
3//! This crate is the stable contract that handler authors and Rust embedders
4//! depend on. It defines:
5//!
6//! - The [`LexHandler`] trait — the protocol's source of truth.
7//! - Wire types ([`LabelCtx`], [`WireNode`], [`WireInline`], diagnostics,
8//!   render output, hover, completions, code actions) — the cross-version
9//!   stable representation of Lex content and hook payloads.
10//! - Schema types ([`Schema`] and friends) — the read-only structs a YAML
11//!   loader produces.
12//! - The [`Format`] enum used by render hooks.
13//!
14//! The runtime registry, schema loader, transports (subprocess, WASM), trust
15//! gate, and sandboxing live in the internal `lex-extension-host` crate.
16//! Handler authors depend on `lex-extension` only.
17//!
18//! # Versioning
19//!
20//! There are two version axes, intentionally decoupled:
21//!
22//! - [`WIRE_VERSION`] identifies the JSON-RPC wire-format contract
23//!   exchanged at the `initialize` handshake. Handlers across any
24//!   transport (subprocess, native, future WASM) speaking the same
25//!   `WIRE_VERSION` interoperate. Once stable, breaking changes to the
26//!   wire format bump this integer.
27//! - The crate's *Cargo* version (`0.1.x` today) tracks the Rust API.
28//!
29//! The two axes line up at 1.0: this crate ticks to `1.0.0` when its Rust
30//! API stabilises, and at that point a handler built against
31//! `lex-extension = "1"` speaks `WIRE_VERSION = 1`. Until then the Rust
32//! API is per-Cargo unstable: any 0.x → 0.y bump may be source-incompatible.
33//!
34//! Where forward-compatibility is implementable today without API churn,
35//! it is:
36//!
37//! - String-shaped enums (severity, completion kind, code-action kind,
38//!   ref kind, hover format) deserialise unknown wire values as a
39//!   documented fallback (`Info`, `Value`, `Refactor`, `General`,
40//!   `Plaintext`). New variants in the wire protocol are non-breaking
41//!   *for handlers* — older handlers see the fallback.
42//! - Block AST kinds ([`WireNode`], [`WireInline`]) are *closed* within a
43//!   `WIRE_VERSION`. Adding a new kind is a wire-version bump, not a
44//!   silent extension. The `#[non_exhaustive]` attribute on those enums
45//!   keeps the Rust side additive across `lex-extension` major versions.
46//! - Public structs (`Diagnostic`, `Hover`, `Completion`, etc.) are *not*
47//!   `#[non_exhaustive]` today, by design — pre-1.0, struct-literal
48//!   construction is the right ergonomics for handler authors. Before
49//!   tagging 1.0 the public structs will gain `#[non_exhaustive]` plus
50//!   constructors, so post-1.0 field additions stay non-breaking.
51//!
52//! See `comms/specs/proposals/lex-extension-wire.lex` for the normative
53//! wire-format spec.
54
55pub mod handler;
56pub mod schema;
57pub mod wire;
58
59pub use handler::{HandlerError, LexHandler};
60pub use wire::{
61    AnnotationBody, CodeAction, CodeActionKind, Completion, CompletionKind, Diagnostic,
62    DiagnosticSeverity, Format, FormatCtx, HostNodeKind, Hover, HoverFormat, LabelCtx,
63    LexAnnotationOut, NodeRef, Position, Range, RefKind, RelatedDiagnostic, RenderOut, TextEdit,
64    WireFootnote, WireInline, WireListItem, WireNode, WireRow, WireTableCell,
65};
66
67pub use schema::{
68    BodyKind, BodyPresence, BodyShape, Capabilities, DiagnosticDecl, EnumValue, HandlerSpec,
69    HandlerTransport, HookSet, ParamSpec, ParamType, RenderHook, Schema,
70};
71
72/// The wire-format protocol version exchanged in the `initialize` handshake.
73///
74/// A host that receives a higher `wire_version` than it understands negotiates
75/// down to the highest version both sides support. A host that receives a
76/// lower `wire_version` than this constant refuses the handler with a startup
77/// diagnostic.
78pub const WIRE_VERSION: u32 = 2;