Working req res

This commit is contained in:
2026-05-24 06:29:58 +02:00
parent b2f5f2fdc8
commit 9b1acb8cc3
2 changed files with 92 additions and 21 deletions
+35 -13
View File
@@ -7,8 +7,10 @@ use std::fs;
use std::path::{Component, PathBuf}; use std::path::{Component, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use serde_json::Value;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tower_lsp::jsonrpc::Result; use tower_lsp::jsonrpc::Result;
use tower_lsp::lsp_types::request::Request;
use tower_lsp::lsp_types::*; use tower_lsp::lsp_types::*;
use tower_lsp::{Client, LanguageServer, LspService, Server}; use tower_lsp::{Client, LanguageServer, LspService, Server};
@@ -82,7 +84,7 @@ impl LanguageServer for Backend {
analyzer analyzer
.lock() .lock()
.await .await
.init(root) .initialize(root)
.await .await
.expect("Failed to initialize rust analyzer"); .expect("Failed to initialize rust analyzer");
} }
@@ -95,6 +97,13 @@ impl LanguageServer for Backend {
self.client self.client
.log_message(MessageType::INFO, "server initialized!") .log_message(MessageType::INFO, "server initialized!")
.await; .await;
self.rust_analyzer
.lock()
.await
.initialized()
.await
.expect("Failed to initialize rust analyzer");
} }
async fn shutdown(&self) -> Result<()> { async fn shutdown(&self) -> Result<()> {
@@ -231,23 +240,36 @@ impl LanguageServer for Backend {
self.rust_analyzer self.rust_analyzer
.lock() .lock()
.await .await
.request::<lsp_types::request::GotoDefinition>(lsp_types::GotoDefinitionParams { .send(
text_document_position_params: lsp_types::TextDocumentPositionParams { request::GotoDefinition::METHOD,
position: lsp_types::Position { lsp_types::GotoDefinitionParams {
line: line as u32, text_document_position_params: lsp_types::TextDocumentPositionParams {
character: character as u32, position: lsp_types::Position {
}, line: line as u32,
text_document: lsp_types::TextDocumentIdentifier { character: character as u32,
uri: Url::from_file_path(from_mist_to_rust(file_path)) },
.expect("failed to generate rs url"), text_document: lsp_types::TextDocumentIdentifier {
uri: Url::from_file_path(from_mist_to_rust(file_path))
.expect("failed to generate rs url"),
},
}, },
partial_result_params: lsp_types::PartialResultParams::default(),
work_done_progress_params: lsp_types::WorkDoneProgressParams::default(),
}, },
partial_result_params: lsp_types::PartialResultParams::default(), )
work_done_progress_params: lsp_types::WorkDoneProgressParams::default(),
})
.await .await
.expect("Failed to send to rust"); .expect("Failed to send to rust");
self.client
.log_message(
MessageType::INFO,
format!(
"{:?}",
self.rust_analyzer.lock().await.read::<Value>().await
),
)
.await;
Ok(None) Ok(None)
} }
} }
+57 -8
View File
@@ -1,13 +1,31 @@
use std::{path::PathBuf, process::Stdio}; use std::{path::PathBuf, process::Stdio};
use lsp_types::{ use lsp_types::{
ClientCapabilities, InitializeParams, Url, WorkspaceFolder, ClientCapabilities, InitializeParams, InitializedParams, Url, WorkspaceFolder,
notification::{Initialized, Notification},
request::{self, Request}, request::{self, Request},
}; };
use serde::Serialize; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}; use tokio::io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader};
#[derive(Deserialize)]
pub struct JsonRpcResponse<T> {
pub jsonrpc: String,
// id can be a number or null, so we use serde_json::Value to be safe
pub id: serde_json::Value,
// We only unpack the result if it exists
pub result: Option<T>,
pub error: Option<JsonRpcError>,
}
#[derive(Debug, Deserialize)]
pub struct JsonRpcError {
pub code: i64,
pub message: String,
pub data: Option<serde_json::Value>,
}
#[derive(Debug)] #[derive(Debug)]
pub struct RustAnalyzer { pub struct RustAnalyzer {
stdin: tokio::process::ChildStdin, stdin: tokio::process::ChildStdin,
@@ -103,14 +121,38 @@ impl RustAnalyzer {
where where
T: for<'de> serde::Deserialize<'de>, T: for<'de> serde::Deserialize<'de>,
{ {
read_lsp_message(&mut self.stdout) let raw_string = read_lsp_message(&mut self.stdout).await?;
.await
.map(|v| serde_json::from_str(&v).unwrap()) let envelope: JsonRpcResponse<T> = serde_json::from_str(&raw_string)?;
if let Some(err) = envelope.error {
return Err(format!("LSP Error ({}): {}", err.code, err.message).into());
}
envelope.result.ok_or_else(|| {
format!(
"LSP response missing both result and error fields. Raw: {}",
raw_string
)
.into()
})
}
pub async fn notify<T: Serialize>(&mut self, method: &str, req: T) -> std::io::Result<()> {
send_lsp_message(
&mut self.stdin,
&json!({
"jsonrpc": "2.0",
"method": method,
"params": req,
}),
)
.await
} }
} }
impl RustAnalyzer { impl RustAnalyzer {
pub async fn init(&mut self, root: &PathBuf) -> Result<(), Box<dyn std::error::Error>> { pub async fn initialize(&mut self, root: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let project_uri = Url::from_directory_path(root) let project_uri = Url::from_directory_path(root)
.map_err(|_| "Failed to convert path to valid file:// URL")?; .map_err(|_| "Failed to convert path to valid file:// URL")?;
@@ -135,9 +177,16 @@ impl RustAnalyzer {
..Default::default() ..Default::default()
}; };
let _response = self.request::<request::Initialize>(init_params); let response = self.request::<request::Initialize>(init_params).await;
eprintln!("<- Received: initialize response"); eprintln!("<- Received: initialize response {response:?}");
Ok(())
}
pub async fn initialized(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.notify(Initialized::METHOD, InitializedParams {})
.await?;
Ok(()) Ok(())
} }