Skip to content

Commit 160aa71

Browse files
authored
Merge pull request #36 from dregad/colors-wrap
Fix color not continued on next line when wrapping text
2 parents 8189c68 + 19482c0 commit 160aa71

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

src/Colors.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class Colors
3131
const C_LIGHTGRAY = 'lightgray';
3232
const C_WHITE = 'white';
3333

34+
// Regex pattern to match color codes
35+
const C_CODE_REGEX = "/(\33\[[0-9;]+m)/";
36+
3437
/** @var array known color names */
3538
protected $colors = array(
3639
self::C_RESET => "\33[0m",

src/TableFormatter.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ protected function substr($string, $start = 0, $length = null)
293293
protected function wordwrap($str, $width = 75, $break = "\n", $cut = false)
294294
{
295295
$lines = explode($break, $str);
296+
$color_reset = $this->colors->getColorCode(Colors::C_RESET);
296297
foreach ($lines as &$line) {
297298
$line = rtrim($line);
298299
if ($this->strlen($line) <= $width) {
@@ -301,18 +302,30 @@ protected function wordwrap($str, $width = 75, $break = "\n", $cut = false)
301302
$words = explode(' ', $line);
302303
$line = '';
303304
$actual = '';
305+
$color = '';
304306
foreach ($words as $word) {
307+
if (preg_match_all(Colors::C_CODE_REGEX, $word, $color_codes) ) {
308+
# Word contains color codes
309+
foreach ($color_codes[0] as $code) {
310+
if ($code == $color_reset) {
311+
$color = '';
312+
} else {
313+
# Remember color so we can reapply it after a line break
314+
$color = $code;
315+
}
316+
}
317+
}
305318
if ($this->strlen($actual . $word) <= $width) {
306319
$actual .= $word . ' ';
307320
} else {
308321
if ($actual != '') {
309322
$line .= rtrim($actual) . $break;
310323
}
311-
$actual = $word;
324+
$actual = $color . $word;
312325
if ($cut) {
313326
while ($this->strlen($actual) > $width) {
314327
$line .= $this->substr($actual, 0, $width) . $break;
315-
$actual = $this->substr($actual, $width);
328+
$actual = $color . $this->substr($actual, $width);
316329
}
317330
}
318331
$actual .= ' ';
@@ -322,4 +335,4 @@ protected function wordwrap($str, $width = 75, $break = "\n", $cut = false)
322335
}
323336
return implode($break, $lines);
324337
}
325-
}
338+
}

tests/TableFormatterTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,51 @@ public function test_onewrap()
138138
$result = $tf->format([5, '*'], [$col1, $col2]);
139139
$this->assertEquals($expect, $result);
140140
}
141+
142+
/**
143+
* Test that colors are correctly applied when text is wrapping across lines.
144+
*
145+
* @dataProvider colorwrapProvider
146+
*/
147+
public function test_colorwrap($text, $expect)
148+
{
149+
$tf = new TableFormatter();
150+
$tf->setMaxWidth(15);
151+
152+
$this->assertEquals($expect, $tf->format(['*'], [$text]));
153+
}
154+
155+
/**
156+
* Data provider for test_colorwrap.
157+
*
158+
* @return array[]
159+
*/
160+
public function colorwrapProvider()
161+
{
162+
$color = new Colors();
163+
$cyan = $color->getColorCode(Colors::C_CYAN);
164+
$reset = $color->getColorCode(Colors::C_RESET);
165+
$wrap = function ($str) use ($color) {
166+
return $color->wrap($str, Colors::C_CYAN);
167+
};
168+
169+
return [
170+
'color word line 1' => [
171+
"This is ". $wrap("cyan") . " text wrapping",
172+
"This is {$cyan}cyan{$reset} \ntext wrapping \n",
173+
],
174+
'color word line 2' => [
175+
"This is text ". $wrap("cyan") . " wrapping",
176+
"This is text \n{$cyan}cyan{$reset} wrapping \n",
177+
],
178+
'color across lines' => [
179+
"This is ". $wrap("cyan text",) . " wrapping",
180+
"This is {$cyan}cyan \ntext{$reset} wrapping \n",
181+
],
182+
'color across lines until end' => [
183+
"This is ". $wrap("cyan text wrapping"),
184+
"This is {$cyan}cyan \n{$cyan}text wrapping{$reset} \n",
185+
],
186+
];
187+
}
141188
}

0 commit comments

Comments
 (0)