Completed
Push — master ( c103e3...61e87b )
by Harry
02:34
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\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
     * @return TerminalInterface
105
     */
106
    public function getTerminal()
107
    {
108
        return $this->terminal;
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
     * Writes a message to the output and adds a newline at the end.
150
     *
151
     * @param string|array $messages The message as an array of lines of a single string
152
     * @param int          $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered
153
     *                               the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
154
     */
155
    public function writeln($messages, $options = 0)
156
    {
157
        $this->write($messages, true, $options);
158
    }
159
160
    /**
161
     * Sets the verbosity of the output.
162
     *
163
     * @param int $level The level of verbosity (one of the VERBOSITY constants)
164
     */
165
    public function setVerbosity($level)
166
    {
167
        $this->output->setVerbosity($level);
168
    }
169
170
    /**
171
     * Gets the current verbosity of the output.
172
     *
173
     * @return int The current level of verbosity (one of the VERBOSITY constants)
174
     */
175
    public function getVerbosity()
176
    {
177
        return $this->output->getVerbosity();
178
    }
179
180
    /**
181
     * Returns whether verbosity is quiet (-q).
182
     *
183
     * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise
184
     */
185
    public function isQuiet()
186
    {
187
        return $this->output->isQuiet();
188
    }
189
190
    /**
191
     * Returns whether verbosity is verbose (-v).
192
     *
193
     * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise
194
     */
195
    public function isVerbose()
196
    {
197
        return $this->output->isVerbose();
198
    }
199
200
    /**
201
     * Returns whether verbosity is very verbose (-vv).
202
     *
203
     * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise
204
     */
205
    public function isVeryVerbose()
206
    {
207
        return $this->output->isVeryVerbose();
208
    }
209
210
    /**
211
     * Returns whether verbosity is debug (-vvv).
212
     *
213
     * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise
214
     */
215
    public function isDebug()
216
    {
217
        return $this->output->isDebug();
218
    }
219
220
    /**
221
     * Sets the decorated flag.
222
     *
223
     * @param bool $decorated Whether to decorate the messages
224
     */
225
    public function setDecorated($decorated)
226
    {
227
        $this->output->setDecorated($decorated);
228
    }
229
230
    /**
231
     * Gets the decorated flag.
232
     *
233
     * @return bool true if the output will decorate messages, false otherwise
234
     */
235
    public function isDecorated()
236
    {
237
        return $this->output->isDecorated();
238
    }
239
240
    /**
241
     * Sets output formatter.
242
     *
243
     * @param OutputFormatterInterface $formatter
244
     */
245
    public function setFormatter(OutputFormatterInterface $formatter)
246
    {
247
        $this->output->setFormatter($formatter);
248
    }
249
250
    /**
251
     * Returns current output formatter instance.
252
     *
253
     * @return OutputFormatterInterface
254
     */
255
    public function getFormatter()
256
    {
257
        return $this->output->getFormatter();
258
    }
259
260
    /**
261
     * @return bool
262
     */
263
    public function isTrim()
264
    {
265
        return $this->trim;
266
    }
267
268
    /**
269
     * Should we wrap the input or not, if this is set to false, it will trim each line
270
     *
271
     * @param bool $trim
272
     *
273
     * @return $this
274
     */
275
    public function setTrim($trim)
276
    {
277
        $this->trim = $trim;
278
        return $this;
279
    }
280
}
281