From 41bf1d581137855596e00ad7702e8827325714b0 Mon Sep 17 00:00:00 2001 From: Skyler Hawthorne Date: Thu, 31 Mar 2022 10:58:50 -0400 Subject: [PATCH] fix(command): write-quit: do not quit if write fails During write-quit, if the file fails to be written for any reason, helix will still quit without saving the changes. This fixes this behavior by introducing fallibility to the asynchronous job queues. This will also benefit all contexts which may depend on these job queues. Fixes #1575 --- helix-term/src/application.rs | 2 +- helix-term/src/commands/typed.rs | 2 ++ helix-term/src/job.rs | 20 ++++++++++++++++---- helix-term/tests/test/commands.rs | 1 - 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index 15b44a856..2790c9a49 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -814,7 +814,7 @@ impl Application { } pub async fn close(&mut self) -> anyhow::Result<()> { - self.jobs.finish().await; + self.jobs.finish().await?; if self.editor.close_language_servers(None).await.is_err() { log::error!("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 3c88b0ce2..5b48ca488 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -233,6 +233,7 @@ fn write_impl( doc.detect_language(cx.editor.syn_loader.clone()); let _ = cx.editor.refresh_language_server(id); } + Ok(()) } @@ -422,6 +423,7 @@ fn write_quit( event: PromptEvent, ) -> anyhow::Result<()> { write_impl(cx, args.first(), false)?; + helix_lsp::block_on(cx.jobs.finish())?; quit(cx, &[], event) } diff --git a/helix-term/src/job.rs b/helix-term/src/job.rs index d21099f73..e51479925 100644 --- a/helix-term/src/job.rs +++ b/helix-term/src/job.rs @@ -2,7 +2,7 @@ use helix_view::Editor; use crate::compositor::Compositor; -use futures_util::future::{self, BoxFuture, Future, FutureExt}; +use futures_util::future::{BoxFuture, Future, FutureExt}; use futures_util::stream::{FuturesUnordered, StreamExt}; pub type Callback = Box; @@ -93,9 +93,21 @@ impl Jobs { } /// Blocks until all the jobs that need to be waited on are done. - pub async fn finish(&mut self) { - let wait_futures = std::mem::take(&mut self.wait_futures); + pub async fn finish(&mut self) -> anyhow::Result<()> { log::debug!("waiting on jobs..."); - wait_futures.for_each(|_| future::ready(())).await + let mut wait_futures = std::mem::take(&mut self.wait_futures); + while let (Some(job), tail) = wait_futures.into_future().await { + match job { + Ok(_) => { + wait_futures = tail; + } + Err(e) => { + self.wait_futures = tail; + return Err(e); + } + } + } + + Ok(()) } } diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index 27b4da580..01f13c5c0 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -9,7 +9,6 @@ use helix_term::application::Application; use super::*; #[tokio::test] -#[ignore] async fn test_write_quit_fail() -> anyhow::Result<()> { let file = helpers::new_readonly_tempfile()?;