From 51a686f7dc7096ff4da6d3612c44fbcc2a244880 Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Thu, 1 Sep 2022 09:18:41 +0400 Subject: [PATCH 1/6] Ability to set optional|drop-able columns --- .../Component/Console/Helper/Table.php | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 81598dfb49929..391a654bf6170 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -50,6 +50,9 @@ class Table private array $columnStyles = []; private array $columnWidths = []; private array $columnMaxWidths = []; + private array $optionalColumns = []; + private array $droppedColumns = []; + private int $maxWidth = 0; private bool $rendered = false; private string $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT; @@ -174,6 +177,18 @@ public function setColumnMaxWidth(int $columnIndex, int $width): static return $this; } + public function setOptionalColumns(array $columns): static + { + $this->optionalColumns = $columns; + return $this; + } + + public function setMaxWidth(int $maxWidth): static + { + $this->maxWidth = $maxWidth; + return $this; + } + /** * @return $this */ @@ -402,6 +417,16 @@ public function render() continue; } + if ($this->droppedColumns) { + foreach ($this->droppedColumns as $column) { + if ($this->numberOfColumns < count($row)) { + unset($row[$column]); + } + } + + $row = array_values($row); + } + if ($isHeader && !$isHeaderSeparatorRendered) { $this->renderRowSeparator( $isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, @@ -815,6 +840,36 @@ private function calculateColumnsWidth(iterable $groups) $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } + + $effectiveColumnWidths = $this->effectiveColumnWidths; + + for ($column = $this->numberOfColumns; $this->numberOfColumns > 0; --$column) { + if ($this->maxWidth && $this->maxWidth > array_sum($effectiveColumnWidths)) { + break; + } + + $droppedColumn = array_pop($this->optionalColumns); + unset($effectiveColumnWidths[$droppedColumn]); + $this->droppedColumns[] = $droppedColumn; + } + + if ($this->droppedColumns) { + foreach ($this->droppedColumns as $column) { + unset( + $this->effectiveColumnWidths[$column], + $this->columnMaxWidths[$column], + $this->columnStyles[$column], + $this->columnWidths[$column], + ); + } + + $this->effectiveColumnWidths = array_values($this->effectiveColumnWidths); + $this->columnMaxWidths = array_values($this->columnMaxWidths); + $this->columnStyles = array_values($this->columnStyles); + $this->columnWidths = array_values($this->columnWidths); + + $this->numberOfColumns -= count($this->droppedColumns); + } } private function getColumnSeparatorWidth(): int From 36465fb02d66cb8f31499a917050012d1da925ce Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Thu, 1 Sep 2022 10:10:16 +0400 Subject: [PATCH 2/6] Handle colspan use-case --- src/Symfony/Component/Console/Helper/Table.php | 16 ++++++++++++++++ .../Component/Console/Helper/TableCell.php | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 391a654bf6170..681da82f8e278 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -392,6 +392,9 @@ public function render() $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); + $this->dropColumn($rowGroups); + $this->calculateColumnsWidth($rowGroups); + $isHeader = !$horizontal; $isFirstRow = $horizontal; $hasTitle = (bool) $this->headerTitle; @@ -840,7 +843,10 @@ private function calculateColumnsWidth(iterable $groups) $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } + } + private function dropColumn(iterable $groups) + { $effectiveColumnWidths = $this->effectiveColumnWidths; for ($column = $this->numberOfColumns; $this->numberOfColumns > 0; --$column) { @@ -855,6 +861,16 @@ private function calculateColumnsWidth(iterable $groups) if ($this->droppedColumns) { foreach ($this->droppedColumns as $column) { + foreach ($groups as $group) { + foreach ($group as $row) { + foreach ($row as $index => $cell) { + if ($cell instanceof TableCell && $index + $cell->getColspan() >= $column) { + $cell->reduceColspan(); + } + } + } + } + unset( $this->effectiveColumnWidths[$column], $this->columnMaxWidths[$column], diff --git a/src/Symfony/Component/Console/Helper/TableCell.php b/src/Symfony/Component/Console/Helper/TableCell.php index 394b2bc959f5f..71ec5cf2f5dda 100644 --- a/src/Symfony/Component/Console/Helper/TableCell.php +++ b/src/Symfony/Component/Console/Helper/TableCell.php @@ -57,6 +57,17 @@ public function getColspan(): int return (int) $this->options['colspan']; } + /** + * Reduces number of colspan. + * Used by optional columns. + */ + public function reduceColspan(): void + { + if ((int) $this->options['colspan'] > 1) { + --$this->options['colspan']; + } + } + /** * Gets number of rowspan. */ From 30fc55e05968529980689a2a34c41db4bffa395f Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Thu, 1 Sep 2022 10:11:28 +0400 Subject: [PATCH 3/6] Update CHANGELOG.md --- src/Symfony/Component/Console/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 5c37be6d3a21c..e797f7174518a 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Improve truecolor terminal detection in some cases * Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it) +* Adding optional columns to Table 6.1 --- From 18942d5bd84ba87eddbdf9b5697e345e04d44d0f Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Thu, 1 Sep 2022 14:48:45 +0400 Subject: [PATCH 4/6] Handle multiple optional columns --- .../Component/Console/Helper/Table.php | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 681da82f8e278..a55f7e456b183 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -816,6 +816,7 @@ private function getRowColumns(array $row): array */ private function calculateColumnsWidth(iterable $groups) { + $pass2 = count($this->effectiveColumnWidths); for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; foreach ($groups as $group) { @@ -843,20 +844,36 @@ private function calculateColumnsWidth(iterable $groups) $this->effectiveColumnWidths[$column] = max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; } + + if ($pass2) { + $this->effectiveColumnWidths = array_values($this->effectiveColumnWidths); + $this->columnMaxWidths = array_values($this->columnMaxWidths); + $this->columnStyles = array_values($this->columnStyles); + $this->columnWidths = array_values($this->columnWidths); + } } private function dropColumn(iterable $groups) { $effectiveColumnWidths = $this->effectiveColumnWidths; + $optionalColumns = []; + + foreach ($this->optionalColumns as $column) { + $optionalColumns[$column] = $effectiveColumnWidths[$column]; + } for ($column = $this->numberOfColumns; $this->numberOfColumns > 0; --$column) { if ($this->maxWidth && $this->maxWidth > array_sum($effectiveColumnWidths)) { break; } - $droppedColumn = array_pop($this->optionalColumns); - unset($effectiveColumnWidths[$droppedColumn]); - $this->droppedColumns[] = $droppedColumn; + $largestOptionalColumn = array_keys($optionalColumns, max($optionalColumns))[0]; + unset($effectiveColumnWidths[$largestOptionalColumn], $optionalColumns[$largestOptionalColumn]); + $this->droppedColumns[] = $largestOptionalColumn; + + if (empty($optionalColumns)) { + break; + } } if ($this->droppedColumns) { @@ -864,7 +881,7 @@ private function dropColumn(iterable $groups) foreach ($groups as $group) { foreach ($group as $row) { foreach ($row as $index => $cell) { - if ($cell instanceof TableCell && $index + $cell->getColspan() >= $column) { + if ($cell instanceof TableCell && $index + $cell->getColspan() > $column) { $cell->reduceColspan(); } } @@ -879,11 +896,6 @@ private function dropColumn(iterable $groups) ); } - $this->effectiveColumnWidths = array_values($this->effectiveColumnWidths); - $this->columnMaxWidths = array_values($this->columnMaxWidths); - $this->columnStyles = array_values($this->columnStyles); - $this->columnWidths = array_values($this->columnWidths); - $this->numberOfColumns -= count($this->droppedColumns); } } From 27a4e0db72f57028b2bb0ba3bec1aa0bfda154f5 Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Thu, 1 Sep 2022 15:08:10 +0400 Subject: [PATCH 5/6] Fix coding standards --- src/Symfony/Component/Console/Helper/Table.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index a55f7e456b183..fbc2f7cac630d 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -180,12 +180,14 @@ public function setColumnMaxWidth(int $columnIndex, int $width): static public function setOptionalColumns(array $columns): static { $this->optionalColumns = $columns; + return $this; } public function setMaxWidth(int $maxWidth): static { $this->maxWidth = $maxWidth; + return $this; } @@ -422,7 +424,7 @@ public function render() if ($this->droppedColumns) { foreach ($this->droppedColumns as $column) { - if ($this->numberOfColumns < count($row)) { + if ($this->numberOfColumns < \count($row)) { unset($row[$column]); } } @@ -816,7 +818,7 @@ private function getRowColumns(array $row): array */ private function calculateColumnsWidth(iterable $groups) { - $pass2 = count($this->effectiveColumnWidths); + $pass2 = \count($this->effectiveColumnWidths); for ($column = 0; $column < $this->numberOfColumns; ++$column) { $lengths = []; foreach ($groups as $group) { @@ -896,7 +898,7 @@ private function dropColumn(iterable $groups) ); } - $this->numberOfColumns -= count($this->droppedColumns); + $this->numberOfColumns -= \count($this->droppedColumns); } } From 0b54134b289079061664268c86a398864c8c0a54 Mon Sep 17 00:00:00 2001 From: Jonathan LS Date: Wed, 7 Sep 2022 11:13:47 +0400 Subject: [PATCH 6/6] Fix failing tests --- src/Symfony/Component/Console/Helper/Table.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index fbc2f7cac630d..f21b101528145 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -394,8 +394,10 @@ public function render() $rowGroups = $this->buildTableRows($rows); $this->calculateColumnsWidth($rowGroups); - $this->dropColumn($rowGroups); - $this->calculateColumnsWidth($rowGroups); + if ($this->maxWidth && $this->optionalColumns) { + $this->dropColumn($rowGroups); + $this->calculateColumnsWidth($rowGroups); + } $isHeader = !$horizontal; $isFirstRow = $horizontal;