Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
6
 * (c) 2012-2022 Justin Hileman
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Psy\Output;
13
 
14
use Symfony\Component\Console\Formatter\OutputFormatter;
15
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
16
use Symfony\Component\Console\Output\ConsoleOutput;
17
 
18
/**
19
 * A ConsoleOutput subclass specifically for Psy Shell output.
20
 */
21
class ShellOutput extends ConsoleOutput
22
{
23
    const NUMBER_LINES = 128;
24
 
25
    private $paging = 0;
26
 
27
    /** @var OutputPager */
28
    private $pager;
29
 
30
    /** @var Theme */
31
    private $theme;
32
 
33
    /**
34
     * Construct a ShellOutput instance.
35
     *
36
     * @param mixed                         $verbosity (default: self::VERBOSITY_NORMAL)
37
     * @param bool|null                     $decorated (default: null)
38
     * @param OutputFormatterInterface|null $formatter (default: null)
39
     * @param string|OutputPager|null       $pager     (default: null)
40
     */
41
    public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null, $pager = null, $theme = null)
42
    {
43
        parent::__construct($verbosity, $decorated, $formatter);
44
 
45
        $this->theme = $theme ?? new Theme('modern');
46
        $this->initFormatters();
47
 
48
        if ($pager === null) {
49
            $this->pager = new PassthruPager($this);
50
        } elseif (\is_string($pager)) {
51
            $this->pager = new ProcOutputPager($this, $pager);
52
        } elseif ($pager instanceof OutputPager) {
53
            $this->pager = $pager;
54
        } else {
55
            throw new \InvalidArgumentException('Unexpected pager parameter: '.$pager);
56
        }
57
    }
58
 
59
    /**
60
     * Page multiple lines of output.
61
     *
62
     * The output pager is started
63
     *
64
     * If $messages is callable, it will be called, passing this output instance
65
     * for rendering. Otherwise, all passed $messages are paged to output.
66
     *
67
     * Upon completion, the output pager is flushed.
68
     *
69
     * @param string|array|\Closure $messages A string, array of strings or a callback
70
     * @param int                   $type     (default: 0)
71
     */
72
    public function page($messages, int $type = 0)
73
    {
74
        if (\is_string($messages)) {
75
            $messages = (array) $messages;
76
        }
77
 
78
        if (!\is_array($messages) && !\is_callable($messages)) {
79
            throw new \InvalidArgumentException('Paged output requires a string, array or callback');
80
        }
81
 
82
        $this->startPaging();
83
 
84
        if (\is_callable($messages)) {
85
            $messages($this);
86
        } else {
87
            $this->write($messages, true, $type);
88
        }
89
 
90
        $this->stopPaging();
91
    }
92
 
93
    /**
94
     * Start sending output to the output pager.
95
     */
96
    public function startPaging()
97
    {
98
        $this->paging++;
99
    }
100
 
101
    /**
102
     * Stop paging output and flush the output pager.
103
     */
104
    public function stopPaging()
105
    {
106
        $this->paging--;
107
        $this->closePager();
108
    }
109
 
110
    /**
111
     * Writes a message to the output.
112
     *
113
     * Optionally, pass `$type | self::NUMBER_LINES` as the $type parameter to
114
     * number the lines of output.
115
     *
116
     * @throws \InvalidArgumentException When unknown output type is given
117
     *
118
     * @param string|array $messages The message as an array of lines or a single string
119
     * @param bool         $newline  Whether to add a newline or not
120
     * @param int          $type     The type of output
121
     */
122
    public function write($messages, $newline = false, $type = 0)
123
    {
124
        if ($this->getVerbosity() === self::VERBOSITY_QUIET) {
125
            return;
126
        }
127
 
128
        $messages = (array) $messages;
129
 
130
        if ($type & self::NUMBER_LINES) {
131
            $pad = \strlen((string) \count($messages));
132
            $template = $this->isDecorated() ? "<aside>%{$pad}s</aside>: %s" : "%{$pad}s: %s";
133
 
134
            if ($type & self::OUTPUT_RAW) {
135
                $messages = \array_map([OutputFormatter::class, 'escape'], $messages);
136
            }
137
 
138
            foreach ($messages as $i => $line) {
139
                $messages[$i] = \sprintf($template, $i, $line);
140
            }
141
 
142
            // clean this up for super.
143
            $type = $type & ~self::NUMBER_LINES & ~self::OUTPUT_RAW;
144
        }
145
 
146
        parent::write($messages, $newline, $type);
147
    }
148
 
149
    /**
150
     * Writes a message to the output.
151
     *
152
     * Handles paged output, or writes directly to the output stream.
153
     *
154
     * @param string $message A message to write to the output
155
     * @param bool   $newline Whether to add a newline or not
156
     */
157
    public function doWrite($message, $newline)
158
    {
159
        if ($this->paging > 0) {
160
            $this->pager->doWrite($message, $newline);
161
        } else {
162
            parent::doWrite($message, $newline);
163
        }
164
    }
165
 
166
    /**
167
     * Set the output Theme.
168
     */
169
    public function setTheme(Theme $theme)
170
    {
171
        $this->theme = $theme;
172
        $this->initFormatters();
173
    }
174
 
175
    /**
176
     * Flush and close the output pager.
177
     */
178
    private function closePager()
179
    {
180
        if ($this->paging <= 0) {
181
            $this->pager->close();
182
        }
183
    }
184
 
185
    /**
186
     * Initialize output formatter styles.
187
     */
188
    private function initFormatters()
189
    {
190
        $useGrayFallback = !$this->grayExists();
191
        $this->theme->applyStyles($this->getFormatter(), $useGrayFallback);
192
        $this->theme->applyErrorStyles($this->getErrorOutput()->getFormatter(), $useGrayFallback);
193
    }
194
 
195
    /**
196
     * Checks if the "gray" color exists on the output.
197
     *
198
     * @return bool
199
     */
200
    private function grayExists(): bool
201
    {
202
        try {
203
            $this->write('<fg=gray></>');
204
        } catch (\InvalidArgumentException $e) {
205
            return false;
206
        }
207
 
208
        return true;
209
    }
210
}