on master help sign in
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

commit41bf1d581137855596e00ad7702e8827325714b0 authorSkyler Hawthorne <skyler@dead10ck.com> dateThu 31 Mar 2022, 10:58 (5 years ago) parentfac36bc
4 files changed+19−6
helix-term/src/application.rs+1−1 helix-term/src/commands/typed.rs+2 helix-term/src/job.rs+16−4 helix-term/tests/test/commands.rs−1
helix-term/src/application.rs+1−1
@@ -814,7 +814,7 @@ impl Application {
814814 }
815815
816816 pub async fn close(&mut self) -> anyhow::Result<()> {
817− self.jobs.finish().await;
817+ self.jobs.finish().await?;
818818
819819 if self.editor.close_language_servers(None).await.is_err() {
820820 log::error!("Timed out waiting for language servers to shutdown");
helix-term/src/commands/typed.rs+2
@@ -233,6 +233,7 @@ fn write_impl(
233233 doc.detect_language(cx.editor.syn_loader.clone());
234234 let _ = cx.editor.refresh_language_server(id);
235235 }
236+
236237 Ok(())
237238}
238239
@@ -422,6 +423,7 @@ fn write_quit(
422423 event: PromptEvent,
423424) -> anyhow::Result<()> {
424425 write_impl(cx, args.first(), false)?;
426+ helix_lsp::block_on(cx.jobs.finish())?;
425427 quit(cx, &[], event)
426428}
427429
helix-term/src/job.rs+16−4
@@ -2,7 +2,7 @@ use helix_view::Editor;
22
33use crate::compositor::Compositor;
44
5−use futures_util::future::{self, BoxFuture, Future, FutureExt};
5+use futures_util::future::{BoxFuture, Future, FutureExt};
66use futures_util::stream::{FuturesUnordered, StreamExt};
77
88pub type Callback = Box<dyn FnOnce(&mut Editor, &mut Compositor) + Send>;
@@ -93,9 +93,21 @@ impl Jobs {
9393 }
9494
9595 /// Blocks until all the jobs that need to be waited on are done.
96− pub async fn finish(&mut self) {
97− let wait_futures = std::mem::take(&mut self.wait_futures);
96+ pub async fn finish(&mut self) -> anyhow::Result<()> {
9897 log::debug!("waiting on jobs...");
99− wait_futures.for_each(|_| future::ready(())).await
98+ let mut wait_futures = std::mem::take(&mut self.wait_futures);
99+ while let (Some(job), tail) = wait_futures.into_future().await {
100+ match job {
101+ Ok(_) => {
102+ wait_futures = tail;
103+ }
104+ Err(e) => {
105+ self.wait_futures = tail;
106+ return Err(e);
107+ }
108+ }
109+ }
110+
111+ Ok(())
100112 }
101113}
helix-term/tests/test/commands.rs−1
@@ -9,7 +9,6 @@ use helix_term::application::Application;
99use super::*;
1010
1111#[tokio::test]
12−#[ignore]
1312async fn test_write_quit_fail() -> anyhow::Result<()> {
1413 let file = helpers::new_readonly_tempfile()?;
1514