aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-16 21:59:35 +0900
committernsfisis <nsfisis@gmail.com>2026-06-19 22:17:11 +0900
commitfd733a87364b877d5e66b4973bd61b5379ec4d61 (patch)
tree64bd6c37ca1c33581a851eba22e4261bf5b62b49 /crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
parent7f3171b14a89762b2f0c71969d7243f2297af7c9 (diff)
downloadphp-shirabe-fd733a87364b877d5e66b4973bd61b5379ec4d61.tar.gz
php-shirabe-fd733a87364b877d5e66b4973bd61b5379ec4d61.tar.zst
php-shirabe-fd733a87364b877d5e66b4973bd61b5379ec4d61.zip
feat(command): implement Symfony Command
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs339
1 files changed, 115 insertions, 224 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs b/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
index 88a3bba..522bb78 100644
--- a/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
+++ b/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
@@ -7,7 +7,7 @@ use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
-use crate::symfony::console::command::command::{BaseCommand, Command};
+use crate::symfony::console::command::command::{Command, CommandData};
use crate::symfony::console::command::lazy_command::LazyCommand;
use crate::symfony::console::completion::completion_input::CompletionInput;
use crate::symfony::console::completion::completion_suggestions::{
@@ -16,18 +16,18 @@ use crate::symfony::console::completion::completion_suggestions::{
use crate::symfony::console::completion::output::completion_output_interface::CompletionOutputInterface;
use crate::symfony::console::input::input_interface::InputInterface;
use crate::symfony::console::input::input_option::InputOption;
-use crate::symfony::console::output::output_interface::{self, OutputInterface};
+use crate::symfony::console::output::output_interface::OutputInterface;
/// Responsible for providing the values to the shell completion.
#[derive(Debug)]
pub struct CompleteCommand {
- inner: BaseCommand,
+ inner: CommandData,
completion_outputs: IndexMap<String, PhpMixed>,
is_debug: bool,
}
impl Deref for CompleteCommand {
- type Target = BaseCommand;
+ type Target = CommandData;
fn deref(&self) -> &Self::Target {
&self.inner
@@ -60,15 +60,108 @@ impl CompleteCommand {
)
});
- let this = Self {
- inner: BaseCommand::__construct(None)?,
+ let mut this = Self {
+ inner: CommandData::new(None),
completion_outputs,
is_debug: false,
};
+ // PHP: static $defaultName = '|_complete' / $defaultDescription, applied by the parent
+ // constructor before configure().
+ this.inner.apply_default_name(Self::DEFAULT_NAME)?;
+ this.inner.set_description(Self::DEFAULT_DESCRIPTION);
+ this.configure()?;
Ok(this)
}
+ fn create_completion_input(
+ &self,
+ input: &dyn InputInterface,
+ ) -> anyhow::Result<CompletionInput> {
+ let current_index = input.get_option("current")?;
+ if !current_index.to_bool() || !shirabe_php_shim::ctype_digit(&current_index.to_string()) {
+ anyhow::bail!(shirabe_php_shim::RuntimeException {
+ message: "The \"--current\" option must be set and it must be an integer."
+ .to_string(),
+ code: 0,
+ });
+ }
+
+ let tokens: Vec<String> = match input.get_option("input")?.as_list() {
+ Some(list) => list.iter().map(|v| v.to_string()).collect(),
+ None => Vec::new(),
+ };
+ let mut completion_input = CompletionInput::from_tokens(
+ tokens,
+ current_index.to_string().parse::<i64>().unwrap_or(0),
+ )?;
+
+ // try { $completionInput->bind(...); } catch (ExceptionInterface $e) {}
+ let application = self.get_application().unwrap();
+ let definition = application.borrow_mut().get_definition();
+ let _ = completion_input.bind(&definition.borrow());
+
+ Ok(completion_input)
+ }
+
+ fn find_command(
+ &self,
+ completion_input: &CompletionInput,
+ _output: &dyn OutputInterface,
+ ) -> Option<Rc<RefCell<dyn Command>>> {
+ // try { ... } catch (CommandNotFoundException $e) {}
+ let input_name = completion_input.get_first_argument()?;
+
+ let application = self.get_application().unwrap();
+ // CommandNotFoundException is caught and swallowed by returning None.
+ application.borrow_mut().find(&input_name).ok()
+ }
+
+ fn log(&self, messages: &str) {
+ self.log_many(vec![messages.to_string()]);
+ }
+
+ fn log_many(&self, messages: Vec<String>) {
+ if !self.is_debug {
+ return;
+ }
+
+ let command_name = shirabe_php_shim::basename(&shirabe_php_shim::server_argv()[0]);
+ shirabe_php_shim::file_put_contents3(
+ &format!(
+ "{}/sf_{}.log",
+ shirabe_php_shim::sys_get_temp_dir(),
+ command_name
+ ),
+ &(messages.join(shirabe_php_shim::PHP_EOL) + shirabe_php_shim::PHP_EOL),
+ shirabe_php_shim::FILE_APPEND,
+ );
+ }
+}
+
+/// \get_class($command instanceof LazyCommand ? $command->getCommand() : $command)
+fn get_class_of_command(command: &Rc<RefCell<dyn Command>>) -> String {
+ let borrowed = command.borrow();
+ let _is_lazy = (*borrowed).as_any().downcast_ref::<LazyCommand>().is_some();
+ // TODO: get_class() takes a PhpMixed but the command is a `dyn Command`; reflecting the
+ // concrete class name of a trait object requires a class-name hook on Command (Phase C).
+ todo!()
+}
+
+/// $command->getDefinition()->getOptions()
+fn get_definition_options(_command: &Rc<RefCell<dyn Command>>) -> Vec<InputOption> {
+ // TODO: InputDefinition::get_options() returns `&IndexMap<String, Rc<InputOption>>` but
+ // CompletionSuggestions::suggest_options() takes `Vec<InputOption>`; the option ownership
+ // model must be reconciled (Phase C).
+ todo!()
+}
+
+/// new $completionOutput();
+fn instantiate_completion_output(_class: &PhpMixed) -> Box<dyn CompletionOutputInterface> {
+ todo!()
+}
+
+impl Command for CompleteCommand {
fn configure(&mut self) -> anyhow::Result<()> {
let shells = self
.completion_outputs
@@ -109,17 +202,24 @@ impl CompleteCommand {
Ok(())
}
- fn initialize(&mut self, _input: &dyn InputInterface, _output: &dyn OutputInterface) {
+ fn initialize(
+ &mut self,
+ input: Rc<RefCell<dyn InputInterface>>,
+ output: Rc<RefCell<dyn OutputInterface>>,
+ ) -> anyhow::Result<()> {
+ let _ = (input, output);
self.is_debug = shirabe_php_shim::filter_var(
&shirabe_php_shim::getenv("SYMFONY_COMPLETION_DEBUG").unwrap_or_default(),
shirabe_php_shim::FILTER_VALIDATE_BOOLEAN,
);
+
+ Ok(())
}
fn execute(
&mut self,
- input: &mut dyn InputInterface,
- output: &mut dyn OutputInterface,
+ input: Rc<RefCell<dyn InputInterface>>,
+ output: Rc<RefCell<dyn OutputInterface>>,
) -> anyhow::Result<i64> {
// try { ... } catch (\Throwable $e) { ...; if ($output->isDebug()) { throw $e; } return 2; }
let result: anyhow::Result<i64> = (|| {
@@ -132,7 +232,7 @@ impl CompleteCommand {
// return 126;
// }
- let shell = input.get_option("shell")?;
+ let shell = input.borrow().get_option("shell")?;
if !shell.to_bool() {
anyhow::bail!(shirabe_php_shim::RuntimeException {
message: "The \"--shell\" option must be set.".to_string(),
@@ -160,7 +260,7 @@ impl CompleteCommand {
});
}
- let mut completion_input = self.create_completion_input(input)?;
+ let mut completion_input = self.create_completion_input(&*input.borrow())?;
let mut suggestions = CompletionSuggestions::new();
self.log_many(vec![
@@ -176,7 +276,7 @@ impl CompleteCommand {
"<info>Messages:</>".to_string(),
]);
- let command = self.find_command(&completion_input, output);
+ let command = self.find_command(&completion_input, &*output.borrow());
match command {
None => {
self.log(" No command found, completing using the Application class.");
@@ -273,7 +373,7 @@ impl CompleteCommand {
}
}
- completion_output.write(&suggestions, output);
+ completion_output.write(&suggestions, &mut *output.borrow_mut());
Ok(0)
})();
@@ -283,7 +383,7 @@ impl CompleteCommand {
Err(e) => {
self.log_many(vec!["<error>Error!</error>".to_string(), format!("{}", e)]);
- if output.is_debug() {
+ if output.borrow().is_debug() {
return Err(e);
}
@@ -292,214 +392,5 @@ impl CompleteCommand {
}
}
- fn create_completion_input(
- &self,
- input: &dyn InputInterface,
- ) -> anyhow::Result<CompletionInput> {
- let current_index = input.get_option("current")?;
- if !current_index.to_bool() || !shirabe_php_shim::ctype_digit(&current_index.to_string()) {
- anyhow::bail!(shirabe_php_shim::RuntimeException {
- message: "The \"--current\" option must be set and it must be an integer."
- .to_string(),
- code: 0,
- });
- }
-
- let tokens: Vec<String> = match input.get_option("input")?.as_list() {
- Some(list) => list.iter().map(|v| v.to_string()).collect(),
- None => Vec::new(),
- };
- let mut completion_input = CompletionInput::from_tokens(
- tokens,
- current_index.to_string().parse::<i64>().unwrap_or(0),
- )?;
-
- // try { $completionInput->bind(...); } catch (ExceptionInterface $e) {}
- let application = self.get_application().unwrap();
- let definition = application.borrow_mut().get_definition();
- let _ = completion_input.bind(&definition.borrow());
-
- Ok(completion_input)
- }
-
- fn find_command(
- &self,
- completion_input: &CompletionInput,
- _output: &dyn OutputInterface,
- ) -> Option<Rc<RefCell<dyn Command>>> {
- // try { ... } catch (CommandNotFoundException $e) {}
- let input_name = completion_input.get_first_argument()?;
-
- let application = self.get_application().unwrap();
- // CommandNotFoundException is caught and swallowed by returning None.
- application.borrow_mut().find(&input_name).ok()
- }
-
- fn log(&self, messages: &str) {
- self.log_many(vec![messages.to_string()]);
- }
-
- fn log_many(&self, messages: Vec<String>) {
- if !self.is_debug {
- return;
- }
-
- let command_name = shirabe_php_shim::basename(&shirabe_php_shim::server_argv()[0]);
- shirabe_php_shim::file_put_contents3(
- &format!(
- "{}/sf_{}.log",
- shirabe_php_shim::sys_get_temp_dir(),
- command_name
- ),
- &(messages.join(shirabe_php_shim::PHP_EOL) + shirabe_php_shim::PHP_EOL),
- shirabe_php_shim::FILE_APPEND,
- );
- }
-}
-
-/// \get_class($command instanceof LazyCommand ? $command->getCommand() : $command)
-fn get_class_of_command(command: &Rc<RefCell<dyn Command>>) -> String {
- let borrowed = command.borrow();
- let _is_lazy = (*borrowed).as_any().downcast_ref::<LazyCommand>().is_some();
- // TODO: get_class() takes a PhpMixed but the command is a `dyn Command`; reflecting the
- // concrete class name of a trait object requires a class-name hook on Command (Phase C).
- todo!()
-}
-
-/// $command->getDefinition()->getOptions()
-fn get_definition_options(_command: &Rc<RefCell<dyn Command>>) -> Vec<InputOption> {
- // TODO: InputDefinition::get_options() returns `&IndexMap<String, Rc<InputOption>>` but
- // CompletionSuggestions::suggest_options() takes `Vec<InputOption>`; the option ownership
- // model must be reconciled (Phase C).
- todo!()
-}
-
-/// new $completionOutput();
-fn instantiate_completion_output(_class: &PhpMixed) -> Box<dyn CompletionOutputInterface> {
- todo!()
-}
-
-impl Command for CompleteCommand {
- fn configure(&mut self) {
- let _ = CompleteCommand::configure(self);
- }
-
- fn run(
- &mut self,
- input: &mut dyn InputInterface,
- output: &mut dyn OutputInterface,
- ) -> anyhow::Result<i64> {
- self.inner.run(input, output)
- }
-
- fn is_enabled(&self) -> bool {
- self.inner.is_enabled()
- }
-
- fn set_application(
- &mut self,
- application: Option<Rc<RefCell<dyn crate::symfony::console::application::Application>>>,
- ) {
- self.inner.set_application(application);
- }
-
- fn get_application(
- &self,
- ) -> Option<Rc<RefCell<dyn crate::symfony::console::application::Application>>> {
- self.inner.get_application()
- }
-
- fn set_helper_set(
- &mut self,
- helper_set: Rc<RefCell<crate::symfony::console::helper::helper_set::HelperSet>>,
- ) {
- self.inner.set_helper_set(helper_set);
- }
-
- fn get_helper_set(
- &self,
- ) -> Option<Rc<RefCell<crate::symfony::console::helper::helper_set::HelperSet>>> {
- 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<String> {
- 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<String>) -> anyhow::Result<()> {
- self.inner.set_aliases(aliases)?;
- Ok(())
- }
-
- fn get_aliases(&self) -> Vec<String> {
- self.inner.get_aliases()
- }
-
- fn get_synopsis(&mut self, short: bool) -> String {
- self.inner.get_synopsis(short)
- }
-
- fn get_usages(&self) -> Vec<String> {
- self.inner.get_usages()
- }
-
- fn get_helper(
- &self,
- name: &str,
- ) -> anyhow::Result<
- Result<PhpMixed, crate::symfony::console::exception::logic_exception::LogicException>,
- > {
- self.inner.get_helper(name)
- }
-
- fn ignore_validation_errors(&mut self) {
- self.inner.ignore_validation_errors();
- }
+ crate::delegate_command_trait_impls_to_inner!(inner);
}