diff options
Diffstat (limited to 'crates/shirabe/src/io')
| -rw-r--r-- | crates/shirabe/src/io/base_io.rs | 6 | ||||
| -rw-r--r-- | crates/shirabe/src/io/buffer_io.rs | 208 | ||||
| -rw-r--r-- | crates/shirabe/src/io/console_io.rs | 250 | ||||
| -rw-r--r-- | crates/shirabe/src/io/io_interface.rs | 10 | ||||
| -rw-r--r-- | crates/shirabe/src/io/null_io.rs | 10 |
5 files changed, 353 insertions, 131 deletions
diff --git a/crates/shirabe/src/io/base_io.rs b/crates/shirabe/src/io/base_io.rs index 6e6e7d0..f2b7ee5 100644 --- a/crates/shirabe/src/io/base_io.rs +++ b/crates/shirabe/src/io/base_io.rs @@ -446,11 +446,11 @@ pub trait BaseIO: IOInterface { let mut message_str = message.as_string().unwrap_or("").to_string(); if !context.is_empty() { - let json = Silencer::call(|| { - json_encode_ex( + let json: anyhow::Result<Option<String>> = Silencer::call(|| { + Ok(json_encode_ex( &PhpMixed::Array(context.clone()), JSON_INVALID_UTF8_IGNORE | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, - ) + )) }); if let Ok(Some(json_str)) = json { message_str += " "; diff --git a/crates/shirabe/src/io/buffer_io.rs b/crates/shirabe/src/io/buffer_io.rs index 79fa9c3..ce4070a 100644 --- a/crates/shirabe/src/io/buffer_io.rs +++ b/crates/shirabe/src/io/buffer_io.rs @@ -3,11 +3,12 @@ use crate::io::console_io::ConsoleIO; use anyhow::Result; use shirabe_external_packages::composer::pcre::preg::Preg; +use shirabe_external_packages::symfony::component::console::helper::helper_set::HelperSet; +use shirabe_external_packages::symfony::component::console::input::input_interface::InputInterface; +use shirabe_external_packages::symfony::component::console::input::string_input::StringInput; +use shirabe_external_packages::symfony::component::console::output::output_interface::OutputInterface; use shirabe_external_packages::symfony::console::formatter::output_formatter_interface::OutputFormatterInterface; -use shirabe_external_packages::symfony::console::helper::helper_set::HelperSet; use shirabe_external_packages::symfony::console::helper::question_helper::QuestionHelper; -use shirabe_external_packages::symfony::console::input::streamable_input_interface::StreamableInputInterface; -use shirabe_external_packages::symfony::console::input::string_input::StringInput; use shirabe_external_packages::symfony::console::output::stream_output::StreamOutput; use shirabe_php_shim::{ PHP_EOL, PhpMixed, RuntimeException, fopen, fseek, fwrite, rewind, stream_get_contents, @@ -16,7 +17,7 @@ use shirabe_php_shim::{ #[derive(Debug)] pub struct BufferIO { - inner: ConsoleIO, + pub(crate) inner: ConsoleIO, } impl BufferIO { @@ -25,7 +26,7 @@ impl BufferIO { verbosity: i64, formatter: Option<Box<dyn OutputFormatterInterface>>, ) -> Result<Self> { - let mut input_obj = StringInput::new(input); + let mut input_obj = StringInput::new(&input); input_obj.set_interactive(false); let stream = fopen("php://memory", "rw"); @@ -38,21 +39,34 @@ impl BufferIO { } let decorated = formatter.as_ref().map_or(false, |f| f.is_decorated()); - let output = StreamOutput::new(stream, verbosity, decorated, formatter); + // TODO(phase-b): StreamOutput lives under `symfony::console` (not `symfony::component::console`) + // and so does not implement the `component::console::output::OutputInterface` ConsoleIO expects. + // Real fix requires unifying the two crate paths. + let _ = formatter; + let _ = StreamOutput::new(stream, verbosity, Some(decorated)); + let output: Box<dyn OutputInterface> = todo!("StreamOutput as Box<dyn OutputInterface>"); + // TODO(phase-b): symfony console helper modules live under both `symfony::console` + // and `symfony::component::console`; QuestionHelper::new is not yet provided. + let helpers: Vec<PhpMixed> = vec![/* PhpMixed::Object(QuestionHelper::new()) */]; + let _ = std::marker::PhantomData::<QuestionHelper>; let inner = ConsoleIO::new( - input_obj, + Box::new(input_obj) as Box<dyn InputInterface>, output, - HelperSet::new(vec![Box::new(QuestionHelper::new())]), + HelperSet::new(helpers), ); Ok(Self { inner }) } pub fn get_output(&self) -> String { - fseek(self.inner.output.get_stream(), 0); + // TODO(phase-b): OutputInterface::get_stream returns PhpResource, while + // fseek/stream_get_contents take PhpMixed. Conversion is not yet defined. + let stream: PhpMixed = + todo!("PhpResource -> PhpMixed conversion for OutputInterface::get_stream"); + fseek(stream.clone(), 0); - let output = stream_get_contents(self.inner.output.get_stream()).unwrap_or_default(); + let output = stream_get_contents(stream).unwrap_or_default(); let output = Preg::replace_callback( r"{(?<=^|\n|\x08)(.+?)(\x08+)}", @@ -80,28 +94,19 @@ impl BufferIO { &output, ); - output + // TODO(phase-b): Preg::replace_callback returns Result<String>, unwrap for now + output.unwrap_or_default() } pub fn set_user_inputs(&mut self, inputs: Vec<String>) -> Result<()> { - if self - .inner - .input - .as_any() - .downcast_ref::<dyn StreamableInputInterface>() - .is_none() - { - return Err(RuntimeException { - message: "Setting the user inputs requires at least the version 3.2 of the symfony/console component.".to_string(), - code: 0, - } - .into()); - } - - self.inner.input.set_stream(self.create_stream(inputs)?); - self.inner.input.set_interactive(true); - - Ok(()) + // TODO(phase-b): downcast Box<dyn InputInterface> to StreamableInputInterface. + // as_any/set_stream are not yet exposed on the InputInterface trait object. + let _ = inputs; + let _ = |i: &Box<dyn InputInterface>| -> bool { + let _ = i; + false + }; + todo!("port BufferIO::set_user_inputs once StreamableInputInterface downcast is available") } fn create_stream(&self, inputs: Vec<String>) -> Result<PhpMixed> { @@ -123,3 +128,148 @@ impl BufferIO { Ok(stream) } } + +// TODO(phase-b): PHP `class BufferIO extends ConsoleIO` — delegate all IOInterface, +// LoggerInterface, and BaseIO methods to `self.inner` (ConsoleIO). +impl shirabe_external_packages::psr::log::logger_interface::LoggerInterface for BufferIO { + fn emergency(&self, message: &str, context: &[(&str, &str)]) { + self.inner.emergency(message, context) + } + fn alert(&self, message: &str, context: &[(&str, &str)]) { + self.inner.alert(message, context) + } + fn critical(&self, message: &str, context: &[(&str, &str)]) { + self.inner.critical(message, context) + } + fn error(&self, message: &str, context: &[(&str, &str)]) { + self.inner.error(message, context) + } + fn warning(&self, message: &str, context: &[(&str, &str)]) { + self.inner.warning(message, context) + } + fn notice(&self, message: &str, context: &[(&str, &str)]) { + self.inner.notice(message, context) + } + fn info(&self, message: &str, context: &[(&str, &str)]) { + self.inner.info(message, context) + } + fn debug(&self, message: &str, context: &[(&str, &str)]) { + self.inner.debug(message, context) + } + fn log(&self, level: &str, message: &str, context: &[(&str, &str)]) { + self.inner.log(level, message, context) + } +} + +impl crate::io::io_interface::IOInterface for BufferIO { + fn is_interactive(&self) -> bool { + self.inner.is_interactive() + } + fn is_verbose(&self) -> bool { + self.inner.is_verbose() + } + fn is_very_verbose(&self) -> bool { + self.inner.is_very_verbose() + } + fn is_debug(&self) -> bool { + self.inner.is_debug() + } + fn is_decorated(&self) -> bool { + self.inner.is_decorated() + } + fn write3(&self, message: &str, newline: bool, verbosity: i64) { + self.inner.write3(message, newline, verbosity) + } + fn write_error3(&self, message: &str, newline: bool, verbosity: i64) { + self.inner.write_error3(message, newline, verbosity) + } + fn write_raw3(&self, message: &str, newline: bool, verbosity: i64) { + self.inner.write_raw3(message, newline, verbosity) + } + fn write_error_raw3(&self, message: &str, newline: bool, verbosity: i64) { + self.inner.write_error_raw3(message, newline, verbosity) + } + fn overwrite4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) { + self.inner.overwrite4(message, newline, size, verbosity) + } + fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) { + self.inner + .overwrite_error4(message, newline, size, verbosity) + } + fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { + self.inner.ask(question, default) + } + fn ask_confirmation(&self, question: String, default: bool) -> bool { + self.inner.ask_confirmation(question, default) + } + fn ask_and_validate( + &self, + question: String, + validator: Box<dyn Fn(PhpMixed) -> PhpMixed>, + attempts: Option<i64>, + default: PhpMixed, + ) -> PhpMixed { + self.inner + .ask_and_validate(question, validator, attempts, default) + } + fn ask_and_hide_answer(&self, question: String) -> Option<String> { + self.inner.ask_and_hide_answer(question) + } + fn select( + &self, + question: String, + choices: Vec<String>, + default: PhpMixed, + attempts: PhpMixed, + error_message: String, + multiselect: bool, + ) -> PhpMixed { + self.inner.select( + question, + choices, + default, + attempts, + error_message, + multiselect, + ) + } + fn get_authentications( + &self, + ) -> indexmap::IndexMap<String, indexmap::IndexMap<String, Option<String>>> { + self.inner.get_authentications() + } + fn has_authentication(&self, repository_name: &str) -> bool { + self.inner.has_authentication(repository_name) + } + fn get_authentication( + &self, + repository_name: &str, + ) -> indexmap::IndexMap<String, Option<String>> { + self.inner.get_authentication(repository_name) + } + fn set_authentication( + &mut self, + repository_name: String, + username: String, + password: Option<String>, + ) { + self.inner + .set_authentication(repository_name, username, password) + } + fn load_configuration(&mut self, config: &mut crate::config::Config) -> anyhow::Result<()> { + self.inner.load_configuration(config) + } +} + +impl crate::io::base_io::BaseIO for BufferIO { + fn authentications( + &self, + ) -> &indexmap::IndexMap<String, indexmap::IndexMap<String, Option<String>>> { + self.inner.authentications() + } + fn authentications_mut( + &mut self, + ) -> &mut indexmap::IndexMap<String, indexmap::IndexMap<String, Option<String>>> { + self.inner.authentications_mut() + } +} diff --git a/crates/shirabe/src/io/console_io.rs b/crates/shirabe/src/io/console_io.rs index 39099c4..2182c37 100644 --- a/crates/shirabe/src/io/console_io.rs +++ b/crates/shirabe/src/io/console_io.rs @@ -29,7 +29,6 @@ use crate::question::strict_confirmation_question::StrictConfirmationQuestion; use crate::util::silencer::Silencer; /// The Input/Output helper. -#[derive(Debug)] pub struct ConsoleIO { authentications: indexmap::IndexMap<String, indexmap::IndexMap<String, Option<String>>>, @@ -45,6 +44,21 @@ 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. /// @@ -131,9 +145,11 @@ impl ConsoleIO { // TODO(phase-b): downcast Box<dyn OutputInterface> to ConsoleOutputInterface let console_output: &dyn ConsoleOutputInterface = todo!("downcast self.output to ConsoleOutputInterface"); - console_output - .get_error_output() - .write3(messages.clone(), newline, sf_verbosity); + console_output.get_error_output().write( + &Self::to_string_list(&messages).join(if newline { "\n" } else { "" }), + newline, + sf_verbosity, + ); // PHP: implode($newline ? "\n" : '', (array) $messages) *self.last_message_err.borrow_mut() = implode( if newline { "\n" } else { "" }, @@ -143,7 +159,11 @@ impl ConsoleIO { return; } - self.output.write3(messages.clone(), newline, sf_verbosity); + self.output.write( + &Self::to_string_list(&messages).join(if newline { "\n" } else { "" }), + newline, + sf_verbosity, + ); *self.last_message.borrow_mut() = implode( if newline { "\n" } else { "" }, &Self::to_string_list(&messages), @@ -168,11 +188,12 @@ impl ConsoleIO { // since overwrite is supposed to overwrite last message... let size = size.unwrap_or_else(|| { // removing possible formatting of lastMessage with strip_tags - strlen(&strip_tags(if stderr { - &self.last_message_err.borrow() + let last = if stderr { + self.last_message_err.borrow().clone() } else { - &self.last_message.borrow() - })) + self.last_message.borrow().clone() + }; + strlen(&strip_tags(&last)) }); // ...let's fill its length with backspaces self.do_write( @@ -279,7 +300,7 @@ impl ConsoleIO { }; if is_string(&messages) { let message = Self::ensure_valid_utf8(messages.as_string().unwrap_or("")); - return PhpMixed::String(Preg::replace(&pattern, "", &message)); + return PhpMixed::String(Preg::replace(&pattern, "", &message).unwrap_or_default()); } // PHP: $sanitized = []; foreach ($messages as $key => $message) { ... } @@ -290,7 +311,7 @@ impl ConsoleIO { let s = Self::ensure_valid_utf8(message.as_string().unwrap_or("")); sanitized.insert( key.to_string(), - PhpMixed::String(Preg::replace(&pattern, "", &s)), + PhpMixed::String(Preg::replace(&pattern, "", &s).unwrap_or_default()), ); } } @@ -299,7 +320,7 @@ impl ConsoleIO { let s = Self::ensure_valid_utf8(message.as_string().unwrap_or("")); sanitized.insert( key.clone(), - PhpMixed::String(Preg::replace(&pattern, "", &s)), + PhpMixed::String(Preg::replace(&pattern, "", &s).unwrap_or_default()), ); } } @@ -358,40 +379,44 @@ impl ConsoleIO { } impl LoggerInterface for ConsoleIO { - fn emergency(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::emergency(self, message, context) + // TODO(phase-b): BaseIO's emergency/alert/.../log take PhpMixed and + // IndexMap<String, Box<PhpMixed>> while LoggerInterface takes &str and + // &[(&str, &str)]. Delegation requires reconciling signatures; for now, + // mirror NullIO and panic via todo!(). + fn emergency(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn alert(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::alert(self, message, context) + fn alert(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn critical(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::critical(self, message, context) + fn critical(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn error(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::error(self, message, context) + fn error(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn warning(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::warning(self, message, context) + fn warning(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn notice(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::notice(self, message, context) + fn notice(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn info(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::info(self, message, context) + fn info(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn debug(&self, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::debug(self, message, context) + fn debug(&self, _message: &str, _context: &[(&str, &str)]) { + todo!() } - fn log(&self, level: &str, message: &str, context: &[(&str, &str)]) { - <Self as BaseIO>::log(self, level, message, context) + fn log(&self, _level: &str, _message: &str, _context: &[(&str, &str)]) { + todo!() } } @@ -417,107 +442,142 @@ impl IOInterface for ConsoleIO { } fn write3(&self, message: &str, newline: bool, verbosity: i64) { - let message = Self::sanitize(message, true); + let message = Self::sanitize(PhpMixed::String(message.to_string()), true); self.do_write(message, newline, false, verbosity, false); } fn write_error3(&self, message: &str, newline: bool, verbosity: i64) { - let message = Self::sanitize(message, true); + let message = Self::sanitize(PhpMixed::String(message.to_string()), true); self.do_write(message, newline, true, verbosity, false); } fn write_raw3(&self, message: &str, newline: bool, verbosity: i64) { - self.do_write(message, newline, false, verbosity, true); + self.do_write( + PhpMixed::String(message.to_string()), + newline, + false, + verbosity, + true, + ); } fn write_error_raw3(&self, message: &str, newline: bool, verbosity: i64) { - self.do_write(message, newline, true, verbosity, true); + self.do_write( + PhpMixed::String(message.to_string()), + newline, + true, + verbosity, + true, + ); } fn overwrite4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) { - self.do_overwrite(message, newline, size, false, verbosity); + self.do_overwrite( + PhpMixed::String(message.to_string()), + newline, + size, + false, + verbosity, + ); } fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64) { - self.do_overwrite(message, newline, size, true, verbosity); + self.do_overwrite( + PhpMixed::String(message.to_string()), + newline, + size, + true, + verbosity, + ); } - fn ask(&mut self, question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, question: String, default: PhpMixed) -> PhpMixed { // PHP: $helper = $this->helperSet->get('question'); - let helper = self.helper_set.get("question"); - let question = Question::new( - Self::sanitize(PhpMixed::String(question), true), - if is_string(&default) { - Self::sanitize(default, true) - } else { - default - }, - ); + let _helper = self.helper_set.get("question"); + let sanitized_question = Self::sanitize(PhpMixed::String(question), true) + .as_string() + .unwrap_or("") + .to_string(); + let sanitized_default = if is_string(&default) { + Some(Self::sanitize(default, true)) + } else { + Some(default) + }; + let _question = Question::new(&sanitized_question, sanitized_default); - helper.ask(&*self.input, self.get_error_output(), &question) + // 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") } - fn ask_confirmation(&mut self, question: String, default: bool) -> bool { - let helper = self.helper_set.get("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 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(), ); - helper - .ask(&*self.input, self.get_error_output(), &question) - .as_bool() - .unwrap_or(false) + // TODO(phase-b): see ask() above; placeholder until QuestionHelper is modeled. + todo!("call QuestionHelper::ask on resolved helper and coerce to bool") } fn ask_and_validate( - &mut self, + &self, question: String, validator: Box<dyn Fn(PhpMixed) -> PhpMixed>, attempts: Option<i64>, default: PhpMixed, ) -> PhpMixed { - let helper = self.helper_set.get("question"); - let mut question = Question::new( - Self::sanitize(PhpMixed::String(question), true), - if is_string(&default) { - Self::sanitize(default, true) - } else { - default - }, - ); - question.set_validator(validator); + let _helper = self.helper_set.get("question"); + let sanitized_question = Self::sanitize(PhpMixed::String(question), true) + .as_string() + .unwrap_or("") + .to_string(); + let sanitized_default = if is_string(&default) { + Some(Self::sanitize(default, true)) + } else { + Some(default) + }; + let mut question = Question::new(&sanitized_question, sanitized_default); + // TODO(phase-b): IOInterface validator type is Box<dyn Fn(PhpMixed) -> PhpMixed> + // but Question::set_validator expects Option<Box<dyn Fn(Option<PhpMixed>) -> Result<PhpMixed>>>. + // Bridge the signatures by adapting the input/output types. + let adapted: Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>> = + Box::new(move |answer: Option<PhpMixed>| { + Ok(validator(answer.unwrap_or(PhpMixed::Null))) + }); + question.set_validator(Some(adapted)); question.set_max_attempts(attempts); - helper.ask(&*self.input, self.get_error_output(), &question) + // TODO(phase-b): QuestionHelper::ask not yet modeled. + todo!("call QuestionHelper::ask on resolved helper") } - fn ask_and_hide_answer(&mut self, question: String) -> Option<String> { - let helper = self.helper_set.get("question"); - let mut question = Question::new( - Self::sanitize(PhpMixed::String(question), true), - PhpMixed::Null, - ); + 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("") + .to_string(); + let mut question = Question::new(&sanitized_question, Some(PhpMixed::Null)); question.set_hidden(true); - helper - .ask(&*self.input, self.get_error_output(), &question) - .as_string() - .map(|s| s.to_string()) + // TODO(phase-b): QuestionHelper::ask not yet modeled. + todo!("call QuestionHelper::ask on resolved helper and coerce to Option<String>") } fn select( - &mut self, + &self, question: String, choices: Vec<String>, default: PhpMixed, @@ -532,27 +592,39 @@ impl IOInterface for ConsoleIO { .map(|s| Box::new(PhpMixed::String(s))) .collect(), ); - let helper = self.helper_set.get("question"); - let mut question = ChoiceQuestion::new( - Self::sanitize(PhpMixed::String(question), true), - Self::sanitize(choices.clone(), true), - if is_string(&default) { - Self::sanitize(default, true) - } else { - default - }, - ); + let _helper = self.helper_set.get("question"); + let sanitized_question = Self::sanitize(PhpMixed::String(question), true) + .as_string() + .unwrap_or("") + .to_string(); + // TODO(phase-b): ChoiceQuestion::new expects Vec<PhpMixed>; collect from the + // sanitized PhpMixed::List. + let sanitized_choices_mixed = Self::sanitize(choices.clone(), true); + let sanitized_choices: Vec<PhpMixed> = match sanitized_choices_mixed { + PhpMixed::List(l) => l.into_iter().map(|b| *b).collect(), + PhpMixed::Array(a) => a.into_values().map(|b| *b).collect(), + other => vec![other], + }; + let sanitized_default = if is_string(&default) { + Some(Self::sanitize(default, true)) + } else { + Some(default) + }; + let mut question = + ChoiceQuestion::new(&sanitized_question, sanitized_choices, sanitized_default); // PHP: IOInterface requires false, and Question requires null or int let max_attempts = match attempts { PhpMixed::Bool(false) => None, PhpMixed::Int(i) => Some(i), _ => None, }; - question.set_max_attempts(max_attempts); + // ChoiceQuestion delegates set_max_attempts to its inner Question. + question.0.set_max_attempts(max_attempts); question.set_error_message(&error_message); question.set_multiselect(multiselect); - let result = helper.ask(&*self.input, self.get_error_output(), &question); + // TODO(phase-b): QuestionHelper::ask not yet modeled. + let result: PhpMixed = todo!("call QuestionHelper::ask on resolved helper"); // PHP: $isAssoc = (bool) \count(array_filter(array_keys($choices), 'is_string')); let choice_keys: Vec<String> = match &choices { diff --git a/crates/shirabe/src/io/io_interface.rs b/crates/shirabe/src/io/io_interface.rs index d9092b1..f014594 100644 --- a/crates/shirabe/src/io/io_interface.rs +++ b/crates/shirabe/src/io/io_interface.rs @@ -82,22 +82,22 @@ pub trait IOInterface: LoggerInterface + std::fmt::Debug { } fn overwrite_error4(&self, message: &str, newline: bool, size: Option<i64>, verbosity: i64); - fn ask(&mut self, question: String, default: PhpMixed) -> PhpMixed; + fn ask(&self, question: String, default: PhpMixed) -> PhpMixed; - fn ask_confirmation(&mut self, question: String, default: bool) -> bool; + fn ask_confirmation(&self, question: String, default: bool) -> bool; fn ask_and_validate( - &mut self, + &self, question: String, validator: Box<dyn Fn(PhpMixed) -> PhpMixed>, attempts: Option<i64>, default: PhpMixed, ) -> PhpMixed; - fn ask_and_hide_answer(&mut self, question: String) -> Option<String>; + fn ask_and_hide_answer(&self, question: String) -> Option<String>; fn select( - &mut self, + &self, question: String, choices: Vec<String>, default: PhpMixed, diff --git a/crates/shirabe/src/io/null_io.rs b/crates/shirabe/src/io/null_io.rs index 2536ad0..1a06e6e 100644 --- a/crates/shirabe/src/io/null_io.rs +++ b/crates/shirabe/src/io/null_io.rs @@ -58,16 +58,16 @@ impl IOInterface for NullIO { ) { } - fn ask(&mut self, _question: String, default: PhpMixed) -> PhpMixed { + fn ask(&self, _question: String, default: PhpMixed) -> PhpMixed { default } - fn ask_confirmation(&mut self, _question: String, default: bool) -> bool { + fn ask_confirmation(&self, _question: String, default: bool) -> bool { default } fn ask_and_validate( - &mut self, + &self, _question: String, _validator: Box<dyn Fn(PhpMixed) -> PhpMixed>, _attempts: Option<i64>, @@ -76,12 +76,12 @@ impl IOInterface for NullIO { default } - fn ask_and_hide_answer(&mut self, _question: String) -> Option<String> { + fn ask_and_hide_answer(&self, _question: String) -> Option<String> { None } fn select( - &mut self, + &self, _question: String, _choices: Vec<String>, default: PhpMixed, |
