Completed
Push — master ( e4e762...910c9d )
by Harry
14s
created

BufferedConsoleOutput::setTrim()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Graze\BufferedConsole;
4
5
use Graze\BufferedConsole\Diff\ConsoleDiff;
6
use Graze\BufferedConsole\Terminal\Terminal;
7
use Graze\BufferedConsole\Terminal\TerminalInterface;
8
use Graze\BufferedConsole\Wrap\Wrapper;
9
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
10
use Symfony\Component\Console\Output\ConsoleOutputInterface;
11
use Symfony\Component\Console\Output\OutputInterface;
12
13
/**
14
 * This takes an array of lines to write to the console, does a different and only over-writes what has changed to the
15
 * console
16
 */
17
class BufferedConsoleOutput implements ConsoleOutputInterface
18
{
19
    /** @var string[] */
20
    private $buffer = [];
21
    /** @var ConsoleDiff */
22
    private $diff;
23
    /** @var TerminalInterface */
24
    private $terminal;
25
    /** @var ConsoleOutputInterface */
26
    private $output;
27
    /** @var Wrapper */
28
    private $wrapper;
29
    /** @var bool */
30
    private $trim = false;
31
32
    /**
33
     * Constructor.
34
     *
35
     * @param ConsoleOutputInterface $output
36
     * @param TerminalInterface      $terminal
37
     * @param Wrapper                $wrapper
38
     */
39
    public function __construct(
40
        ConsoleOutputInterface $output,
41
        TerminalInterface $terminal = null,
42
        Wrapper $wrapper = null
43
    ) {
44
        $this->output = $output;
45
        $this->diff = new ConsoleDiff();
46
        $this->terminal = $terminal ?: new Terminal();
47
        $this->wrapper = $wrapper ?: new Wrapper($this->terminal->getWidth());
48
    }
49
50
    /**
51
     * Sets information about the terminal
52
     *
53
     * @param TerminalInterface $terminal
54
     */
55
    public function setTerminal(TerminalInterface $terminal)
56
    {
57
        $this->terminal = $terminal;
58
        $this->wrapper->setWidth($terminal->getWidth());
59
    }
60
61
    /**
62
     * @return TerminalInterface
63
     */
64
    public function getTerminal()
65
    {
66
        return $this->terminal;
67
    }
68
69
    /**
70
     * @param string|array $messages The message as an array of lines or a single string
71
     * @param bool         $newline  Whether to add a newline
72
     * @param int          $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered
73
     *                               the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
74
     */
75
    public function write($messages, $newline = false, $options = 0)
76
    {
77
        $this->buffer = [];
78
        $this->output->write($messages, $newline, $options);
79
    }
80
81
    /**
82
     * @param string|string[] $messages The message as an array of lines or a single string
83
     * @param bool            $newline  Whether to add a newline
84
     * @param int             $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered
85
     *                                  the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
86
     */
87
    public function reWrite($messages, $newline = false, $options = 0)
88
    {
89
        $messages = (array) $messages;
90
        $messages = ($this->trim) ? $this->wrapper->trim($messages) : $this->wrapper->wrap($messages);
91
92
        if (count($this->buffer) === 0) {
93
            $this->buffer = $messages;
94
            $this->output->write($messages, $newline, $options);
95
            return;
96
        }
97
98
        $sizeDiff = ($newline ? 1 : 0);
99
        if (count($messages) + $sizeDiff > $this->terminal->getHeight()) {
100
            $messages = array_slice($messages, count($messages) + $sizeDiff - $this->terminal->getHeight());
101
        }
102
103
        $diff = $this->diff->lines($this->buffer, $messages);
104
105
        $output = $this->buildOutput($diff, $newline);
106
        $this->buffer = $messages;
107
108
        $this->output->write($output, $newline, $options);
109
    }
110
111
    /**
112
     * @param array $diff
113
     * @param bool  $newline
114
     *
115
     * @return string
116
     */
117
    private function buildOutput(array $diff, $newline = false)
118
    {
119
        $buffer = '';
120
121
        // reset cursor position
122
        $count = count($this->buffer);
123
        $mod = ($newline ? 1 : 0);
124
        $up = ($count > 0 ? $count - 1 + $mod : $mod);
125
        if ($up > 0) {
126
            $buffer .= $this->terminal->moveUp($up);
127
        }
128
        $buffer .= "\r";
129
130
        $diffSize = count($diff);
131
132
        for ($i = 0; $i < $diffSize; $i++) {
133
            $d = $diff[$i];
134
            if ($i !== 0) {
135
                $buffer .= PHP_EOL;
136
            }
137
            if (!is_null($d)) {
138
                if ($d['col'] > 0) {
139
                    $buffer .= $this->terminal->moveRight($d['col']);
140
                }
141
                $buffer .= $this->terminal->eraseToEnd() . $d['str'];
142
            }
143
        }
144
145
        return $buffer;
146
    }
147
148
    /**
149
     * Gets the OutputInterface for errors.
150
     *
151
     * @return OutputInterface
152
     */
153
    public function getErrorOutput()
154
    {
155
        return $this->output->getErrorOutput();
156
    }
157
158
    /**
159
     * Sets the OutputInterface used for errors.
160
     *
161
     * @param OutputInterface $error
162
     */
163
    public function setErrorOutput(OutputInterface $error)
164
    {
165
        $this->output->setErrorOutput($error);
166
    }
167
168
    /**
169
     * Writes a message to the output and adds a newline at the end.
170
     *
171
     * @param string|array $messages The message as an array of lines of a single string
172
     * @param int          $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered
173
     *                               the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
174
     */
175
    public function writeln($messages, $options = 0)
176
    {
177
        $this->write($messages, true, $options);
178
    }
179
180
    /**
181
     * Sets the verbosity of the output.
182
     *
183
     * @param int $level The level of verbosity (one of the VERBOSITY constants)
184
     */
185
    public function setVerbosity($level)
186
    {
187
        $this->output->setVerbosity($level);
188
    }
189
190
    /**
191
     * Gets the current verbosity of the output.
192
     *
193
     * @return int The current level of verbosity (one of the VERBOSITY constants)
194
     */
195
    public function getVerbosity()
196
    {
197
        return $this->output->getVerbosity();
198
    }
199
200
    /**
201
     * Returns whether verbosity is quiet (-q).
202
     *
203
     * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise
204
     */
205
    public function isQuiet()
206
    {
207
        return $this->output->isQuiet();
208
    }
209
210
    /**
211
     * Returns whether verbosity is verbose (-v).
212
     *
213
     * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise
214
     */
215
    public function isVerbose()
216
    {
217
        return $this->output->isVerbose();
218
    }
219
220
    /**
221
     * Returns whether verbosity is very verbose (-vv).
222
     *
223
     * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise
224
     */
225
    public function isVeryVerbose()
226
    {
227
        return $this->output->isVeryVerbose();
228
    }
229
230
    /**
231
     * Returns whether verbosity is debug (-vvv).
232
     *
233
     * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise
234
     */
235
    public function isDebug()
236
    {
237
        return $this->output->isDebug();
238
    }
239
240
    /**
241
     * Sets the decorated flag.
242
     *
243
     * @param bool $decorated Whether to decorate the messages
244
     */
245
    public function setDecorated($decorated)
246
    {
247
        $this->output->setDecorated($decorated);
248
    }
249
250
    /**
251
     * Gets the decorated flag.
252
     *
253
     * @return bool true if the output will decorate messages, false otherwise
254
     */
255
    public function isDecorated()
256
    {
257
        return $this->output->isDecorated();
258
    }
259
260
    /**
261
     * Sets output formatter.
262
     *
263
     * @param OutputFormatterInterface $formatter
264
     */
265
    public function setFormatter(OutputFormatterInterface $formatter)
266
    {
267
        $this->output->setFormatter($formatter);
268
    }
269
270
    /**
271
     * Returns current output formatter instance.
272
     *
273
     * @return OutputFormatterInterface
274
     */
275
    public function getFormatter()
276
    {
277
        return $this->output->getFormatter();
278
    }
279
280
    /**
281
     * @return bool
282
     */
283
    public function isTrim()
284
    {
285
        return $this->trim;
286
    }
287
288
    /**
289
     * Should we wrap the input or not, if this is set to false, it will trim each line
290
     *
291
     * @param bool $trim
292
     *
293
     * @return $this
294
     */
295
    public function setTrim($trim)
296
    {
297
        $this->trim = $trim;
298
        return $this;
299
    }
300
}
301