items)) { return $this; } $maxWidth = $grid->maxWidth - 2; $cellWidth = max(array_map(fn ($item) => mb_strwidth($this->stripEscapeSequences($item)), $grid->items)) + 4; $maxColumns = max(1, (int) floor(($maxWidth - 1) / ($cellWidth + 1))); $columnCount = max(1, $this->balancedColumnCount(count($grid->items), $maxColumns)); $rows = $this->buildRowsWithSeparators($grid->items, $columnCount); $tableStyle = (new TableStyle) ->setHorizontalBorderChars('─') ->setVerticalBorderChars('│', '│') ->setCellRowFormat('%s') ->setCrossingChars('┼', '', '', '', '┤', '┘', '┴', '└', '├', '┌', '┬', '┐'); $buffered = new BufferedConsoleOutput; (new SymfonyTable($buffered)) ->setRows($rows) ->setStyle($tableStyle) ->render(); foreach (explode(PHP_EOL, trim($buffered->content(), PHP_EOL)) as $line) { $this->line(' '.$line); } return $this; } /** * Calculate a balanced column count for even row distribution. */ protected function balancedColumnCount(int $itemCount, int $maxColumns): int { if ($itemCount <= $maxColumns) { return $itemCount; } for ($cols = $maxColumns; $cols >= 1; $cols--) { $remainder = $itemCount % $cols; if ($remainder === 0 || $remainder >= (int) ceil($cols / 2)) { return $cols; } } return $maxColumns; } /** * Build rows with separators between them. * * @param array $items * @param int<1, max> $columnCount * @return array|TableSeparator> */ protected function buildRowsWithSeparators(array $items, int $columnCount): array { $chunks = array_chunk($items, $columnCount); $rows = []; foreach ($chunks as $index => $chunk) { if ($index > 0) { $rows[] = new TableSeparator; } $rows[] = array_pad($chunk, $columnCount, ''); } return $rows; } }