diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-09 11:19:03 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-09 11:19:03 +0900 |
| commit | 6051927c8fa32cfffa102d2a170c5a6cf747a1b9 (patch) | |
| tree | 3fe6769c90cb03ca8f1b9b825e38ad459182361e /crates/shirabe-external-packages/src/symfony/console/output | |
| parent | e3e8806aec771e482899ed3470e920f7b291fa95 (diff) | |
| download | php-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.tar.gz php-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.tar.zst php-shirabe-6051927c8fa32cfffa102d2a170c5a6cf747a1b9.zip | |
refactor(symfony-console): extract symfony/console into the shirabe-symfony-console crate
Move `Symfony\Component\Console` out of shirabe-external-packages and
into its own crate, so the path is
`shirabe_symfony_console::application::Application` instead of
`shirabe_external_packages::symfony::console::application::Application`.
The `delegate_to_inner!` and `delegate_command_trait_impls_to_inner!`
macros move with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/output')
8 files changed, 0 insertions, 1039 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/output/buffered_output.rs b/crates/shirabe-external-packages/src/symfony/console/output/buffered_output.rs deleted file mode 100644 index fa381fa6..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/buffered_output.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/BufferedOutput.php - -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::output::OutputInterface; -use crate::symfony::console::output::output::{DoWrite, Output}; - -#[derive(Debug)] -pub struct BufferedOutput { - inner: Output, - buffer: std::cell::RefCell<String>, -} - -impl BufferedOutput { - pub fn new( - verbosity: Option<i64>, - decorated: bool, - formatter: Option<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, - ) -> Self { - Self { - inner: Output::new(verbosity, decorated, formatter), - buffer: std::cell::RefCell::new(String::new()), - } - } - - /// Empties buffer and returns its content. - pub fn fetch(&self) -> String { - let content = self.buffer.borrow().clone(); - *self.buffer.borrow_mut() = String::new(); - - content - } -} - -impl DoWrite for BufferedOutput { - fn do_write(&self, message: &str, newline: bool) { - self.buffer.borrow_mut().push_str(message); - - if newline { - self.buffer.borrow_mut().push_str(shirabe_php_shim::PHP_EOL); - } - } -} - -impl OutputInterface for BufferedOutput { - fn write(&self, messages: &[String], newline: bool, options: i64) { - self.inner.write(self, messages, newline, options); - } - fn writeln(&self, messages: &[String], options: i64) { - self.inner.writeln(self, messages, options); - } - fn set_verbosity(&self, level: i64) { - self.inner.set_verbosity(level); - } - fn get_verbosity(&self) -> i64 { - self.inner.get_verbosity() - } - fn is_quiet(&self) -> bool { - self.inner.is_quiet() - } - 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 set_decorated(&self, decorated: bool) { - self.inner.set_decorated(decorated); - } - fn is_decorated(&self) -> bool { - self.inner.is_decorated() - } - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - self.inner.set_formatter(formatter); - } - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.inner.get_formatter() - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/console_output.rs b/crates/shirabe-external-packages/src/symfony/console/output/console_output.rs deleted file mode 100644 index 306f1e61..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/console_output.rs +++ /dev/null @@ -1,210 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/ConsoleOutput.php - -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::output::ConsoleOutputInterface; -use crate::symfony::console::output::OutputInterface; -use crate::symfony::console::output::console_section_output::ConsoleSectionOutput; -use crate::symfony::console::output::output_interface::VERBOSITY_NORMAL; -use crate::symfony::console::output::stream_output::StreamOutput; - -/// ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. -/// -/// This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. -/// -/// ```php -/// $output = new ConsoleOutput(); -/// ``` -/// -/// This is equivalent to: -/// -/// ```php -/// $output = new StreamOutput(fopen('php://stdout', 'w')); -/// $stdErr = new StreamOutput(fopen('php://stderr', 'w')); -/// ``` -#[derive(Debug)] -pub struct ConsoleOutput { - inner: StreamOutput, - stderr: std::cell::RefCell<std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>>, - console_section_outputs: - std::rc::Rc<std::cell::RefCell<Vec<std::rc::Rc<std::cell::RefCell<ConsoleSectionOutput>>>>>, -} - -impl ConsoleOutput { - /// `$verbosity` defaults to `self::VERBOSITY_NORMAL`; pass `None` to use it. - pub fn new( - verbosity: Option<i64>, - decorated: Option<bool>, - formatter: Option<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, - ) -> anyhow::Result<Self> { - let verbosity = verbosity.unwrap_or(VERBOSITY_NORMAL); - - let inner = StreamOutput::new( - Self::open_output_stream(), - Some(verbosity), - decorated, - formatter.clone(), - )? - .expect("ConsoleOutput stdout stream is always valid"); - - let this = if formatter.is_none() { - // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. - let stderr = - StreamOutput::new(Self::open_error_stream(), Some(verbosity), decorated, None)? - .expect("ConsoleOutput stderr stream is always valid"); - Self { - inner, - stderr: std::cell::RefCell::new(std::rc::Rc::new(std::cell::RefCell::new(stderr))), - console_section_outputs: std::rc::Rc::new(std::cell::RefCell::new(Vec::new())), - } - } else { - let actual_decorated = inner.is_decorated(); - let stderr = StreamOutput::new( - Self::open_error_stream(), - Some(verbosity), - decorated, - Some(inner.get_formatter()), - )? - .expect("ConsoleOutput stderr stream is always valid"); - let stderr_decorated = stderr.is_decorated(); - let this = Self { - inner, - stderr: std::cell::RefCell::new(std::rc::Rc::new(std::cell::RefCell::new(stderr))), - console_section_outputs: std::rc::Rc::new(std::cell::RefCell::new(Vec::new())), - }; - - if decorated.is_none() { - this.set_decorated(actual_decorated && stderr_decorated); - } - - this - }; - - Ok(this) - } - - /// Returns true if current environment supports writing console output to - /// STDOUT. - fn has_stdout_support() -> bool { - !Self::is_running_os400() - } - - /// Returns true if current environment supports writing console output to - /// STDERR. - fn has_stderr_support() -> bool { - !Self::is_running_os400() - } - - /// Checks if current executing environment is IBM iSeries (OS400), which - /// doesn't properly convert character-encodings between ASCII to EBCDIC. - fn is_running_os400() -> bool { - let checks = [ - if shirabe_php_shim::function_exists("php_uname") { - shirabe_php_shim::php_uname("s") - } else { - String::new() - }, - shirabe_php_shim::getenv("OSTYPE") - .unwrap_or_default() - .to_string_lossy() - .into_owned(), - shirabe_php_shim::PHP_OS.to_string(), - ]; - - shirabe_php_shim::stripos(&shirabe_php_shim::implode(";", &checks), "OS400").is_some() - } - - /// For testing only. Overwrites the inner `StreamOutput`'s private `stream` field, mirroring - /// what `Symfony\Component\Console\Tester\TesterTrait::initOutput` does via reflection on the - /// parent `StreamOutput::$stream` property of a `ConsoleOutput`. - pub fn __set_stream(&mut self, stream: shirabe_php_shim::PhpResource) { - self.inner.__set_stream(stream); - } - - fn open_output_stream() -> shirabe_php_shim::PhpResource { - if !Self::has_stdout_support() { - return shirabe_php_shim::php_fopen_resource("php://output", "w"); - } - - // Use STDOUT when possible to prevent from opening too many file descriptors - shirabe_php_shim::php_stdout_resource() - } - - fn open_error_stream() -> shirabe_php_shim::PhpResource { - if !Self::has_stderr_support() { - return shirabe_php_shim::php_fopen_resource("php://output", "w"); - } - - // Use STDERR when possible to prevent from opening too many file descriptors - shirabe_php_shim::php_stderr_resource() - } -} - -impl ConsoleOutputInterface for ConsoleOutput { - /// Creates a new output section. - fn section(&self) -> std::rc::Rc<std::cell::RefCell<ConsoleSectionOutput>> { - // ConsoleSectionOutput::new pushes itself into the shared sections list. - ConsoleSectionOutput::new( - self.inner.get_stream().clone(), - &self.console_section_outputs, - self.get_verbosity(), - self.is_decorated(), - self.get_formatter(), - ) - } - - fn get_error_output(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputInterface>> { - self.stderr.borrow().clone() - } - - fn set_error_output(&self, error: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>) { - *self.stderr.borrow_mut() = error; - } -} - -impl OutputInterface for ConsoleOutput { - fn write(&self, messages: &[String], newline: bool, options: i64) { - self.inner.write(messages, newline, options); - } - fn writeln(&self, messages: &[String], options: i64) { - self.inner.writeln(messages, options); - } - fn set_verbosity(&self, level: i64) { - self.inner.set_verbosity(level); - self.stderr.borrow().borrow().set_verbosity(level); - } - fn get_verbosity(&self) -> i64 { - self.inner.get_verbosity() - } - fn is_quiet(&self) -> bool { - self.inner.is_quiet() - } - 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 set_decorated(&self, decorated: bool) { - self.inner.set_decorated(decorated); - self.stderr.borrow().borrow().set_decorated(decorated); - } - fn is_decorated(&self) -> bool { - self.inner.is_decorated() - } - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - self.inner.set_formatter(formatter.clone()); - self.stderr.borrow().borrow().set_formatter(formatter); - } - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.inner.get_formatter() - } - fn as_console_output(&self) -> Option<&dyn ConsoleOutputInterface> { - Some(self) - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/console_output_interface.rs b/crates/shirabe-external-packages/src/symfony/console/output/console_output_interface.rs deleted file mode 100644 index 53db5d6a..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/console_output_interface.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/ConsoleOutputInterface.php - -use crate::symfony::console::output::ConsoleSectionOutput; -use crate::symfony::console::output::OutputInterface; - -/// ConsoleOutputInterface is the interface implemented by ConsoleOutput class. -/// This adds information about stderr and section output stream. -pub trait ConsoleOutputInterface: OutputInterface { - /// Gets the OutputInterface for errors. - fn get_error_output(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>; - - fn set_error_output(&self, error: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>); - - fn section(&self) -> std::rc::Rc<std::cell::RefCell<ConsoleSectionOutput>>; -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/console_section_output.rs b/crates/shirabe-external-packages/src/symfony/console/output/console_section_output.rs deleted file mode 100644 index 3f469fca..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/console_section_output.rs +++ /dev/null @@ -1,206 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/ConsoleSectionOutput.php - -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::helper::Helper; -use crate::symfony::console::output::OutputInterface; -use crate::symfony::console::output::output::DoWrite; -use crate::symfony::console::output::stream_output::StreamOutput; -use crate::symfony::console::terminal::Terminal; - -type Sections = - std::rc::Rc<std::cell::RefCell<Vec<std::rc::Rc<std::cell::RefCell<ConsoleSectionOutput>>>>>; - -#[derive(Debug)] -pub struct ConsoleSectionOutput { - inner: StreamOutput, - content: std::cell::RefCell<Vec<String>>, - lines: std::cell::Cell<i64>, - sections: Sections, - terminal: Terminal, -} - -impl ConsoleSectionOutput { - /// `$sections` is shared by reference (PHP `array &$sections`); the new instance - /// is unshifted into it. - pub fn new( - stream: shirabe_php_shim::PhpResource, - sections: &Sections, - verbosity: i64, - decorated: bool, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) -> std::rc::Rc<std::cell::RefCell<Self>> { - let inner = StreamOutput::new(stream, Some(verbosity), Some(decorated), Some(formatter)) - .expect("ConsoleSectionOutput stream operation must not fatal") - .expect("ConsoleSectionOutput stream is valid"); - - let this = std::rc::Rc::new(std::cell::RefCell::new(Self { - inner, - content: std::cell::RefCell::new(Vec::new()), - lines: std::cell::Cell::new(0), - sections: sections.clone(), - terminal: Terminal::new(), - })); - - shirabe_php_shim::array_unshift(&mut sections.borrow_mut(), this.clone()); - - this - } - - /// Clears previous output for this section. - /// - /// `$lines` is the number of lines to clear. If null, then the entire output - /// of this section is cleared. - pub fn clear(&self, lines: Option<i64>) { - if self.content.borrow().is_empty() || !self.is_decorated() { - return; - } - - let lines = if let Some(lines) = lines.filter(|l| *l != 0) { - // Multiply lines by 2 to cater for each new line added between content - shirabe_php_shim::array_splice( - &mut self.content.borrow_mut(), - -(lines * 2), - None, - Vec::new(), - ); - lines - } else { - let lines = self.lines.get(); - *self.content.borrow_mut() = Vec::new(); - lines - }; - - self.lines.set(self.lines.get() - lines); - - let erased = self.pop_stream_content_until_current_section(lines); - self.inner.do_write(&erased, false); - } - - /// Overwrites the previous output with a new message. - pub fn overwrite(&self, message: &[String]) { - self.clear(None); - self.writeln( - message, - crate::symfony::console::output::output_interface::OUTPUT_NORMAL, - ); - } - - pub fn get_content(&self) -> String { - self.content.borrow().join("") - } - - /// @internal - pub fn add_content(&self, input: &str) { - for line_content in shirabe_php_shim::explode(shirabe_php_shim::PHP_EOL, input) { - let count = (self.get_display_length(&line_content) as f64 - / self.terminal.get_width() as f64) - .ceil(); - self.lines - .set(self.lines.get() + if count != 0.0 { count as i64 } else { 1 }); - self.content.borrow_mut().push(line_content); - self.content - .borrow_mut() - .push(shirabe_php_shim::PHP_EOL.to_string()); - } - } - - /// At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits - /// current section. Then it erases content it crawled through. Optionally, it erases part of current section too. - /// - /// `$numberOfLinesToClearFromCurrentSection` defaults to 0 in PHP. - fn pop_stream_content_until_current_section( - &self, - number_of_lines_to_clear_from_current_section: i64, - ) -> String { - let mut number_of_lines_to_clear = number_of_lines_to_clear_from_current_section; - let mut erased_content: Vec<String> = Vec::new(); - - for section in self.sections.borrow().iter() { - // PHP: `if ($section === $this) break;` — identity comparison against $this. - // The current section is the same object stored in the shared list. - if section.as_ptr() == (self as *const Self).cast_mut() { - break; - } - - let section_ref = section.borrow(); - number_of_lines_to_clear += section_ref.lines.get(); - erased_content.push(section_ref.get_content()); - } - - if number_of_lines_to_clear > 0 { - // move cursor up n lines - self.inner - .do_write(&format!("\x1b[{}A", number_of_lines_to_clear), false); - // erase to end of screen - self.inner.do_write("\x1b[0J", false); - } - - shirabe_php_shim::array_reverse(&erased_content, false).join("") - } - - fn get_display_length(&self, text: &str) -> i64 { - Helper::width(&Helper::remove_decoration( - &mut *self.get_formatter().borrow_mut(), - &shirabe_php_shim::str_replace("\t", " ", text), - )) - } -} - -impl DoWrite for ConsoleSectionOutput { - fn do_write(&self, message: &str, newline: bool) { - if !self.is_decorated() { - self.inner.do_write(message, newline); - - return; - } - - let erased_content = self.pop_stream_content_until_current_section(0); - - self.add_content(message); - - self.inner.do_write(message, true); - self.inner.do_write(&erased_content, false); - } -} - -impl OutputInterface for ConsoleSectionOutput { - fn write(&self, messages: &[String], newline: bool, options: i64) { - self.inner.inner().write(self, messages, newline, options); - } - fn writeln(&self, messages: &[String], options: i64) { - self.inner.inner().writeln(self, messages, options); - } - fn set_verbosity(&self, level: i64) { - self.inner.set_verbosity(level); - } - fn get_verbosity(&self) -> i64 { - self.inner.get_verbosity() - } - fn is_quiet(&self) -> bool { - self.inner.is_quiet() - } - 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 set_decorated(&self, decorated: bool) { - self.inner.set_decorated(decorated); - } - fn is_decorated(&self) -> bool { - self.inner.is_decorated() - } - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - self.inner.set_formatter(formatter); - } - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.inner.get_formatter() - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/output.rs b/crates/shirabe-external-packages/src/symfony/console/output/output.rs deleted file mode 100644 index ec0c060e..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/output.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/Output.php - -use crate::symfony::console::formatter::OutputFormatter; -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::output::output_interface::{ - OUTPUT_NORMAL, OUTPUT_PLAIN, OUTPUT_RAW, VERBOSITY_DEBUG, VERBOSITY_NORMAL, VERBOSITY_QUIET, - VERBOSITY_VERBOSE, VERBOSITY_VERY_VERBOSE, -}; - -/// Base class for output classes. -/// -/// There are five levels of verbosity: -/// -/// * normal: no option passed (normal output) -/// * verbose: -v (more output) -/// * very verbose: -vv (highly extended output) -/// * debug: -vvv (all debug output) -/// * quiet: -q (no output) -pub struct Output { - verbosity: std::cell::Cell<i64>, - formatter: std::cell::RefCell<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, -} - -impl std::fmt::Debug for Output { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Output") - .field("verbosity", &self.verbosity) - .finish_non_exhaustive() - } -} - -/// Subclasses provide the concrete sink by implementing `do_write`. -/// -/// This mirrors the PHP `abstract protected function doWrite(string $message, bool $newline)`. -pub trait DoWrite { - fn do_write(&self, message: &str, newline: bool); -} - -impl Output { - pub fn new( - verbosity: Option<i64>, - decorated: bool, - formatter: Option<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, - ) -> Self { - let verbosity = verbosity.unwrap_or(VERBOSITY_NORMAL); - let formatter = formatter.unwrap_or_else(|| { - std::rc::Rc::new(std::cell::RefCell::new(OutputFormatter::new( - false, - indexmap::IndexMap::new(), - ))) - }); - formatter.borrow_mut().set_decorated(decorated); - Self { - verbosity: std::cell::Cell::new(verbosity), - formatter: std::cell::RefCell::new(formatter), - } - } - - pub fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - *self.formatter.borrow_mut() = formatter; - } - - pub fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.formatter.borrow().clone() - } - - pub fn set_decorated(&self, decorated: bool) { - self.formatter - .borrow() - .borrow_mut() - .set_decorated(decorated); - } - - pub fn is_decorated(&self) -> bool { - self.formatter.borrow().borrow().is_decorated() - } - - pub fn set_verbosity(&self, level: i64) { - self.verbosity.set(level); - } - - pub fn get_verbosity(&self) -> i64 { - self.verbosity.get() - } - - pub fn is_quiet(&self) -> bool { - VERBOSITY_QUIET == self.verbosity.get() - } - - pub fn is_verbose(&self) -> bool { - VERBOSITY_VERBOSE <= self.verbosity.get() - } - - pub fn is_very_verbose(&self) -> bool { - VERBOSITY_VERY_VERBOSE <= self.verbosity.get() - } - - pub fn is_debug(&self) -> bool { - VERBOSITY_DEBUG <= self.verbosity.get() - } - - pub fn writeln(&self, do_writer: &dyn DoWrite, messages: &[String], options: i64) { - self.write(do_writer, messages, true, options); - } - - pub fn write(&self, do_writer: &dyn DoWrite, messages: &[String], newline: bool, options: i64) { - let types = OUTPUT_NORMAL | OUTPUT_RAW | OUTPUT_PLAIN; - let r#type = { - let masked = types & options; - if masked != 0 { masked } else { OUTPUT_NORMAL } - }; - - let verbosities = VERBOSITY_QUIET - | VERBOSITY_NORMAL - | VERBOSITY_VERBOSE - | VERBOSITY_VERY_VERBOSE - | VERBOSITY_DEBUG; - let verbosity = { - let masked = verbosities & options; - if masked != 0 { - masked - } else { - VERBOSITY_NORMAL - } - }; - - if verbosity > self.get_verbosity() { - return; - } - - for message in messages { - let message = match r#type { - OUTPUT_NORMAL => self - .formatter - .borrow() - .borrow_mut() - .format(Some(message)) - .unwrap() - .unwrap_or_default(), - OUTPUT_RAW => message.clone(), - OUTPUT_PLAIN => shirabe_php_shim::strip_tags( - &self - .formatter - .borrow() - .borrow_mut() - .format(Some(message)) - .unwrap() - .unwrap_or_default(), - ), - _ => message.clone(), - }; - - do_writer.do_write(&message, newline); - } - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/output_interface.rs b/crates/shirabe-external-packages/src/symfony/console/output/output_interface.rs deleted file mode 100644 index 28ebd85c..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/output_interface.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/OutputInterface.php - -use crate::symfony::console::formatter::OutputFormatterInterface; - -pub const VERBOSITY_QUIET: i64 = 16; -pub const VERBOSITY_NORMAL: i64 = 32; -pub const VERBOSITY_VERBOSE: i64 = 64; -pub const VERBOSITY_VERY_VERBOSE: i64 = 128; -pub const VERBOSITY_DEBUG: i64 = 256; - -pub const OUTPUT_NORMAL: i64 = 1; -pub const OUTPUT_RAW: i64 = 2; -pub const OUTPUT_PLAIN: i64 = 4; - -/// OutputInterface is the interface implemented by all Output classes. -pub trait OutputInterface: std::fmt::Debug + shirabe_php_shim::AsAny { - /// Writes a message to the output. - /// - /// `$messages` is a single string or an iterable of strings. - fn write(&self, messages: &[String], newline: bool, options: i64); - - /// Writes a message to the output and adds a newline at the end. - fn writeln(&self, messages: &[String], options: i64); - - /// Sets the verbosity of the output. - fn set_verbosity(&self, level: i64); - - /// Gets the current verbosity of the output. - fn get_verbosity(&self) -> i64; - - /// Returns whether verbosity is quiet (-q). - fn is_quiet(&self) -> bool; - - /// Returns whether verbosity is verbose (-v). - fn is_verbose(&self) -> bool; - - /// Returns whether verbosity is very verbose (-vv). - fn is_very_verbose(&self) -> bool; - - /// Returns whether verbosity is debug (-vvv). - fn is_debug(&self) -> bool; - - /// Sets the decorated flag. - fn set_decorated(&self, decorated: bool); - - /// Gets the decorated flag. - fn is_decorated(&self) -> bool; - - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ); - - /// Returns current output formatter instance. - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>; - - /// Downcast hook standing in for PHP's `$output instanceof ConsoleOutputInterface` - /// (cf. `InputInterface::as_streamable`). Only `ConsoleOutput` returns `Some`. - fn as_console_output( - &self, - ) -> Option< - &dyn crate::symfony::console::output::console_output_interface::ConsoleOutputInterface, - > { - None - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/stream_output.rs b/crates/shirabe-external-packages/src/symfony/console/output/stream_output.rs deleted file mode 100644 index 8be98a57..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/stream_output.rs +++ /dev/null @@ -1,200 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/StreamOutput.php - -use crate::symfony::console::exception::InvalidArgumentException; -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::output::OutputInterface; -use crate::symfony::console::output::output::{DoWrite, Output}; -use crate::symfony::console::output::output_interface::VERBOSITY_NORMAL; -use shirabe_php_shim::php_regex; - -/// StreamOutput writes the output to a given stream. -/// -/// Usage: -/// -/// ```php -/// $output = new StreamOutput(fopen('php://stdout', 'w')); -/// ``` -/// -/// As `StreamOutput` can use any stream, you can also use a file: -/// -/// ```php -/// $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); -/// ``` -#[derive(Debug)] -pub struct StreamOutput { - inner: Output, - stream: shirabe_php_shim::PhpResource, -} - -impl StreamOutput { - /// `$verbosity` defaults to `self::VERBOSITY_NORMAL`; pass `None` to use it. - pub fn new( - stream: shirabe_php_shim::PhpResource, - verbosity: Option<i64>, - decorated: Option<bool>, - formatter: Option<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, - ) -> anyhow::Result<Result<Self, InvalidArgumentException>> { - let verbosity = verbosity.unwrap_or(VERBOSITY_NORMAL); - - if shirabe_php_shim::get_resource_type(&stream) != "stream" { - return Ok(Err(InvalidArgumentException::new( - "The StreamOutput class needs a stream as its first argument.".to_string(), - ))); - } - - let decorated = match decorated { - None => Some(Self::has_color_support(&stream)), - other => other, - }; - - let inner = Output::new(Some(verbosity), decorated.unwrap_or(false), formatter); - - Ok(Ok(Self { inner, stream })) - } - - pub(crate) fn inner(&self) -> &Output { - &self.inner - } - - /// Gets the stream attached to this StreamOutput instance. - pub fn get_stream(&self) -> &shirabe_php_shim::PhpResource { - &self.stream - } - - /// For testing only. Overwrites the private `stream` field, mirroring what - /// `Symfony\Component\Console\Tester\TesterTrait::initOutput` does via reflection on the - /// `StreamOutput::$stream` property. - pub fn __set_stream(&mut self, stream: shirabe_php_shim::PhpResource) { - self.stream = stream; - } - - /// Returns true if the stream supports colorization. - /// - /// Colorization is disabled if not supported by the stream: - /// - /// This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo - /// terminals via named pipes, so we can only check the environment. - /// - /// Reference: Composer\XdebugHandler\Process::supportsColor - /// https://github.com/composer/xdebug-handler - pub(crate) fn has_color_support(stream: &shirabe_php_shim::PhpResource) -> bool { - // Follow https://no-color.org/ - if !no_color_first_char().is_empty() { - return false; - } - - // Detect msysgit/mingw and assume this is a tty because detection - // does not work correctly, see https://github.com/composer/composer/issues/9690 - if !shirabe_php_shim::stream_isatty_resource(stream) - && !["MINGW32", "MINGW64"].contains( - &shirabe_php_shim::strtoupper( - &shirabe_php_shim::getenv("MSYSTEM") - .unwrap_or_default() - .to_string_lossy(), - ) - .as_str(), - ) - { - return false; - } - - if cfg!(windows) && shirabe_php_shim::sapi_windows_vt100_support(stream) { - return true; - } - - if shirabe_php_shim::getenv("TERM_PROGRAM").as_deref() - == Some(std::ffi::OsStr::new("Hyper")) - || shirabe_php_shim::getenv("COLORTERM").is_some() - || shirabe_php_shim::getenv("ANSICON").is_some() - || shirabe_php_shim::getenv("ConEmuANSI").as_deref() == Some(std::ffi::OsStr::new("ON")) - { - return true; - } - - let term = shirabe_php_shim::getenv("TERM") - .unwrap_or_default() - .to_string_lossy() - .into_owned(); - if "dumb" == term { - return false; - } - - // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 - let mut matches: Vec<Option<String>> = Vec::new(); - shirabe_php_shim::preg_match( - php_regex!( - "/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/" - ), - &term, - &mut matches, - ) - } -} - -/// PHP: `(($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')`. -fn no_color_first_char() -> String { - let value = shirabe_php_shim::getenv("NO_COLOR") - .unwrap_or_default() - .to_string_lossy() - .into_owned(); - value - .chars() - .next() - .map(|c| c.to_string()) - .unwrap_or_default() -} - -impl DoWrite for StreamOutput { - fn do_write(&self, message: &str, newline: bool) { - let mut message = message.to_string(); - if newline { - message.push_str(shirabe_php_shim::PHP_EOL); - } - - shirabe_php_shim::fwrite_resource(&self.stream, &message); - - shirabe_php_shim::fflush_resource(&self.stream); - } -} - -impl OutputInterface for StreamOutput { - fn write(&self, messages: &[String], newline: bool, options: i64) { - self.inner.write(self, messages, newline, options); - } - fn writeln(&self, messages: &[String], options: i64) { - self.inner.writeln(self, messages, options); - } - fn set_verbosity(&self, level: i64) { - self.inner.set_verbosity(level); - } - fn get_verbosity(&self) -> i64 { - self.inner.get_verbosity() - } - fn is_quiet(&self) -> bool { - self.inner.is_quiet() - } - 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 set_decorated(&self, decorated: bool) { - self.inner.set_decorated(decorated); - } - fn is_decorated(&self) -> bool { - self.inner.is_decorated() - } - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - self.inner.set_formatter(formatter); - } - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.inner.get_formatter() - } -} diff --git a/crates/shirabe-external-packages/src/symfony/console/output/trimmed_buffer_output.rs b/crates/shirabe-external-packages/src/symfony/console/output/trimmed_buffer_output.rs deleted file mode 100644 index 4eb91b41..00000000 --- a/crates/shirabe-external-packages/src/symfony/console/output/trimmed_buffer_output.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! ref: composer/vendor/symfony/console/Output/TrimmedBufferOutput.php - -use crate::symfony::console::exception::InvalidArgumentException; -use crate::symfony::console::formatter::OutputFormatterInterface; -use crate::symfony::console::output::OutputInterface; -use crate::symfony::console::output::output::{DoWrite, Output}; - -/// A BufferedOutput that keeps only the last N chars. -#[derive(Debug)] -pub struct TrimmedBufferOutput { - inner: Output, - max_length: i64, - buffer: std::cell::RefCell<String>, -} - -impl TrimmedBufferOutput { - pub fn new( - max_length: i64, - verbosity: Option<i64>, - decorated: bool, - formatter: Option<std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>>, - ) -> Result<Self, InvalidArgumentException> { - if max_length <= 0 { - return Err(InvalidArgumentException::new(format!( - "\"{}()\" expects a strictly positive maxLength. Got {}.", - "Symfony\\Component\\Console\\Output\\TrimmedBufferOutput::__construct", max_length, - ))); - } - - Ok(Self { - inner: Output::new(verbosity, decorated, formatter), - max_length, - buffer: std::cell::RefCell::new(String::new()), - }) - } - - /// Empties buffer and returns its content. - pub fn fetch(&self) -> String { - let content = self.buffer.borrow().clone(); - *self.buffer.borrow_mut() = String::new(); - - content - } -} - -impl DoWrite for TrimmedBufferOutput { - fn do_write(&self, message: &str, newline: bool) { - self.buffer.borrow_mut().push_str(message); - - if newline { - self.buffer.borrow_mut().push_str(shirabe_php_shim::PHP_EOL); - } - - let trimmed = shirabe_php_shim::substr(&self.buffer.borrow(), 0 - self.max_length, None); - *self.buffer.borrow_mut() = trimmed; - } -} - -impl OutputInterface for TrimmedBufferOutput { - fn write(&self, messages: &[String], newline: bool, options: i64) { - self.inner.write(self, messages, newline, options); - } - fn writeln(&self, messages: &[String], options: i64) { - self.inner.writeln(self, messages, options); - } - fn set_verbosity(&self, level: i64) { - self.inner.set_verbosity(level); - } - fn get_verbosity(&self) -> i64 { - self.inner.get_verbosity() - } - fn is_quiet(&self) -> bool { - self.inner.is_quiet() - } - 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 set_decorated(&self, decorated: bool) { - self.inner.set_decorated(decorated); - } - fn is_decorated(&self) -> bool { - self.inner.is_decorated() - } - fn set_formatter( - &self, - formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>, - ) { - self.inner.set_formatter(formatter); - } - fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> { - self.inner.get_formatter() - } -} |
