aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
diff options
context:
space:
mode:
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.rs417
1 files changed, 0 insertions, 417 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
deleted file mode 100644
index 5854e248..00000000
--- a/crates/shirabe-external-packages/src/symfony/console/command/complete_command.rs
+++ /dev/null
@@ -1,417 +0,0 @@
-//! ref: composer/vendor/symfony/console/Command/CompleteCommand.php
-
-use crate::symfony::console::command::command::{Command, CommandData};
-use crate::symfony::console::completion::completion_input::CompletionInput;
-use crate::symfony::console::completion::completion_suggestions::{
- CompletionSuggestions, StringOrSuggestion,
-};
-use crate::symfony::console::completion::output::bash_completion_output::BashCompletionOutput;
-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::OutputInterface;
-use indexmap::IndexMap;
-use shirabe_php_shim::{PhpMixed, impl_php_class};
-use std::ops::{Deref, DerefMut};
-
-/// Responsible for providing the values to the shell completion.
-#[derive(Debug)]
-pub struct CompleteCommand {
- inner: CommandData,
- completion_outputs: IndexMap<String, PhpMixed>,
- is_debug: std::cell::Cell<bool>,
-}
-
-impl_php_class!(
- CompleteCommand,
- r"Symfony\Component\Console\Command\CompleteCommand"
-);
-
-impl Deref for CompleteCommand {
- type Target = CommandData;
-
- fn deref(&self) -> &Self::Target {
- &self.inner
- }
-}
-
-impl DerefMut for CompleteCommand {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.inner
- }
-}
-
-impl CompleteCommand {
- pub const DEFAULT_NAME: &'static str = "|_complete";
- pub const DEFAULT_DESCRIPTION: &'static str =
- "Internal command to provide shell completion suggestions";
-
- /// @param completion_outputs A list of additional completion outputs, with shell name as
- /// key and FQCN as value
- pub fn new(completion_outputs: IndexMap<String, PhpMixed>) -> anyhow::Result<Self> {
- // must be set before the parent constructor, as the property value is used in configure()
- let mut completion_outputs = completion_outputs;
- // $completionOutputs + ['bash' => BashCompletionOutput::class]
- completion_outputs
- .entry("bash".to_string())
- .or_insert_with(|| {
- PhpMixed::from(
- "Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput"
- .to_string(),
- )
- });
-
- let this = Self {
- inner: CommandData::new(None),
- completion_outputs,
- is_debug: std::cell::Cell::new(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::new(
- "The \"--current\" option must be set and it must be an integer.".to_string()
- ));
- }
-
- 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<std::rc::Rc<std::cell::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.get() {
- return;
- }
-
- let command_name = shirabe_php_shim::basename(
- &shirabe_php_shim::PHP_SERVER
- .lock()
- .unwrap()
- .argv()
- .next()
- .unwrap_or_default()
- .to_string_lossy(),
- );
- 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,
- );
- }
-}
-
-fn get_class_of_command(command: &std::rc::Rc<std::cell::RefCell<dyn Command>>) -> String {
- // LazyCommand is intentionally not ported.
- command.borrow().php_class_name()
-}
-
-fn get_definition_options(
- command: &std::rc::Rc<std::cell::RefCell<dyn Command>>,
-) -> Vec<std::rc::Rc<InputOption>> {
- command
- .borrow()
- .get_definition()
- .get_options()
- .values()
- .cloned()
- .collect()
-}
-
-/// new $completionOutput();
-fn instantiate_completion_output(class: &PhpMixed) -> Box<dyn CompletionOutputInterface> {
- match class.to_string().as_str() {
- "Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput" => {
- Box::new(BashCompletionOutput)
- }
- // completion_outputs only ever registers the bash output (Composer registers no extra
- // ones), so any other FQCN is a programming error.
- other => panic!("unknown completion output class: {}", other),
- }
-}
-
-impl Command for CompleteCommand {
- fn configure(&self) -> anyhow::Result<()> {
- let shells = self
- .completion_outputs
- .keys()
- .cloned()
- .collect::<Vec<_>>()
- .join("\", \"");
- self.inner
- .add_option(
- "shell",
- PhpMixed::from("s".to_string()),
- Some(InputOption::VALUE_REQUIRED),
- &format!("The shell type (\"{}\")", shells),
- PhpMixed::Null,
- )?
- .add_option(
- "input",
- PhpMixed::from("i".to_string()),
- Some(InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY),
- "An array of input tokens (e.g. COMP_WORDS or argv)",
- PhpMixed::Null,
- )?
- .add_option(
- "current",
- PhpMixed::from("c".to_string()),
- Some(InputOption::VALUE_REQUIRED),
- "The index of the \"input\" array that the cursor is in (e.g. COMP_CWORD)",
- PhpMixed::Null,
- )?
- .add_option(
- "symfony",
- PhpMixed::from("S".to_string()),
- Some(InputOption::VALUE_REQUIRED),
- "The version of the completion script",
- PhpMixed::Null,
- )?;
-
- Ok(())
- }
-
- fn initialize(
- &self,
- input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
- output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> anyhow::Result<()> {
- let _ = (input, output);
- self.is_debug.set(shirabe_php_shim::filter_var_boolean(
- &shirabe_php_shim::getenv("SYMFONY_COMPLETION_DEBUG")
- .unwrap_or_default()
- .to_string_lossy(),
- ));
-
- Ok(())
- }
-
- fn execute(
- &self,
- input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
- output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> anyhow::Result<i64> {
- // try { ... } catch (\Throwable $e) { ...; if ($output->isDebug()) { throw $e; } return 2; }
- let result: anyhow::Result<i64> = (|| {
- // uncomment when a bugfix or BC break has been introduced in the shell completion scripts
- // $version = $input->getOption('symfony');
- // if ($version && version_compare($version, 'x.y', '>=')) {
- // $message = sprintf('Completion script version is not supported ("%s" given, ">=x.y" required).', $version);
- // $this->log($message);
- // $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.');
- // return 126;
- // }
-
- let shell = input.borrow().get_option("shell")?;
- if !shell.to_bool() {
- anyhow::bail!(shirabe_php_shim::RuntimeException::new(
- "The \"--shell\" option must be set.".to_string()
- ));
- }
-
- let completion_output = self
- .completion_outputs
- .get(&shell.to_string())
- .cloned()
- .unwrap_or(PhpMixed::Bool(false));
- if !completion_output.to_bool() {
- anyhow::bail!(shirabe_php_shim::RuntimeException::new(format!(
- "Shell completion is not supported for your shell: \"{}\" (supported: \"{}\").",
- shell,
- self.completion_outputs
- .keys()
- .cloned()
- .collect::<Vec<_>>()
- .join("\", \"")
- )));
- }
-
- let mut completion_input = self.create_completion_input(&*input.borrow())?;
- let mut suggestions = CompletionSuggestions::new();
-
- self.log_many(vec![
- String::new(),
- format!(
- "<comment>{}</>",
- shirabe_php_shim::date("Y-m-d H:i:s", None)
- ),
- "<info>Input:</> <comment>(\"|\" indicates the cursor position)</>".to_string(),
- format!(" {}", completion_input.to_string()),
- "<info>Command:</>".to_string(),
- format!(
- " {}",
- shirabe_php_shim::PHP_SERVER
- .lock()
- .unwrap()
- .argv()
- .map(|a| a.to_string_lossy().into_owned())
- .collect::<Vec<_>>()
- .join(" ")
- ),
- "<info>Messages:</>".to_string(),
- ]);
-
- let command = self.find_command(&completion_input, &*output.borrow());
- match command {
- None => {
- self.log(" No command found, completing using the Application class.");
-
- let application = self.get_application().unwrap();
- application
- .borrow_mut()
- .complete(&completion_input, &mut suggestions)?;
- }
- Some(command)
- if completion_input.must_suggest_argument_values_for("command")
- && command.borrow().get_name().as_deref()
- != Some(&completion_input.get_completion_value())
- && !command
- .borrow()
- .get_aliases()
- .iter()
- .any(|a| a == &completion_input.get_completion_value()) =>
- {
- self.log(" No command found, completing using the Application class.");
-
- // expand shortcut names ("cache:cl<TAB>") into their full name ("cache:clear")
- let mut values = vec![command.borrow().get_name()];
- values.extend(command.borrow().get_aliases().into_iter().map(Some));
- suggestions.suggest_values(
- values
- .into_iter()
- .flatten()
- .filter(|v| !v.is_empty())
- .map(StringOrSuggestion::String)
- .collect(),
- );
- }
- Some(command) => {
- // PHP: $command->mergeApplicationDefinition() — $mergeArgs defaults to true.
- command.borrow().merge_application_definition(true);
- completion_input.bind(&command.borrow().get_definition())?;
-
- if CompletionInput::TYPE_OPTION_NAME == completion_input.get_completion_type() {
- self.log(&format!(
- " Completing option names for the <comment>{}</> command.",
- get_class_of_command(&command)
- ));
-
- suggestions.suggest_options(get_definition_options(&command));
- } else {
- self.log_many(vec![
- format!(
- " Completing using the <comment>{}</> class.",
- get_class_of_command(&command)
- ),
- format!(
- " Completing <comment>{}</> for <comment>{}</>",
- completion_input.get_completion_type(),
- completion_input.get_completion_name().unwrap_or_default()
- ),
- ]);
- let compval = completion_input.get_completion_value();
- if !compval.is_empty() {
- self.log(&format!(" Current value: <comment>{}</>", compval));
- }
-
- command
- .borrow()
- .complete(&completion_input, &mut suggestions)?;
- }
- }
- }
-
- // $completionOutput = new $completionOutput();
- let completion_output: Box<dyn CompletionOutputInterface> =
- instantiate_completion_output(&completion_output);
-
- self.log("<info>Suggestions:</>");
- let option_suggestions = suggestions.get_option_suggestions();
- if !option_suggestions.is_empty() {
- self.log(&format!(
- " --{}",
- option_suggestions
- .iter()
- .map(|o| o.get_name())
- .collect::<Vec<_>>()
- .join(" --")
- ));
- } else {
- let value_suggestions: Vec<String> = suggestions
- .get_value_suggestions()
- .iter()
- .map(|s| s.get_value())
- .collect();
- if !value_suggestions.is_empty() {
- self.log(&format!(" {}", value_suggestions.join(" ")));
- } else {
- self.log(" <comment>No suggestions were provided</>");
- }
- }
-
- completion_output.write(&suggestions, &*output.borrow_mut());
-
- Ok(0)
- })();
-
- match result {
- Ok(code) => Ok(code),
- Err(e) => {
- self.log_many(vec!["<error>Error!</error>".to_string(), format!("{}", e)]);
-
- if output.borrow().is_debug() {
- return Err(e);
- }
-
- Ok(2)
- }
- }
- }
-
- crate::delegate_command_trait_impls_to_inner!(inner);
-}