aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs')
-rw-r--r--crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs757
1 files changed, 0 insertions, 757 deletions
diff --git a/crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs b/crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs
deleted file mode 100644
index 8ae4d885..00000000
--- a/crates/shirabe-external-packages/src/symfony/console/style/symfony_style.rs
+++ /dev/null
@@ -1,757 +0,0 @@
-//! ref: composer/vendor/symfony/console/Style/SymfonyStyle.php
-
-use crate::symfony::console::exception::invalid_argument_exception::InvalidArgumentException;
-use crate::symfony::console::formatter::OutputFormatter;
-use crate::symfony::console::formatter::OutputFormatterInterface;
-use crate::symfony::console::helper::Helper;
-use crate::symfony::console::helper::ProgressBar;
-use crate::symfony::console::helper::SymfonyQuestionHelper;
-use crate::symfony::console::helper::Table;
-use crate::symfony::console::helper::TableCell;
-use crate::symfony::console::helper::TableSeparator;
-use crate::symfony::console::helper::question_helper::QuestionHelperInterface;
-use crate::symfony::console::helper::table::{Cell, Row};
-use crate::symfony::console::input::InputInterface;
-use crate::symfony::console::output::ConsoleOutputInterface;
-use crate::symfony::console::output::OutputInterface;
-use crate::symfony::console::output::TrimmedBufferOutput;
-use crate::symfony::console::output::console_output::ConsoleOutput;
-use crate::symfony::console::output::output_interface::OUTPUT_NORMAL;
-use crate::symfony::console::question::ChoiceQuestion;
-use crate::symfony::console::question::ConfirmationQuestion;
-use crate::symfony::console::question::Question;
-use crate::symfony::console::question::QuestionInterface;
-use crate::symfony::console::style::output_style::OutputStyle;
-use crate::symfony::console::style::style_interface::StyleInterface;
-use crate::symfony::console::terminal::Terminal;
-use shirabe_php_shim::PhpMixed;
-
-/// Output decorator helpers for the Symfony Style Guide.
-#[derive(Debug)]
-pub struct SymfonyStyle {
- inner: OutputStyle,
- 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, PhpMixed>),
- TableSeparator(TableSeparator),
-}
-
-impl SymfonyStyle {
- pub fn new(
- input: std::rc::Rc<std::cell::RefCell<dyn InputInterface>>,
- output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> Self {
- let buffered_output = TrimmedBufferOutput::new(
- if cfg!(windows) { 4 } else { 2 },
- Some(output.borrow().get_verbosity()),
- false,
- // TODO(plugin): clone of the formatter; PHP `clone $output->getFormatter()`.
- Some(output.borrow().get_formatter()),
- )
- .unwrap();
- // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
- let width = {
- let w = Terminal::new().get_width();
- if w != 0 { w } else { MAX_LINE_LENGTH }
- };
- let line_length = std::cmp::min(width - cfg!(windows) as i64, MAX_LINE_LENGTH);
-
- let inner = OutputStyle::new(output.clone());
-
- Self {
- inner,
- input,
- output,
- question_helper: None,
- progress_bar: None,
- line_length,
- buffered_output,
- }
- }
-
- /// Formats a message as a block of text.
- pub fn block(
- &mut self,
- messages: PhpMixed,
- r#type: Option<&str>,
- style: Option<&str>,
- prefix: &str,
- padding: bool,
- escape: bool,
- ) {
- let messages: Vec<PhpMixed> = if shirabe_php_shim::is_array(&messages) {
- match messages {
- PhpMixed::Array(entries) => entries.into_values().collect(),
- PhpMixed::List(items) => items,
- _ => unreachable!("value is an array past the is_array guard"),
- }
- } else {
- vec![messages]
- };
-
- self.auto_prepend_block();
- let block = self.create_block(messages, r#type, style, prefix, padding, escape);
- self.writeln(
- PhpMixed::List(block.into_iter().map(PhpMixed::String).collect()),
- OUTPUT_NORMAL,
- );
- self.new_line(1);
- }
-
- /// Formats a command comment.
- pub fn comment(&mut self, message: PhpMixed) {
- self.block(
- message,
- None,
- None,
- "<fg=default;bg=default> // </>",
- false,
- false,
- );
- }
-
- /// Formats an info message.
- pub fn info(&mut self, message: PhpMixed) {
- 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::symfony::console::helper::table_cell::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()
- .map(|k| PhpMixed::String(k.clone()))
- .unwrap_or(PhpMixed::Null);
- let first_value = value
- .values()
- .next()
- .cloned()
- .unwrap_or(PhpMixed::Bool(false));
- headers.push(Cell::from(first_key));
- row.push(Cell::from(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();
- }
-
- if self.question_helper.is_none() {
- self.question_helper = Some(SymfonyQuestionHelper::new());
- }
-
- // TODO(phase-c): PHP passes `$this` as the OutputInterface, so SymfonyQuestionHelper's
- // write_error renders through SymfonyStyle::error; SymfonyStyle is not an OutputInterface
- // trait object here, so the raw output is passed instead.
- let answer = {
- let input = self.input.clone();
- let mut input = input.borrow_mut();
- self.question_helper
- .as_mut()
- .unwrap()
- .ask(&mut *input, self.output.clone(), question)
- };
- // PHP `askQuestion` returns the answer directly; exceptions propagate. The double
- // `Result` is collapsed here by panicking on either error.
- let answer = answer
- .expect("question helper error")
- .expect("missing input");
-
- if self.input.borrow().is_interactive() {
- self.new_line(1);
- self.buffered_output
- .write(&["\n".to_string()], false, OUTPUT_NORMAL);
- }
-
- 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) {
- Self::as_console_output_interface(&self.output)
- .unwrap()
- .section()
- } else {
- self.output.clone()
- };
- let mut style = Table::get_style_definition("symfony-style-guide".to_string())
- .expect("style definition lookup")
- .expect("undefined style definition");
- style.set_cell_header_format("<info>%s</info>".to_string());
-
- let mut table = Table::new(output);
- let _ = table.set_style(crate::symfony::console::helper::table::StyleName::Style(
- style,
- ));
- 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(
- shirabe_php_shim::PHP_EOL,
- "\n",
- &self.buffered_output.fetch(),
- ),
- -2,
- None,
- );
-
- if chars.is_empty() {
- self.new_line(1); // empty history, so we should start with a new line.
-
- return;
- }
- // Prepend new line for each non LF chars (This means no blank line was output before)
- 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 !shirabe_php_shim::str_ends_with(&fetched, "\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
- .write(&[message.to_string()], new_line, r#type);
- }
-
- fn create_block(
- &mut self,
- messages: Vec<PhpMixed>,
- r#type: Option<&str>,
- style: Option<&str>,
- prefix: &str,
- padding: bool,
- escape: bool,
- ) -> Vec<String> {
- let mut indent_length: i64 = 0;
- let prefix_length = Helper::width(&Helper::remove_decoration(
- &mut *self.get_formatter().borrow_mut(),
- prefix,
- ));
- let mut lines: Vec<String> = Vec::new();
-
- let mut r#type = r#type.map(|t| t.to_string());
- let mut line_indentation = String::new();
- if let Some(t) = &r#type {
- let formatted = format!("[{}] ", t.clone());
- indent_length = shirabe_php_shim::strlen(&formatted);
- line_indentation = shirabe_php_shim::str_repeat(" ", indent_length as usize);
- r#type = Some(formatted);
- }
-
- let messages_count = messages.len() as i64;
- // wrap and add newlines for each element
- for (key, message) in messages.into_iter().enumerate() {
- let key = key as i64;
- let mut message = Self::php_string(&message);
- if escape {
- message = OutputFormatter::escape(&message).unwrap();
- }
-
- let decoration_length = Helper::width(&message)
- - Helper::width(&Helper::remove_decoration(
- &mut *self.get_formatter().borrow_mut(),
- &message,
- ));
- let message_line_length = std::cmp::min(
- self.line_length - prefix_length - indent_length + decoration_length,
- self.line_length,
- );
- let message_lines = shirabe_php_shim::explode(
- shirabe_php_shim::PHP_EOL,
- &shirabe_php_shim::wordwrap(
- &message,
- message_line_length,
- shirabe_php_shim::PHP_EOL,
- true,
- ),
- );
- for message_line in message_lines {
- lines.push(message_line);
- }
-
- if messages_count > 1 && key < messages_count - 1 {
- lines.push(String::new());
- }
- }
-
- let mut first_line_index: i64 = 0;
- if padding && self.inner.is_decorated() {
- first_line_index = 1;
- shirabe_php_shim::array_unshift(&mut lines, String::new());
- lines.push(String::new());
- }
-
- for (i, line) in lines.iter_mut().enumerate() {
- let i = i as i64;
- if let Some(t) = &r#type {
- *line = if first_line_index == i {
- format!("{}{}", t, line)
- } else {
- format!("{}{}", line_indentation, line)
- };
- }
-
- *line = format!("{}{}", prefix, line);
- line.push_str(&shirabe_php_shim::str_repeat(
- " ",
- (self.line_length
- - Helper::width(&Helper::remove_decoration(
- &mut *self.output.borrow().get_formatter().borrow_mut(),
- line,
- )))
- .max(0) as usize,
- ));
-
- if let Some(style) = style {
- *line = format!("<{}>{}</>", style, line.clone());
- }
- }
-
- lines
- }
-
- fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> {
- self.output.borrow().get_formatter()
- }
-
- fn is_console_output_interface(
- output: &std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> bool {
- // ConsoleOutput is the only OutputInterface implementor that also implements
- // ConsoleOutputInterface, so `instanceof ConsoleOutputInterface` reduces to this downcast.
- shirabe_php_shim::AsAny::as_any(&*output.borrow())
- .downcast_ref::<ConsoleOutput>()
- .is_some()
- }
-
- /// PHP casts to `ConsoleOutputInterface`; `ConsoleOutput` being its only implementor, a
- /// borrow of the concrete type serves as the cast result.
- fn as_console_output_interface(
- output: &std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
- ) -> Option<std::cell::Ref<'_, ConsoleOutput>> {
- std::cell::Ref::filter_map(output.borrow(), |output| {
- output.as_any().downcast_ref::<ConsoleOutput>()
- })
- .ok()
- }
-
- fn php_string(value: &PhpMixed) -> String {
- shirabe_php_shim::strval(value)
- }
-
- /// 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: PhpMixed, r#type: i64) {
- let messages: Vec<PhpMixed> = if !shirabe_php_shim::is_iterable(&messages) {
- vec![messages]
- } else {
- match messages {
- PhpMixed::Array(entries) => entries.into_values().collect(),
- PhpMixed::List(items) => items,
- _ => unreachable!("value is iterable past the is_iterable guard"),
- }
- };
-
- for message in messages {
- let message = Self::php_string(&message);
- self.inner.writeln(std::slice::from_ref(&message), r#type);
- self.write_buffer(&message, true, r#type);
- }
- }
-
- /// {@inheritdoc}
- pub fn write(&mut self, messages: PhpMixed, newline: bool, r#type: i64) {
- let messages: Vec<PhpMixed> = if !shirabe_php_shim::is_iterable(&messages) {
- vec![messages]
- } else {
- match messages {
- PhpMixed::Array(entries) => entries.into_values().collect(),
- PhpMixed::List(items) => items,
- _ => unreachable!("value is iterable past the is_iterable guard"),
- }
- };
-
- for message in messages {
- let message = Self::php_string(&message);
- 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();
- self.writeln(
- PhpMixed::List(vec![
- PhpMixed::String(format!(
- "<comment>{}</>",
- OutputFormatter::escape_trailing_backslash(message),
- )),
- PhpMixed::String(format!(
- "<comment>{}</>",
- shirabe_php_shim::str_repeat(
- "=",
- Helper::width(&Helper::remove_decoration(
- &mut *self.get_formatter().borrow_mut(),
- message,
- )) as usize,
- ),
- )),
- ]),
- OUTPUT_NORMAL,
- );
- self.new_line(1);
- }
-
- /// {@inheritdoc}
- fn section(&mut self, message: &str) {
- self.auto_prepend_block();
- self.writeln(
- PhpMixed::List(vec![
- PhpMixed::String(format!(
- "<comment>{}</>",
- OutputFormatter::escape_trailing_backslash(message),
- )),
- PhpMixed::String(format!(
- "<comment>{}</>",
- shirabe_php_shim::str_repeat(
- "-",
- Helper::width(&Helper::remove_decoration(
- &mut *self.get_formatter().borrow_mut(),
- message,
- )) as usize,
- ),
- )),
- ]),
- OUTPUT_NORMAL,
- );
- self.new_line(1);
- }
-
- /// {@inheritdoc}
- fn listing(&mut self, elements: Vec<PhpMixed>) {
- self.auto_prepend_text();
- let elements: Vec<PhpMixed> = shirabe_php_shim::array_map(
- |element: &PhpMixed| PhpMixed::String(format!(" * {}", element.clone())),
- &elements,
- );
-
- self.writeln(
- PhpMixed::List(elements.into_iter().collect()),
- OUTPUT_NORMAL,
- );
- self.new_line(1);
- }
-
- /// {@inheritdoc}
- fn text(&mut self, message: PhpMixed) {
- self.auto_prepend_text();
-
- let messages: Vec<PhpMixed> = if shirabe_php_shim::is_array(&message) {
- match message {
- PhpMixed::Array(entries) => entries.into_values().collect(),
- PhpMixed::List(items) => items,
- _ => unreachable!("value is an array past the is_array guard"),
- }
- } else {
- vec![message]
- };
- for message in messages {
- self.writeln(PhpMixed::String(format!(" {}", message)), OUTPUT_NORMAL);
- }
- }
-
- /// {@inheritdoc}
- fn success(&mut self, message: PhpMixed) {
- self.block(
- message,
- Some("OK"),
- Some("fg=black;bg=green"),
- " ",
- true,
- true,
- );
- }
-
- /// {@inheritdoc}
- fn error(&mut self, message: PhpMixed) {
- self.block(
- message,
- Some("ERROR"),
- Some("fg=white;bg=red"),
- " ",
- true,
- true,
- );
- }
-
- /// {@inheritdoc}
- fn warning(&mut self, message: PhpMixed) {
- self.block(
- message,
- Some("WARNING"),
- Some("fg=black;bg=yellow"),
- " ",
- true,
- true,
- );
- }
-
- /// {@inheritdoc}
- fn note(&mut self, message: PhpMixed) {
- self.block(message, Some("NOTE"), Some("fg=yellow"), " ! ", false, true);
- }
-
- /// {@inheritdoc}
- fn caution(&mut self, message: PhpMixed) {
- self.block(
- message,
- Some("CAUTION"),
- Some("fg=white;bg=red"),
- " ! ",
- true,
- true,
- );
- }
-
- /// {@inheritdoc}
- fn table(&mut self, headers: Vec<PhpMixed>, rows: Vec<PhpMixed>) {
- self.create_table()
- .set_headers(headers.into_iter().map(Cell::from).collect())
- .set_rows(rows.into_iter().map(Row::from).collect())
- .render();
-
- 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(),
- default,
- "/^y/i".to_string(),
- ));
-
- shirabe_php_shim::boolval(&answer)
- }
-
- /// {@inheritdoc}
- fn choice(
- &mut self,
- question: &str,
- choices: Vec<PhpMixed>,
- default: Option<PhpMixed>,
- ) -> PhpMixed {
- let default = if let Some(default) = default {
- let values = shirabe_php_shim::array_flip(&PhpMixed::List(choices.to_vec()));
- // $default = $values[$default] ?? $default;
- let resolved = match &values {
- PhpMixed::Array(map) => map.get(&default.to_string()).cloned(),
- _ => None,
- };
- Some(resolved.unwrap_or(default))
- } else {
- None
- };
-
- // 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(), 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(
- &[shirabe_php_shim::str_repeat("\n", count as usize)],
- false,
- 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;
- }
-}