PluginProbe
Depicter — Popup & Slider Builder / trunk
Depicter — Popup & Slider Builder vtrunk
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / vendor / symfony / console / Helper / ProgressIndicator.php

ProgressIndicator.php in Depicter — Popup & Slider Builder trunk, at vendor/symfony/console/Helper/ProgressIndicator.php

248 lines 7.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.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
12 namespace Symfony\Component\Console\Helper;
13
14 use Symfony\Component\Console\Exception\InvalidArgumentException;
15 use Symfony\Component\Console\Exception\LogicException;
16 use Symfony\Component\Console\Output\OutputInterface;
17
18 /**
19 * @author Kevin Bond <kevinbond@gmail.com>
20 */
21 class ProgressIndicator
22 {
23 private const FORMATS = [
24 'normal' => ' %indicator% %message%',
25 'normal_no_ansi' => ' %message%',
26
27 'verbose' => ' %indicator% %message% (%elapsed:6s%)',
28 'verbose_no_ansi' => ' %message% (%elapsed:6s%)',
29
30 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)',
31 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)',
32 ];
33
34 private $output;
35 private $startTime;
36 private $format;
37 private $message;
38 private $indicatorValues;
39 private $indicatorCurrent;
40 private $indicatorChangeInterval;
41 private $indicatorUpdateTime;
42 private $started = false;
43
44 /**
45 * @var array<string, callable>
46 */
47 private static $formatters;
48
49 /**
50 * @param int $indicatorChangeInterval Change interval in milliseconds
51 * @param array|null $indicatorValues Animated indicator characters
52 */
53 public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null)
54 {
55 $this->output = $output;
56
57 if (null === $format) {
58 $format = $this->determineBestFormat();
59 }
60
61 if (null === $indicatorValues) {
62 $indicatorValues = ['-', '\\', '|', '/'];
63 }
64
65 $indicatorValues = array_values($indicatorValues);
66
67 if (2 > \count($indicatorValues)) {
68 throw new InvalidArgumentException('Must have at least 2 indicator value characters.');
69 }
70
71 $this->format = self::getFormatDefinition($format);
72 $this->indicatorChangeInterval = $indicatorChangeInterval;
73 $this->indicatorValues = $indicatorValues;
74 $this->startTime = time();
75 }
76
77 /**
78 * Sets the current indicator message.
79 */
80 public function setMessage(?string $message)
81 {
82 $this->message = $message;
83
84 $this->display();
85 }
86
87 /**
88 * Starts the indicator output.
89 */
90 public function start(string $message)
91 {
92 if ($this->started) {
93 throw new LogicException('Progress indicator already started.');
94 }
95
96 $this->message = $message;
97 $this->started = true;
98 $this->startTime = time();
99 $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval;
100 $this->indicatorCurrent = 0;
101
102 $this->display();
103 }
104
105 /**
106 * Advances the indicator.
107 */
108 public function advance()
109 {
110 if (!$this->started) {
111 throw new LogicException('Progress indicator has not yet been started.');
112 }
113
114 if (!$this->output->isDecorated()) {
115 return;
116 }
117
118 $currentTime = $this->getCurrentTimeInMilliseconds();
119
120 if ($currentTime < $this->indicatorUpdateTime) {
121 return;
122 }
123
124 $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval;
125 ++$this->indicatorCurrent;
126
127 $this->display();
128 }
129
130 /**
131 * Finish the indicator with message.
132 */
133 public function finish(string $message)
134 {
135 if (!$this->started) {
136 throw new LogicException('Progress indicator has not yet been started.');
137 }
138
139 $this->message = $message;
140 $this->display();
141 $this->output->writeln('');
142 $this->started = false;
143 }
144
145 /**
146 * Gets the format for a given name.
147 *
148 * @return string|null
149 */
150 public static function getFormatDefinition(string $name)
151 {
152 return self::FORMATS[$name] ?? null;
153 }
154
155 /**
156 * Sets a placeholder formatter for a given name.
157 *
158 * This method also allow you to override an existing placeholder.
159 */
160 public static function setPlaceholderFormatterDefinition(string $name, callable $callable)
161 {
162 if (!self::$formatters) {
163 self::$formatters = self::initPlaceholderFormatters();
164 }
165
166 self::$formatters[$name] = $callable;
167 }
168
169 /**
170 * Gets the placeholder formatter for a given name (including the delimiter char like %).
171 *
172 * @return callable|null
173 */
174 public static function getPlaceholderFormatterDefinition(string $name)
175 {
176 if (!self::$formatters) {
177 self::$formatters = self::initPlaceholderFormatters();
178 }
179
180 return self::$formatters[$name] ?? null;
181 }
182
183 private function display()
184 {
185 if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) {
186 return;
187 }
188
189 $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) {
190 if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) {
191 return $formatter($this);
192 }
193
194 return $matches[0];
195 }, $this->format ?? ''));
196 }
197
198 private function determineBestFormat(): string
199 {
200 switch ($this->output->getVerbosity()) {
201 // OutputInterface::VERBOSITY_QUIET: display is disabled anyway
202 case OutputInterface::VERBOSITY_VERBOSE:
203 return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi';
204 case OutputInterface::VERBOSITY_VERY_VERBOSE:
205 case OutputInterface::VERBOSITY_DEBUG:
206 return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi';
207 default:
208 return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi';
209 }
210 }
211
212 /**
213 * Overwrites a previous message to the output.
214 */
215 private function overwrite(string $message)
216 {
217 if ($this->output->isDecorated()) {
218 $this->output->write("\x0D\x1B[2K");
219 $this->output->write($message);
220 } else {
221 $this->output->writeln($message);
222 }
223 }
224
225 private function getCurrentTimeInMilliseconds(): float
226 {
227 return round(microtime(true) * 1000);
228 }
229
230 private static function initPlaceholderFormatters(): array
231 {
232 return [
233 'indicator' => function (self $indicator) {
234 return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)];
235 },
236 'message' => function (self $indicator) {
237 return $indicator->message;
238 },
239 'elapsed' => function (self $indicator) {
240 return Helper::formatTime(time() - $indicator->startTime);
241 },
242 'memory' => function () {
243 return Helper::formatMemory(memory_get_usage(true));
244 },
245 ];
246 }
247 }
248