From 7929c0719d739e248adfd80cd7e5b8e386a43938 Mon Sep 17 00:00:00 2001 From: Keir Lawson Date: Thu, 27 Mar 2025 17:00:23 +0000 Subject: [PATCH] Track progress title an display in place of internal token (#13180) Co-authored-by: Michael Davis --- helix-lsp/src/lib.rs | 44 ++++++++++++++++--- helix-term/src/application.rs | 81 +++++++++++++++++------------------ 2 files changed, 77 insertions(+), 48 deletions(-) diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index ba41cbc5a..1a2557de2 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -733,14 +733,17 @@ impl Registry { #[derive(Debug)] pub enum ProgressStatus { Created, - Started(lsp::WorkDoneProgress), + Started { + title: String, + progress: lsp::WorkDoneProgress, + }, } impl ProgressStatus { pub fn progress(&self) -> Option<&lsp::WorkDoneProgress> { match &self { ProgressStatus::Created => None, - ProgressStatus::Started(progress) => Some(progress), + ProgressStatus::Started { title: _, progress } => Some(progress), } } } @@ -777,6 +780,13 @@ impl LspProgressMap { self.0.get(&id).and_then(|values| values.get(token)) } + pub fn title(&self, id: LanguageServerId, token: &lsp::ProgressToken) -> Option<&String> { + self.progress(id, token).and_then(|p| match p { + ProgressStatus::Created => None, + ProgressStatus::Started { title, .. } => Some(title), + }) + } + /// Checks if progress `token` for server with `id` is created. pub fn is_created(&mut self, id: LanguageServerId, token: &lsp::ProgressToken) -> bool { self.0 @@ -801,17 +811,39 @@ impl LspProgressMap { self.0.get_mut(&id).and_then(|vals| vals.remove(token)) } - /// Updates the progress of `token` for server with `id` to `status`, returns the value replaced or `None`. + /// Updates the progress of `token` for server with `id` to begin state `status` + pub fn begin( + &mut self, + id: LanguageServerId, + token: lsp::ProgressToken, + status: lsp::WorkDoneProgressBegin, + ) { + self.0.entry(id).or_default().insert( + token, + ProgressStatus::Started { + title: status.title.clone(), + progress: lsp::WorkDoneProgress::Begin(status), + }, + ); + } + + /// Updates the progress of `token` for server with `id` to report state `status`. pub fn update( &mut self, id: LanguageServerId, token: lsp::ProgressToken, - status: lsp::WorkDoneProgress, - ) -> Option { + status: lsp::WorkDoneProgressReport, + ) { self.0 .entry(id) .or_default() - .insert(token, ProgressStatus::Started(status)) + .entry(token) + .and_modify(|e| match e { + ProgressStatus::Created => (), + ProgressStatus::Started { progress, .. } => { + *progress = lsp::WorkDoneProgress::Report(status) + } + }); } } diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 3bc324395..16a26cb26 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -756,10 +756,11 @@ impl Application { .compositor .find::() .expect("expected at least one EditorView"); - let lsp::ProgressParams { token, value } = params; - - let lsp::ProgressParamsValue::WorkDone(work) = value; - let parts = match &work { + let lsp::ProgressParams { + token, + value: lsp::ProgressParamsValue::WorkDone(work), + } = params; + let (title, message, percentage) = match &work { lsp::WorkDoneProgress::Begin(lsp::WorkDoneProgressBegin { title, message, @@ -787,47 +788,43 @@ impl Application { } }; - let token_d: &dyn std::fmt::Display = match &token { - lsp::NumberOrString::Number(n) => n, - lsp::NumberOrString::String(s) => s, - }; - - let status = match parts { - (Some(title), Some(message), Some(percentage)) => { - format!("[{}] {}% {} - {}", token_d, percentage, title, message) + if self.editor.config().lsp.display_progress_messages { + let title = + title.or_else(|| self.lsp_progress.title(server_id, &token)); + if title.is_some() || percentage.is_some() || message.is_some() { + use std::fmt::Write as _; + let mut status = format!("{}: ", language_server!().name()); + if let Some(percentage) = percentage { + write!(status, "{percentage:>2}% ").unwrap(); + } + if let Some(title) = title { + status.push_str(title); + } + if title.is_some() && message.is_some() { + status.push_str(" ⋅ "); + } + if let Some(message) = message { + status.push_str(message); + } + self.editor.set_status(status); } - (Some(title), None, Some(percentage)) => { - format!("[{}] {}% {}", token_d, percentage, title) - } - (Some(title), Some(message), None) => { - format!("[{}] {} - {}", token_d, title, message) - } - (None, Some(message), Some(percentage)) => { - format!("[{}] {}% {}", token_d, percentage, message) - } - (Some(title), None, None) => { - format!("[{}] {}", token_d, title) - } - (None, Some(message), None) => { - format!("[{}] {}", token_d, message) - } - (None, None, Some(percentage)) => { - format!("[{}] {}%", token_d, percentage) - } - (None, None, None) => format!("[{}]", token_d), - }; - - if let lsp::WorkDoneProgress::End(_) = work { - self.lsp_progress.end_progress(server_id, &token); - if !self.lsp_progress.is_progressing(server_id) { - editor_view.spinners_mut().get_or_create(server_id).stop(); - } - } else { - self.lsp_progress.update(server_id, token, work); } - if self.config.load().editor.lsp.display_progress_messages { - self.editor.set_status(status); + match work { + lsp::WorkDoneProgress::Begin(begin_status) => { + self.lsp_progress + .begin(server_id, token.clone(), begin_status); + } + lsp::WorkDoneProgress::Report(report_status) => { + self.lsp_progress + .update(server_id, token.clone(), report_status); + } + lsp::WorkDoneProgress::End(_) => { + self.lsp_progress.end_progress(server_id, &token); + if !self.lsp_progress.is_progressing(server_id) { + editor_view.spinners_mut().get_or_create(server_id).stop(); + }; + } } } Notification::ProgressMessage(_params) => {