]> git.lizzy.rs Git - rust.git/blob - crates/ra_lsp_server/src/main_loop.rs
379dab4384f10eaec459cdcbc51ce5504b16f5ab
[rust.git] / crates / ra_lsp_server / src / main_loop.rs
1 //! FIXME: write short doc here
2
3 mod handlers;
4 mod subscriptions;
5 pub(crate) mod pending_requests;
6
7 use std::{error::Error, fmt, panic, path::PathBuf, sync::Arc, time::Instant};
8
9 use crossbeam_channel::{select, unbounded, RecvError, Sender};
10 use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
11 use lsp_types::{ClientCapabilities, NumberOrString};
12 use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
13 use ra_prof::profile;
14 use ra_vfs::{VfsTask, Watch};
15 use relative_path::RelativePathBuf;
16 use rustc_hash::FxHashSet;
17 use serde::{de::DeserializeOwned, Serialize};
18 use threadpool::ThreadPool;
19
20 use crate::{
21     main_loop::{
22         pending_requests::{PendingRequest, PendingRequests},
23         subscriptions::Subscriptions,
24     },
25     req,
26     world::{Options, WorldSnapshot, WorldState},
27     Result, ServerConfig,
28 };
29
30 const THREADPOOL_SIZE: usize = 8;
31 const MAX_IN_FLIGHT_LIBS: usize = THREADPOOL_SIZE - 3;
32
33 #[derive(Debug)]
34 pub struct LspError {
35     pub code: i32,
36     pub message: String,
37 }
38
39 impl LspError {
40     pub fn new(code: i32, message: String) -> LspError {
41         LspError { code, message }
42     }
43 }
44
45 impl fmt::Display for LspError {
46     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
47         write!(f, "Language Server request failed with {}. ({})", self.code, self.message)
48     }
49 }
50
51 impl Error for LspError {}
52
53 pub fn main_loop(
54     ws_roots: Vec<PathBuf>,
55     client_caps: ClientCapabilities,
56     config: ServerConfig,
57     connection: Connection,
58 ) -> Result<()> {
59     log::info!("server_config: {:#?}", config);
60
61     let mut loop_state = LoopState::default();
62     let mut world_state = {
63         // FIXME: support dynamic workspace loading.
64         let workspaces = {
65             let mut loaded_workspaces = Vec::new();
66             for ws_root in &ws_roots {
67                 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
68                     ws_root.as_path(),
69                     config.with_sysroot,
70                 );
71                 match workspace {
72                     Ok(workspace) => loaded_workspaces.push(workspace),
73                     Err(e) => {
74                         log::error!("loading workspace failed: {}", e);
75
76                         show_message(
77                             req::MessageType::Error,
78                             format!("rust-analyzer failed to load workspace: {}", e),
79                             &connection.sender,
80                         );
81                     }
82                 }
83             }
84             loaded_workspaces
85         };
86
87         let globs = config
88             .exclude_globs
89             .iter()
90             .map(|glob| ra_vfs_glob::Glob::new(glob))
91             .collect::<std::result::Result<Vec<_>, _>>()?;
92
93         if config.use_client_watching {
94             let registration_options = req::DidChangeWatchedFilesRegistrationOptions {
95                 watchers: workspaces
96                     .iter()
97                     .flat_map(|ws| ws.to_roots())
98                     .filter(|root| root.is_member())
99                     .map(|root| format!("{}/**/*.rs", root.path().display()))
100                     .map(|glob_pattern| req::FileSystemWatcher { glob_pattern, kind: None })
101                     .collect(),
102             };
103             let registration = req::Registration {
104                 id: "file-watcher".to_string(),
105                 method: "workspace/didChangeWatchedFiles".to_string(),
106                 register_options: Some(serde_json::to_value(registration_options).unwrap()),
107             };
108             let params = req::RegistrationParams { registrations: vec![registration] };
109             let request =
110                 request_new::<req::RegisterCapability>(loop_state.next_request_id(), params);
111             connection.sender.send(request.into()).unwrap();
112         }
113
114         let options = {
115             let text_document_caps = client_caps.text_document.as_ref();
116             Options {
117                 publish_decorations: config.publish_decorations,
118                 supports_location_link: text_document_caps
119                     .and_then(|it| it.definition)
120                     .and_then(|it| it.link_support)
121                     .unwrap_or(false),
122                 line_folding_only: text_document_caps
123                     .and_then(|it| it.folding_range.as_ref())
124                     .and_then(|it| it.line_folding_only)
125                     .unwrap_or(false),
126             }
127         };
128
129         let feature_flags = {
130             let mut ff = FeatureFlags::default();
131             for (flag, value) in config.feature_flags {
132                 if let Err(_) = ff.set(flag.as_str(), value) {
133                     log::error!("unknown feature flag: {:?}", flag);
134                     show_message(
135                         req::MessageType::Error,
136                         format!("unknown feature flag: {:?}", flag),
137                         &connection.sender,
138                     );
139                 }
140             }
141             ff
142         };
143         log::info!("feature_flags: {:#?}", feature_flags);
144
145         WorldState::new(
146             ws_roots,
147             workspaces,
148             config.lru_capacity,
149             &globs,
150             Watch(!config.use_client_watching),
151             options,
152             feature_flags,
153         )
154     };
155
156     let pool = ThreadPool::new(THREADPOOL_SIZE);
157     let (task_sender, task_receiver) = unbounded::<Task>();
158     let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
159
160     log::info!("server initialized, serving requests");
161     {
162         let task_sender = task_sender;
163         let libdata_sender = libdata_sender;
164         loop {
165             log::trace!("selecting");
166             let event = select! {
167                 recv(&connection.receiver) -> msg => match msg {
168                     Ok(msg) => Event::Msg(msg),
169                     Err(RecvError) => Err("client exited without shutdown")?,
170                 },
171                 recv(task_receiver) -> task => Event::Task(task.unwrap()),
172                 recv(world_state.task_receiver) -> task => match task {
173                     Ok(task) => Event::Vfs(task),
174                     Err(RecvError) => Err("vfs died")?,
175                 },
176                 recv(libdata_receiver) -> data => Event::Lib(data.unwrap())
177             };
178             if let Event::Msg(Message::Request(req)) = &event {
179                 if connection.handle_shutdown(&req)? {
180                     break;
181                 };
182             }
183             loop_turn(
184                 &pool,
185                 &task_sender,
186                 &libdata_sender,
187                 &connection,
188                 &mut world_state,
189                 &mut loop_state,
190                 event,
191             )?;
192         }
193     }
194
195     log::info!("waiting for tasks to finish...");
196     task_receiver.into_iter().for_each(|task| {
197         on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state)
198     });
199     libdata_receiver.into_iter().for_each(drop);
200     log::info!("...tasks have finished");
201     log::info!("joining threadpool...");
202     drop(pool);
203     log::info!("...threadpool has finished");
204
205     let vfs = Arc::try_unwrap(world_state.vfs).expect("all snapshots should be dead");
206     drop(vfs);
207
208     Ok(())
209 }
210
211 #[derive(Debug)]
212 enum Task {
213     Respond(Response),
214     Notify(Notification),
215 }
216
217 enum Event {
218     Msg(Message),
219     Task(Task),
220     Vfs(VfsTask),
221     Lib(LibraryData),
222 }
223
224 impl fmt::Debug for Event {
225     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226         let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter| {
227             f.debug_struct("Notification").field("method", &not.method).finish()
228         };
229
230         match self {
231             Event::Msg(Message::Notification(not)) => {
232                 if notification_is::<req::DidOpenTextDocument>(not)
233                     || notification_is::<req::DidChangeTextDocument>(not)
234                 {
235                     return debug_verbose_not(not, f);
236                 }
237             }
238             Event::Task(Task::Notify(not)) => {
239                 if notification_is::<req::PublishDecorations>(not)
240                     || notification_is::<req::PublishDiagnostics>(not)
241                 {
242                     return debug_verbose_not(not, f);
243                 }
244             }
245             Event::Task(Task::Respond(resp)) => {
246                 return f
247                     .debug_struct("Response")
248                     .field("id", &resp.id)
249                     .field("error", &resp.error)
250                     .finish();
251             }
252             _ => (),
253         }
254         match self {
255             Event::Msg(it) => fmt::Debug::fmt(it, f),
256             Event::Task(it) => fmt::Debug::fmt(it, f),
257             Event::Vfs(it) => fmt::Debug::fmt(it, f),
258             Event::Lib(it) => fmt::Debug::fmt(it, f),
259         }
260     }
261 }
262
263 #[derive(Debug, Default)]
264 struct LoopState {
265     next_request_id: u64,
266     pending_responses: FxHashSet<RequestId>,
267     pending_requests: PendingRequests,
268     subscriptions: Subscriptions,
269     // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same
270     // time to always have a thread ready to react to input.
271     in_flight_libraries: usize,
272     pending_libraries: Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>,
273     workspace_loaded: bool,
274 }
275
276 impl LoopState {
277     fn next_request_id(&mut self) -> RequestId {
278         self.next_request_id += 1;
279         let res: RequestId = self.next_request_id.into();
280         let inserted = self.pending_responses.insert(res.clone());
281         assert!(inserted);
282         res
283     }
284 }
285
286 fn loop_turn(
287     pool: &ThreadPool,
288     task_sender: &Sender<Task>,
289     libdata_sender: &Sender<LibraryData>,
290     connection: &Connection,
291     world_state: &mut WorldState,
292     loop_state: &mut LoopState,
293     event: Event,
294 ) -> Result<()> {
295     let loop_start = Instant::now();
296
297     // NOTE: don't count blocking select! call as a loop-turn time
298     let _p = profile("main_loop_inner/loop-turn");
299     log::info!("loop turn = {:?}", event);
300     let queue_count = pool.queued_count();
301     if queue_count > 0 {
302         log::info!("queued count = {}", queue_count);
303     }
304
305     let mut state_changed = false;
306     match event {
307         Event::Task(task) => {
308             on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state);
309             world_state.maybe_collect_garbage();
310         }
311         Event::Vfs(task) => {
312             world_state.vfs.write().handle_task(task);
313             state_changed = true;
314         }
315         Event::Lib(lib) => {
316             world_state.add_lib(lib);
317             world_state.maybe_collect_garbage();
318             loop_state.in_flight_libraries -= 1;
319         }
320         Event::Msg(msg) => match msg {
321             Message::Request(req) => on_request(
322                 world_state,
323                 &mut loop_state.pending_requests,
324                 pool,
325                 task_sender,
326                 &connection.sender,
327                 loop_start,
328                 req,
329             )?,
330             Message::Notification(not) => {
331                 on_notification(
332                     &connection.sender,
333                     world_state,
334                     &mut loop_state.pending_requests,
335                     &mut loop_state.subscriptions,
336                     not,
337                 )?;
338                 state_changed = true;
339             }
340             Message::Response(resp) => {
341                 let removed = loop_state.pending_responses.remove(&resp.id);
342                 if !removed {
343                     log::error!("unexpected response: {:?}", resp)
344                 }
345             }
346         },
347     };
348
349     loop_state.pending_libraries.extend(world_state.process_changes());
350     while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS
351         && !loop_state.pending_libraries.is_empty()
352     {
353         let (root, files) = loop_state.pending_libraries.pop().unwrap();
354         loop_state.in_flight_libraries += 1;
355         let sender = libdata_sender.clone();
356         pool.execute(move || {
357             log::info!("indexing {:?} ... ", root);
358             let _p = profile(&format!("indexed {:?}", root));
359             let data = LibraryData::prepare(root, files);
360             sender.send(data).unwrap();
361         });
362     }
363
364     if !loop_state.workspace_loaded
365         && world_state.roots_to_scan == 0
366         && loop_state.pending_libraries.is_empty()
367         && loop_state.in_flight_libraries == 0
368     {
369         loop_state.workspace_loaded = true;
370         let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum();
371         if world_state.feature_flags().get("notifications.workspace-loaded") {
372             let msg = format!("workspace loaded, {} rust packages", n_packages);
373             show_message(req::MessageType::Info, msg, &connection.sender);
374         }
375     }
376
377     if state_changed {
378         update_file_notifications_on_threadpool(
379             pool,
380             world_state.snapshot(),
381             world_state.options.publish_decorations,
382             task_sender.clone(),
383             loop_state.subscriptions.subscriptions(),
384         )
385     }
386     Ok(())
387 }
388
389 fn on_task(
390     task: Task,
391     msg_sender: &Sender<Message>,
392     pending_requests: &mut PendingRequests,
393     state: &mut WorldState,
394 ) {
395     match task {
396         Task::Respond(response) => {
397             if let Some(completed) = pending_requests.finish(&response.id) {
398                 log::info!("handled req#{} in {:?}", completed.id, completed.duration);
399                 state.complete_request(completed);
400                 msg_sender.send(response.into()).unwrap();
401             }
402         }
403         Task::Notify(n) => {
404             msg_sender.send(n.into()).unwrap();
405         }
406     }
407 }
408
409 fn on_request(
410     world: &mut WorldState,
411     pending_requests: &mut PendingRequests,
412     pool: &ThreadPool,
413     sender: &Sender<Task>,
414     msg_sender: &Sender<Message>,
415     request_received: Instant,
416     req: Request,
417 ) -> Result<()> {
418     let mut pool_dispatcher = PoolDispatcher {
419         req: Some(req),
420         pool,
421         world,
422         sender,
423         msg_sender,
424         pending_requests,
425         request_received,
426     };
427     pool_dispatcher
428         .on_sync::<req::CollectGarbage>(|s, ()| Ok(s.collect_garbage()))?
429         .on_sync::<req::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
430         .on_sync::<req::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
431         .on_sync::<req::SelectionRangeRequest>(|s, p| {
432             handlers::handle_selection_range(s.snapshot(), p)
433         })?
434         .on_sync::<req::FindMatchingBrace>(|s, p| {
435             handlers::handle_find_matching_brace(s.snapshot(), p)
436         })?
437         .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)?
438         .on::<req::SyntaxTree>(handlers::handle_syntax_tree)?
439         .on::<req::OnTypeFormatting>(handlers::handle_on_type_formatting)?
440         .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)?
441         .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)?
442         .on::<req::GotoDefinition>(handlers::handle_goto_definition)?
443         .on::<req::GotoImplementation>(handlers::handle_goto_implementation)?
444         .on::<req::GotoTypeDefinition>(handlers::handle_goto_type_definition)?
445         .on::<req::ParentModule>(handlers::handle_parent_module)?
446         .on::<req::Runnables>(handlers::handle_runnables)?
447         .on::<req::DecorationsRequest>(handlers::handle_decorations)?
448         .on::<req::Completion>(handlers::handle_completion)?
449         .on::<req::CodeActionRequest>(handlers::handle_code_action)?
450         .on::<req::CodeLensRequest>(handlers::handle_code_lens)?
451         .on::<req::CodeLensResolve>(handlers::handle_code_lens_resolve)?
452         .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
453         .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
454         .on::<req::HoverRequest>(handlers::handle_hover)?
455         .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
456         .on::<req::Rename>(handlers::handle_rename)?
457         .on::<req::References>(handlers::handle_references)?
458         .on::<req::Formatting>(handlers::handle_formatting)?
459         .on::<req::DocumentHighlightRequest>(handlers::handle_document_highlight)?
460         .on::<req::InlayHints>(handlers::handle_inlay_hints)?
461         .finish();
462     Ok(())
463 }
464
465 fn on_notification(
466     msg_sender: &Sender<Message>,
467     state: &mut WorldState,
468     pending_requests: &mut PendingRequests,
469     subs: &mut Subscriptions,
470     not: Notification,
471 ) -> Result<()> {
472     let not = match notification_cast::<req::Cancel>(not) {
473         Ok(params) => {
474             let id: RequestId = match params.id {
475                 NumberOrString::Number(id) => id.into(),
476                 NumberOrString::String(id) => id.into(),
477             };
478             if pending_requests.cancel(&id) {
479                 let response = Response::new_err(
480                     id,
481                     ErrorCode::RequestCanceled as i32,
482                     "canceled by client".to_string(),
483                 );
484                 msg_sender.send(response.into()).unwrap()
485             }
486             return Ok(());
487         }
488         Err(not) => not,
489     };
490     let not = match notification_cast::<req::DidOpenTextDocument>(not) {
491         Ok(params) => {
492             let uri = params.text_document.uri;
493             let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
494             if let Some(file_id) =
495                 state.vfs.write().add_file_overlay(&path, params.text_document.text)
496             {
497                 subs.add_sub(FileId(file_id.0));
498             }
499             return Ok(());
500         }
501         Err(not) => not,
502     };
503     let not = match notification_cast::<req::DidChangeTextDocument>(not) {
504         Ok(mut params) => {
505             let uri = params.text_document.uri;
506             let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
507             let text =
508                 params.content_changes.pop().ok_or_else(|| "empty changes".to_string())?.text;
509             state.vfs.write().change_file_overlay(path.as_path(), text);
510             return Ok(());
511         }
512         Err(not) => not,
513     };
514     let not = match notification_cast::<req::DidCloseTextDocument>(not) {
515         Ok(params) => {
516             let uri = params.text_document.uri;
517             let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
518             if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
519                 subs.remove_sub(FileId(file_id.0));
520             }
521             let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() };
522             let not = notification_new::<req::PublishDiagnostics>(params);
523             msg_sender.send(not.into()).unwrap();
524             return Ok(());
525         }
526         Err(not) => not,
527     };
528     let not = match notification_cast::<req::DidChangeConfiguration>(not) {
529         Ok(_params) => {
530             return Ok(());
531         }
532         Err(not) => not,
533     };
534     let not = match notification_cast::<req::DidChangeWatchedFiles>(not) {
535         Ok(params) => {
536             let mut vfs = state.vfs.write();
537             for change in params.changes {
538                 let uri = change.uri;
539                 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
540                 vfs.notify_changed(path)
541             }
542             return Ok(());
543         }
544         Err(not) => not,
545     };
546     log::error!("unhandled notification: {:?}", not);
547     Ok(())
548 }
549
550 struct PoolDispatcher<'a> {
551     req: Option<Request>,
552     pool: &'a ThreadPool,
553     world: &'a mut WorldState,
554     pending_requests: &'a mut PendingRequests,
555     msg_sender: &'a Sender<Message>,
556     sender: &'a Sender<Task>,
557     request_received: Instant,
558 }
559
560 impl<'a> PoolDispatcher<'a> {
561     /// Dispatches the request onto the current thread
562     fn on_sync<R>(
563         &mut self,
564         f: fn(&mut WorldState, R::Params) -> Result<R::Result>,
565     ) -> Result<&mut Self>
566     where
567         R: req::Request + 'static,
568         R::Params: DeserializeOwned + panic::UnwindSafe + 'static,
569         R::Result: Serialize + 'static,
570     {
571         let (id, params) = match self.parse::<R>() {
572             Some(it) => it,
573             None => {
574                 return Ok(self);
575             }
576         };
577         let world = panic::AssertUnwindSafe(&mut *self.world);
578         let task = panic::catch_unwind(move || {
579             let result = f(world.0, params);
580             result_to_task::<R>(id, result)
581         })
582         .map_err(|_| format!("sync task {:?} panicked", R::METHOD))?;
583         on_task(task, self.msg_sender, self.pending_requests, self.world);
584         Ok(self)
585     }
586
587     /// Dispatches the request onto thread pool
588     fn on<R>(&mut self, f: fn(WorldSnapshot, R::Params) -> Result<R::Result>) -> Result<&mut Self>
589     where
590         R: req::Request + 'static,
591         R::Params: DeserializeOwned + Send + 'static,
592         R::Result: Serialize + 'static,
593     {
594         let (id, params) = match self.parse::<R>() {
595             Some(it) => it,
596             None => {
597                 return Ok(self);
598             }
599         };
600
601         self.pool.execute({
602             let world = self.world.snapshot();
603             let sender = self.sender.clone();
604             move || {
605                 let result = f(world, params);
606                 let task = result_to_task::<R>(id, result);
607                 sender.send(task).unwrap();
608             }
609         });
610
611         Ok(self)
612     }
613
614     fn parse<R>(&mut self) -> Option<(RequestId, R::Params)>
615     where
616         R: req::Request + 'static,
617         R::Params: DeserializeOwned + 'static,
618     {
619         let req = self.req.take()?;
620         let (id, params) = match req.extract::<R::Params>(R::METHOD) {
621             Ok(it) => it,
622             Err(req) => {
623                 self.req = Some(req);
624                 return None;
625             }
626         };
627         self.pending_requests.start(PendingRequest {
628             id: id.clone(),
629             method: R::METHOD.to_string(),
630             received: self.request_received,
631         });
632         Some((id, params))
633     }
634
635     fn finish(&mut self) {
636         match self.req.take() {
637             None => (),
638             Some(req) => {
639                 log::error!("unknown request: {:?}", req);
640                 let resp = Response::new_err(
641                     req.id,
642                     ErrorCode::MethodNotFound as i32,
643                     "unknown request".to_string(),
644                 );
645                 self.msg_sender.send(resp.into()).unwrap();
646             }
647         }
648     }
649 }
650
651 fn result_to_task<R>(id: RequestId, result: Result<R::Result>) -> Task
652 where
653     R: req::Request + 'static,
654     R::Params: DeserializeOwned + 'static,
655     R::Result: Serialize + 'static,
656 {
657     let response = match result {
658         Ok(resp) => Response::new_ok(id, &resp),
659         Err(e) => match e.downcast::<LspError>() {
660             Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message),
661             Err(e) => {
662                 if is_canceled(&e) {
663                     // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457
664                     // gets fixed, we can return the proper response.
665                     // This works around the issue where "content modified" error would continuously
666                     // show an message pop-up in VsCode
667                     // Response::err(
668                     //     id,
669                     //     ErrorCode::ContentModified as i32,
670                     //     "content modified".to_string(),
671                     // )
672                     Response::new_ok(id, ())
673                 } else {
674                     Response::new_err(id, ErrorCode::InternalError as i32, e.to_string())
675                 }
676             }
677         },
678     };
679     Task::Respond(response)
680 }
681
682 fn update_file_notifications_on_threadpool(
683     pool: &ThreadPool,
684     world: WorldSnapshot,
685     publish_decorations: bool,
686     sender: Sender<Task>,
687     subscriptions: Vec<FileId>,
688 ) {
689     log::trace!("updating notifications for {:?}", subscriptions);
690     let publish_diagnostics = world.feature_flags().get("lsp.diagnostics");
691     pool.execute(move || {
692         for file_id in subscriptions {
693             if publish_diagnostics {
694                 match handlers::publish_diagnostics(&world, file_id) {
695                     Err(e) => {
696                         if !is_canceled(&e) {
697                             log::error!("failed to compute diagnostics: {:?}", e);
698                         }
699                     }
700                     Ok(params) => {
701                         let not = notification_new::<req::PublishDiagnostics>(params);
702                         sender.send(Task::Notify(not)).unwrap();
703                     }
704                 }
705             }
706             if publish_decorations {
707                 match handlers::publish_decorations(&world, file_id) {
708                     Err(e) => {
709                         if !is_canceled(&e) {
710                             log::error!("failed to compute decorations: {:?}", e);
711                         }
712                     }
713                     Ok(params) => {
714                         let not = notification_new::<req::PublishDecorations>(params);
715                         sender.send(Task::Notify(not)).unwrap();
716                     }
717                 }
718             }
719         }
720     });
721 }
722
723 pub fn show_message(typ: req::MessageType, message: impl Into<String>, sender: &Sender<Message>) {
724     let message = message.into();
725     let params = req::ShowMessageParams { typ, message };
726     let not = notification_new::<req::ShowMessage>(params);
727     sender.send(not.into()).unwrap();
728 }
729
730 fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool {
731     e.downcast_ref::<Canceled>().is_some()
732 }
733
734 fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool {
735     notification.method == N::METHOD
736 }
737
738 fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification>
739 where
740     N: lsp_types::notification::Notification,
741     N::Params: DeserializeOwned,
742 {
743     notification.extract(N::METHOD)
744 }
745
746 fn notification_new<N>(params: N::Params) -> Notification
747 where
748     N: lsp_types::notification::Notification,
749     N::Params: Serialize,
750 {
751     Notification::new(N::METHOD.to_string(), params)
752 }
753
754 fn request_new<R>(id: RequestId, params: R::Params) -> Request
755 where
756     R: lsp_types::request::Request,
757     R::Params: Serialize,
758 {
759     Request::new(id, R::METHOD.to_string(), params)
760 }