1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace AlecRabbit\Spinner\Core; |
4
|
|
|
|
5
|
|
|
use AlecRabbit\Accessories\Circular; |
6
|
|
|
use AlecRabbit\ConsoleColour\ConsoleColor; |
7
|
|
|
use AlecRabbit\ConsoleColour\Terminal; |
8
|
|
|
use AlecRabbit\Spinner\Contracts\SpinnerInterface; |
9
|
|
|
|
10
|
|
|
abstract class AbstractSpinner implements SpinnerInterface |
11
|
|
|
{ |
12
|
|
|
protected const ESC = ConsoleColor::ESC_CHAR; |
13
|
|
|
protected const ERASING_SHIFT = 1; |
14
|
|
|
|
15
|
|
|
/** @var Circular */ |
16
|
|
|
protected $spinnerSymbols; |
17
|
|
|
/** @var null|Circular */ |
18
|
|
|
protected $styles; |
19
|
|
|
/** @var string */ |
20
|
|
|
protected $message; |
21
|
|
|
/** @var string */ |
22
|
|
|
protected $moveBackStr; |
23
|
|
|
/** @var \Closure */ |
24
|
|
|
protected $style; |
25
|
|
|
/** @var string */ |
26
|
|
|
protected $paddingStr; |
27
|
|
|
/** @var string */ |
28
|
|
|
protected $eraseBySpacesStr; |
29
|
|
|
|
30
|
|
|
|
31
|
8 |
|
public function __construct( |
32
|
|
|
?string $message = null, |
33
|
|
|
?string $prefix = null, |
34
|
|
|
?string $suffix = null, |
35
|
|
|
?string $paddingStr = null |
36
|
|
|
) { |
37
|
8 |
|
$this->spinnerSymbols = $this->getSymbols(); |
38
|
8 |
|
$this->styles = $this->getStyles(); |
39
|
8 |
|
$this->paddingStr = $paddingStr ?? SpinnerInterface::PADDING_NEXT_LINE; |
40
|
8 |
|
$this->message = $this->refineMessage($message, $prefix, $suffix); |
41
|
8 |
|
$this->setFields(); |
42
|
8 |
|
$this->style = $this->getStyle(); |
43
|
8 |
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @return Circular |
47
|
|
|
*/ |
48
|
|
|
abstract protected function getSymbols(): Circular; |
49
|
|
|
|
50
|
4 |
|
protected function getStyles(): ?Circular |
51
|
|
|
{ |
52
|
4 |
|
$terminal = new Terminal(); |
53
|
4 |
|
if ($terminal->supports256Color()) { |
54
|
|
|
return new Circular([ |
55
|
|
|
'38;5;197', |
56
|
|
|
'38;5;198', |
57
|
|
|
'38;5;199', |
58
|
|
|
'38;5;200', |
59
|
|
|
'38;5;201', |
60
|
|
|
'38;5;202', |
61
|
|
|
'38;5;203', |
62
|
|
|
'38;5;204', |
63
|
|
|
'38;5;205', |
64
|
|
|
]); |
65
|
|
|
} |
66
|
|
|
// @codeCoverageIgnoreStart |
67
|
|
|
if ($terminal->supportsColor()) { |
68
|
|
|
return new Circular([ |
69
|
|
|
'96', |
70
|
|
|
]); |
71
|
|
|
} |
72
|
|
|
return null; |
73
|
|
|
// @codeCoverageIgnoreEnd |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @param null|string $message |
78
|
|
|
* @param null|string $prefix |
79
|
|
|
* @param null|string $suffix |
80
|
|
|
* @return string |
81
|
|
|
*/ |
82
|
8 |
|
protected function refineMessage(?string $message, ?string $prefix, ?string $suffix): string |
83
|
|
|
{ |
84
|
8 |
|
$message = ucfirst($message ?? SpinnerInterface::DEFAULT_MESSAGE); |
85
|
8 |
|
$prefix = $prefix ?? SpinnerInterface::DEFAULT_PREFIX; |
86
|
8 |
|
$suffix = $suffix ?? (empty($message) ? '' : SpinnerInterface::DEFAULT_SUFFIX); |
87
|
8 |
|
return $prefix . $message . $suffix; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @return \Closure |
92
|
|
|
*/ |
93
|
8 |
|
protected function getStyle(): \Closure |
94
|
|
|
{ |
95
|
8 |
|
if (null === $this->styles) { |
96
|
|
|
return |
97
|
|
|
function (): string { |
98
|
2 |
|
$value = (string)$this->spinnerSymbols->value(); |
99
|
2 |
|
return $this->paddingStr . $value; |
100
|
2 |
|
}; |
101
|
|
|
} |
102
|
|
|
return |
103
|
|
|
function (): string { |
104
|
6 |
|
$symbol = (string)$this->spinnerSymbols->value(); |
105
|
6 |
|
$style = $this->styles ? (string)$this->styles->value() : ''; |
106
|
|
|
return |
107
|
6 |
|
$this->paddingStr . |
108
|
6 |
|
self::ESC . |
109
|
6 |
|
"[{$style}m{$symbol}" . |
110
|
6 |
|
self::ESC . '[0m'; |
111
|
6 |
|
}; |
112
|
|
|
} |
113
|
|
|
|
114
|
1 |
|
public function inline(bool $inline): SpinnerInterface |
115
|
|
|
{ |
116
|
1 |
|
$this->paddingStr = $inline ? SpinnerInterface::PADDING_INLINE : SpinnerInterface::PADDING_NEXT_LINE; |
117
|
1 |
|
$this->setFields(); |
118
|
|
|
|
119
|
1 |
|
return $this; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** {@inheritDoc} */ |
123
|
8 |
|
public function begin(): string |
124
|
|
|
{ |
125
|
8 |
|
return $this->spin(); |
126
|
|
|
} |
127
|
|
|
|
128
|
8 |
|
protected function work(): string |
129
|
|
|
{ |
130
|
8 |
|
return ($this->style)() . $this->message; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** {@inheritDoc} */ |
134
|
8 |
|
public function spin(): string |
135
|
|
|
{ |
136
|
8 |
|
return $this->work() . $this->moveBackStr; |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** {@inheritDoc} */ |
140
|
8 |
|
public function end(): string |
141
|
|
|
{ |
142
|
8 |
|
return $this->erase(); |
143
|
|
|
// return self::ESC . '[K'; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** {@inheritDoc} */ |
147
|
8 |
|
public function erase(): string |
148
|
|
|
{ |
149
|
8 |
|
return $this->eraseBySpacesStr . $this->moveBackStr; |
150
|
|
|
} |
151
|
|
|
|
152
|
8 |
|
protected function setFields(): void |
153
|
|
|
{ |
154
|
8 |
|
$strLen = strlen($this->message . $this->paddingStr) + static::ERASING_SHIFT; |
155
|
8 |
|
$this->moveBackStr = self::ESC . "[{$strLen}D"; |
156
|
8 |
|
$this->eraseBySpacesStr = str_repeat(' ', $strLen); |
157
|
8 |
|
} |
158
|
|
|
} |
159
|
|
|
|