From 715faaacebe80f600698ab8bf7a3fdf5e2408b4d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 21 Oct 2021 19:27:10 +0200 Subject: [PATCH] WIP --- crates/lsp/build.rs | 36 ++++++++++++++++++ crates/lsp/src/lib.rs | 85 ++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 crates/lsp/build.rs diff --git a/crates/lsp/build.rs b/crates/lsp/build.rs new file mode 100644 index 0000000000..a29aa4b016 --- /dev/null +++ b/crates/lsp/build.rs @@ -0,0 +1,36 @@ +use std::{ + env, + fs::{self, Permissions}, + os::unix::prelude::PermissionsExt, + process::Command, +}; + +fn main() { + let target = env::var("TARGET").unwrap(); + let rust_analyzer_filename = format!("rust-analyzer-{}", target); + let rust_analyzer_url = format!( + "https://github.com/rust-analyzer/rust-analyzer/releases/download/2021-10-18/{}.gz", + rust_analyzer_filename + ); + println!( + "cargo:rustc-env=RUST_ANALYZER_FILENAME={}", + rust_analyzer_filename + ); + + let target_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let rust_analyzer_target_path = format!("{}/{}", target_dir, rust_analyzer_filename); + assert!( + Command::new("/bin/sh") + .arg("-c") + .arg(format!( + "curl -L {} | gunzip > {}", + rust_analyzer_url, rust_analyzer_target_path + )) + .status() + .unwrap() + .success(), + "failed to download rust-analyzer" + ); + fs::set_permissions(rust_analyzer_target_path, Permissions::from_mode(0x755)) + .expect("failed to make rust-analyzer executable"); +} diff --git a/crates/lsp/src/lib.rs b/crates/lsp/src/lib.rs index e05b435ba4..53e85a373a 100644 --- a/crates/lsp/src/lib.rs +++ b/crates/lsp/src/lib.rs @@ -41,18 +41,6 @@ struct Request { params: T, } -#[derive(Deserialize)] -struct Error { - message: String, -} - -#[derive(Deserialize)] -struct Notification<'a> { - method: String, - #[serde(borrow)] - params: &'a RawValue, -} - #[derive(Deserialize)] struct Response<'a> { id: usize, @@ -62,6 +50,26 @@ struct Response<'a> { result: Option<&'a RawValue>, } +#[derive(Serialize)] +struct OutboundNotification { + jsonrpc: &'static str, + method: &'static str, + params: T, +} + +#[derive(Deserialize)] +struct InboundNotification<'a> { + #[serde(borrow)] + method: &'a str, + #[serde(borrow)] + params: &'a RawValue, +} + +#[derive(Deserialize)] +struct Error { + message: String, +} + impl LanguageServer { pub fn new(path: &Path, background: &executor::Background) -> Result> { let mut server = Command::new(path) @@ -91,7 +99,7 @@ impl LanguageServer { buffer.resize(message_len, 0); stdout.read_exact(&mut buffer).await?; - if let Ok(Notification { .. }) = serde_json::from_slice(&buffer) { + if let Ok(InboundNotification { .. }) = serde_json::from_slice(&buffer) { } else if let Ok(Response { id, error, result }) = serde_json::from_slice(&buffer) { @@ -146,19 +154,19 @@ impl LanguageServer { } async fn init(self: Arc) -> Result<()> { - let init_response = self - .request::(lsp_types::InitializeParams { - process_id: Default::default(), - root_path: Default::default(), - root_uri: Default::default(), - initialization_options: Default::default(), - capabilities: Default::default(), - trace: Default::default(), - workspace_folders: Default::default(), - client_info: Default::default(), - locale: Default::default(), - }) - .await?; + self.request::(lsp_types::InitializeParams { + process_id: Default::default(), + root_path: Default::default(), + root_uri: Default::default(), + initialization_options: Default::default(), + capabilities: Default::default(), + trace: Default::default(), + workspace_folders: Default::default(), + client_info: Default::default(), + locale: Default::default(), + }) + .await?; + self.notify::(lsp_types::InitializedParams {})?; Ok(()) } @@ -198,4 +206,29 @@ impl LanguageServer { rx.recv().await? } } + + pub fn notify( + &self, + params: T::Params, + ) -> Result<()> { + let message = serde_json::to_vec(&OutboundNotification { + jsonrpc: JSON_RPC_VERSION, + method: T::METHOD, + params, + }) + .unwrap(); + smol::block_on(self.outbound_tx.send(message))?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use gpui::TestAppContext; + + #[gpui::test] + async fn test_basic(cx: TestAppContext) { + let server = LanguageServer::new(); + } }