use crate::symfony::console::command::command::{BaseCommand, Command, SetDefinitionArg}; use crate::symfony::console::completion::completion_input::CompletionInput; use crate::symfony::console::completion::completion_suggestions::{ CompletionSuggestions, StringOrSuggestion, }; use crate::symfony::console::descriptor::application_description::ApplicationDescription; use crate::symfony::console::helper::descriptor_helper::DescriptorHelper; use crate::symfony::console::input::input_argument::InputArgument; use crate::symfony::console::input::input_definition::DefinitionItem; use crate::symfony::console::input::input_interface::InputInterface; use crate::symfony::console::input::input_option::InputOption; use crate::symfony::console::output::output_interface::OutputInterface; use shirabe_php_shim::PhpMixed; use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::rc::Rc; /// ListCommand displays the list of all available commands for the application. #[derive(Debug)] pub struct ListCommand { inner: BaseCommand, } impl Deref for ListCommand { type Target = BaseCommand; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for ListCommand { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl ListCommand { fn configure(&mut self) -> anyhow::Result<()> { self.inner .set_name("list")? .set_definition(SetDefinitionArg::Array(vec![ DefinitionItem::InputArgument(InputArgument::new( "namespace".to_string(), Some(InputArgument::OPTIONAL), "The namespace name".to_string(), PhpMixed::Null, )?), DefinitionItem::InputOption(InputOption::new( "raw", PhpMixed::Null, Some(InputOption::VALUE_NONE), "To output raw command list".to_string(), PhpMixed::Null, )?), DefinitionItem::InputOption(InputOption::new( "format", PhpMixed::Null, Some(InputOption::VALUE_REQUIRED), "The output format (txt, xml, json, or md)".to_string(), PhpMixed::from("txt".to_string()), )?), DefinitionItem::InputOption(InputOption::new( "short", PhpMixed::Null, Some(InputOption::VALUE_NONE), "To skip describing commands' arguments".to_string(), PhpMixed::Null, )?), ])) .set_description("List commands") .set_help( "The %command.name% command lists all commands:\n\ \n\ \x20\x20%command.full_name%\n\ \n\ You can also display the commands for a specific namespace:\n\ \n\ \x20\x20%command.full_name% test\n\ \n\ You can also output the information in other formats by using the --format option:\n\ \n\ \x20\x20%command.full_name% --format=xml\n\ \n\ It's also possible to get raw list of commands (useful for embedding command runner):\n\ \n\ \x20\x20%command.full_name% --raw", ); Ok(()) } fn execute( &mut self, input: &mut dyn InputInterface, output: &mut dyn OutputInterface, ) -> anyhow::Result { let helper = DescriptorHelper::new(); // TODO: DescriptorHelper::describe2 takes the described object as Option, // but PhpMixed cannot hold an Application. The Command/Application object mixing for // describe needs a dedicated type (Phase C). let object: Option = todo!(); let mut options = indexmap::IndexMap::new(); options.insert("format".to_string(), input.get_option("format")?); options.insert("raw_text".to_string(), input.get_option("raw")?); options.insert("namespace".to_string(), input.get_argument("namespace")?); options.insert("short".to_string(), input.get_option("short")?); let _ = helper.describe2(output, object, options); Ok(0) } pub fn complete_impl(&self, input: &CompletionInput, suggestions: &mut CompletionSuggestions) { if input.must_suggest_argument_values_for("namespace") { let application = self.get_application().unwrap(); let mut descriptor = ApplicationDescription::new(application, None, false); suggestions.suggest_values( descriptor .get_namespaces() .keys() .cloned() .map(StringOrSuggestion::String) .collect(), ); return; } if input.must_suggest_option_values_for("format") { let helper = DescriptorHelper::new(); suggestions.suggest_values( helper .get_formats() .into_iter() .map(StringOrSuggestion::String) .collect(), ); } } } impl Command for ListCommand { fn configure(&mut self) { let _ = ListCommand::configure(self); } fn run( &mut self, input: &mut dyn InputInterface, output: &mut dyn OutputInterface, ) -> anyhow::Result { self.inner.run(input, output) } fn complete(&self, input: &CompletionInput, suggestions: &mut CompletionSuggestions) { self.complete_impl(input, suggestions); } fn is_enabled(&self) -> bool { self.inner.is_enabled() } fn set_application( &mut self, application: Option>>, ) { self.inner.set_application(application); } fn get_application( &self, ) -> Option>> { self.inner.get_application() } fn set_helper_set( &mut self, helper_set: Rc>, ) { self.inner.set_helper_set(helper_set); } fn get_helper_set( &self, ) -> Option>> { self.inner.get_helper_set() } fn merge_application_definition(&mut self, merge_args: bool) { self.inner.merge_application_definition(merge_args); } fn get_definition(&self) -> &crate::symfony::console::input::input_definition::InputDefinition { self.inner.get_definition() } fn get_native_definition( &self, ) -> &crate::symfony::console::input::input_definition::InputDefinition { self.inner.get_native_definition() } fn set_name(&mut self, name: &str) -> anyhow::Result<()> { self.inner.set_name(name)?; Ok(()) } fn get_name(&self) -> Option { self.inner.get_name() } fn set_hidden(&mut self, hidden: bool) { self.inner.set_hidden(hidden); } fn is_hidden(&self) -> bool { self.inner.is_hidden() } fn set_description(&mut self, description: &str) { self.inner.set_description(description); } fn get_description(&self) -> String { self.inner.get_description() } fn set_help(&mut self, help: &str) { self.inner.set_help(help); } fn get_help(&self) -> String { self.inner.get_help() } fn get_processed_help(&self) -> String { self.inner.get_processed_help() } fn set_aliases(&mut self, aliases: Vec) -> anyhow::Result<()> { self.inner.set_aliases(aliases)?; Ok(()) } fn get_aliases(&self) -> Vec { self.inner.get_aliases() } fn get_synopsis(&mut self, short: bool) -> String { self.inner.get_synopsis(short) } fn get_usages(&self) -> Vec { self.inner.get_usages() } fn get_helper( &self, name: &str, ) -> anyhow::Result< Result, > { self.inner.get_helper(name) } fn ignore_validation_errors(&mut self) { self.inner.ignore_validation_errors(); } }