use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use anyhow::Ok;
use nu_protocol::{
PipelineData, Signals,
ast::Block,
debugger::WithoutDebug,
engine::{EngineState, Stack, StateWorkingSet},
};
use crate::prelude::*;
pub(crate) struct Activity {
name: String,
engine_state: EngineState,
block: Arc<Block>,
ctrl_c: Arc<AtomicBool>,
}
impl Activity {
pub(crate) fn new(name: String, command: String) -> Result<Self> {
let ctrl_c = Arc::new(AtomicBool::new(false));
let mut engine_state = nu_cmd_lang::create_default_context();
engine_state = nu_command::add_shell_command_context(engine_state);
engine_state.set_signals(Signals::new(ctrl_c.clone()));
let init_cwd = std::env::current_dir()?;
nu_cli::gather_parent_env_vars(&mut engine_state, init_cwd.as_ref());
let mut working_set = StateWorkingSet::new(&engine_state);
let block = nu_parser::parse(&mut working_set, None, command.as_bytes(), false);
engine_state.merge_delta(working_set.render())?;
Ok(Self {
name,
engine_state,
block,
ctrl_c,
})
}
pub(crate) fn start_activity(&self) -> impl Future<Output = Result<()>> + use<> {
let engine_state = self.engine_state.clone();
let block = self.block.clone();
let name = self.name.clone();
async {
tokio::task::spawn_blocking(move || {
let mut stack = Stack::new();
log::info!("Start activity '{name}'");
let output = nu_engine::eval_block_with_early_return::<WithoutDebug>(
&engine_state,
&mut stack,
&block,
PipelineData::empty(),
)?;
output.drain()?;
log::info!("Finished activity '{name}'");
Ok(())
})
.await??;
Ok(())
}
}
pub(crate) fn cancel_activity(&self) {
self.ctrl_c.store(true, Ordering::Relaxed);
}
}