Completed
Pull Request — master (#8)
by Harry
02:18
created

DiffConsoleOutput::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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