Completed
Push — master ( d2ff2c...93fad5 )
by Harry
02:21
created

DiffConsoleOutput::getTerminal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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