Skip to main content

lex_lsp/
lib.rs

1//! Language Server Protocol (LSP) implementation for Lex
2//!
3//!     This crate provides language server capabilities for the Lex format, enabling rich editor
4//!     support in any LSP-compatible editor (VSCode, Neovim, Emacs, Sublime, etc.).
5//!
6//! Design Decision: tower-lsp
7//!
8//!     After evaluating the Rust LSP ecosystem, we chose tower-lsp as our framework:
9//!
10//!     Considered Options:
11//!         1. tower-lsp: High-level async framework built on Tower (~204K monthly downloads)
12//!         2. lsp-server: Low-level sync library from rust-analyzer (~309K monthly downloads)
13//!         3. async-lsp: Low-level async with full Tower integration (~135 GitHub stars)
14//!
15//!     Why tower-lsp:
16//!         - Best balance of ease-of-use and functionality for a new LSP project
17//!         - Strong ecosystem support with extensive documentation and examples
18//!         - Modern async/await patterns ideal for Lex's structured parsing needs
19//!         - Built-in LSP 3.18 support with proposed features
20//!         - Active community with production usage in many language servers
21//!         - Good integration with Rust async ecosystem (tokio, futures)
22//!
23//!     Trade-offs:
24//!         - Less flexible than async-lsp for custom Tower layers (acceptable for our needs)
25//!         - Requires &self for trait methods, forcing Arc<Mutex<>> for mutable state (standard pattern)
26//!         - Notification ordering is async (not an issue for initial feature set)
27//!
28//!     Future Migration Path:
29//!         If we later need precise notification ordering or custom middleware, we can migrate
30//!         to async-lsp with minimal disruption as both use similar async patterns.
31//!
32//! Feature Set
33//!
34//!     Lex is a structured document format, not a programming language. LSP features are selected
35//!     to optimize document authoring and navigation workflows:
36//!
37//!     Core Features:
38//!
39//!         a. Syntax Highlighting
40
41//!             1. Semantic Tokens (textDocument/semanticTokens/*):
42//!                 - Syntax highlighting for sessions, lists, definitions, annotations
43//!                 - Inline formatting: bold, italic, code, math
44//!                 - References, footnotes, citations
45//!                 - Verbatim blocks with language-specific highlighting
46//!             2. Document Symbols (textDocument/documentSymbol):
47//!                 - Hierarchical outline view of document structure
48//!                 - Sessions with nesting (1., 1.1., 1.1.1., etc.)
49//!                 - Definitions, annotations, lists as navigable symbols
50//!            3. Hover Information (textDocument/hover):
51//!                 - Preview footnote/citation content on hover
52//!                 - Show annotation metadata
53//!                 - Preview definition content when hovering over reference
54//!             4. Folding Ranges (textDocument/foldingRange):
55//!                 - Fold sessions and nested content
56//!                 - Fold list items with children
57//!                 - Fold annotations, definitions, verbatim blocks
58//!
59//!         b. Navigation
60//!
61//!             5. Go to Definition / Find References (textDocument/definition, textDocument/references):
62//!                 - Find all references to footnotes/citations
63//!                 - Jump from footnote reference [42] to annotation
64//!                 - Jump from citation [@spec2025] to bibliography entry
65//!                 - Jump from internal reference [TK-rootlist] to target
66//!             6. Document Links (textDocument/documentLink):
67//!                 - Clickable links in text
68//!                 - Verbatim block src parameters (images, includes)
69//!                 - External references
70//!
71//!         c. Editing
72//!
73//!             7. Document Formatting (textDocument/formatting, textDocument/rangeFormatting):
74//!                 - Fix indentation issues
75//!                 - Normalize blank lines
76//!                 - Align list markers //!         
77//!
78//!
79//!
80//! Architecture
81//!
82//!     The server follows a layered architecture:
83//!
84//!     LSP Layer (tower-lsp):
85//!         - Handles JSON-RPC communication
86//!         - Protocol handshaking and capability negotiation
87//!         - Request/response routing
88//!
89//!     Server Layer (this crate):
90//!         - Implements LanguageServer trait
91//!         - Manages document state and parsing
92//!         - Coordinates feature implementations
93//!         - Very thing, mostly calls the the feature layers over lex-parser
94//!         - Thin tests just asserting the right things are being called and returned
95//!
96//!     Feature Layer:
97//!         - Each feature operates on Lex AST
98//!         - Stateless transformations where possible
99//!         - All logic and dense unit tests
100//!
101//!
102//! Testing Strategy
103//!
104//!     Following Lex project conventions:
105//!         - Use official sample files from specs/ for all tests
106//!         - Use lexplore loader for consistent test data
107//!         - Use ast_assertions library for AST validation
108//!         - Test each feature in isolation and integration
109//!         - Test against kitchensink and trifecta fixtures
110//!
111//! Non-Features
112//!
113//!     The following LSP features are intentionally excluded as they don't apply to document formats:
114//!         - Code Lens: Not applicable to documents
115//!         - Type Hierarchy: No type system
116//!         - Implementation: No interfaces/implementations
117//!         - Moniker: For cross-repo linking, not needed
118//!         - Linked Editing Range: For paired tags (HTML/XML)
119//!         - Diagnostics: we don't have a clear vision for how that would work.
120//!
121//! Error Handling and Robustness
122//!
123//!     The server is designed to be highly robust and crash-resistant, following these principles:
124//!
125//!     1. No Panics:
126//!         - We strictly avoid `unwrap()` and `expect()` in production code paths.
127//!         - All potential failure points (parsing, serialization, IO) return `Result`.
128//!         - Errors are propagated up the stack and handled gracefully.
129//!
130//!     2. Graceful Degradation:
131//!         - If a feature fails (e.g., semantic tokens calculation), we log the error and return
132//!           an empty result or `None` rather than crashing the server.
133//!         - This ensures that a bug in one feature doesn't bring down the entire editor experience.
134//!
135//!     3. Error Propagation:
136//!         - The `lex-parser` crate returns `Result` types for all parsing operations.
137//!         - The `lex-lsp` server maps these internal errors to appropriate LSP error codes
138//!           (e.g., `InternalError`, `InvalidRequest`) when communicating with the client.
139//!
140//!     4. Property-Based Testing:
141//!         - We use `proptest` to fuzz the server with random inputs (commands, document text)
142//!           to uncover edge cases and ensure stability under unexpected conditions.
143//!
144//! Usage
145//!
146//!     This crate provides both a library and binary:
147//!
148//!     Library:
149//!         ```rust
150//!         use lex_lsp::LexLanguageServer;
151//!         use tower_lsp::Server;
152//!
153//!         #[tokio::main]
154//!         async fn main() {
155//!             let stdin = tokio::io::stdin();
156//!             let stdout = tokio::io::stdout();
157//!
158//!             let (service, socket) = LspService::new(|client| LexLanguageServer::new(client));
159//!             Server::new(stdin, stdout, socket).serve(service).await;
160//!         }
161//!         ```
162//!
163//!     Binary:
164//!         $ lex-lsp
165//!         Starts the language server on stdin/stdout for editor integration.
166//!
167
168pub mod features;
169pub mod server;
170
171pub use server::LexLanguageServer;