@@ -8,8 +8,10 @@ use std::collections::BTreeSet;
88use std:: fmt:: Debug ;
99use std:: fmt:: Display ;
1010use std:: path:: Path ;
11+ use std:: process:: ExitStatus ;
1112use std:: process:: Stdio ;
1213use std:: time:: Instant ;
14+ use tokio:: task:: JoinHandle ;
1315
1416use aho_corasick:: AhoCorasick ;
1517use camino:: Utf8Path ;
@@ -57,6 +59,7 @@ use crate::buffers::LINE_BUFFER_CAPACITY;
5759use crate :: cli:: HookOpts ;
5860use crate :: cli:: Opts ;
5961use crate :: clonable_command:: ClonableCommand ;
62+ use crate :: command_ext:: SpawnExt ;
6063use crate :: event_filter:: FileEvent ;
6164use crate :: format_bulleted_list;
6265use crate :: haskell_source_file:: is_haskell_source_file;
@@ -157,6 +160,8 @@ pub struct Ghci {
157160 eval_commands : BTreeMap < NormalPath , Vec < EvalCommand > > ,
158161 /// Search paths / current working directory for this `ghci` session.
159162 search_paths : ShowPaths ,
163+ /// Tasks running `async:` shell commands in the background.
164+ command_handles : Vec < JoinHandle < miette:: Result < ExitStatus > > > ,
160165}
161166
162167impl Debug for Ghci {
@@ -174,9 +179,14 @@ impl Ghci {
174179 /// streams.
175180 #[ instrument( skip_all, level = "debug" , name = "ghci" ) ]
176181 pub async fn new ( mut shutdown : ShutdownHandle , opts : GhciOpts ) -> miette:: Result < Self > {
177- for command in & opts. hooks . before_startup_shell {
178- shutdown. error_if_shutdown_requested ( ) ?;
179- Self :: before_startup_shell ( command) . await ?;
182+ let mut command_handles = Vec :: new ( ) ;
183+ {
184+ let span = tracing:: debug_span!( "before_startup_shell" ) ;
185+ let _enter = span. enter ( ) ;
186+ for command in & opts. hooks . before_startup_shell {
187+ tracing:: info!( %command, "Running before-startup command" ) ;
188+ command. run_on ( & mut command_handles) . await ?;
189+ }
180190 }
181191
182192 let mut group = {
@@ -271,6 +281,7 @@ impl Ghci {
271281 cwd : crate :: current_dir_utf8 ( ) ?,
272282 search_paths : Default :: default ( ) ,
273283 } ,
284+ command_handles,
274285 } )
275286 }
276287
@@ -410,6 +421,10 @@ impl Ghci {
410421 tracing:: info!( %command, "Running after-restart command" ) ;
411422 self . stdin . run_command ( & mut self . stdout , command) . await ?;
412423 }
424+ for command in & self . opts . hooks . after_restart_shell {
425+ tracing:: info!( %command, "Running after-restart command" ) ;
426+ command. run_on ( & mut self . command_handles ) . await ?;
427+ }
413428 // Once we restart, everything is freshly loaded. We don't need to add or
414429 // reload any other modules.
415430 return Ok ( ( ) ) ;
@@ -455,6 +470,10 @@ impl Ghci {
455470 tracing:: info!( %command, "Running after-reload command" ) ;
456471 self . stdin . run_command ( & mut self . stdout , command) . await ?;
457472 }
473+ for command in & self . opts . hooks . after_reload_shell {
474+ tracing:: info!( %command, "Running after-reload command" ) ;
475+ command. run_on ( & mut self . command_handles ) . await ?;
476+ }
458477
459478 if compilation_failed {
460479 tracing:: debug!( "Compilation failed, skipping running tests." ) ;
@@ -465,6 +484,9 @@ impl Ghci {
465484 }
466485 }
467486
487+ // Get rid of any handles for background commands that have finished.
488+ self . command_handles . retain ( |handle| !handle. is_finished ( ) ) ;
489+
468490 Ok ( ( ) )
469491 }
470492
0 commit comments