Completed
Push — master ( 8dcfdd...64482a )
by Harry
02:20
created

DiffConsoleOutput::setFormatter()   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 1
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 array $diff
105
     * @param bool  $newline
106
     *
107
     * @return string
108
     */
109
    private function buildOutput(array $diff, $newline = false)
110
    {
111
        $buffer = '';
112
113
        // reset cursor position
114
        $count = count($this->buffer);
115
        $mod = ($newline ? 1 : 0);
116
        $up = ($count > 0 ? $count - 1 + $mod : $mod);
117
        if ($up > 0) {
118
            $buffer .= $this->terminal->moveUp($up);
119
        }
120
        $buffer .= "\r";
121
122
        $diffSize = count($diff);
123
124
        for ($i = 0; $i < $diffSize; $i++) {
125
            $d = $diff[$i];
126
            if ($i !== 0) {
127
                $buffer .= PHP_EOL;
128
            }
129
            if (!is_null($d)) {
130
                if ($d['col'] > 0) {
131
                    $buffer .= $this->terminal->moveRight($d['col']);
132
                }
133
                $buffer .= $this->terminal->eraseToEnd() . $d['str'];
134
            }
135
        }
136
137
        return $buffer;
138
    }
139
140
    /**
141
     * Writes a message to the output and adds a newline at the end.
142
     *
143
     * @param string|array $messages The message as an array of lines of a single string
144
     * @param int          $options  A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered
145
     *                               the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
146
     */
147
    public function writeln($messages, $options = 0)
148
    {
149
        $this->write($messages, true, $options);
150
    }
151
152
    /**
153
     * Sets the verbosity of the output.
154
     *
155
     * @param int $level The level of verbosity (one of the VERBOSITY constants)
156
     */
157
    public function setVerbosity($level)
158
    {
159
        $this->output->setVerbosity($level);
160
    }
161
162
    /**
163
     * Gets the current verbosity of the output.
164
     *
165
     * @return int The current level of verbosity (one of the VERBOSITY constants)
166
     */
167
    public function getVerbosity()
168
    {
169
        return $this->output->getVerbosity();
170
    }
171
172
    /**
173
     * Returns whether verbosity is quiet (-q).
174
     *
175
     * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise
176
     */
177
    public function isQuiet()
178
    {
179
        return $this->output->isQuiet();
180
    }
181
182
    /**
183
     * Returns whether verbosity is verbose (-v).
184
     *
185
     * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise
186
     */
187
    public function isVerbose()
188
    {
189
        return $this->output->isVerbose();
190
    }
191
192
    /**
193
     * Returns whether verbosity is very verbose (-vv).
194
     *
195
     * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise
196
     */
197
    public function isVeryVerbose()
198
    {
199
        return $this->output->isVeryVerbose();
200
    }
201
202
    /**
203
     * Returns whether verbosity is debug (-vvv).
204
     *
205
     * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise
206
     */
207
    public function isDebug()
208
    {
209
        return $this->output->isDebug();
210
    }
211
212
    /**
213
     * Sets the decorated flag.
214
     *
215
     * @param bool $decorated Whether to decorate the messages
216
     */
217
    public function setDecorated($decorated)
218
    {
219
        $this->output->setDecorated($decorated);
220
    }
221
222
    /**
223
     * Gets the decorated flag.
224
     *
225
     * @return bool true if the output will decorate messages, false otherwise
226
     */
227
    public function isDecorated()
228
    {
229
        return $this->output->isDecorated();
230
    }
231
232
    /**
233
     * Sets output formatter.
234
     *
235
     * @param OutputFormatterInterface $formatter
236
     */
237
    public function setFormatter(OutputFormatterInterface $formatter)
238
    {
239
        $this->output->setFormatter($formatter);
240
    }
241
242
    /**
243
     * Returns current output formatter instance.
244
     *
245
     * @return OutputFormatterInterface
246
     */
247
    public function getFormatter()
248
    {
249
        return $this->output->getFormatter();
250
    }
251
252
    /**
253
     * @return bool
254
     */
255
    public function isTrim()
256
    {
257
        return $this->trim;
258
    }
259
260
    /**
261
     * Should we wrap the input or not, if this is set to false, it will trim each line
262
     *
263
     * @param bool $trim
264
     *
265
     * @return $this
266
     */
267
    public function setTrim($trim)
268
    {
269
        $this->trim = $trim;
270
        return $this;
271
    }
272
}
273