aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-12 01:01:35 +0900
committernsfisis <nsfisis@gmail.com>2026-06-12 01:01:43 +0900
commit1e44f5723e4c0e0903d00a61f254901e612fe5e1 (patch)
tree9c2e1eec364bbf6418a4072ee7767b04c3df0297 /crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs
parentddf0a624145b618c05c2ee47414545b99b685f37 (diff)
downloadphp-shirabe-1e44f5723e4c0e0903d00a61f254901e612fe5e1.tar.gz
php-shirabe-1e44f5723e4c0e0903d00a61f254901e612fe5e1.tar.zst
php-shirabe-1e44f5723e4c0e0903d00a61f254901e612fe5e1.zip
feat(symfony-console): port Symfony Console and make the workspace compile
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs182
1 files changed, 182 insertions, 0 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs b/crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs
new file mode 100644
index 0000000..dd14513
--- /dev/null
+++ b/crates/shirabe-external-packages/src/symfony/console/helper/symfony_question_helper.rs
@@ -0,0 +1,182 @@
+use crate::symfony::console::formatter::output_formatter::OutputFormatter;
+use crate::symfony::console::helper::question_helper::QuestionHelper;
+use crate::symfony::console::output::output_interface;
+use crate::symfony::console::output::output_interface::OutputInterface;
+use crate::symfony::console::question::choice_question::ChoiceQuestion;
+use crate::symfony::console::question::confirmation_question::ConfirmationQuestion;
+use crate::symfony::console::question::question::Question;
+use crate::symfony::console::style::symfony_style::SymfonyStyle;
+use shirabe_php_shim::AsAny;
+use shirabe_php_shim::PhpMixed;
+use std::cell::RefCell;
+use std::ops::{Deref, DerefMut};
+use std::rc::Rc;
+
+/// Symfony Style Guide compliant question helper.
+#[derive(Debug, Default)]
+pub struct SymfonyQuestionHelper {
+ inner: QuestionHelper,
+}
+
+impl SymfonyQuestionHelper {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub(crate) fn write_prompt(
+ &self,
+ output: Rc<RefCell<dyn OutputInterface>>,
+ question: &Question,
+ ) {
+ let mut text = OutputFormatter::escape_trailing_backslash(&question.get_question());
+ let default = question.get_default();
+
+ if question.is_multiline() {
+ text += &shirabe_php_shim::sprintf(
+ " (press %s to continue)",
+ &[PhpMixed::String(self.get_eof_shortcut())],
+ );
+ }
+
+ // switch (true)
+ if matches!(default, PhpMixed::Null) {
+ text = shirabe_php_shim::sprintf(" <info>%s</info>:", &[PhpMixed::String(text)]);
+ } else if question
+ .as_any()
+ .downcast_ref::<ConfirmationQuestion>()
+ .is_some()
+ {
+ text = shirabe_php_shim::sprintf(
+ " <info>%s (yes/no)</info> [<comment>%s</comment>]:",
+ &[
+ PhpMixed::String(text),
+ PhpMixed::String(
+ if shirabe_php_shim::boolval(&default) {
+ "yes"
+ } else {
+ "no"
+ }
+ .to_string(),
+ ),
+ ],
+ );
+ } else if let Some(choice_question) = question
+ .as_any()
+ .downcast_ref::<ChoiceQuestion>()
+ .filter(|q| q.is_multiselect())
+ {
+ let choices = choice_question.get_choices();
+ let default_parts = shirabe_php_shim::explode(",", &default.to_string());
+
+ let resolved: Vec<String> = default_parts
+ .iter()
+ .map(|value| {
+ choices
+ .get(&shirabe_php_shim::trim(value, None))
+ .map(|v| v.to_string())
+ .unwrap()
+ })
+ .collect();
+
+ text = shirabe_php_shim::sprintf(
+ " <info>%s</info> [<comment>%s</comment>]:",
+ &[
+ PhpMixed::String(text),
+ PhpMixed::String(OutputFormatter::escape(&resolved.join(", ")).unwrap()),
+ ],
+ );
+ } else if let Some(choice_question) = question.as_any().downcast_ref::<ChoiceQuestion>() {
+ let choices = choice_question.get_choices();
+ text = shirabe_php_shim::sprintf(
+ " <info>%s</info> [<comment>%s</comment>]:",
+ &[
+ PhpMixed::String(text),
+ PhpMixed::String(
+ OutputFormatter::escape(
+ &choices
+ .get(&default.to_string())
+ .map(|v| (**v).clone())
+ .unwrap_or(default.clone())
+ .to_string(),
+ )
+ .unwrap(),
+ ),
+ ],
+ );
+ } else {
+ text = shirabe_php_shim::sprintf(
+ " <info>%s</info> [<comment>%s</comment>]:",
+ &[
+ PhpMixed::String(text),
+ PhpMixed::String(OutputFormatter::escape(&default.to_string()).unwrap()),
+ ],
+ );
+ }
+
+ output
+ .borrow()
+ .writeln(&[text], output_interface::OUTPUT_NORMAL);
+
+ let mut prompt = " > ".to_string();
+
+ if let Some(choice_question) = question.as_any().downcast_ref::<ChoiceQuestion>() {
+ output.borrow().writeln(
+ &self
+ .inner
+ .format_choice_question_choices(choice_question, "comment"),
+ output_interface::OUTPUT_NORMAL,
+ );
+
+ prompt = choice_question.get_prompt().to_string();
+ }
+
+ output
+ .borrow()
+ .write(&[prompt], false, output_interface::OUTPUT_NORMAL);
+ }
+
+ pub(crate) fn write_error(
+ &self,
+ output: Rc<RefCell<dyn OutputInterface>>,
+ error: &shirabe_php_shim::Exception,
+ ) {
+ let is_symfony_style = {
+ let borrowed = output.borrow();
+ (*borrowed)
+ .as_any()
+ .downcast_ref::<SymfonyStyle>()
+ .is_some()
+ };
+ if is_symfony_style {
+ // $output->newLine(); $output->error($error->getMessage());
+ // SymfonyStyle's newLine()/error() require mutable access to the
+ // concrete type; mutable downcasting through the trait object is
+ // resolved in a later phase.
+ todo!("SymfonyStyle newLine()/error() require &mut SymfonyStyle");
+ }
+
+ self.inner.write_error(output, error);
+ }
+
+ fn get_eof_shortcut(&self) -> String {
+ if shirabe_php_shim::php_os_family() == "Windows" {
+ return "<comment>Ctrl+Z</comment> then <comment>Enter</comment>".to_string();
+ }
+
+ "<comment>Ctrl+D</comment>".to_string()
+ }
+}
+
+impl Deref for SymfonyQuestionHelper {
+ type Target = QuestionHelper;
+
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+impl DerefMut for SymfonyQuestionHelper {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.inner
+ }
+}