improve reliability of shutdown

pull/2267/head
Skyler Hawthorne 2 years ago
parent b8a07f7d15
commit cb23399dee

@ -937,26 +937,26 @@ impl Application {
self.event_loop(input_stream).await; self.event_loop(input_stream).await;
let mut save_errs = Vec::new(); // let mut save_errs = Vec::new();
for doc in self.editor.documents_mut() { // for doc in self.editor.documents_mut() {
if let Some(Err(err)) = doc.close().await { // if let Some(Err(err)) = doc.close().await {
save_errs.push(( // save_errs.push((
doc.path() // doc.path()
.map(|path| path.to_string_lossy().into_owned()) // .map(|path| path.to_string_lossy().into_owned())
.unwrap_or_else(|| "".into()), // .unwrap_or_else(|| "".into()),
err, // err,
)); // ));
} // }
} // }
let close_err = self.close().await.err(); let close_err = self.close().await.err();
restore_term()?; restore_term()?;
for (path, err) in save_errs { // for (path, err) in save_errs {
self.editor.exit_code = 1; // self.editor.exit_code = 1;
eprintln!("Error closing '{}': {}", path, err); // eprintln!("Error closing '{}': {}", path, err);
} // }
if let Some(err) = close_err { if let Some(err) = close_err {
self.editor.exit_code = 1; self.editor.exit_code = 1;
@ -967,12 +967,44 @@ impl Application {
} }
pub async fn close(&mut self) -> anyhow::Result<()> { 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() { let mut result = match self.jobs.finish().await {
log::error!("Timed out waiting for language servers to shutdown"); 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"
))
}
}
} }
} }

@ -1,5 +1,7 @@
use std::ops::Deref; use std::ops::Deref;
use crate::job::Job;
use super::*; use super::*;
use helix_view::{ use helix_view::{
@ -19,6 +21,8 @@ pub struct TypableCommand {
} }
fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> { fn quit(cx: &mut compositor::Context, args: &[Cow<str>], event: PromptEvent) -> anyhow::Result<()> {
log::info!("quitting...");
if event != PromptEvent::Validate { if event != PromptEvent::Validate {
return Ok(()); return Ok(());
} }
@ -274,7 +278,7 @@ fn write_impl(
doc.auto_format().map(|fmt| { doc.auto_format().map(|fmt| {
let shared = fmt.shared(); let shared = fmt.shared();
let callback = make_format_callback(doc.id(), doc.version(), shared.clone()); let callback = make_format_callback(doc.id(), doc.version(), shared.clone());
jobs.callback(callback); jobs.add(Job::with_callback(callback).wait_before_exiting());
shared shared
}) })
} else { } else {
@ -512,8 +516,10 @@ fn write_quit(
} }
write_impl(cx, args.first(), false)?; write_impl(cx, args.first(), false)?;
let doc = doc_mut!(cx.editor); 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())) tokio::task::block_in_place(|| helix_lsp::block_on(doc.try_flush_saves()))
.map(|result| result.map(|_| ())) .map(|result| result.map(|_| ()))
.unwrap_or(Ok(()))?; .unwrap_or(Ok(()))?;

@ -551,6 +551,11 @@ impl Document {
bail!("saves are closed for this 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 // we clone and move text + path into the future so that we asynchronously save the current
// state without blocking any further edits. // state without blocking any further edits.
let mut text = self.text().clone(); let mut text = self.text().clone();
@ -695,7 +700,14 @@ impl Document {
self.set_last_saved_revision(event.revision); self.set_last_saved_revision(event.revision);
false 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); final_result = Some(save_event);
@ -1072,7 +1084,8 @@ impl Document {
let current_revision = history.current_revision(); let current_revision = history.current_revision();
self.history.set(history); self.history.set(history);
log::debug!( log::debug!(
"modified - last saved: {}, current: {}", "id {} modified - last saved: {}, current: {}",
self.id,
self.last_saved_revision, self.last_saved_revision,
current_revision current_revision
); );

@ -816,12 +816,16 @@ impl Editor {
#[inline] #[inline]
pub fn set_status<T: Into<Cow<'static, str>>>(&mut self, status: T) { pub fn set_status<T: Into<Cow<'static, str>>>(&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] #[inline]
pub fn set_error<T: Into<Cow<'static, str>>>(&mut self, error: T) { pub fn set_error<T: Into<Cow<'static, str>>>(&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] #[inline]

Loading…
Cancel
Save