aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/io
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/io')
-rw-r--r--crates/shirabe/src/io/buffer_io.rs4
-rw-r--r--crates/shirabe/src/io/console_io.rs44
-rw-r--r--crates/shirabe/src/io/io_interface.rs15
-rw-r--r--crates/shirabe/src/io/null_io.rs8
4 files changed, 44 insertions, 27 deletions
diff --git a/crates/shirabe/src/io/buffer_io.rs b/crates/shirabe/src/io/buffer_io.rs
index 491cd316..bbe1db9f 100644
--- a/crates/shirabe/src/io/buffer_io.rs
+++ b/crates/shirabe/src/io/buffer_io.rs
@@ -186,7 +186,7 @@ impl crate::io::IOInterfaceImmutable for BufferIO {
self.inner
.overwrite_error4(message, newline, size, verbosity)
}
- fn ask(&self, question: String, default: PhpMixed) -> PhpMixed {
+ fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> {
self.inner.ask(question, default)
}
fn ask_confirmation(&self, question: String, default: bool) -> bool {
@@ -213,7 +213,7 @@ impl crate::io::IOInterfaceImmutable for BufferIO {
attempts: PhpMixed,
error_message: String,
multiselect: bool,
- ) -> PhpMixed {
+ ) -> anyhow::Result<PhpMixed> {
self.inner.select(
question,
choices,
diff --git a/crates/shirabe/src/io/console_io.rs b/crates/shirabe/src/io/console_io.rs
index cf488855..83e84fd3 100644
--- a/crates/shirabe/src/io/console_io.rs
+++ b/crates/shirabe/src/io/console_io.rs
@@ -338,18 +338,17 @@ impl ConsoleIO {
/// Delegates to `QuestionHelper::ask`.
///
/// PHP: `$helper->ask($this->input, $this->getErrorOutput(), $question)`.
- /// `QuestionHelper::ask` surfaces PHP exceptions; ConsoleIO does not catch them, so an
- /// unrecoverable error here is a PHP fatal. The double `Result` is collapsed: the outer
- /// `anyhow::Result` (fatal) and the inner `MissingInputException` (unhandled, hence also fatal
- /// in PHP) both abort.
- fn ask_question(&self, question: &impl QuestionInterface) -> PhpMixed {
+ /// `QuestionHelper::ask` surfaces PHP exceptions; ConsoleIO does not catch them, they
+ /// propagate to the caller. The double `Result` is flattened: the inner
+ /// `MissingInputException` is wrapped with its concrete type preserved so that
+ /// `Application`'s `instanceof ExceptionInterface` downcast still recognizes it.
+ fn ask_question(&self, question: &impl QuestionInterface) -> anyhow::Result<PhpMixed> {
let error_output = self.get_error_output();
let mut question_helper = self.question_helper.borrow_mut();
let mut input = self.input.borrow_mut();
question_helper
- .ask(&mut *input, error_output, question)
- .expect("QuestionHelper::ask raised a fatal error")
- .expect("QuestionHelper::ask returned no input")
+ .ask(&mut *input, error_output, question)?
+ .map_err(anyhow::Error::new)
}
}
@@ -426,7 +425,7 @@ impl IOInterfaceImmutable for ConsoleIO {
);
}
- fn ask(&self, question: String, default: PhpMixed) -> PhpMixed {
+ fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> {
let sanitized_question = Self::sanitize(PhpMixed::String(question), true)
.as_string()
.unwrap_or("")
@@ -441,6 +440,9 @@ impl IOInterfaceImmutable for ConsoleIO {
self.ask_question(&question)
}
+ // TODO(phase-c): ask_confirmation and ask_and_hide_answer still collapse ask_question
+ // errors with .expect() instead of propagating them; extending Result propagation to
+ // them is a further IOInterface signature change that has not been decided yet.
fn ask_confirmation(&self, question: String, default: bool) -> bool {
let sanitized = Self::sanitize(PhpMixed::String(question), true)
.as_string()
@@ -453,7 +455,9 @@ impl IOInterfaceImmutable for ConsoleIO {
"/^no?$/i".to_string(),
);
- let result = self.ask_question(&question);
+ let result = self
+ .ask_question(&question)
+ .expect("QuestionHelper::ask raised an error");
result.as_bool().unwrap_or(false)
}
@@ -499,7 +503,7 @@ impl IOInterfaceImmutable for ConsoleIO {
.set_max_attempts(attempts)
.map_err(|e| anyhow::anyhow!(e.0.message))?;
- Ok(self.ask_question(&question))
+ self.ask_question(&question)
}
fn ask_and_hide_answer(&self, question: String) -> Option<String> {
@@ -513,7 +517,9 @@ impl IOInterfaceImmutable for ConsoleIO {
.set_hidden(true)
.expect("a freshly constructed question has no autocompleter");
- let result = self.ask_question(&question);
+ let result = self
+ .ask_question(&question)
+ .expect("QuestionHelper::ask raised an error");
result.as_string().map(|s| s.to_string())
}
@@ -525,7 +531,7 @@ impl IOInterfaceImmutable for ConsoleIO {
attempts: PhpMixed,
error_message: String,
multiselect: bool,
- ) -> PhpMixed {
+ ) -> anyhow::Result<PhpMixed> {
let sanitized_question = Self::sanitize(PhpMixed::String(question), true)
.as_string()
.unwrap_or("")
@@ -563,7 +569,7 @@ impl IOInterfaceImmutable for ConsoleIO {
question.set_error_message(error_message);
question.set_multiselect(multiselect);
- let result: PhpMixed = self.ask_question(&question);
+ let result: PhpMixed = self.ask_question(&question)?;
// PHP: $isAssoc = (bool) \count(array_filter(array_keys($choices), 'is_string'));
let choice_keys: Vec<String> = match &choices {
@@ -574,7 +580,7 @@ impl IOInterfaceImmutable for ConsoleIO {
let is_assoc =
!choice_keys.is_empty() && choice_keys.iter().any(|k| k.parse::<i64>().is_err());
if is_assoc {
- return result;
+ return Ok(result);
}
if !is_array(&result) {
@@ -591,7 +597,9 @@ impl IOInterfaceImmutable for ConsoleIO {
.collect(),
_ => IndexMap::new(),
};
- return PhpMixed::String(array_search(&result_str, &haystack).unwrap_or_default());
+ return Ok(PhpMixed::String(
+ array_search(&result_str, &haystack).unwrap_or_default(),
+ ));
}
let mut results: Vec<String> = vec![];
@@ -611,7 +619,9 @@ impl IOInterfaceImmutable for ConsoleIO {
}
}
- PhpMixed::List(results.into_iter().map(PhpMixed::String).collect())
+ Ok(PhpMixed::List(
+ results.into_iter().map(PhpMixed::String).collect(),
+ ))
}
fn get_authentications(&self) -> IndexMap<String, IndexMap<String, Option<String>>> {
diff --git a/crates/shirabe/src/io/io_interface.rs b/crates/shirabe/src/io/io_interface.rs
index 33a2f017..b0271767 100644
--- a/crates/shirabe/src/io/io_interface.rs
+++ b/crates/shirabe/src/io/io_interface.rs
@@ -92,7 +92,10 @@ pub trait IOInterfaceImmutable: std::fmt::Debug {
}
fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64);
- fn ask(&self, question: String, default: PhpMixed) -> PhpMixed;
+ /// PHP: `@throws \RuntimeException If there is no data to read in the input stream`.
+ /// `QuestionHelper::ask` exceptions (validator errors, `MissingInputException`) propagate
+ /// to the caller, hence the `anyhow::Result` return type.
+ fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed>;
fn ask_confirmation(&self, question: String, default: bool) -> bool;
@@ -109,6 +112,10 @@ pub trait IOInterfaceImmutable: std::fmt::Debug {
/// PHP `array $choices` may be a list (`PhpMixed::List`) or an associative
/// array (`PhpMixed::Array`); list choices resolve to their index, while
/// associative choices resolve to their key.
+ ///
+ /// PHP: `@throws \InvalidArgumentException` — the `ChoiceQuestion` validator error
+ /// propagates to the caller once `$attempts` is exhausted, hence the `anyhow::Result`
+ /// return type.
fn select(
&self,
question: String,
@@ -117,7 +124,7 @@ pub trait IOInterfaceImmutable: std::fmt::Debug {
attempts: PhpMixed,
error_message: String,
multiselect: bool,
- ) -> PhpMixed;
+ ) -> anyhow::Result<PhpMixed>;
fn get_authentications(&self) -> IndexMap<String, IndexMap<String, Option<String>>>;
@@ -278,7 +285,7 @@ impl IOInterfaceImmutable for std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
.overwrite_error4(message, newline, size, verbosity)
}
- fn ask(&self, question: String, default: PhpMixed) -> PhpMixed {
+ fn ask(&self, question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> {
self.borrow().ask(question, default)
}
@@ -309,7 +316,7 @@ impl IOInterfaceImmutable for std::rc::Rc<std::cell::RefCell<dyn IOInterface>> {
attempts: PhpMixed,
error_message: String,
multiselect: bool,
- ) -> PhpMixed {
+ ) -> anyhow::Result<PhpMixed> {
self.borrow().select(
question,
choices,
diff --git a/crates/shirabe/src/io/null_io.rs b/crates/shirabe/src/io/null_io.rs
index 71a81408..6db473ae 100644
--- a/crates/shirabe/src/io/null_io.rs
+++ b/crates/shirabe/src/io/null_io.rs
@@ -65,8 +65,8 @@ impl IOInterfaceImmutable for NullIO {
) {
}
- fn ask(&self, _question: String, default: PhpMixed) -> PhpMixed {
- default
+ fn ask(&self, _question: String, default: PhpMixed) -> anyhow::Result<PhpMixed> {
+ Ok(default)
}
fn ask_confirmation(&self, _question: String, default: bool) -> bool {
@@ -95,8 +95,8 @@ impl IOInterfaceImmutable for NullIO {
_attempts: PhpMixed,
_error_message: String,
_multiselect: bool,
- ) -> PhpMixed {
- default
+ ) -> anyhow::Result<PhpMixed> {
+ Ok(default)
}
fn get_authentications(