|
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; |
| 19 | +use phpDocumentor\Guides\Nodes\TableNode; |
16 | 20 | use phpDocumentor\Guides\Nodes\TitleNode;
|
| 21 | +use phpDocumentor\Guides\RenderContext; |
17 | 22 | use phpDocumentor\Guides\RstTheme\Configuration\HeaderSyntax;
|
18 | 23 | use Twig\Extension\AbstractExtension;
|
19 | 24 | use Twig\TwigFilter;
|
|
22 | 27 | use function array_map;
|
23 | 28 | use function explode;
|
24 | 29 | use function implode;
|
| 30 | +use function max; |
| 31 | +use function mb_str_pad; |
| 32 | +use function mb_strlen; |
25 | 33 | use function min;
|
26 | 34 | use function preg_replace;
|
27 | 35 | use function rtrim;
|
|
30 | 38 |
|
31 | 39 | final class RstExtension extends AbstractExtension
|
32 | 40 | {
|
| 41 | + public function __construct( |
| 42 | + private NodeRenderer $nodeRenderer, |
| 43 | + ) { |
| 44 | + } |
| 45 | + |
33 | 46 | /** @return TwigFunction[] */
|
34 | 47 | public function getFunctions(): array
|
35 | 48 | {
|
36 | 49 | return [
|
37 | 50 | new TwigFunction('renderRstTitle', $this->renderRstTitle(...), ['is_safe' => ['rst'], 'needs_context' => false]),
|
| 51 | + new TwigFunction('renderRstTable', $this->renderRstTable(...), ['is_safe' => ['rst'], 'needs_context' => true]), |
38 | 52 | new TwigFunction('renderRstIndent', $this->renderRstIndent(...), ['is_safe' => ['rst'], 'needs_context' => false]),
|
39 | 53 | ];
|
40 | 54 | }
|
@@ -75,6 +89,75 @@ public function renderRstTitle(TitleNode $node, string $content): string
|
75 | 89 |
|
76 | 90 | $ret .= $content . "\n" . str_repeat($headerSyntax->delimiter(), strlen($content));
|
77 | 91 |
|
| 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 | + } |
| 128 | + } |
| 129 | + |
| 130 | + /** |
| 131 | + * @param TableRow[] $rows |
| 132 | + * @param int[] $columnWidths |
| 133 | + */ |
| 134 | + private function renderRows(array $rows, RenderContext $env, array $columnWidths, string $separator = '-'): string |
| 135 | + { |
| 136 | + $ret = ''; |
| 137 | + foreach ($rows as $row) { |
| 138 | + $ret .= '|'; |
| 139 | + foreach ($row->getColumns() as $index => $column) { |
| 140 | + $content = $this->renderCellContent($env, $column); |
| 141 | + |
| 142 | + $ret .= ' ' . mb_str_pad($content, $columnWidths[$index] - 2) . ' |'; |
| 143 | + } |
| 144 | + |
| 145 | + $ret .= "\n" . $this->renderTableRowEnd($columnWidths, $separator); |
| 146 | + } |
| 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); |
| 157 | + } |
| 158 | + |
| 159 | + $ret .= '+' . "\n"; |
| 160 | + |
78 | 161 | return $ret;
|
79 | 162 | }
|
80 | 163 | }
|
0 commit comments