#[cfg(test)]
use std::cell::RefCell;
#[cfg(test)]
use std::collections::VecDeque;
use std::io;
use newt_core::interaction_surface::SurfaceInteraction;
use newt_core::HumanQuestionOutcome;
use newt_interaction::InteractionDefinition;
pub(super) struct Operator<'a> {
ask: Box<dyn Fn(&SurfaceInteraction) -> HumanQuestionOutcome + 'a>,
say: Box<dyn Fn(&str) + 'a>,
}
impl Operator<'static> {
pub(super) fn terminal() -> Self {
Self {
ask: Box::new(|interaction| {
let window = newt_core::tty::Terminal::suspend_for_prompt(
newt_core::tty::TerminalTaker::SetupWizard,
);
crate::permissions::present_on_terminal(&window, interaction)
}),
say: Box::new(|line| println!("{line}")),
}
}
}
impl<'a> Operator<'a> {
pub(super) fn ask(&self, definition: &InteractionDefinition) -> io::Result<String> {
match (self.ask)(&SurfaceInteraction::blocking(definition.clone())) {
HumanQuestionOutcome::Answer(line) => Ok(line.trim().to_string()),
HumanQuestionOutcome::Cancelled | HumanQuestionOutcome::ExitRequested => {
Err(io::Error::new(io::ErrorKind::Interrupted, "cancelled"))
}
HumanQuestionOutcome::InputClosed => {
Err(io::Error::new(io::ErrorKind::UnexpectedEof, "eof"))
}
HumanQuestionOutcome::Unavailable | HumanQuestionOutcome::InputFailed => {
Err(io::Error::other("no operator available"))
}
}
}
pub(super) fn ask_seam(&self) -> &dyn Fn(&SurfaceInteraction) -> HumanQuestionOutcome {
&*self.ask
}
pub(super) fn say(&self, line: &str) {
(self.say)(line);
}
}
#[cfg(test)]
pub(super) struct Script {
answers: RefCell<VecDeque<String>>,
pub(super) output: RefCell<Vec<String>>,
}
#[cfg(test)]
impl Script {
pub(super) fn new(answers: &[&str]) -> Self {
Self {
answers: RefCell::new(answers.iter().map(|a| (*a).to_string()).collect()),
output: RefCell::new(Vec::new()),
}
}
pub(super) fn operator(&self) -> Operator<'_> {
Operator {
ask: Box::new(move |interaction| {
self.output
.borrow_mut()
.push(newt_core::markup::plain::render(&interaction.definition));
HumanQuestionOutcome::Answer(
self.answers.borrow_mut().pop_front().unwrap_or_default(),
)
}),
say: Box::new(move |line| self.output.borrow_mut().push(line.to_string())),
}
}
pub(super) fn next_answer(&self) -> Option<String> {
self.answers.borrow().front().cloned()
}
pub(super) fn transcript(&self) -> String {
self.output.borrow().join("\n")
}
}