diff options
Diffstat (limited to 'crates/shirabe-symfony-console')
| -rw-r--r-- | crates/shirabe-symfony-console/src/style/style_interface.rs | 57 | ||||
| -rw-r--r-- | crates/shirabe-symfony-console/src/style/symfony_style.rs | 350 |
2 files changed, 0 insertions, 407 deletions
diff --git a/crates/shirabe-symfony-console/src/style/style_interface.rs b/crates/shirabe-symfony-console/src/style/style_interface.rs index 14c7ba86..8ac8b49f 100644 --- a/crates/shirabe-symfony-console/src/style/style_interface.rs +++ b/crates/shirabe-symfony-console/src/style/style_interface.rs @@ -2,75 +2,18 @@ use crate::helper::Cell; use crate::helper::Row; -use shirabe_php_shim::PhpMixed; /// Output style helpers. pub trait StyleInterface { - /// Formats a command title. - fn title(&mut self, message: &str); - - /// Formats a section title. - fn section(&mut self, message: &str); - - /// Formats a list. - fn listing(&mut self, elements: &[String]); - - /// Formats informational text. - fn text(&mut self, message: &[String]); - - /// Formats a success result bar. - fn success(&mut self, message: &[String]); - /// Formats an error result bar. fn error(&mut self, message: &[String]); - /// Formats an warning result bar. - fn warning(&mut self, message: &[String]); - - /// Formats a note admonition. - fn note(&mut self, message: &[String]); - - /// Formats a caution admonition. - fn caution(&mut self, message: &[String]); - /// Formats a table. fn table(&mut self, headers: Vec<Cell>, rows: Vec<Row>); - /// Asks a question. - fn ask( - &mut self, - question: &str, - default: Option<&str>, - validator: Option<Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>>>, - ) -> PhpMixed; - - /// Asks a question with the user input hidden. - fn ask_hidden( - &mut self, - question: &str, - validator: Option<Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>>>, - ) -> PhpMixed; - /// Asks for confirmation. fn confirm(&mut self, question: &str, default: bool) -> bool; - /// Asks a choice question. - fn choice( - &mut self, - question: &str, - choices: Vec<String>, - default: Option<PhpMixed>, - ) -> PhpMixed; - /// Add newline(s). fn new_line(&mut self, count: i64); - - /// Starts the progress output. - fn progress_start(&mut self, max: i64); - - /// Advances the progress output X steps. - fn progress_advance(&mut self, step: i64); - - /// Finishes the progress output. - fn progress_finish(&mut self); } diff --git a/crates/shirabe-symfony-console/src/style/symfony_style.rs b/crates/shirabe-symfony-console/src/style/symfony_style.rs index 487ded24..ebab7687 100644 --- a/crates/shirabe-symfony-console/src/style/symfony_style.rs +++ b/crates/shirabe-symfony-console/src/style/symfony_style.rs @@ -1,15 +1,11 @@ //! ref: composer/vendor/symfony/console/Style/SymfonyStyle.php -use crate::exception::InvalidArgumentException; use crate::formatter::OutputFormatter; use crate::formatter::OutputFormatterInterface; use crate::helper::Helper; -use crate::helper::ProgressBar; use crate::helper::QuestionHelperInterface; use crate::helper::SymfonyQuestionHelper; use crate::helper::Table; -use crate::helper::TableCell; -use crate::helper::TableSeparator; use crate::helper::{Cell, Row}; use crate::input::InputInterface; use crate::output::ConsoleOutput; @@ -17,9 +13,7 @@ use crate::output::ConsoleOutputInterface; use crate::output::OUTPUT_NORMAL; use crate::output::OutputInterface; use crate::output::TrimmedBufferOutput; -use crate::question::ChoiceQuestion; use crate::question::ConfirmationQuestion; -use crate::question::Question; use crate::question::QuestionInterface; use crate::style::output_style::OutputStyle; use crate::style::style_interface::StyleInterface; @@ -33,23 +27,12 @@ pub struct SymfonyStyle { input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>, output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>, question_helper: Option<SymfonyQuestionHelper>, - progress_bar: Option<ProgressBar>, line_length: i64, buffered_output: TrimmedBufferOutput, } pub const MAX_LINE_LENGTH: i64 = 120; -/// A `definition_list` entry. PHP types it as `string|array|TableSeparator`; any other type is -/// rejected with an `InvalidArgumentException` (a `LogicException`), which this enum makes -/// unrepresentable. -#[derive(Debug)] -pub enum DefinitionListItem { - String(String), - Array(indexmap::IndexMap<String, String>), - TableSeparator(TableSeparator), -} - impl SymfonyStyle { pub fn new( input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>, @@ -77,7 +60,6 @@ impl SymfonyStyle { input, output, question_helper: None, - progress_bar: None, line_length, buffered_output, } @@ -99,93 +81,6 @@ impl SymfonyStyle { self.new_line(1); } - /// Formats a command comment. - pub fn comment(&mut self, message: &[String]) { - self.block( - message, - None, - None, - "<fg=default;bg=default> // </>", - false, - false, - ); - } - - /// Formats an info message. - pub fn info(&mut self, message: &[String]) { - self.block(message, Some("INFO"), Some("fg=green"), " ", true, true); - } - - /// Formats a horizontal table. - pub fn horizontal_table(&mut self, headers: Vec<Cell>, rows: Vec<Row>) { - self.create_table() - .set_horizontal(true) - .set_headers(headers) - .set_rows(rows) - .render(); - - self.new_line(1); - } - - /// Formats a list of key/value horizontally. - /// - /// Each row can be one of: - /// * 'A title' - /// * ['key' => 'value'] - /// * new TableSeparator() - pub fn definition_list(&mut self, list: Vec<DefinitionListItem>) { - let mut headers: Vec<Cell> = Vec::new(); - let mut row: Vec<Cell> = Vec::new(); - for value in list { - match value { - DefinitionListItem::TableSeparator(separator) => { - headers.push(Cell::Separator(separator.clone())); - row.push(Cell::Separator(separator)); - } - DefinitionListItem::String(value) => { - headers.push(Cell::Cell( - TableCell::new(&value, { - let mut options = indexmap::IndexMap::new(); - options.insert( - "colspan".to_string(), - crate::helper::TableCellOption::Int(2), - ); - options - }) - .expect("colspan is a valid TableCell option"), - )); - row.push(Cell::Null); - } - DefinitionListItem::Array(value) => { - // $headers[] = key($value); $row[] = current($value); - let first_key = value.keys().next().cloned(); - // `current()` on an empty array is false, which renders as an empty cell. - let first_value = value.values().next().cloned().unwrap_or_default(); - headers.push(first_key.map_or(Cell::Null, Cell::Value)); - row.push(Cell::Value(first_value)); - } - } - } - - self.horizontal_table(headers, vec![Row::Cells(row)]); - } - - /// @see ProgressBar::iterate() - /// - /// PHP returns a generator (`yield from`); this port evaluates eagerly, following - /// `ProgressBar::iterate`. - pub fn progress_iterate( - &mut self, - iterable: Vec<(PhpMixed, PhpMixed)>, - max: Option<i64>, - ) -> anyhow::Result<Vec<(PhpMixed, PhpMixed)>> { - let yielded = self.create_progress_bar(0).iterate(iterable, max)?; - - self.new_line(2); - - Ok(yielded) - } - pub fn ask_question(&mut self, question: &impl QuestionInterface) -> PhpMixed { if self.input.borrow().is_interactive() { self.auto_prepend_block(); @@ -221,11 +116,6 @@ impl SymfonyStyle { answer } - /// Returns a new instance which makes use of stderr if available. - pub fn get_error_style(&self) -> Self { - Self::new(self.input.clone(), self.inner.get_error_output()) - } - pub fn create_table(&mut self) -> Table { let output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>> = if Self::is_console_output_interface(&self.output) { @@ -245,30 +135,6 @@ impl SymfonyStyle { table } - pub fn create_progress_bar(&self, max: i64) -> ProgressBar { - let mut progress_bar = self.inner.create_progress_bar(max); - - if !cfg!(windows) - || shirabe_php_shim::getenv("TERM_PROGRAM").as_deref() - == Some(std::ffi::OsStr::new("Hyper")) - { - progress_bar.set_empty_bar_character("░"); // light shade character ░ - progress_bar.set_progress_character(""); - progress_bar.set_bar_character("▓"); // dark shade character ▓ - } - - progress_bar - } - - fn get_progress_bar(&mut self) -> &mut ProgressBar { - // PHP throws RuntimeException('The ProgressBar is not started.'). Reaching this without a - // prior progress_start() call is a caller bug, and the StyleInterface signatures carry no - // Result, so panic. - self.progress_bar - .as_mut() - .expect("The ProgressBar is not started.") - } - fn auto_prepend_block(&mut self) { let chars = shirabe_php_shim::substr( &shirabe_php_shim::str_replace( @@ -289,14 +155,6 @@ impl SymfonyStyle { self.new_line(2 - shirabe_php_shim::substr_count(&chars, "\n")); } - fn auto_prepend_text(&mut self) { - let fetched = self.buffered_output.fetch(); - // Prepend new line if last char isn't EOL: - if !fetched.ends_with('\n') { - self.new_line(1); - } - } - fn write_buffer(&mut self, message: &str, new_line: bool, r#type: i64) { // We need to know if the last chars are PHP_EOL self.buffered_output @@ -425,118 +283,15 @@ impl SymfonyStyle { .ok() } - /// Bridges the `StyleInterface` validator (which yields `anyhow::Error`) to the - /// `Question::set_validator` validator (which yields `InvalidArgumentException`) by - /// converting any error into an `InvalidArgumentException` carrying its message. - #[allow(clippy::type_complexity)] - fn adapt_validator( - validator: Option<Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>>>, - ) -> Option<Box<dyn Fn(Option<PhpMixed>) -> Result<PhpMixed, InvalidArgumentException>>> { - validator.map(|validator| { - Box::new(move |value: Option<PhpMixed>| { - validator(value).map_err(|e| InvalidArgumentException::new(e.to_string())) - }) - as Box<dyn Fn(Option<PhpMixed>) -> Result<PhpMixed, InvalidArgumentException>> - }) - } - - /// {@inheritdoc} pub fn writeln(&mut self, messages: &[String], r#type: i64) { for message in messages { self.inner.writeln(std::slice::from_ref(message), r#type); self.write_buffer(message, true, r#type); } } - - /// {@inheritdoc} - pub fn write(&mut self, messages: &[String], newline: bool, r#type: i64) { - for message in messages { - self.inner - .write(std::slice::from_ref(message), newline, r#type); - self.write_buffer(message, newline, r#type); - } - } } impl StyleInterface for SymfonyStyle { - /// {@inheritdoc} - fn title(&mut self, message: &str) { - self.auto_prepend_block(); - let lines = [ - format!( - "<comment>{}</>", - OutputFormatter::escape_trailing_backslash(message), - ), - format!( - "<comment>{}</>", - shirabe_php_shim::str_repeat( - "=", - Helper::width(&Helper::remove_decoration( - &mut *self.get_formatter().borrow_mut(), - message, - )) as usize, - ), - ), - ]; - self.writeln(&lines, OUTPUT_NORMAL); - self.new_line(1); - } - - /// {@inheritdoc} - fn section(&mut self, message: &str) { - self.auto_prepend_block(); - let lines = [ - format!( - "<comment>{}</>", - OutputFormatter::escape_trailing_backslash(message), - ), - format!( - "<comment>{}</>", - shirabe_php_shim::str_repeat( - "-", - Helper::width(&Helper::remove_decoration( - &mut *self.get_formatter().borrow_mut(), - message, - )) as usize, - ), - ), - ]; - self.writeln(&lines, OUTPUT_NORMAL); - self.new_line(1); - } - - /// {@inheritdoc} - fn listing(&mut self, elements: &[String]) { - self.auto_prepend_text(); - let elements: Vec<String> = - shirabe_php_shim::array_map(|element: &String| format!(" * {}", element), elements); - - self.writeln(&elements, OUTPUT_NORMAL); - self.new_line(1); - } - - /// {@inheritdoc} - fn text(&mut self, message: &[String]) { - self.auto_prepend_text(); - - for message in message { - self.writeln(&[format!(" {}", message)], OUTPUT_NORMAL); - } - } - - /// {@inheritdoc} - fn success(&mut self, message: &[String]) { - self.block( - message, - Some("OK"), - Some("fg=black;bg=green"), - " ", - true, - true, - ); - } - - /// {@inheritdoc} fn error(&mut self, message: &[String]) { self.block( message, @@ -548,36 +303,6 @@ impl StyleInterface for SymfonyStyle { ); } - /// {@inheritdoc} - fn warning(&mut self, message: &[String]) { - self.block( - message, - Some("WARNING"), - Some("fg=black;bg=yellow"), - " ", - true, - true, - ); - } - - /// {@inheritdoc} - fn note(&mut self, message: &[String]) { - self.block(message, Some("NOTE"), Some("fg=yellow"), " ! ", false, true); - } - - /// {@inheritdoc} - fn caution(&mut self, message: &[String]) { - self.block( - message, - Some("CAUTION"), - Some("fg=white;bg=red"), - " ! ", - true, - true, - ); - } - - /// {@inheritdoc} fn table(&mut self, headers: Vec<Cell>, rows: Vec<Row>) { self.create_table() .set_headers(headers) @@ -587,37 +312,6 @@ impl StyleInterface for SymfonyStyle { self.new_line(1); } - /// {@inheritdoc} - fn ask( - &mut self, - question: &str, - default: Option<&str>, - validator: Option<Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>>>, - ) -> PhpMixed { - let mut question = Question::new( - question.to_string(), - default.map(|d| PhpMixed::String(d.to_string())), - ); - question.set_validator(Self::adapt_validator(validator)); - - self.ask_question(&question) - } - - /// {@inheritdoc} - fn ask_hidden( - &mut self, - question: &str, - validator: Option<Box<dyn Fn(Option<PhpMixed>) -> anyhow::Result<PhpMixed>>>, - ) -> PhpMixed { - let mut question = Question::new(question.to_string(), None); - - question.set_hidden(true); - question.set_validator(Self::adapt_validator(validator)); - - self.ask_question(&question) - } - - /// {@inheritdoc} fn confirm(&mut self, question: &str, default: bool) -> bool { let answer = self.ask_question(&ConfirmationQuestion::new( question.to_string(), @@ -628,31 +322,6 @@ impl StyleInterface for SymfonyStyle { shirabe_php_shim::boolval(&answer) } - /// {@inheritdoc} - fn choice( - &mut self, - question: &str, - choices: Vec<String>, - default: Option<PhpMixed>, - ) -> PhpMixed { - let default = default.map(|default| { - let values = shirabe_php_shim::array_flip_strings(&choices); - // $default = $values[$default] ?? $default; - values.get(&default.to_string()).cloned().unwrap_or(default) - }); - - // PHP: return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); - let choices_map: indexmap::IndexMap<String, PhpMixed> = choices - .into_iter() - .enumerate() - .map(|(i, c)| (i.to_string(), PhpMixed::String(c))) - .collect(); - let choice_question = ChoiceQuestion::new(question.to_string(), choices_map, default) - .expect("choice() always provides at least one choice"); - self.ask_question(&choice_question) - } - - /// {@inheritdoc} fn new_line(&mut self, count: i64) { self.inner.new_line(count); self.buffered_output.write( @@ -661,23 +330,4 @@ impl StyleInterface for SymfonyStyle { OUTPUT_NORMAL, ); } - - /// {@inheritdoc} - fn progress_start(&mut self, max: i64) { - let mut progress_bar = self.create_progress_bar(max); - progress_bar.start(None); - self.progress_bar = Some(progress_bar); - } - - /// {@inheritdoc} - fn progress_advance(&mut self, step: i64) { - self.get_progress_bar().advance(step); - } - - /// {@inheritdoc} - fn progress_finish(&mut self) { - self.get_progress_bar().finish(); - self.new_line(2); - self.progress_bar = None; - } } |
