diff options
Diffstat (limited to 'crates/shirabe/src/io/console_io.rs')
| -rw-r--r-- | crates/shirabe/src/io/console_io.rs | 78 |
1 files changed, 39 insertions, 39 deletions
diff --git a/crates/shirabe/src/io/console_io.rs b/crates/shirabe/src/io/console_io.rs index a4a3c21..18287e3 100644 --- a/crates/shirabe/src/io/console_io.rs +++ b/crates/shirabe/src/io/console_io.rs @@ -7,6 +7,7 @@ use indexmap::indexmap; use shirabe_external_packages::composer::pcre::Preg; use shirabe_external_packages::symfony::console::helper::HelperSet; use shirabe_external_packages::symfony::console::helper::ProgressBar; +use shirabe_external_packages::symfony::console::helper::QuestionHelper; use shirabe_external_packages::symfony::console::helper::Table; use shirabe_external_packages::symfony::console::input::InputInterface; use shirabe_external_packages::symfony::console::output::ConsoleOutputInterface; @@ -30,10 +31,11 @@ use crate::question::StrictConfirmationQuestion; use crate::util::Silencer; /// The Input/Output helper. +#[derive(Debug)] pub struct ConsoleIO { authentications: indexmap::IndexMap<String, indexmap::IndexMap<String, Option<String>>>, - pub(crate) input: Box<dyn InputInterface>, + pub(crate) input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>, pub(crate) output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>, pub(crate) helper_set: HelperSet, pub(crate) last_message: RefCell<String>, @@ -45,21 +47,6 @@ pub struct ConsoleIO { verbosity_map: IndexMap<i64, i64>, } -// TODO(phase-b): dyn InputInterface / dyn OutputInterface do not implement Debug, -// so we cannot derive Debug. Provide a manual impl that omits those fields. -impl std::fmt::Debug for ConsoleIO { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ConsoleIO") - .field("authentications", &self.authentications) - .field("helper_set", &self.helper_set) - .field("last_message", &self.last_message) - .field("last_message_err", &self.last_message_err) - .field("start_time", &self.start_time) - .field("verbosity_map", &self.verbosity_map) - .finish() - } -} - impl ConsoleIO { /// Constructor. /// @@ -67,7 +54,7 @@ impl ConsoleIO { /// @param OutputInterface $output The output instance /// @param HelperSet $helperSet The helperSet instance pub fn new( - input: Box<dyn InputInterface>, + input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>, output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>, helper_set: HelperSet, ) -> Self { @@ -375,7 +362,7 @@ impl ConsoleIO { impl IOInterfaceImmutable for ConsoleIO { fn is_interactive(&self) -> bool { - self.input.is_interactive() + self.input.borrow().is_interactive() } fn is_verbose(&self) -> bool { @@ -447,8 +434,7 @@ impl IOInterfaceImmutable for ConsoleIO { } fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { - // PHP: $helper = $this->helperSet->get('question'); - let _helper = self.helper_set.get("question"); + let helper = self.helper_set.get::<QuestionHelper>("question"); let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -458,30 +444,32 @@ impl IOInterfaceImmutable for ConsoleIO { } else { Some(default) }; - let _question = Question::new(&sanitized_question, sanitized_default); + let question = Question::new(&sanitized_question, sanitized_default); - // TODO(phase-b): HelperSet::get returns PhpMixed; QuestionHelper::ask is - // not yet modeled. Returning a placeholder until helper types are wired up. - todo!("call QuestionHelper::ask on resolved helper") + helper + .borrow() + .ask(self.input.clone(), self.get_error_output(), &question) } fn ask_confirmation(&self, question: String, default: bool) -> bool { - let _helper = self.helper_set.get("question"); - // TODO(phase-b): Self::sanitize returns PhpMixed but new() expects String; - // also true/false regexes need to come through composer/symfony defaults. + let helper = self.helper_set.get::<QuestionHelper>("question"); let sanitized = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") .to_string(); - let _question = StrictConfirmationQuestion::new( + let question = StrictConfirmationQuestion::new( sanitized, default, "/^y(?:es)?$/i".to_string(), "/^no?$/i".to_string(), ); - // TODO(phase-b): see ask() above; placeholder until QuestionHelper is modeled. - todo!("call QuestionHelper::ask on resolved helper and coerce to bool") + let result = helper.borrow().ask( + self.input.clone(), + self.get_error_output(), + question.inner(), + ); + result.as_bool().unwrap_or(false) } fn ask_and_validate( @@ -491,7 +479,6 @@ impl IOInterfaceImmutable for ConsoleIO { attempts: Option<i64>, default: PhpMixed, ) -> anyhow::Result<PhpMixed> { - let _helper = self.helper_set.get("question"); let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -509,12 +496,13 @@ impl IOInterfaceImmutable for ConsoleIO { question.set_validator(Some(adapted)); question.set_max_attempts(attempts); - // TODO(phase-b): QuestionHelper::ask not yet modeled. - todo!("call QuestionHelper::ask on resolved helper") + let helper = self.helper_set.get::<QuestionHelper>("question"); + Ok(helper + .borrow() + .ask(self.input.clone(), self.get_error_output(), &question)) } fn ask_and_hide_answer(&self, question: String) -> Option<String> { - let _helper = self.helper_set.get("question"); let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -522,8 +510,11 @@ impl IOInterfaceImmutable for ConsoleIO { let mut question = Question::new(&sanitized_question, Some(PhpMixed::Null)); question.set_hidden(true); - // TODO(phase-b): QuestionHelper::ask not yet modeled. - todo!("call QuestionHelper::ask on resolved helper and coerce to Option<String>") + let helper = self.helper_set.get::<QuestionHelper>("question"); + let result = helper + .borrow() + .ask(self.input.clone(), self.get_error_output(), &question); + result.as_string().map(|s| s.to_string()) } fn select( @@ -542,7 +533,7 @@ impl IOInterfaceImmutable for ConsoleIO { .map(|s| Box::new(PhpMixed::String(s))) .collect(), ); - let _helper = self.helper_set.get("question"); + let _helper = self.helper_set.get::<QuestionHelper>("question"); let sanitized_question = Self::sanitize(PhpMixed::String(question), true) .as_string() .unwrap_or("") @@ -573,8 +564,13 @@ impl IOInterfaceImmutable for ConsoleIO { question.set_error_message(&error_message); question.set_multiselect(multiselect); - // TODO(phase-b): QuestionHelper::ask not yet modeled. - let result: PhpMixed = todo!("call QuestionHelper::ask on resolved helper"); + // TODO(phase-c): QuestionHelper::ask takes a concrete `&Question`, but PHP passes a + // ChoiceQuestion whose getValidator/getDefault/autocompleter overrides drive the answer + // handling via polymorphism. Passing the inner Question would silently drop that behaviour. + // Faithful support needs the Symfony Question hierarchy modelled as a trait (or ask taking a + // trait object) so ChoiceQuestion's overrides dispatch — unlike StrictConfirmationQuestion, + // whose behaviour lives entirely on its inner Question (see ask_confirmation above). + let result: PhpMixed = todo!("call QuestionHelper::ask with a polymorphic ChoiceQuestion"); // PHP: $isAssoc = (bool) \count(array_filter(array_keys($choices), 'is_string')); let choice_keys: Vec<String> = match &choices { @@ -670,6 +666,10 @@ impl IOInterface for ConsoleIO { fn as_any(&self) -> &dyn std::any::Any { self } + + fn as_base_io_mut(&mut self) -> Option<&mut dyn BaseIO> { + Some(self) + } } impl BaseIO for ConsoleIO { |
