Skip to content

Commit 9e27aec

Browse files
Merge branch '7.2' into 7.3
* 7.2: - [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 [TypeInfo] Fix handling `ConstFetchNode` [VarDumper] Avoid deprecated call in PgSqlCaster Fix command option mode (InputOption::VALUE_REQUIRED) use an EOL-agnostic approach to parse class uses [Uid] Improve entropy of the increment for UUIDv7 [HttpKernel] Fix `#[MapUploadedFile]` handling for optional file uploads
2 parents 66c1440 + a08090d commit 9e27aec

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
@@ -1275,7 +1275,7 @@ private function splitStringByWidth(string $string, int $width): array
12751275

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

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
@@ -561,10 +561,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string
561561
}
562562

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

570567
if ($cell instanceof TableSeparator) {
@@ -629,8 +626,48 @@ private function buildTableRows(array $rows): TableRows
629626
foreach ($rows[$rowKey] as $column => $cell) {
630627
$colspan = $cell instanceof TableCell ? $cell->getColspan() : 1;
631628

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

Tests/Helper/TableTest.php

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,9 +1308,9 @@ public static function renderSetTitle()
13081308
'footer',
13091309
'default',
13101310
<<<'TABLE'
1311-
+---------------+---- Multiline
1311+
+---------------+--- Multiline
13121312
header
1313-
here -+------------------+
1313+
here +------------------+
13141314
| ISBN | Title | Author |
13151315
+---------------+--------------------------+------------------+
13161316
| 99921-58-10-7 | Divine Comedy | Dante Alighieri |
@@ -1590,17 +1590,17 @@ public function testWithColspanAndMaxWith()
15901590
$expected =
15911591
<<<TABLE
15921592
+-----------------+-----------------+-----------------+
1593-
| Lorem ipsum dolor sit amet, consectetur adipi |
1594-
| scing elit, sed do eiusmod tempor |
1593+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1594+
| elit, sed do eiusmod tempor |
15951595
+-----------------+-----------------+-----------------+
1596-
| Lorem ipsum dolor sit amet, consectetur |
1597-
| adipiscing elit, sed do eiusmod tempor |
1596+
| Lorem ipsum dolor sit amet, consectetur adipiscing |
1597+
| elit, sed do eiusmod tempor |
15981598
+-----------------+-----------------+-----------------+
1599-
| Lorem ipsum dolor sit amet, co | hello world |
1600-
| nsectetur | |
1599+
| Lorem ipsum dolor sit amet, conse | hello world |
1600+
| ctetur | |
16011601
+-----------------+-----------------+-----------------+
1602-
| hello world | Lorem ipsum dolor sit amet, co |
1603-
| | nsectetur adipiscing elit |
1602+
| hello world | Lorem ipsum dolor sit amet, conse |
1603+
| | ctetur adipiscing elit |
16041604
+-----------------+-----------------+-----------------+
16051605
| hello | world | Lorem ipsum |
16061606
| | | dolor sit amet, |
@@ -2092,4 +2092,36 @@ public function testGithubIssue52101HorizontalFalse()
20922092
$this->getOutputContent($output)
20932093
);
20942094
}
2095+
2096+
public function testGithubIssue60038WidthOfCellWithEmoji()
2097+
{
2098+
$table = (new Table($output = $this->getOutputStream()))
2099+
->setHeaderTitle('Test Title')
2100+
->setHeaders(['Title', 'Author'])
2101+
->setRows([
2102+
["🎭 💫 ☯"." Divine Comedy", "Dante Alighieri"],
2103+
// the snowflake (e2 9d 84 ef b8 8f) has a variant selector
2104+
["👑 ❄️ 🗡"." Game of Thrones", "George R.R. Martin"],
2105+
// the snowflake in text style (e2 9d 84 ef b8 8e) has a variant selector
2106+
["❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎", ""],
2107+
["And a very long line to show difference in previous lines", ""],
2108+
])
2109+
;
2110+
$table->render();
2111+
2112+
$this->assertSame(<<<TABLE
2113+
+---------------------------------- Test Title -------------+--------------------+
2114+
| Title | Author |
2115+
+-----------------------------------------------------------+--------------------+
2116+
| 🎭 💫 ☯ Divine Comedy | Dante Alighieri |
2117+
| 👑 ❄️ 🗡 Game of Thrones | George R.R. Martin |
2118+
| ❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎ | |
2119+
| And a very long line to show difference in previous lines | |
2120+
+-----------------------------------------------------------+--------------------+
2121+
2122+
TABLE
2123+
,
2124+
$this->getOutputContent($output)
2125+
);
2126+
}
20952127
}

0 commit comments

Comments
 (0)