Files
galaxy/crates/lsp/examples/rust-lsp/main.rs
T

175 lines
5.1 KiB
Rust

//! LSP crate demonstration showing proper usage of LspService and core LSP functionality.
//!
//! This demo showcases:
//! - LSP server initialization using rust-analyzer
//! - Document lifecycle management (open/close)
//! - Core LSP features: go-to-definition, hover, completion, symbols
//! - Proper shutdown and error handling
use std::env;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
use chrono::Utc;
use galaxyui::r#async::{executor::Background, Timer};
use log::LevelFilter;
use lsp::supported_servers::LSPServerType;
use lsp::{spawn_lsp_service, LspServerConfig, LspService, LspServiceInitializationResult};
use lsp_types::Position;
use galaxyui_core::r#async::executor::Background;
use galaxyui_core::r#async::Timer;
fn init_logging() {
let mut base_logger = env_logger::builder();
base_logger.filter_level(LevelFilter::Info);
base_logger.parse_default_env();
base_logger.init();
}
fn find_workspace_root() -> anyhow::Result<PathBuf> {
let current_dir = env::current_dir()?;
// Walk up directory tree to find Cargo.toml (workspace root)
let mut path = current_dir.as_path();
loop {
if path.join("Cargo.toml").exists() {
return Ok(path.to_path_buf());
}
match path.parent() {
Some(parent) => path = parent,
None => {
return Err(anyhow::anyhow!(
"Could not find workspace root with Cargo.toml"
))
}
}
}
}
async fn demo_goto_definition(
service: &LspService,
file_path: &Path,
_content: &str,
) -> anyhow::Result<()> {
println!("\n=== Testing Go-to-Definition ===");
// This attempts to target find_workspace_root currently on line 105
// Note that "lines" are 0-indexed
let test_position = Position {
line: 92,
character: 7,
};
println!(
"Testing go-to-definition at line {}, character {}",
test_position.line, test_position.character
);
let start = Utc::now();
// Use the text document service instead of direct send_request
match service
.text_document()
.definition(file_path, test_position)
.await
{
Ok(response) => {
println!("Definition response: {response:?}");
}
Err(e) => {
println!("Error requesting definition: {e}");
}
}
let elapsed = Utc::now() - start;
println!("Elapsed time for goto-definition: {elapsed:?}");
Ok(())
}
/// Main demo function
fn main() -> anyhow::Result<()> {
init_logging();
println!("Starting LSP Crate Demonstration");
println!("Using rust-analyzer as the LSP server");
// === Setup Phase ===
// Find workspace root for testing
let workspace_root = find_workspace_root()?;
log::info!("Workspace root: {}", workspace_root.display());
let executor = Arc::new(Background::default());
let executor_clone = executor.clone();
let task = executor.spawn(async move {
if let Err(e) = async_main(executor_clone, workspace_root).await {
log::error!("LSP demo failed: {e}");
eprintln!("LSP demo failed: {e}");
}
});
galaxyui_core::r#async::block_on(task)?;
Ok(())
}
async fn async_main(executor: Arc<Background>, workspace_root: PathBuf) -> anyhow::Result<()> {
println!("Initializing LSP Server (rust-analyzer)...");
let config = LspServerConfig::new(
LSPServerType::RustAnalyzer,
workspace_root,
None,
"warp-dev-example".to_string(),
Arc::new(http_client::Client::new()),
);
let LspServiceInitializationResult {
service: lsp_service,
channel: _rx,
} = spawn_lsp_service(config, executor, None).await?;
if let Some(capabilities) = lsp_service.server_capabilities() {
println!("Server capabilities received");
if capabilities.definition_provider.is_some() {
println!(" - Go-to-definition supported");
}
if capabilities.hover_provider.is_some() {
println!(" - Hover information supported");
}
if capabilities.completion_provider.is_some() {
println!(" - Code completion supported");
}
}
// Use this main.rs file as our test document
let test_file = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples/rust-lsp/main.rs");
let file_content = std::fs::read_to_string(&test_file)?;
// This ensures rust-analyzer has finished its initial indexing and setup
println!("Waiting 30 seconds for LSP service to be ready...");
Timer::after(Duration::from_secs(30)).await;
println!("Opening document: {}", test_file.display());
lsp_service
.text_document()
.did_open(&test_file, file_content.clone(), 0)
.await?;
println!("Running first goto-definition call");
demo_goto_definition(&lsp_service, &test_file, &file_content).await?;
println!("Running second goto-definition call");
demo_goto_definition(&lsp_service, &test_file, &file_content).await?;
println!("Shutting down LSP service...");
lsp_service.shutdown().await?;
Ok(())
}