8000 feature #43094 [Console] Add support of RGB functional notation (alex… · symfony/symfony@eb324a1 · GitHub
[go: up one dir, main page]

Skip to content

Commit eb324a1

Browse files
committed
feature #43094 [Console] Add support of RGB functional notation (alexandre-daubois)
This PR was merged into the 5.4 branch. Discussion ---------- [Console] Add support of RGB functional notation | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | _NA_ | License | MIT | Doc PR | symfony/symfony-docs#15833 Commits ------- 8f76128 [Console] Add support of RGB functional notation for output colors
2 parents 310f230 + 8f76128 commit eb324a1

File tree

3 files changed

+58
-0
lines changed

3 files changed

+58
-0
lines changed

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ CHANGELOG
66

77
* Add `TesterTrait::assertCommandIsSuccessful()` to test command
88
* Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement
9+
* Add `rgb(r, g, b)` notation support for output colors
910

1011
5.3
1112
---

src/Symfony/Component/Console/Color.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ final class Color
4949
'conceal' => ['set' => 8, 'unset' => 28],
5050
];
5151

52+
private const RGB_FUNCTIONAL_NOTATION_REGEX = '/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/';
53+
5254
private $foreground;
5355
private $background;
5456
private $options = [];
@@ -116,6 +118,10 @@ private function parseColor(string $color, bool $background = false): string
116118
return '';
117119
}
118120

121+
if (str_starts_with($color, 'rgb(')) {
122+
$color = $this->rgbToHex($color);
123+
}
124+
119125
if ('#' === $color[0]) {
120126
$color = substr($color, 1);
121127

@@ -177,4 +183,23 @@ private function getSaturation(int $r, int $g, int $b): int
177183

178184
return (int) $diff * 100 / $v;
179185
}
186+
187+
private function rgbToHex(string $color): string
188+
{
189+
if (!preg_match(self::RGB_FUNCTIONAL_NOTATION_REGEX, $color, $matches)) {
190+
throw new InvalidArgumentException(sprintf('Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "%s".', $color));
191+
}
192+
193+
$rgb = \array_slice($matches, 1);
194+
195+
$hexString = array_map(function ($element) {
196+
if ($element > 255) {
197+
throw new InvalidArgumentException(sprintf('Invalid color component; value should be between 0 and 255, got %d.', $element));
198+
}
199+
200+
return str_pad(dechex((int) $element), 2, '0', \STR_PAD_LEFT);
201+
}, $rgb);
202+
203+
return '#'.implode('', $hexString);
204+
}
180205
}

src/Symfony/Component/Console/Tests/ColorTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Console\Color;
16+
use Symfony\Component\Console\Exception\InvalidArgumentException;
1617

1718
class ColorTest extends TestCase
1819
{
@@ -42,6 +43,9 @@ public function testTrueColors()
4243

4344
$color = new Color('#ffffff', '#000000');
4445
$this->assertSame("\033[38;2;255;255;255;48;2;0;0;0m \033[39;49m", $color->apply(' '));
46+
47+
$color = new Color('rgb(255, 255, 255)', 'rgb(0, 0, 0)');
48+
$this->assertSame("\033[38;2;255;255;255;48;2;0;0;0m \033[39;49m", $color->apply(' '));
4549
}
4650

4751
public function testDegradedTrueColors()
@@ -59,4 +63,32 @@ public function testDegradedTrueColors()
5963
putenv('COLORTERM='.$colorterm);
6064
}
6165
}
66+
67+
/**
68+
* @dataProvider provideMalformedRgbStrings
69+
*/
70+
public function testMalformedRgbString(string $color, string $exceptionMessage)
71+
{
72+
$this->expectException(InvalidArgumentException::class);
73+
$this->expectExceptionMessage($exceptionMessage);
74+
75+
new Color($color);
76+
}
77+
78+
public function provideMalformedRgbStrings(): \Generator
79+
{
80+
yield ['rgb()', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb()".'];
81+
82+
yield ['rgb(0, 0)', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb(0, 0)".'];
83+
84+
yield ['rgb(0, 0, 0, 0)', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb(0, 0, 0, 0)".'];
85+
86+
yield ['rgb(-1, 0, 0)', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb(-1, 0, 0)".'];
87+
88+
yield ['rgb(invalid, 0, 0)', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb(invalid, 0, 0)".'];
89+
90+
yield ['rgb(256, 0, 0)', 'Invalid color component; value should be between 0 and 255, got 256.'];
91+
92+
yield ['rgb(0, 0, 0', 'Invalid RGB functional notation; should be of the form "rgb(r, g, b)", got "rgb(0, 0, 0".'];
93+
}
6294
}

0 commit comments

Comments
 (0)
0