Skip to main content

lattice_protocol/
lib.rs

1//! The shared vocabulary of the editor: the value types, identifiers, event
2//! catalogue and wire envelopes that every other lattice crate speaks. It is
3//! the dependency floor — every crate depends on it, and it depends on no
4//! other lattice crate.
5//!
6//! ## What it owns
7//!
8//! - **Coordinates.** [`Position`] (0-based line, 0-based UTF-8 *byte* offset
9//!   within the line) and the half-open [`Range`] built from two of them. Core,
10//!   plugins and the dispatcher work only in these logical coordinates; the
11//!   renderer converts to screen cells, and protocol peers (LSP's UTF-16
12//!   columns) convert at their own boundary.
13//! - **Edits.** [`Edit`] / [`EditKind`] (one atomic replace), and
14//!   [`EditDelta`], the tree-sitter-shaped by-product of applying one.
15//! - **Selections.** [`Selection`] (anchor + head + [`VisualMode`]) and the
16//!   never-empty [`SelectionSet`] with a designated primary.
17//! - **Identifiers.** `u64` newtypes ([`DocumentId`], [`BufferId`],
18//!   [`CommandId`], ...) that cannot be mixed up with each other.
19//! - **Events.** The closed catalogue of editor-core transitions ([`Event`],
20//!   discriminated by [`EventKind`]) and, in [`event_registry`], the open
21//!   typed-event surface feature crates and plugins declare their own events
22//!   through.
23//! - **Chords.** [`KeyChord`] and friends — the renderer-neutral key the
24//!   keymap trie indexes by — plus the `"<C-w>j"` notation parser
25//!   ([`parse_chord_sequence`]) and its `Display` inverse.
26//! - **Peer-protocol envelopes.** JSON-RPC 2.0 [`Message`]s, shared by the
27//!   LSP client and the Claude Code IDE peer.
28//! - **Small shared primitives.** [`CancellationToken`], [`ProtocolError`],
29//!   and the error-list entry ([`error_list::ErrorEntry`]).
30//!
31//! ## What it must not depend on
32//!
33//! No other lattice crate, no async runtime, no parser, no renderer, no
34//! plugin host. Everything here is plain data (plus the cancellation flag and
35//! the event registries), because anything this crate imported would sit
36//! beneath the entire editor and every plugin-facing type. That is why the
37//! event payloads carry mode names and modal states as `String`s rather than
38//! `ModeId` / `ModalState`, why [`EditDelta`] mirrors tree-sitter's
39//! `InputEdit` without importing it, and why [`error_list::ErrorSeverity`]
40//! is not LSP's severity. Its dependencies are `serde`, `serde_json`,
41//! `thiserror` and `linkme`.
42//!
43//! Everything is in-process today: the editor is one process, and nothing
44//! here defines a cross-process transport. The serde derives exist for the
45//! plugin boundary, snapshots and tests, not for a client/server split.
46//!
47//! ## Example
48//!
49//! ```
50//! use lattice_protocol::{
51//!     Edit, KeyChord, Position, Range, Selection, SelectionSet, parse_chord_sequence,
52//! };
53//!
54//! // Coordinates are (line, byte) — both 0-based, the byte offset in UTF-8.
55//! let hello = Range::new(Position::new(0, 0), Position::new(0, 5));
56//! let edit = Edit::replace(hello, "howdy");
57//! assert_eq!(edit.range.end.byte, 5);
58//!
59//! // A cursor is a zero-width selection; a set always has a primary.
60//! let set = SelectionSet::single(Selection::cursor(Position::new(2, 4)));
61//! assert!(set.primary().is_cursor());
62//!
63//! // Chord notation parses to typed keys and prints back canonically.
64//! let chords = parse_chord_sequence("<C-w>j").unwrap();
65//! assert_eq!(chords, vec![KeyChord::ctrl('w'), KeyChord::char('j')]);
66//! assert_eq!(chords[0].to_string(), "<C-w>");
67//! ```
68//!
69//! Design: `docs/dev/architecture/design.md` §5.10 (events and hooks) and §6
70//! (core protocol); `docs/dev/architecture/keymap-architecture.md` (chords);
71//! `docs/dev/architecture/error-list.md` (error-list entries);
72//! `docs/dev/architecture/cancellation.md` (cancellation).
73//!
74//! ## Note on the retired `Command` enum
75//!
76//! Earlier revisions exposed a `lattice_protocol::Command` enum
77//! (document-management + editing variants) intended as a wire-protocol
78//! message set from clients (UI / plugins) to a central core dispatcher.
79//! That client-server framing was abandoned: the editor runs as one process
80//! today, the keymap / cmdline / dispatcher use
81//! `lattice_grammar::CommandInvocation` for typed runtime invocation, and
82//! the document actor exposes its own typed mailbox via
83//! `lattice_runtime::RopeDocumentHandle`. The legacy `Command` enum had no
84//! callers anywhere in the workspace and was retired.
85//! `lattice_grammar::CommandInvocation` is the canonical "runtime
86//! command" type now.
87#![warn(missing_docs)]
88
89pub mod cancel;
90pub mod chord;
91pub mod edit;
92pub mod error;
93pub mod error_list;
94pub mod event;
95pub mod event_registry;
96pub mod ids;
97/// JSON-RPC 2.0 message types. Lifted out of `lattice-lsp` (IDE-protocol
98/// Risk 3) so a second peer-protocol crate (`lattice-claude-code`) can
99/// reuse the wire shape without an `ide -> lsp` crate edge. The types are
100/// transport-agnostic; each peer's codec writes the bytes.
101pub mod jsonrpc;
102pub mod position;
103pub mod selection;
104
105pub use crate::cancel::CancellationToken;
106pub use crate::chord::{
107    ChordParseError, ChordPattern, KeyChord, KeyKind, KeyMods, SpecialKey,
108    last_chord_token_byte_len, parse_chord_sequence, special_label,
109};
110pub use crate::edit::{Edit, EditDelta, EditKind};
111pub use crate::error::{ProtocolError, Result};
112pub use crate::event::{Event, EventKind};
113pub use crate::ids::{
114    BufferId, CommandId, DocumentId, MajorModeId, MinorModeId, PaneId, PluginId, TabId, WindowId,
115};
116pub use crate::jsonrpc::{
117    Message, MessageDecodeError, Notification, Request, RequestId, Response, ResponseError,
118};
119pub use crate::position::{Position, Range};
120pub use crate::selection::{Selection, SelectionSet, VisualMode};