⭐️ A friendly language for building type-safe, scalable systems!
at main 3.5 kB view raw
1use debug_ignore::DebugIgnore; 2use lsp_types::{ 3 InitializeParams, NumberOrString, ProgressParams, ProgressParamsValue, WorkDoneProgress, 4 WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, 5}; 6 7const DOWNLOADING_TOKEN: &str = "downloading-dependencies"; 8 9pub trait ProgressReporter { 10 fn compilation_started(&self); 11 fn compilation_finished(&self); 12 fn dependency_downloading_started(&self); 13 fn dependency_downloading_finished(&self); 14} 15 16// Used to publish progress notifications to the client without waiting for 17// the usual request-response loop of the language server. 18#[derive(Debug, Clone)] 19pub struct ConnectionProgressReporter<'a> { 20 connection: DebugIgnore<&'a lsp_server::Connection>, 21} 22 23impl<'a> ConnectionProgressReporter<'a> { 24 pub fn new( 25 connection: &'a lsp_server::Connection, 26 // We don't actually need these but we take them anyway to ensure that 27 // this object is only created after the server has been initialised. 28 // If it was created before then the creation of the progress token 29 // would fail. 30 _initialise_params: &InitializeParams, 31 ) -> Self { 32 create_token(DOWNLOADING_TOKEN, connection); 33 Self { 34 connection: connection.into(), 35 } 36 } 37 38 fn send_notification(&self, token: &str, work_done: WorkDoneProgress) { 39 let params = ProgressParams { 40 token: NumberOrString::String(token.to_string()), 41 value: ProgressParamsValue::WorkDone(work_done), 42 }; 43 let notification = lsp_server::Notification { 44 method: "$/progress".into(), 45 params: serde_json::to_value(params).expect("ProgressParams json"), 46 }; 47 self.connection 48 .sender 49 .send(lsp_server::Message::Notification(notification)) 50 .expect("send_work_done_notification send") 51 } 52} 53 54impl ProgressReporter for ConnectionProgressReporter<'_> { 55 fn compilation_started(&self) { 56 // Do nothing. This is only used for tests currently. 57 // In future we could make this emit a message to the client if compilation is taking a 58 // long time. 59 } 60 61 fn compilation_finished(&self) { 62 // Do nothing. This is only used for tests currently. 63 } 64 65 fn dependency_downloading_started(&self) { 66 let title = "Downloading Gleam dependencies"; 67 self.send_notification(DOWNLOADING_TOKEN, begin_message(title)); 68 } 69 70 fn dependency_downloading_finished(&self) { 71 self.send_notification(DOWNLOADING_TOKEN, end_message()); 72 } 73} 74 75fn end_message() -> WorkDoneProgress { 76 WorkDoneProgress::End(WorkDoneProgressEnd { message: None }) 77} 78 79fn begin_message(title: &str) -> WorkDoneProgress { 80 WorkDoneProgress::Begin(WorkDoneProgressBegin { 81 title: title.into(), 82 cancellable: Some(false), 83 message: None, 84 percentage: None, 85 }) 86} 87 88fn create_token(token: &str, connection: &lsp_server::Connection) { 89 let params = WorkDoneProgressCreateParams { 90 token: NumberOrString::String(token.into()), 91 }; 92 let request = lsp_server::Request { 93 id: format!("create-token--{token}").into(), 94 method: "window/workDoneProgress/create".into(), 95 params: serde_json::to_value(params).expect("WorkDoneProgressCreateParams json"), 96 }; 97 connection 98 .sender 99 .send(lsp_server::Message::Request(request)) 100 .expect("WorkDoneProgressCreate"); 101}