Working req res
This commit is contained in:
+35
-13
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user