turbo_static/
lsp_client.rs1use std::{path::PathBuf, process, sync::mpsc};
2
3use lsp_server::Message;
4
5pub struct RAClient {
7 handle: process::Child,
9 sender: Option<mpsc::SyncSender<Message>>,
10 receiver: Option<mpsc::Receiver<Message>>,
11}
12
13impl RAClient {
14 pub fn new() -> Self {
16 let stdin = process::Stdio::piped();
17 let stdout = process::Stdio::piped();
18 let stderr = process::Stdio::inherit();
19
20 let child = process::Command::new("rust-analyzer")
21 .stdin(stdin)
22 .stdout(stdout)
23 .stderr(stderr)
24 .env("RUST_BACKTRACE", "1")
26 .spawn()
27 .expect("Failed to start RA LSP server");
28 Self {
29 handle: child,
30 sender: None,
31 receiver: None,
32 }
33 }
34
35 pub fn start(&mut self, folders: &[PathBuf]) {
36 let stdout = self.handle.stdout.take().unwrap();
37 let mut stdin = self.handle.stdin.take().unwrap();
38
39 let (writer_sender, writer_receiver) = mpsc::sync_channel::<Message>(0);
40 _ = std::thread::spawn(move || {
41 writer_receiver
42 .into_iter()
43 .try_for_each(|it| it.write(&mut stdin))
44 });
45
46 let (reader_sender, reader_receiver) = mpsc::sync_channel::<Message>(0);
47 _ = std::thread::spawn(move || {
48 let mut reader = std::io::BufReader::new(stdout);
49 while let Ok(Some(msg)) = Message::read(&mut reader) {
50 reader_sender
51 .send(msg)
52 .expect("receiver was dropped, failed to send a message");
53 }
54 });
55
56 self.sender = Some(writer_sender);
57 self.receiver = Some(reader_receiver);
58
59 let workspace_paths = folders
60 .iter()
61 .map(|p| std::fs::canonicalize(p).unwrap())
62 .map(|p| lsp_types::WorkspaceFolder {
63 name: p.file_name().unwrap().to_string_lossy().to_string(),
64 uri: lsp_types::Url::from_file_path(p).unwrap(),
65 })
66 .collect::<Vec<_>>();
67
68 _ = self.request(lsp_server::Request {
69 id: 1.into(),
70 method: "initialize".to_string(),
71 params: serde_json::to_value(lsp_types::InitializeParams {
72 workspace_folders: Some(workspace_paths),
73 process_id: Some(std::process::id()),
74 capabilities: lsp_types::ClientCapabilities {
75 workspace: Some(lsp_types::WorkspaceClientCapabilities {
76 workspace_folders: Some(true),
77 ..Default::default()
78 }),
79 ..Default::default()
80 },
81 work_done_progress_params: lsp_types::WorkDoneProgressParams {
82 work_done_token: Some(lsp_types::ProgressToken::String("prepare".to_string())),
83 },
84 ..Default::default()
87 })
88 .unwrap(),
89 });
90
91 self.notify(lsp_server::Notification {
92 method: "initialized".to_string(),
93 params: serde_json::to_value(lsp_types::InitializedParams {}).unwrap(),
94 });
95 }
96
97 pub fn request(&mut self, message: lsp_server::Request) -> Option<lsp_server::Response> {
101 tracing::debug!("sending {:?}", message);
102 self.sender
103 .as_mut()
104 .unwrap()
105 .send(Message::Request(message))
106 .ok()?;
107
108 loop {
109 match self.receiver.as_mut().unwrap().recv() {
110 Ok(lsp_server::Message::Response(response)) => {
111 tracing::debug!("received {:?}", response);
112 return Some(response);
113 }
114 Ok(m) => tracing::trace!("unexpected message: {:?}", m),
115 Err(_) => {
116 tracing::trace!("error receiving message");
117 return None;
118 }
119 }
120 }
121 }
122
123 pub fn notify(&mut self, message: lsp_server::Notification) {
124 self.sender
125 .as_mut()
126 .unwrap()
127 .send(Message::Notification(message))
128 .expect("failed to send message");
129 }
130}
131
132impl Drop for RAClient {
133 fn drop(&mut self) {
134 if self.sender.is_some() {
135 let Some(resp) = self.request(lsp_server::Request {
136 id: 1.into(),
137 method: "shutdown".to_string(),
138 params: serde_json::to_value(()).unwrap(),
139 }) else {
140 return;
141 };
142
143 if resp.error.is_none() {
144 tracing::info!("shutting down RA LSP server");
145 self.notify(lsp_server::Notification {
146 method: "exit".to_string(),
147 params: serde_json::to_value(()).unwrap(),
148 });
149 self.handle
150 .wait()
151 .expect("failed to wait for RA LSP server");
152 tracing::info!("shut down RA LSP server");
153 } else {
154 tracing::error!("failed to shutdown RA LSP server: {:#?}", resp);
155 }
156 }
157
158 self.sender = None;
159 self.receiver = None;
160 }
161}