1use crate::{
6 buffer::{Buffer, Buffers},
7 config::{FtypeConfig, LspConfig, ftype_config_for_path_and_first_line},
8 die,
9 editor::{Action, MbSelect},
10 input::Event,
11 lsp::{
12 capabilities::{Capabilities, PositionEncoding},
13 client::{LspClient, LspMessage},
14 messages::{
15 Diagnostic, Diagnostics, LspNotification, LspRequest, NotificationHandler,
16 OpenDocument, PendingLspRequest, PreparedLspNotification, PreparedLspRequest,
17 RequestHandler, txt_doc_id,
18 },
19 rpc::{Message, Notification, Request, RequestId, Response},
20 },
21 util::ReadOnlyLock,
22};
23use lsp_types::{NumberOrString, Uri, notification as notif, request as req, request::Initialize};
24use std::{
25 collections::HashMap,
26 path::Path,
27 sync::{
28 Arc, RwLock,
29 mpsc::{Receiver, Sender, channel},
30 },
31 thread::{sleep, spawn},
32 time::Duration,
33};
34use tracing::{debug, error, warn};
35
36mod capabilities;
37mod client;
38mod messages;
39mod rpc;
40
41pub use capabilities::Coords;
42
43const LSP_FILE: &str = "+lsp";
44
45#[derive(Debug)]
46pub(crate) enum PreparedMessage {
47 Request(Box<dyn PreparedLspRequest>),
48 Notification(Box<dyn PreparedLspNotification>),
49}
50
51#[derive(Debug)]
52pub(crate) enum Req {
53 Start {
54 ftype: String,
55 cmd: String,
56 args: Vec<String>,
57 init_opts: Option<serde_json::Value>,
58 root: String,
59 open_docs: Vec<OpenDocument>,
60 },
61 Stop {
62 lsp_id: usize,
63 },
64 Prepared(PreparedMessage),
65 Message(LspMessage),
66}
67
68#[derive(Debug)]
69pub struct LspManagerHandle {
70 tx_req: Sender<Req>,
71 capabilities: ReadOnlyLock<HashMap<String, (usize, Capabilities)>>,
72 diagnostics: ReadOnlyLock<HashMap<Uri, Vec<Diagnostic>>>,
73 configs: HashMap<String, FtypeConfig>,
74 autostart: bool,
75}
76
77impl LspManagerHandle {
78 pub(crate) fn new_stubbed(tx_req: Sender<Req>) -> Self {
79 Self {
80 tx_req,
81 capabilities: Default::default(),
82 diagnostics: Default::default(),
83 configs: Default::default(),
84 autostart: false,
85 }
86 }
87
88 fn send_req(&self, req: impl PreparedLspRequest) {
89 let msg = PreparedMessage::Request(Box::new(req));
90 if let Err(e) = self.tx_req.send(Req::Prepared(msg)) {
91 die!("LSP manager died: {e}")
92 }
93 }
94
95 fn send_notification(&self, notif: impl PreparedLspNotification) {
96 let msg = PreparedMessage::Notification(Box::new(notif));
97 if let Err(e) = self.tx_req.send(Req::Prepared(msg)) {
98 die!("LSP manager died: {e}")
99 }
100 }
101
102 fn lsp_id_and_encoding_for(&self, b: &Buffer) -> Option<(usize, PositionEncoding)> {
105 let (ftype, _) = &self.config_for_buffer(b)?;
106
107 self.capabilities
108 .read()
109 .unwrap()
110 .get(ftype.as_str())
111 .map(|(id, caps)| (*id, caps.position_encoding))
112 }
113
114 fn lsp_id_and_encoding_for_ftype(&self, ftype: &str) -> Option<(usize, PositionEncoding)> {
115 self.capabilities
116 .read()
117 .unwrap()
118 .get(ftype)
119 .map(|(id, caps)| (*id, caps.position_encoding))
120 }
121
122 fn config_for_path_and_first_line(
123 &self,
124 path: &Path,
125 first_line: &str,
126 ) -> Option<(&String, &LspConfig)> {
127 ftype_config_for_path_and_first_line(path, first_line, &self.configs)
128 .and_then(|(name, c)| c.lsp.as_ref().map(|lsp| (name, lsp)))
129 }
130
131 fn config_for_buffer(&self, b: &Buffer) -> Option<(&String, &LspConfig)> {
132 let first_line = b.line(0).map(|l| l.to_string()).unwrap_or_default();
133
134 self.config_for_path_and_first_line(b.path()?, &first_line)
135 }
136
137 fn start_req_for_buf(&self, bs: &Buffers) -> Option<Req> {
138 let b = bs.active();
139 let (ftype, config) = self.config_for_buffer(b)?;
140 let root = config.root_for_buffer(b)?.to_str()?.to_owned();
141 let open_docs: Vec<_> = bs
142 .iter()
143 .flat_map(|b| match self.config_for_buffer(b) {
144 Some((bftype, _)) if bftype == ftype => Some(OpenDocument {
145 ftype: ftype.to_owned(),
146 path: b.full_name().to_owned(),
147 content: b.str_contents(),
148 }),
149 _ => None,
150 })
151 .collect();
152
153 Some(Req::Start {
154 ftype: ftype.to_owned(),
155 cmd: config.command.clone(),
156 args: config.args.clone(),
157 init_opts: config.init_opts.clone(),
158 root,
159 open_docs,
160 })
161 }
162
163 pub fn start_client(&self, bs: &Buffers) -> Option<&'static str> {
164 match self.start_req_for_buf(bs) {
165 Some(req) => {
166 debug!("starting LSP server");
167 if let Err(e) = self.tx_req.send(req) {
168 die!("LSP manager died: {e}")
169 }
170 None
171 }
172
173 None => Some("no LSP available for buffer"),
174 }
175 }
176
177 pub fn stop_client(&self, b: &Buffer) {
178 if let Some((lsp_id, _)) = self.lsp_id_and_encoding_for(b) {
179 debug!("stopping LSP server {lsp_id}");
180 if let Err(e) = self.tx_req.send(Req::Stop { lsp_id }) {
181 die!("LSP manager died: {e}")
182 }
183 };
184 }
185
186 pub fn show_server_capabilities(&self, b: &Buffer) -> Option<(&'static str, String)> {
187 let (ftype, _) = &self.config_for_buffer(b)?;
188 let txt = self
189 .capabilities
190 .read()
191 .unwrap()
192 .get(ftype.as_str())?
193 .1
194 .as_pretty_json()?;
195
196 Some((LSP_FILE, txt))
197 }
198
199 pub fn show_diagnostics(&self, b: &Buffer) -> Action {
200 if b.dirty {
201 self.document_changed(b);
203 sleep(Duration::from_millis(300));
204 }
205
206 debug!("showing LSP diagnostics");
207 let guard = self.diagnostics.read().unwrap();
208 let mut diags: Vec<Diagnostic> = guard.values().flatten().cloned().collect();
209 diags.sort_unstable();
210
211 Action::MbSelect(Diagnostics(diags).into_selector())
212 }
213
214 pub fn document_opened(&self, bs: &Buffers) {
219 let b = bs.active();
220 let ftype = match self.config_for_buffer(b) {
221 Some((ftype, _)) => ftype,
222 None => return,
223 };
224
225 match self.lsp_id_and_encoding_for_ftype(ftype) {
226 Some((lsp_id, _)) => {
227 debug!("sending LSP textDocument/didOpen ({lsp_id})");
228 let path = b.full_name().to_string();
229 let content = b.str_contents();
230
231 self.send_notification(notif::DidOpenTextDocument::data(
232 lsp_id,
233 (ftype.clone(), path, content),
234 ));
235 }
236
237 None if self.autostart => {
238 self.start_client(bs);
239 }
240
241 None => (),
242 }
243 }
244
245 pub fn document_closed(&self, b: &Buffer) {
246 if let Some((lsp_id, _)) = self.lsp_id_and_encoding_for(b) {
247 debug!("sending LSP textDocument/didClose ({lsp_id})");
248 let path = b.full_name().to_string();
249
250 self.send_notification(notif::DidCloseTextDocument::data(lsp_id, path));
251 }
252 }
253
254 pub fn document_changed(&self, b: &Buffer) {
255 if let Some((lsp_id, _)) = self.lsp_id_and_encoding_for(b) {
256 debug!("sending LSP textDocument/didChange ({lsp_id})");
257 let path = b.full_name().to_string();
258 let content = b.str_contents();
259 let version = b.next_edit_version() as i32;
260
261 self.send_notification(notif::DidChangeTextDocument::data(
262 lsp_id,
263 (path, content, version),
264 ));
265 }
266 }
267
268 pub fn document_saved(&self, b: &Buffer) {
269 if let Some((lsp_id, _)) = self.lsp_id_and_encoding_for(b) {
270 debug!("sending LSP textDocument/didSave ({lsp_id})");
271 let path = b.full_name().to_string();
272
273 self.send_notification(notif::DidSaveTextDocument::data(lsp_id, path));
274 }
275 }
276
277 pub fn goto_declaration(&self, b: &Buffer) {
278 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
279 if b.dirty {
280 self.document_changed(b);
281 }
282
283 debug!("sending LSP textDocument/declaration ({lsp_id})");
284 self.send_req(req::GotoDeclaration::data(lsp_id, enc.buffer_pos(b), ()));
285 }
286 }
287
288 pub fn goto_definition(&self, b: &Buffer) {
289 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
290 if b.dirty {
291 self.document_changed(b);
292 }
293
294 debug!("sending LSP textDocument/definition ({lsp_id})");
295 self.send_req(req::GotoDefinition::data(lsp_id, enc.buffer_pos(b), ()));
296 }
297 }
298
299 pub fn goto_type_definition(&self, b: &Buffer) {
300 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
301 if b.dirty {
302 self.document_changed(b);
303 }
304
305 debug!("sending LSP textDocument/typeDefinition ({lsp_id})");
306 self.send_req(req::GotoTypeDefinition::data(lsp_id, enc.buffer_pos(b), ()));
307 }
308 }
309
310 pub fn hover(&self, b: &Buffer) {
311 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
312 if b.dirty {
313 self.document_changed(b);
314 }
315
316 debug!("sending LSP textDocument/hover ({lsp_id})");
317 self.send_req(req::HoverRequest::data(lsp_id, enc.buffer_pos(b), ()));
318 }
319 }
320
321 pub fn completion(&self, b: &Buffer) {
322 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
323 if b.dirty {
324 self.document_changed(b);
325 }
326
327 debug!("sending LSP textDocument/completion ({lsp_id})");
328 let pos = enc.buffer_pos(b);
329 self.send_req(req::Completion::data(lsp_id, pos.clone(), pos));
330 }
331 }
332
333 pub fn find_references(&self, b: &Buffer) {
334 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
335 if b.dirty {
336 self.document_changed(b);
337 }
338
339 debug!("sending LSP textDocument/references ({lsp_id})");
340 self.send_req(req::References::data(lsp_id, enc.buffer_pos(b), ()));
341 }
342 }
343
344 pub fn format(&self, b: &Buffer) {
345 if let Some((lsp_id, _)) = self.lsp_id_and_encoding_for(b) {
346 if b.dirty {
347 self.document_changed(b);
348 }
349
350 debug!("sending LSP textDocument/formatting ({lsp_id})");
351 self.send_req(req::Formatting::data(
352 lsp_id,
353 (txt_doc_id(b.full_name()), b.tabstop() as u32),
354 (),
355 ));
356 }
357 }
358
359 pub fn prepare_rename(&self, b: &Buffer) {
360 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
361 if b.dirty {
362 self.document_changed(b);
363 }
364
365 debug!("sending LSP textDocument/prepareRename ({lsp_id})");
366 let pos = enc.buffer_pos(b);
367 self.send_req(req::PrepareRenameRequest::data(lsp_id, pos, ()));
368 }
369 }
370
371 pub fn rename(&self, b: &Buffer, new_name: String) {
372 if let Some((lsp_id, enc)) = self.lsp_id_and_encoding_for(b) {
373 if b.dirty {
374 self.document_changed(b);
375 }
376
377 debug!("sending LSP textDocument/rename ({lsp_id})");
378 let pos = enc.buffer_pos(b);
379 self.send_req(req::Rename::data(
380 lsp_id,
381 (pos.clone(), new_name),
382 (pos, b.id),
383 ));
384 }
385 }
386}
387
388#[derive(Debug)]
389pub struct LspManager {
390 clients: HashMap<usize, LspClient>,
391 capabilities: Arc<RwLock<HashMap<String, (usize, Capabilities)>>>,
393 pending: HashMap<(usize, RequestId), Box<dyn PendingLspRequest>>,
395 progress_tokens: HashMap<usize, HashMap<NumberOrString, String>>,
397 diagnostics: Arc<RwLock<HashMap<Uri, Vec<Diagnostic>>>>,
398 pub(super) tx_req: Sender<Req>,
399 tx_events: Sender<Event>,
400 next_id: usize,
401}
402
403impl LspManager {
404 pub fn spawn(
405 configs: HashMap<String, FtypeConfig>,
406 tx_events: Sender<Event>,
407 autostart: bool,
408 ) -> LspManagerHandle {
409 let (tx_req, rx_req) = channel();
410 let manager = Self {
411 clients: Default::default(),
412 capabilities: Default::default(),
413 pending: Default::default(),
414 progress_tokens: Default::default(),
415 diagnostics: Default::default(),
416 tx_req: tx_req.clone(),
417 tx_events,
418 next_id: 0,
419 };
420
421 let capabilities = ReadOnlyLock::new(manager.capabilities.clone());
422 let diagnostics = ReadOnlyLock::new(manager.diagnostics.clone());
423 spawn(move || manager.run(rx_req));
424
425 LspManagerHandle {
426 tx_req,
427 capabilities,
428 diagnostics,
429 configs,
430 autostart,
431 }
432 }
433
434 fn run(mut self, rx_req: Receiver<Req>) {
435 for r in rx_req.into_iter() {
436 match r {
437 Req::Start {
438 ftype,
439 cmd,
440 args,
441 init_opts,
442 root,
443 open_docs,
444 } => self.start_client(ftype, cmd, args, init_opts, root, open_docs),
445 Req::Stop { lsp_id } => self.stop_client(lsp_id),
446 Req::Prepared(p) => self.handle_prepared_message(p),
447 Req::Message(LspMessage { lsp_id, msg }) => match msg {
448 Message::Request(r) => self.handle_request(lsp_id, r),
449 Message::Response(r) => self.handle_response(lsp_id, r),
450 Message::Notification(n) => self.handle_notification(lsp_id, n),
451 },
452 }
453 }
454 }
455
456 fn handle_prepared_message(&mut self, msg: PreparedMessage) {
457 match msg {
458 PreparedMessage::Request(mut req) => req.send(self),
459 PreparedMessage::Notification(mut notif) => notif.send(self),
460 }
461 }
462
463 fn handle_request(&mut self, lsp_id: usize, req: Request) {
464 use lsp_types::request as req;
465
466 RequestHandler {
467 lsp_id,
468 r: Some(req),
469 man: self,
470 }
471 .handle::<req::WorkDoneProgressCreate>()
472 .log_unhandled();
473 }
474
475 fn handle_response(&mut self, lsp_id: usize, res: Response) {
476 let mut p = match self.pending.remove(&(lsp_id, res.id())) {
477 Some(p) => p,
478 None => {
479 warn!("LSP - got response for unknown request: {res:?}");
480 return;
481 }
482 };
483
484 if let Some(actions) = p.handle(res, self)
485 && self.tx_events.send(Event::Actions(actions)).is_err()
486 {
487 error!("LSP - sender actions channel closed: exiting");
488 }
489 }
490
491 pub fn handle_notification(&mut self, lsp_id: usize, n: Notification) {
492 use lsp_types::notification as notif;
493
494 NotificationHandler {
495 lsp_id,
496 n: Some(n),
497 man: self,
498 }
499 .handle::<notif::Progress>()
500 .handle::<notif::PublishDiagnostics>()
501 .log_unhandled();
502 }
503
504 pub(super) fn progress_tokens(&mut self, lsp_id: usize) -> &mut HashMap<RequestId, String> {
505 self.progress_tokens.entry(lsp_id).or_default()
506 }
507
508 fn next_id(&mut self) -> usize {
509 let id = self.next_id;
510 self.next_id += 1;
511
512 id
513 }
514
515 fn send_status(&self, message: impl Into<String>) {
516 _ = self.tx_events.send(Event::Action(Action::SetStatusMessage {
517 message: message.into(),
518 }));
519 }
520
521 #[inline]
522 fn report_error(&self, message: impl Into<String>) {
523 let message = message.into();
524 error!("{message}");
525 self.send_status(message);
526 }
527
528 fn start_client(
529 &mut self,
530 ftype: String,
531 cmd: String,
532 args: Vec<String>,
533 init_opts: Option<serde_json::Value>,
534 root: String,
535 open_bufs: Vec<OpenDocument>,
536 ) {
537 let lsp_id = self.next_id();
538 match LspClient::new(lsp_id, &cmd, args, self.tx_req.clone()) {
539 Ok(client) => self.clients.insert(lsp_id, client),
540 Err(e) => {
541 return self.report_error(format!("failed to start LSP server: {e}"));
542 }
543 };
544
545 Initialize::send(lsp_id, (root, init_opts), (ftype, open_bufs), self);
546 self.send_status("LSP server started");
547 }
548
549 fn stop_client(&mut self, lsp_id: usize) {
550 use lsp_types::{notification::Exit, request::Shutdown};
551
552 Shutdown::send(lsp_id, (), (), self);
553 Exit::send(lsp_id, (), self);
554
555 match self.clients.remove(&lsp_id) {
556 Some(client) => client.join(),
557 None => self.report_error("no attached LSP server"),
558 }
559 }
560}
561
562#[derive(Debug, Clone)]
563pub(crate) struct Pos {
564 pub(crate) file: String,
565 pub(crate) line: u32,
566 pub(crate) character: u32,
567}
568
569impl Pos {
570 fn new(file: impl Into<String>, line: u32, character: u32) -> Self {
571 Self {
572 file: file.into(),
573 line,
574 character,
575 }
576 }
577}