| Crates.io | lsp-bridge |
| lib.rs | lsp-bridge |
| version | 0.2.0 |
| created_at | 2025-07-17 08:13:00.659442+00 |
| updated_at | 2025-07-17 17:11:17.593074+00 |
| description | A comprehensive Rust library that provides a bridge between Language Server Protocol (LSP) servers and clients |
| homepage | https://github.com/ciresnave/lsp-bridge |
| repository | https://github.com/ciresnave/lsp-bridge |
| max_upload_size | |
| id | 1757204 |
| size | 320,269 |
A comprehensive Rust library that provides a bridge between Language Server Protocol (LSP) servers and clients. It simplifies the integration of LSP capabilities into applications, tools, and IDEs by handling the complexity of protocol communication, lifecycle management, and feature negotiation.
Add this to your Cargo.toml:
[dependencies]
lsp-bridge = "0.1"
tokio = { version = "1.0", features = ["full"] }
use lsp_bridge::{LspBridge, LspServerConfig};
use lsp_types::{Position, CompletionParams, TextDocumentIdentifier};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Configure an LSP server
let rust_analyzer_config = LspServerConfig::new()
.command("rust-analyzer")
.root_path("/path/to/project")
.initialization_options(serde_json::json!({
"checkOnSave": {
"command": "clippy"
}
}))
.workspace_folder("/path/to/project");
// Create the LSP bridge
let mut bridge = LspBridge::new();
// Register and start the server
let server_id = bridge.register_server("rust", rust_analyzer_config).await?;
bridge.start_server(&server_id).await?;
// Wait for server to be ready
bridge.wait_server_ready(&server_id).await?;
// Open a document
let document_uri = "file:///path/to/project/src/main.rs";
let content = "fn main() {\n println!(\"Hello, world!\");\n}";
bridge.open_document(&server_id, document_uri, content).await?;
// Get completions
let completions = bridge.get_completions(
&server_id,
document_uri,
Position { line: 1, character: 15 }
).await?;
for item in completions {
println!("Completion: {}", item.label);
}
// Get diagnostics
let diagnostics = bridge.get_diagnostics(&server_id, document_uri)?;
for diagnostic in diagnostics {
println!("Diagnostic: {}", diagnostic.message);
}
// Shutdown
bridge.shutdown().await?;
Ok(())
}
use lsp_bridge::{LspBridge, LspServerConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut bridge = LspBridge::new();
// Configure multiple servers
let rust_config = LspServerConfig::new()
.command("rust-analyzer")
.root_path("/path/to/rust/project");
let python_config = LspServerConfig::new()
.command("pylsp")
.root_path("/path/to/python/project");
// Register servers
let rust_server = bridge.register_server("rust", rust_config).await?;
let python_server = bridge.register_server("python", python_config).await?;
// Start servers
bridge.start_server(&rust_server).await?;
bridge.start_server(&python_server).await?;
// Use different servers for different file types
bridge.open_document(&rust_server, "file:///project/src/main.rs", "fn main() {}").await?;
bridge.open_document(&python_server, "file:///project/main.py", "print('hello')").await?;
Ok(())
}
use lsp_bridge::{LspBridge, LspServerConfig};
use lsp_types::{request::Request, notification::Notification};
// Define custom request
#[derive(Debug)]
enum CustomRequest {}
impl Request for CustomRequest {
type Params = serde_json::Value;
type Result = serde_json::Value;
const METHOD: &'static str = "custom/request";
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut bridge = LspBridge::new();
let server_id = bridge.register_server("custom", LspServerConfig::new().command("custom-server")).await?;
bridge.start_server(&server_id).await?;
// Send custom request
let params = serde_json::json!({"key": "value"});
let response = bridge.request::<CustomRequest>(&server_id, params).await?;
println!("Custom response: {:?}", response);
Ok(())
}
use lsp_bridge::{LspBridge, LspServerConfig, LspError};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut bridge = LspBridge::new();
let config = LspServerConfig::new()
.command("language-server")
.max_restart_attempts(3)
.restart_delay(std::time::Duration::from_secs(2));
let server_id = bridge.register_server("lang", config).await?;
// Handle server startup errors
match bridge.start_server(&server_id).await {
Ok(_) => println!("Server started successfully"),
Err(LspError::ServerStartup { message }) => {
eprintln!("Failed to start server: {}", message);
// Attempt restart
bridge.restart_server(&server_id).await?;
}
Err(e) => return Err(e.into()),
}
Ok(())
}
use lsp_bridge::LspServerConfig;
use std::time::Duration;
let config = LspServerConfig::new()
.command("rust-analyzer")
.args(["--help"])
.working_directory("/path/to/project")
.env("RUST_LOG", "debug")
.root_path("/path/to/project")
.workspace_folders(["/path/to/project", "/path/to/workspace"])
.startup_timeout(Duration::from_secs(30))
.request_timeout(Duration::from_secs(30))
.max_restart_attempts(3)
.restart_delay(Duration::from_secs(2))
.initialization_options(serde_json::json!({
"cargo": {
"buildScripts": {
"enable": true
}
}
}));
use lsp_bridge::{LspServerConfig, LspClientCapabilities};
let capabilities = LspClientCapabilities {
text_document: TextDocumentClientCapabilities {
completion: Some(CompletionClientCapabilities {
completion_item: Some(CompletionItemCapability {
snippet_support: Some(true),
commit_characters_support: Some(true),
..Default::default()
}),
..Default::default()
}),
..Default::default()
},
..Default::default()
};
let config = LspServerConfig::new()
.command("language-server")
.client_capabilities(capabilities);
let config = LspServerConfig::new()
.command("rust-analyzer")
.initialization_options(serde_json::json!({
"checkOnSave": {
"command": "clippy"
},
"cargo": {
"buildScripts": {
"enable": true
}
}
}));
let config = LspServerConfig::new()
.command("pylsp")
.initialization_options(serde_json::json!({
"plugins": {
"pycodestyle": {"enabled": false},
"mccabe": {"enabled": false},
"pyflakes": {"enabled": false},
"flake8": {
"enabled": true,
"maxLineLength": 88
}
}
}));
let config = LspServerConfig::new()
.command("typescript-language-server")
.args(["--stdio"])
.initialization_options(serde_json::json!({
"preferences": {
"disableSuggestions": false,
"quotePreference": "double"
}
}));
graph TB
subgraph "Client Application"
App[Your Application]
App --> API[LSPBridge API]
end
subgraph "LSPBridge Core"
API --> Bridge[LspBridge]
Bridge --> Client[LspClient]
Bridge --> Config[Configuration]
Client --> Server1[LspServer 1]
Client --> Server2[LspServer 2]
Client --> ServerN[LspServer N]
end
subgraph "LSP Servers"
Server1 --> Process1[rust-analyzer]
Server2 --> Process2[typescript-language-server]
ServerN --> ProcessN[Other LSP Servers]
end
style Bridge fill:#e1f5fe
style Client fill:#f3e5f5
style API fill:#e8f5e8
The LSP Bridge is organized into several key modules:
bridge - Main interface coordinating client-server communicationclient - Client-side bridge implementation for LSP interactionsserver - Server lifecycle management and communicationprotocol - LSP protocol implementation and message typesconfig - Configuration types and builderserror - Comprehensive error types and handlingutils - Shared utilities and helper functionssequenceDiagram
participant App as Your App
participant Bridge as LspBridge
participant Server as LspServer
participant LSP as LSP Process
App->>Bridge: request()
Bridge->>Server: forward_request()
Server->>LSP: JSON-RPC
LSP->>Server: response
Server->>Bridge: response
Bridge->>App: result
For detailed architecture diagrams and component interactions, see Architecture Diagrams.
LSP Bridge provides comprehensive error handling with detailed error types:
use lsp_bridge::LspError;
match error {
LspError::ServerStartup { message } => {
// Handle server startup failures
}
LspError::Communication { message } => {
// Handle communication errors
}
LspError::Timeout { timeout_ms } => {
// Handle timeout errors
}
LspError::ServerCrash { server_id } => {
// Handle server crashes
}
// ... other error types
}
LSP Bridge is designed for high performance:
Run the test suite:
cargo test
Run with logging:
RUST_LOG=debug cargo test
Integration tests with real LSP servers:
cargo test --features integration-tests
Our documentation includes comprehensive diagrams showing:
We welcome contributions! Please see CONTRIBUTING.md for details.
Clone the repository:
git clone https://github.com/your-username/lsp-bridge.git
cd lsp-bridge
Install dependencies:
cargo build
Run tests:
cargo test
Check formatting and linting:
cargo fmt --check
cargo clippy -- -D warnings
This project is licensed under either of
at your option.
See CHANGELOG.md for details about changes in each release.