| Crates.io | tokio-lsp |
| lib.rs | tokio-lsp |
| version | 0.1.1 |
| created_at | 2025-08-29 00:30:03.53961+00 |
| updated_at | 2025-08-29 00:45:44.04+00 |
| description | A robust, async Language Server Protocol (LSP) client implementation in Rust with full LSP 3.16 support |
| homepage | https://github.com/scook12/rust-lsp |
| repository | https://github.com/scook12/rust-lsp |
| max_upload_size | |
| id | 1814976 |
| size | 212,156 |
A Language Server Protocol (LSP) client implementation in Rust.
This crate provides a lightweight, async-first LSP client that can be integrated into text editors and IDEs. It implements the LSP 3.16 specification and focuses on providing a clean, safe API for communicating with language servers.
unsafe blocksThe crate is organized into several key modules:
types - LSP and JSON-RPC type definitionstransport - Low-level message framing and I/Oclient - High-level client interfaceerror - Comprehensive error handlingAdd this to your Cargo.toml:
[dependencies]
tokio-lsp = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
use tokio_lsp::Client;
use std::process::Stdio;
use tokio::process::Command;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Start a language server process
let mut server = Command::new("rust-analyzer")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
let stdin = server.stdin.take().unwrap();
let stdout = server.stdout.take().unwrap();
// Create LSP client
let client = Client::new(stdout, stdin);
// Initialize the server
let init_result = client.initialize_default(
"My Editor",
Some("1.0.0".to_string()),
Some("file:///path/to/workspace".to_string())
).await?;
println!("Server capabilities: {:?}", init_result.capabilities);
// Send requests and notifications
// client.send_notification("textDocument/didOpen", Some(params)).await?;
Ok(())
}
For more control over the initialization process:
use tokio_lsp::{Client, InitializeParams, ClientCapabilities, ClientInfo};
// Create initialize parameters
let params = InitializeParams {
process_id: Some(std::process::id()),
client_info: Some(ClientInfo {
name: "My Editor".to_string(),
version: Some("1.0.0".to_string()),
}),
root_uri: Some("file:///path/to/workspace".to_string()),
capabilities: ClientCapabilities::default(),
// ... other fields
..Default::default()
};
let result = client.initialize(params).await?;
client.initialized().await?;
// Listen for messages from the server
while let Some(message) = client.receive_message().await {
match message {
RpcMessage::Request(req) => {
// Handle server requests
println!("Server request: {}", req.method);
// Send response back
client.send_response(req.id, Some(serde_json::json!({})), None).await?;
}
RpcMessage::Notification(notif) => {
// Handle server notifications
println!("Server notification: {}", notif.method);
}
_ => {} // Responses are handled internally
}
}
The repository includes several examples:
basic_client.rs - Simple client initializationfile_operations.rs - Text document synchronizationdiagnostics.rs - Handling diagnostic messagesRun examples with:
cargo run --example basic_client
The crate provides comprehensive type definitions for all LSP messages:
Position, Range, Location - Text document positioningTextEdit, WorkspaceEdit - Document modificationsDiagnostic - Error/warning informationCommand - Executable commandsInitializeParams / InitializeResultCompletionParams / CompletionListHoverParams / HoverDidOpenTextDocumentParamsDidChangeTextDocumentParamsPublishDiagnosticsParamsThe transport layer handles the LSP base protocol:
The crate provides detailed error types:
use tokio_lsp::{LspError, Result};
match client.send_request("textDocument/hover", params).await {
Ok(response) => { /* handle success */ },
Err(LspError::Timeout) => { /* request timed out */ },
Err(LspError::Protocol(err)) => { /* LSP protocol error */ },
Err(LspError::Transport(msg)) => { /* transport layer error */ },
// ... other error types
}
Run the full test suite:
cargo test
Run with coverage:
cargo test --all-features
Contributions are welcome! Please:
This project is dual-licensed under either:
at your option.
This implementation is based on the Language Server Protocol Specification v3.16.