use super::prompt::ContextPrompter;
use anyhow::Result;
use std::cell::Cell;
#[derive(Debug)]
pub(crate) struct ScriptedPrompter {
pub(crate) responses: Vec<ScriptedResponse>,
index: Cell<usize>,
}
#[derive(Debug, Clone)]
pub(crate) enum ScriptedResponse {
Select(usize),
MultiSelect(Vec<usize>),
Confirm(bool),
Input(String),
Edit(String),
}
impl ScriptedPrompter {
pub(crate) fn new(responses: Vec<ScriptedResponse>) -> Self {
Self {
responses,
index: Cell::new(0),
}
}
fn next_response(&self) -> Result<ScriptedResponse> {
let idx = self.index.get();
if idx >= self.responses.len() {
anyhow::bail!(
"Scripted prompter ran out of responses (requested #{}, have {})",
idx + 1,
self.responses.len()
);
}
self.index.set(idx + 1);
Ok(self.responses[idx].clone())
}
}
impl ContextPrompter for ScriptedPrompter {
fn select(&self, prompt: &str, items: &[String], _default: usize) -> Result<usize> {
match self.next_response()? {
ScriptedResponse::Select(idx) => {
if idx >= items.len() {
anyhow::bail!(
"Scripted select index {} out of range for '{}' ({} items)",
idx,
prompt,
items.len()
);
}
Ok(idx)
}
other => anyhow::bail!("Expected Select response for '{}', got {:?}", prompt, other),
}
}
fn multi_select(
&self,
prompt: &str,
items: &[String],
_defaults: &[bool],
) -> Result<Vec<usize>> {
match self.next_response()? {
ScriptedResponse::MultiSelect(indices) => {
for &idx in &indices {
if idx >= items.len() {
anyhow::bail!(
"Scripted multi-select index {} out of range for '{}' ({} items)",
idx,
prompt,
items.len()
);
}
}
Ok(indices)
}
other => anyhow::bail!(
"Expected MultiSelect response for '{}', got {:?}",
prompt,
other
),
}
}
fn confirm(&self, prompt: &str, _default: bool) -> Result<bool> {
match self.next_response()? {
ScriptedResponse::Confirm(value) => Ok(value),
other => anyhow::bail!(
"Expected Confirm response for '{}', got {:?}",
prompt,
other
),
}
}
fn input(&self, prompt: &str, _default: Option<&str>, _allow_empty: bool) -> Result<String> {
match self.next_response()? {
ScriptedResponse::Input(value) => Ok(value),
other => anyhow::bail!("Expected Input response for '{}', got {:?}", prompt, other),
}
}
fn edit(&self, prompt: &str, _initial: &str) -> Result<String> {
match self.next_response()? {
ScriptedResponse::Edit(value) => Ok(value),
other => anyhow::bail!("Expected Edit response for '{}', got {:?}", prompt, other),
}
}
}