|
13 | 13 |
|
14 | 14 | namespace phpDocumentor\Guides\RstTheme\Twig;
|
15 | 15 |
|
| 16 | +use phpDocumentor\Guides\NodeRenderers\NodeRenderer; |
| 17 | +use phpDocumentor\Guides\Nodes\Table\TableColumn; |
| 18 | +use phpDocumentor\Guides\Nodes\Table\TableRow; |
16 | 19 | use phpDocumentor\Guides\Nodes\TableNode;
|
17 | 20 | use phpDocumentor\Guides\Nodes\TitleNode;
|
| 21 | +use phpDocumentor\Guides\RenderContext; |
18 | 22 | use phpDocumentor\Guides\RstTheme\Configuration\HeaderSyntax;
|
19 | 23 | use Twig\Extension\AbstractExtension;
|
20 | 24 | use Twig\TwigFilter;
|
|
23 | 27 | use function array_map;
|
24 | 28 | use function explode;
|
25 | 29 | use function implode;
|
| 30 | +use function max; |
| 31 | +use function mb_str_pad; |
| 32 | +use function mb_strlen; |
26 | 33 | use function min;
|
27 | 34 | use function preg_replace;
|
28 | 35 | use function rtrim;
|
|
31 | 38 |
|
32 | 39 | final class RstExtension extends AbstractExtension
|
33 | 40 | {
|
| 41 | + public function __construct( |
| 42 | + private NodeRenderer $nodeRenderer, |
| 43 | + ) { |
| 44 | + } |
| 45 | + |
34 | 46 | /** @return TwigFunction[] */
|
35 | 47 | public function getFunctions(): array
|
36 | 48 | {
|
37 | 49 | return [
|
38 | 50 | new TwigFunction('renderRstTitle', $this->renderRstTitle(...), ['is_safe' => ['rst'], 'needs_context' => false]),
|
39 |
| - new TwigFunction('renderRstTable', $this->renderRstTable(...), ['is_safe' => ['rst'], 'needs_context' => false]), |
| 51 | + new TwigFunction('renderRstTable', $this->renderRstTable(...), ['is_safe' => ['rst'], 'needs_context' => true]), |
40 | 52 | new TwigFunction('renderRstIndent', $this->renderRstIndent(...), ['is_safe' => ['rst'], 'needs_context' => false]),
|
41 | 53 | ];
|
42 | 54 | }
|
@@ -77,23 +89,75 @@ public function renderRstTitle(TitleNode $node, string $content): string
|
77 | 89 |
|
78 | 90 | $ret .= $content . "\n" . str_repeat($headerSyntax->delimiter(), strlen($content));
|
79 | 91 |
|
80 |
| - return $ret; |
| 92 | + return $ret . "\n"; |
| 93 | + } |
| 94 | + |
| 95 | + /** @param array{env: RenderContext} $context */ |
| 96 | + public function renderRstTable(array $context, TableNode $node): string |
| 97 | + { |
| 98 | + $columnWidths = []; |
| 99 | + |
| 100 | + $this->determineMaxLenght($node->getHeaders(), $context['env'], $columnWidths); |
| 101 | + $this->determineMaxLenght($node->getData(), $context['env'], $columnWidths); |
| 102 | + |
| 103 | + $ret = $this->renderTableRowEnd($columnWidths); |
| 104 | + $ret .= $this->renderRows($node->getHeaders(), $context['env'], $columnWidths, '='); |
| 105 | + $ret .= $this->renderRows($node->getData(), $context['env'], $columnWidths); |
| 106 | + |
| 107 | + return $ret . "\n"; |
| 108 | + } |
| 109 | + |
| 110 | + private function renderCellContent(RenderContext $env, TableColumn $column): string |
| 111 | + { |
| 112 | + return implode('', array_map(fn ($node) => $this->nodeRenderer->render($node, $env), $column->getValue())); |
| 113 | + } |
| 114 | + |
| 115 | + /** |
| 116 | + * @param TableRow[] $rows |
| 117 | + * @param int[] &$columnWidths |
| 118 | + */ |
| 119 | + private function determineMaxLenght(array $rows, RenderContext $env, array &$columnWidths): void |
| 120 | + { |
| 121 | + foreach ($rows as $row) { |
| 122 | + foreach ($row->getColumns() as $index => $column) { |
| 123 | + $content = $this->renderCellContent($env, $column); |
| 124 | + |
| 125 | + $columnWidths[$index] = max(mb_strlen($content) + 2, $columnWidths[$index] ?? 0); |
| 126 | + } |
| 127 | + } |
81 | 128 | }
|
82 | 129 |
|
83 |
| - public function renderRstTable(TableNode $node): string |
| 130 | + /** |
| 131 | + * @param TableRow[] $rows |
| 132 | + * @param int[] $columnWidths |
| 133 | + */ |
| 134 | + private function renderRows(array $rows, RenderContext $env, array $columnWidths, string $separator = '-'): string |
84 | 135 | {
|
85 | 136 | $ret = '';
|
| 137 | + foreach ($rows as $row) { |
| 138 | + $ret .= '|'; |
| 139 | + foreach ($row->getColumns() as $index => $column) { |
| 140 | + $content = $this->renderCellContent($env, $column); |
86 | 141 |
|
87 |
| - foreach ($node->getHeaders() as $header) { |
88 |
| - foreach ($header->getColumns() as $column) { |
89 |
| - $ret .= $column->getContent() . ' '; |
| 142 | + $ret .= ' ' . mb_str_pad($content, $columnWidths[$index] - 2) . ' |'; |
90 | 143 | }
|
91 |
| - $ret .= "header \n"; |
| 144 | + |
| 145 | + $ret .= "\n" . $this->renderTableRowEnd($columnWidths, $separator); |
92 | 146 | }
|
93 |
| - foreach ($node->getData() as $row) { |
94 |
| - $ret .= 'row'. "\n"; |
| 147 | + |
| 148 | + return $ret; |
| 149 | + } |
| 150 | + |
| 151 | + /** @param int[] $columnWidths */ |
| 152 | + private function renderTableRowEnd(array $columnWidths, string $char = '-'): string |
| 153 | + { |
| 154 | + $ret = ''; |
| 155 | + foreach ($columnWidths as $width) { |
| 156 | + $ret .= '+' . str_repeat($char, $width); |
95 | 157 | }
|
96 | 158 |
|
| 159 | + $ret .= '+' . "\n"; |
| 160 | + |
97 | 161 | return $ret;
|
98 | 162 | }
|
99 | 163 | }
|
0 commit comments