aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe-external-packages/src/symfony/console/style/output_style.rs
blob: 8d28e76db210bd7a93f8b696eff1b30c4e15a834 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//! ref: composer/vendor/symfony/console/Style/OutputStyle.php

use crate::symfony::console::formatter::OutputFormatterInterface;
use crate::symfony::console::helper::ProgressBar;
use crate::symfony::console::output::ConsoleOutputInterface;
use crate::symfony::console::output::OutputInterface;
use crate::symfony::console::output::output_interface::OUTPUT_NORMAL;

/// Decorates output to add console style guide helpers.
#[derive(Debug)]
pub struct OutputStyle {
    output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>,
}

impl OutputStyle {
    pub fn new(output: std::rc::Rc<std::cell::RefCell<dyn OutputInterface>>) -> Self {
        Self { output }
    }

    pub fn create_progress_bar(&self, max: i64) -> ProgressBar {
        ProgressBar::new(self.output.clone(), max, 1.0 / 25.0)
    }

    pub fn new_line(&self, count: i64) {
        self.output.borrow().write(
            &[shirabe_php_shim::str_repeat(
                shirabe_php_shim::PHP_EOL,
                count as usize,
            )],
            false,
            OUTPUT_NORMAL,
        );
    }

    pub(crate) fn get_error_output(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputInterface>> {
        // PHP checks `$this->output instanceof ConsoleOutputInterface`; this requires
        // runtime type information that the OutputInterface trait object lacks.
        if !Self::is_console_output_interface(&self.output) {
            return self.output.clone();
        }

        Self::as_console_output_interface(&self.output)
            .unwrap()
            .get_error_output()
    }

    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::<crate::symfony::console::output::console_output::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<'_, crate::symfony::console::output::console_output::ConsoleOutput>>
    {
        std::cell::Ref::filter_map(output.borrow(), |output| {
            output
                .as_any()
                .downcast_ref::<crate::symfony::console::output::console_output::ConsoleOutput>()
        })
        .ok()
    }
}

impl OutputInterface for OutputStyle {
    fn write(&self, messages: &[String], newline: bool, options: i64) {
        self.output.borrow().write(messages, newline, options);
    }

    fn writeln(&self, messages: &[String], options: i64) {
        self.output.borrow().writeln(messages, options);
    }

    fn set_verbosity(&self, level: i64) {
        self.output.borrow().set_verbosity(level);
    }

    fn get_verbosity(&self) -> i64 {
        self.output.borrow().get_verbosity()
    }

    fn is_quiet(&self) -> bool {
        self.output.borrow().is_quiet()
    }

    fn is_verbose(&self) -> bool {
        self.output.borrow().is_verbose()
    }

    fn is_very_verbose(&self) -> bool {
        self.output.borrow().is_very_verbose()
    }

    fn is_debug(&self) -> bool {
        self.output.borrow().is_debug()
    }

    fn set_decorated(&self, decorated: bool) {
        self.output.borrow().set_decorated(decorated);
    }

    fn is_decorated(&self) -> bool {
        self.output.borrow().is_decorated()
    }

    fn set_formatter(
        &self,
        formatter: std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>>,
    ) {
        self.output.borrow().set_formatter(formatter);
    }

    fn get_formatter(&self) -> std::rc::Rc<std::cell::RefCell<dyn OutputFormatterInterface>> {
        self.output.borrow().get_formatter()
    }
}