From a657802c7045972ccbce22aebcd9221eb471b2f8 Mon Sep 17 00:00:00 2001 From: Funky Waddle Date: Sun, 22 Feb 2026 04:10:30 -0600 Subject: [PATCH] fix: account for Phred tags in TableAdapter width calculation and alignment --- src/Phred/TableAdapter.php | 49 +++++++++++++++++++++++++++++++++++--- tests/PhredBridgeTest.php | 21 ++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/Phred/TableAdapter.php b/src/Phred/TableAdapter.php index ab0d6be..7b4c720 100644 --- a/src/Phred/TableAdapter.php +++ b/src/Phred/TableAdapter.php @@ -86,12 +86,12 @@ class TableAdapter implements TableInterface $widths = []; foreach ($this->headers as $index => $header) { - $widths[$index] = mb_strlen((string)$header); + $widths[$index] = $this->getContentLength((string)$header); } foreach ($this->rows as $row) { foreach ($row as $index => $value) { - $width = mb_strlen((string)$value); + $width = $this->getContentLength((string)$value); if (!isset($widths[$index]) || $width > $widths[$index]) { $widths[$index] = $width; } @@ -118,11 +118,54 @@ class TableAdapter implements TableInterface default => STR_PAD_RIGHT, }; - $formatted .= ' ' . str_pad($value, $width, ' ', $padType) . ' |'; + // We need to account for tags in the value when padding + $displayValue = $this->stripTags($value); + $displayLength = mb_strlen($displayValue); + $paddingLength = $width - $displayLength; + + if ($paddingLength < 0) { + $paddingLength = 0; + } + + $leftPadding = 0; + $rightPadding = 0; + + if ($padType === STR_PAD_LEFT) { + $leftPadding = $paddingLength; + } elseif ($padType === STR_PAD_BOTH) { + $leftPadding = (int) floor($paddingLength / 2); + $rightPadding = (int) ceil($paddingLength / 2); + } else { + $rightPadding = $paddingLength; + } + + $formatted .= ' ' . str_repeat(' ', $leftPadding) . $value . str_repeat(' ', $rightPadding) . ' |'; } $this->output->writeln($formatted); } + /** + * Strips Phred console tags from a string. + * + * @param string $text + * @return string + */ + private function stripTags(string $text): string + { + return preg_replace('/<[a-z]+>(.*?)<\/.*?>/i', '$1', $text) ?? $text; + } + + /** + * Gets the length of a string without console tags. + * + * @param string $text + * @return int + */ + private function getContentLength(string $text): int + { + return mb_strlen($this->stripTags($text)); + } + /** * @param array $widths */ diff --git a/tests/PhredBridgeTest.php b/tests/PhredBridgeTest.php index 6a30505..c82551b 100644 --- a/tests/PhredBridgeTest.php +++ b/tests/PhredBridgeTest.php @@ -71,6 +71,27 @@ class PhredBridgeTest extends TestCase $this->assertStringContainsString('| Active |', $content); } + public function testTableAdapterWithTags(): void + { + $output = new OutputAdapter(false); + $table = new TableAdapter($output); + + // Header with tags (8 chars displayed, more in raw string) + $table->setHeaders(['ID', 'Name']); + $table->addRow(['1', 'John']); + + ob_start(); + $table->render(); + $content = ob_get_clean(); + + // If bug exists, the ID column width will be 13 (mb_strlen('ID')) + // but it should be 2 (length of 'ID') + // The separator line will have '-' x (width + 2) + // Correct width 2 -> "+----+" + // Buggy width 13 -> "+---------------+" + $this->assertStringContainsString('+----+', $content); + } + public function testMarkdownConverter(): void { $output = new OutputAdapter(false);