Sending goto to rust
This commit is contained in:
@@ -197,15 +197,14 @@ impl LanguageServer for Backend {
|
|||||||
&self,
|
&self,
|
||||||
params: GotoDefinitionParams,
|
params: GotoDefinitionParams,
|
||||||
) -> Result<Option<GotoDefinitionResponse>> {
|
) -> Result<Option<GotoDefinitionResponse>> {
|
||||||
let mut source = fs::read_to_string(
|
let file_path = params
|
||||||
params
|
.text_document_position_params
|
||||||
.text_document_position_params
|
.text_document
|
||||||
.text_document
|
.uri
|
||||||
.uri
|
.to_file_path()
|
||||||
.to_file_path()
|
.unwrap();
|
||||||
.unwrap(),
|
|
||||||
)
|
let mut source = fs::read_to_string(&file_path).expect("Failed to read source");
|
||||||
.expect("Failed to read source");
|
|
||||||
|
|
||||||
let inject = "__mist_23";
|
let inject = "__mist_23";
|
||||||
|
|
||||||
@@ -223,10 +222,32 @@ impl LanguageServer for Backend {
|
|||||||
.expect("Didn't find injection")
|
.expect("Didn't find injection")
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
|
|
||||||
|
let (line, character) = find_row_col(&output, inject).unwrap();
|
||||||
|
|
||||||
self.client
|
self.client
|
||||||
.log_message(MessageType::INFO, format!("Found at {position}"))
|
.log_message(MessageType::INFO, format!("Found at {position}"))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
self.rust_analyzer
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.request::<lsp_types::request::GotoDefinition>(lsp_types::GotoDefinitionParams {
|
||||||
|
text_document_position_params: lsp_types::TextDocumentPositionParams {
|
||||||
|
position: lsp_types::Position {
|
||||||
|
line: line as u32,
|
||||||
|
character: character as u32,
|
||||||
|
},
|
||||||
|
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(),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("Failed to send to rust");
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,3 +307,20 @@ fn insert_at_position(s: &str, line: usize, col: usize, insert: &str) -> String
|
|||||||
|
|
||||||
lines.join("\n")
|
lines.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_row_col(output: &str, inject: &str) -> Option<(usize, usize)> {
|
||||||
|
// 1. Find the flat byte index just like your original code
|
||||||
|
let byte_idx = output.find(inject)?;
|
||||||
|
|
||||||
|
// 2. Slice the string up to the match point
|
||||||
|
let prefix = &output[..byte_idx];
|
||||||
|
|
||||||
|
// 3. Row = number of newlines found before the match + 1 (1-indexed)
|
||||||
|
let row = prefix.lines().count();
|
||||||
|
|
||||||
|
// 4. Column = character count of the remaining text on the current line + 1
|
||||||
|
// (Using .chars().count() ensures it works with multi-byte UTF-8 symbols)
|
||||||
|
let col = prefix.lines().last().unwrap_or("").chars().count() + 1;
|
||||||
|
|
||||||
|
Some((row, col))
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,92 +15,6 @@ pub struct RustAnalyzer {
|
|||||||
id: usize,
|
id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RustAnalyzer {
|
|
||||||
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
|
||||||
let mut child = tokio::process::Command::new("rust-analyzer")
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::null()) // Ignore logs for simplicity
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
let stdin = child.stdin.take().unwrap();
|
|
||||||
let stdout = BufReader::new(child.stdout.take().unwrap());
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
stdin,
|
|
||||||
stdout,
|
|
||||||
id: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn init(&mut self, root: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let project_uri = Url::from_directory_path(root)
|
|
||||||
.map_err(|_| "Failed to convert path to valid file:// URL")?;
|
|
||||||
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let init_params = InitializeParams {
|
|
||||||
process_id: Some(std::process::id()),
|
|
||||||
root_uri: Some(project_uri.clone()),
|
|
||||||
workspace_folders: Some(vec![WorkspaceFolder {
|
|
||||||
uri: project_uri,
|
|
||||||
name: "workspace".to_string(),
|
|
||||||
}]),
|
|
||||||
capabilities: ClientCapabilities {
|
|
||||||
workspace: Some(lsp_types::WorkspaceClientCapabilities {
|
|
||||||
workspace_folders: Some(true),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
text_document: Some(lsp_types::TextDocumentClientCapabilities {
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let _response = self.request::<request::Initialize>(init_params);
|
|
||||||
|
|
||||||
eprintln!("<- Received: initialize response");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn request<R: Request>(
|
|
||||||
&mut self,
|
|
||||||
params: R::Params,
|
|
||||||
) -> Result<R::Result, Box<dyn std::error::Error>> {
|
|
||||||
self.send(R::METHOD, params).await?;
|
|
||||||
self.read().await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send<T: Serialize>(&mut self, method: &str, req: T) -> std::io::Result<()> {
|
|
||||||
let id = {
|
|
||||||
self.id += 1;
|
|
||||||
self.id
|
|
||||||
};
|
|
||||||
|
|
||||||
send_lsp_message(
|
|
||||||
&mut self.stdin,
|
|
||||||
&json!({
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": id,
|
|
||||||
"method": method,
|
|
||||||
"params": req,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read<T>(&mut self) -> Result<T, Box<dyn std::error::Error>>
|
|
||||||
where
|
|
||||||
T: for<'de> serde::Deserialize<'de>,
|
|
||||||
{
|
|
||||||
read_lsp_message(&mut self.stdout)
|
|
||||||
.await
|
|
||||||
.map(|v| serde_json::from_str(&v).unwrap())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_lsp_message<W: AsyncWriteExt + Unpin>(
|
async fn send_lsp_message<W: AsyncWriteExt + Unpin>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
value: &serde_json::Value,
|
value: &serde_json::Value,
|
||||||
@@ -140,3 +54,91 @@ async fn read_lsp_message<R: AsyncBufReadExt + Unpin>(
|
|||||||
|
|
||||||
Ok(String::from_utf8(buffer)?)
|
Ok(String::from_utf8(buffer)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RustAnalyzer {
|
||||||
|
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
|
let mut child = tokio::process::Command::new("rust-analyzer")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::null()) // Ignore logs for simplicity
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
let stdin = child.stdin.take().unwrap();
|
||||||
|
let stdout = BufReader::new(child.stdout.take().unwrap());
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
stdin,
|
||||||
|
stdout,
|
||||||
|
id: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn request<R: Request>(
|
||||||
|
&mut self,
|
||||||
|
params: R::Params,
|
||||||
|
) -> Result<R::Result, Box<dyn std::error::Error>> {
|
||||||
|
self.send(R::METHOD, params).await?;
|
||||||
|
self.read().await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send<T: Serialize>(&mut self, method: &str, req: T) -> std::io::Result<()> {
|
||||||
|
let id = {
|
||||||
|
self.id += 1;
|
||||||
|
self.id
|
||||||
|
};
|
||||||
|
|
||||||
|
send_lsp_message(
|
||||||
|
&mut self.stdin,
|
||||||
|
&json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": id,
|
||||||
|
"method": method,
|
||||||
|
"params": req,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read<T>(&mut self) -> Result<T, Box<dyn std::error::Error>>
|
||||||
|
where
|
||||||
|
T: for<'de> serde::Deserialize<'de>,
|
||||||
|
{
|
||||||
|
read_lsp_message(&mut self.stdout)
|
||||||
|
.await
|
||||||
|
.map(|v| serde_json::from_str(&v).unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RustAnalyzer {
|
||||||
|
pub async fn init(&mut self, root: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let project_uri = Url::from_directory_path(root)
|
||||||
|
.map_err(|_| "Failed to convert path to valid file:// URL")?;
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let init_params = InitializeParams {
|
||||||
|
process_id: Some(std::process::id()),
|
||||||
|
root_uri: Some(project_uri.clone()),
|
||||||
|
workspace_folders: Some(vec![WorkspaceFolder {
|
||||||
|
uri: project_uri,
|
||||||
|
name: "workspace".to_string(),
|
||||||
|
}]),
|
||||||
|
capabilities: ClientCapabilities {
|
||||||
|
workspace: Some(lsp_types::WorkspaceClientCapabilities {
|
||||||
|
workspace_folders: Some(true),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
text_document: Some(lsp_types::TextDocumentClientCapabilities {
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let _response = self.request::<request::Initialize>(init_params);
|
||||||
|
|
||||||
|
eprintln!("<- Received: initialize response");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user