Skip to content

Commit a08090d

Browse files
Merge branch '6.4' into 7.2
* 6.4: [Console] Table counts wrong column width when using colspan and `setColumnMaxWidth()` [Console] Table counts wrong number of padding symbols in `renderCell()` method when cell contain unicode variant selector [Cache] Fix using a `ChainAdapter` as an adapter for a pool [Serializer] Fix collect_denormalization_errors flag in defaultContext [VarDumper] Avoid deprecated call in PgSqlCaster Fix command option mode (InputOption::VALUE_REQUIRED) [Uid] Improve entropy of the increment for UUIDv7
2 parents 56d7d02 + 9056771 commit a08090d

File tree

4 files changed

+89
-18
lines changed

4 files changed

+89
-18
lines changed

Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,7 @@ private function splitStringByWidth(string $string, int $width): array
12771277

12781278
foreach (preg_split('//u', $m[0]) as $char) {
12791279
// test if $char could be appended to current line
1280-
if (mb_strwidth($line.$char, 'utf8') <= $width) {
1280+
if (Helper::width($line.$char) <= $width) {
12811281
$line .= $char;
12821282
continue;
12831283
}

Helper/Helper.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ public static function width(?string $string): int
4242
$string ??= '';
4343

4444
if (preg_match('//u', $string)) {
45-
return (new UnicodeString($string))->width(false);
45+
$string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count);
46+
47+
return (new UnicodeString($string))->width(false) + $count;
4648
}
4749

4850
if (false === $encoding = mb_detect_encoding($string, null, true)) {

Helper/Table.php

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -558,10 +558,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string
558558
}
559559

560560
// str_pad won't work properly with multi-byte strings, we need to fix the padding
561-
if (false !== $encoding = mb_detect_encoding($cell, null, true)) {
562-
$width += \strlen($cell) - mb_strwidth($cell, $encoding);
563-
}
564-
561+
$width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0");
565562
$style = $this->getColumnStyle($column);
566563

567564
if ($cell instanceof TableSeparator) {
@@ -626,8 +623,48 @@ private function buildTableRows(array $rows): TableRows
626623
foreach ($rows[$rowKey] as $column => $cell) {
627624
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
628625

629-
if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) {
630-
$cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan);
626+
$minWrappedWidth = 0;
627+
$widthApplied = [];
628+
$lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2;
629+
for ($i = $column; $i < ($column + $colspan); ++$i) {
630+
if (isset($this->columnMaxWidths[$i])) {
631+
$minWrappedWidth += $this->columnMaxWidths[$i];
632+
$widthApplied[] = ['type' => 'max', 'column' => $i];
633+
} elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) {
634+
$minWrappedWidth += $this->columnWidths[$i];
635+
$widthApplied[] = ['type' => 'min', 'column' => $i];
636+
}
637+
}
638+
if (1 === \count($widthApplied)) {
639+
if ($colspan > 1) {
640+
$minWrappedWidth *= $colspan; // previous logic
641+
}
642+
} elseif (\count($widthApplied) > 1) {
643+
$minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder;
644+
}
645+
646+
$cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell));
647+
if ($minWrappedWidth && $cellWidth > $minWrappedWidth) {
648+
$cell = $formatter->formatAndWrap($cell, $minWrappedWidth);
649+
}
650+
// update minimal columnWidths for spanned columns
651+
if ($colspan > 1 && $minWrappedWidth > 0) {
652+
$columnsMinWidthProcessed = [];
653+
$cellWidth = min($cellWidth, $minWrappedWidth);
654+
foreach ($widthApplied as $item) {
655+
if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) {
656+
$minWidthColumn = $this->columnMaxWidths[$item['column']];
657+
$this->columnWidths[$item['column']] = $minWidthColumn;
658+
$columnsMinWidthProcessed[$item['column']] = true;
659+
$cellWidth -= $minWidthColumn + $lengthColumnBorder;
660+
}
661+
}
662+
for ($i = $column; $i < ($column + $colspan); ++$i) {
663+
if (isset($columnsMinWidthProcessed[$i])) {
664+
continue;
665+
}
666+
$this->columnWidths[$i] = $cellWidth + $lengthColumnBorder;
667+
}
631668
}
632669
if (!str_contains($cell ?? '', "\n")) {
633670
continue;

Tests/Helper/TableTest.php

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,9 +1294,9 @@ public static function renderSetTitle()
12941294
'footer',
12951295
'default',
12961296
<<<'TABLE'
1297-
+---------------+---- Multiline
1297+
+---------------+--- Multiline
12981298
header
1299-
here -+------------------+
1299+
here +------------------+
13001300
| ISBN | Title | Author |
13011301
+---------------+--------------------------+------------------+
13021302
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
@@ -1576,17 +1576,17 @@ public function testWithColspanAndMaxWith()
15761576
$expected =
15771577
<<<TABLE
15781578
+-----------------+-----------------+-----------------+
1579-
| Lorem ipsum dolor sit amet, consectetur adipi |
1580-
| scing elit, sed do eiusmod tempor |
1579+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1580+
| elit, sed do eiusmod tempor |
15811581
+-----------------+-----------------+-----------------+
1582-
| Lorem ipsum dolor sit amet, consectetur |
1583-
| adipiscing elit, sed do eiusmod tempor |
1582+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1583+
| elit, sed do eiusmod tempor |
15841584
+-----------------+-----------------+-----------------+
1585-
| Lorem ipsum dolor sit amet, co | hello world |
1586-
| nsectetur | |
1585+
| Lorem ipsum dolor sit amet, conse | hello world |
1586+
| ctetur | |
15871587
+-----------------+-----------------+-----------------+
1588-
| hello world | Lorem ipsum dolor sit amet, co |
1589-
| | nsectetur adipiscing elit |
1588+
| hello world | Lorem ipsum dolor sit amet, conse |
1589+
| | ctetur adipiscing elit |
15901590
+-----------------+-----------------+-----------------+
15911591
| hello | world | Lorem ipsum |
15921592
| | | dolor sit amet, |
@@ -2078,4 +2078,36 @@ public function testGithubIssue52101HorizontalFalse()
20782078
$this->getOutputContent($output)
20792079
);
20802080
}
2081+
2082+
public function testGithubIssue60038WidthOfCellWithEmoji()
2083+
{
2084+
$table = (new Table($output = $this->getOutputStream()))
2085+
->setHeaderTitle('Test Title')
2086+
->setHeaders(['Title', 'Author'])
2087+
->setRows([
2088+
["🎭 💫 ☯"." Divine Comedy", "Dante Alighieri"],
2089+
// the snowflake (e2 9d 84 ef b8 8f) has a variant selector
2090+
["👑 ❄️ 🗡"." Game of Thrones", "George R.R. Martin"],
2091+
// the snowflake in text style (e2 9d 84 ef b8 8e) has a variant selector
2092+
["❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎", ""],
2093+
["And a very long line to show difference in previous lines", ""],
2094+
])
2095+
;
2096+
$table->render();
2097+
2098+
$this->assertSame(<<<TABLE
2099+
+---------------------------------- Test Title -------------+--------------------+
2100+
| Title | Author |
2101+
+-----------------------------------------------------------+--------------------+
2102+
| 🎭 💫 ☯ Divine Comedy | Dante Alighieri |
2103+
| 👑 ❄️ 🗡 Game of Thrones | George R.R. Martin |
2104+
| ❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎ | |
2105+
| And a very long line to show difference in previous lines | |
2106+
+-----------------------------------------------------------+--------------------+
2107+
2108+
TABLE
2109+
,
2110+
$this->getOutputContent($output)
2111+
);
2112+
}
20812113
}

0 commit comments

Comments
 (0)