improve reliability of shutdown
This commit is contained in:
parent
b8a07f7d15
commit
cb23399dee
4 changed files with 79 additions and 24 deletions
|
@ -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…
Reference in a new issue