This commit is contained in:
Antonio Scandurra 2021-10-21 19:27:10 +02:00
parent 2c6aeaed7c
commit 715faaaceb
2 changed files with 95 additions and 26 deletions

36
crates/lsp/build.rs Normal file
View file

@ -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");
}

View file

@ -41,18 +41,6 @@ struct Request<T> {
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<T> {
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<Arc<Self>> {
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<Self>) -> Result<()> {
let init_response = self
.request::<lsp_types::request::Initialize>(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::request::Initialize>(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::notification::Initialized>(lsp_types::InitializedParams {})?;
Ok(())
}
@ -198,4 +206,29 @@ impl LanguageServer {
rx.recv().await?
}
}
pub fn notify<T: lsp_types::notification::Notification>(
&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();
}
}