From cb23399dee723cec67f1a04dbe6514dfddfd7f5f Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Sat, 9 Jul 2022 22:39:40 -0400 Subject: [PATCH] improve reliability of shutdown --- helix-term/src/application.rs | 72 +++++++++++++++++++++++--------- helix-term/src/commands/typed.rs | 8 +++- helix-view/src/document.rs | 17 +++++++- helix-view/src/editor.rs | 8 +++- 4 files changed, 80 insertions(+), 25 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index fd9b7c3e5..e84739cd8 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -937,26 +937,26 @@ impl Application { self.event_loop(input_stream).await; - let mut save_errs = Vec::new(); - - for doc in self.editor.documents_mut() { - if let Some(Err(err)) = doc.close().await { - save_errs.push(( - doc.path() - .map(|path| path.to_string_lossy().into_owned()) - .unwrap_or_else(|| "".into()), - err, - )); - } - } + // let mut save_errs = Vec::new(); + + // for doc in self.editor.documents_mut() { + // if let Some(Err(err)) = doc.close().await { + // save_errs.push(( + // doc.path() + // .map(|path| path.to_string_lossy().into_owned()) + // .unwrap_or_else(|| "".into()), + // err, + // )); + // } + // } let close_err = self.close().await.err(); restore_term()?; - for (path, err) in save_errs { - self.editor.exit_code = 1; - eprintln!("Error closing '{}': {}", path, err); - } + // for (path, err) in save_errs { + // self.editor.exit_code = 1; + // eprintln!("Error closing '{}': {}", path, err); + // } if let Some(err) = close_err { self.editor.exit_code = 1; @@ -967,12 +967,44 @@ impl Application { } pub async fn close(&mut self) -> anyhow::Result<()> { - self.jobs.finish().await?; + // [NOTE] we intentionally do not return early for errors because we + // want to try to run as much cleanup as we can, regardless of + // errors along the way - if self.editor.close_language_servers(None).await.is_err() { - log::error!("Timed out waiting for language servers to shutdown"); + let mut result = match self.jobs.finish().await { + Ok(_) => Ok(()), + Err(err) => { + log::error!("Error executing job: {}", err); + Err(err) + } }; - Ok(()) + for doc in self.editor.documents_mut() { + if let Some(save_result) = doc.close().await { + result = match save_result { + Ok(_) => result, + Err(err) => { + if let Some(path) = doc.path() { + log::error!( + "Error saving document '{}': {}", + path.to_string_lossy(), + err + ); + } + Err(err) + } + }; + } + } + + match self.editor.close_language_servers(None).await { + Ok(_) => result, + Err(_) => { + log::error!("Timed out waiting for language servers to shutdown"); + Err(anyhow::format_err!( + "Timed out waiting for language servers to shutdown" + )) + } + } } } diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 14b23f2ad..650ff75dc 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,5 +1,7 @@ use std::ops::Deref; +use crate::job::Job; + use super::*; use helix_view::{ @@ -19,6 +21,8 @@ pub struct TypableCommand { } fn quit(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> anyhow::Result<()> { + log::info!("quitting..."); + if event != PromptEvent::Validate { return Ok(()); } @@ -274,7 +278,7 @@ fn write_impl( doc.auto_format().map(|fmt| { let shared = fmt.shared(); let callback = make_format_callback(doc.id(), doc.version(), shared.clone()); - jobs.callback(callback); + jobs.add(Job::with_callback(callback).wait_before_exiting()); shared }) } else { @@ -512,8 +516,10 @@ fn write_quit( } write_impl(cx, args.first(), false)?; + let doc = doc_mut!(cx.editor); + tokio::task::block_in_place(|| helix_lsp::block_on(cx.jobs.finish()))?; tokio::task::block_in_place(|| helix_lsp::block_on(doc.try_flush_saves())) .map(|result| result.map(|_| ())) .unwrap_or(Ok(()))?; diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index b6e42065e..1743fac2b 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -551,6 +551,11 @@ impl Document { bail!("saves are closed for this document!"); } + log::debug!( + "submitting save of doc '{:?}'", + self.path().map(|path| path.to_string_lossy()) + ); + // we clone and move text + path into the future so that we asynchronously save the current // state without blocking any further edits. let mut text = self.text().clone(); @@ -695,7 +700,14 @@ impl Document { self.set_last_saved_revision(event.revision); false } - Err(_) => true, + Err(err) => { + log::error!( + "error saving document {:?}: {}", + self.path().map(|path| path.to_string_lossy()), + err + ); + true + } }; final_result = Some(save_event); @@ -1072,7 +1084,8 @@ impl Document { let current_revision = history.current_revision(); self.history.set(history); log::debug!( - "modified - last saved: {}, current: {}", + "id {} modified - last saved: {}, current: {}", + self.id, self.last_saved_revision, current_revision ); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index e54aa7fa5..58fcf238f 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -816,12 +816,16 @@ impl Editor { #[inline] pub fn set_status>>(&mut self, status: T) { - self.status_msg = Some((status.into(), Severity::Info)); + let status = status.into(); + log::debug!("editor status: {}", status); + self.status_msg = Some((status, Severity::Info)); } #[inline] pub fn set_error>>(&mut self, error: T) { - self.status_msg = Some((error.into(), Severity::Error)); + let error = error.into(); + log::error!("editor error: {}", error); + self.status_msg = Some((error, Severity::Error)); } #[inline]