Skip to content

Commit

Permalink
[FEATURE] Support list-table directive
Browse files Browse the repository at this point in the history
  • Loading branch information
linawolf committed Mar 9, 2024
1 parent db49faa commit fc73303
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use phpDocumentor\Guides\RestructuredText\Directives\IncludeDirective;
use phpDocumentor\Guides\RestructuredText\Directives\IndexDirective;
use phpDocumentor\Guides\RestructuredText\Directives\LaTeXMain;
use phpDocumentor\Guides\RestructuredText\Directives\ListTableDirective;
use phpDocumentor\Guides\RestructuredText\Directives\LiteralincludeDirective;
use phpDocumentor\Guides\RestructuredText\Directives\MenuDirective;
use phpDocumentor\Guides\RestructuredText\Directives\MetaDirective;
Expand Down Expand Up @@ -205,6 +206,7 @@
->arg('$startingRule', service(DocumentRule::class))
->set(IndexDirective::class)
->set(LaTeXMain::class)
->set(ListTableDirective::class)
->set(LiteralincludeDirective::class)
->args([
'$codeNodeOptionMapper' => service(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\RestructuredText\Directives;

use phpDocumentor\Guides\Nodes\CollectionNode;
use phpDocumentor\Guides\Nodes\ListItemNode;
use phpDocumentor\Guides\Nodes\ListNode;
use phpDocumentor\Guides\Nodes\Node;
use phpDocumentor\Guides\Nodes\Table\TableColumn;
use phpDocumentor\Guides\Nodes\Table\TableRow;
use phpDocumentor\Guides\Nodes\TableNode;
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
use phpDocumentor\Guides\RestructuredText\Parser\Directive;
use phpDocumentor\Guides\RestructuredText\Parser\Productions\Rule;
use Psr\Log\LoggerInterface;

use function array_map;
use function array_shift;
use function assert;
use function count;
use function explode;
use function sprintf;
use function strval;

class ListTableDirective extends SubDirective
{
public function __construct(
protected Rule $startingRule,
private readonly LoggerInterface $logger,
) {
parent::__construct($startingRule);
}

public function getName(): string
{
return 'list-table';
}

/** {@inheritDoc} */
protected function processSub(
BlockContext $blockContext,
CollectionNode $collectionNode,
Directive $directive,
): Node|null {
$options = $this->optionsToArray($directive->getOptions());

if (count($collectionNode->getChildren()) === 0) {
$this->logger->warning('The list-table directive is missing its content. It has to contain exactly one list with sub-lists of equal count. ', $blockContext->getLoggerInformation());

return null;
}

if (count($collectionNode->getChildren()) > 1) {
$this->logger->warning(
sprintf('The list-table must have exactly one list as sub-content. %s nodes found.', count($collectionNode->getChildren())),
$blockContext->getLoggerInformation(),
);
}

$subNode = $collectionNode->getChildren()[0];
if (!$subNode instanceof ListNode) {
$this->logger->warning(
sprintf('The list-table must have exactly one list as sub-content. A node of type %s found.', $subNode::class),
$blockContext->getLoggerInformation(),
);

return null;
}

$tableData = [];
foreach ($subNode->getChildren() as $listItemNode) {
assert($listItemNode instanceof ListItemNode);
$tableRow = new TableRow();
foreach ($listItemNode->getChildren() as $subListNode) {
if (!$subListNode instanceof ListNode) {
$this->logger->warning(
sprintf('The list-table must have a nested list of 2 levels. A node of type %s was found on level 2.', $subListNode::class),
$blockContext->getLoggerInformation(),
);
continue;
}

foreach ($subListNode->getChildren() as $subListItemNode) {
assert($subListItemNode instanceof ListItemNode);
$tableRow->addColumn(new TableColumn('', 1, $subListItemNode->getChildren()));
}
}

$tableData[] = $tableRow;
}

$headerRows = [];
if ($directive->getOption('header-rows')->getValue() !== null) {
for ($i = $directive->getOption('header-rows')->getValue(); $i > 0; $i--) {
if (empty($tableData)) {
break;
}

$headerRows[] = array_shift($tableData);
}
}

$tableNode = new TableNode($tableData, $headerRows);
if (isset($options['widths']) && $options['widths'] !== 'auto' && $options['widths'] !== 'grid') {
$colWidths = array_map('intval', explode(',', strval($options['widths'])));
// A list of integers is used instead of the input column widths. Implies "grid".
$options['widths'] = 'grid';
$tableNode = $tableNode->withColumnWidth($colWidths);
}

$tableNode = $tableNode->withOptions($options);

return $tableNode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,6 @@ private function parseListItem(array $listConfig, Buffer $buffer, BlockContext $
}

if (!isset($nodes[0])) {
$this->logger->warning('List item without content', $blockContext->getLoggerInformation());

return $listItem;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\Guides\Compiler\NodeTransformers;

use phpDocumentor\Guides\Compiler\CompilerContext;
use phpDocumentor\Guides\Compiler\NodeTransformer;
use phpDocumentor\Guides\Nodes\ListItemNode;
use phpDocumentor\Guides\Nodes\ListNode;
use phpDocumentor\Guides\Nodes\Node;
use Psr\Log\LoggerInterface;

use function assert;

/** @implements NodeTransformer<ListNode> */
final class ListNodeTransformer implements NodeTransformer
{
public function __construct(
private readonly LoggerInterface $logger,
) {
}

public function enterNode(Node $node, CompilerContext $compilerContext): Node
{
return $node;
}

public function leaveNode(Node $node, CompilerContext $compilerContext): Node|null
{
assert($node instanceof ListNode);
foreach ($node->getChildren() as $listItemNode) {
assert($listItemNode instanceof ListItemNode);
if (!empty($listItemNode->getChildren())) {
continue;
}

$this->logger->warning('List item without content', $compilerContext->getLoggerInformation());
}

return $node;
}

public function supports(Node $node): bool
{
return $node instanceof ListNode;
}

public function getPriority(): int
{
return 1000;
}
}
5 changes: 5 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ parameters:
count: 1
path: packages/guides-restructured-text/src/RestructuredText/Parser/Productions/InlineRules/NamedPhraseRule.php

-
message: "#^Property phpDocumentor\\\\Guides\\\\RestructuredText\\\\Parser\\\\Productions\\\\ListRule\\:\\:\\$logger is never read, only written\\.$#"
count: 1
path: packages/guides-restructured-text/src/RestructuredText/Parser/Productions/ListRule.php

-
message: "#^Function Symfony\\\\Component\\\\DependencyInjection\\\\Loader\\\\Configurator\\\\tagged_iterator not found\\.$#"
count: 2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
app.WARNING: List item without content {"rst-file":"index.rst","currentLineNumber":7,"currentLine":""} []
app.WARNING: List item without content {"rst-file":"index.rst","currentLineNumber":11,"currentLine":"*"} []
app.WARNING: List item without content {"rst-file":"index.rst"} []
app.WARNING: List item without content {"rst-file":"index.rst"} []
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>table</title>

</head>
<body>
<!-- content start -->
<div class="section" id="table">
<h1>table</h1>

<table class="colwidths-grid">
<colgroup>
<col style="width: 15%">
<col style="width: 10%">
<col style="width: 30%">
</colgroup>
<thead>
<tr>
<th>Treat</th>
<th>Quantity</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Albatross</td>
<td>2.99</td>
<td>On a stick!</td>
</tr>
<tr>
<td>Crunchy Frog</td>
<td>1.49</td>
<td>If we took the bones out, it wouldn&#039;t be
crunchy, now would it?</td>
</tr>
<tr>
<td>Gannet Ripple</td>
<td>1.99</td>
<td>On a stick!</td>
</tr>
</tbody>
</table>

<table class="colwidths-grid">
<caption>And another table</caption>
<colgroup>
<col style="width: 25%">
</colgroup>
<thead>
<tr>
<th>Heading row 1, column 1</th>
<th>Heading row 1, column 2</th>
<th>Heading row 1, column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row 1, column 1</td>
<td>&nbsp;</td>
<td>Row 1, column 3</td>
</tr>
<tr>
<td>Row 2, column 1</td>
<td>Row 2, column 2</td>
<td>Row 2, column 3</td>
</tr>
</tbody>
</table>

</div>

<!-- content end -->
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
table
=====

.. list-table:: Frozen Delights!
:widths: 15, 10, 30
:header-rows: 1

* - Treat
- Quantity
- Description
* - Albatross
- 2.99
- On a stick!
* - Crunchy Frog
- 1.49
- If we took the bones out, it wouldn't be
crunchy, now would it?
* - Gannet Ripple
- 1.99
- On a stick!

.. list-table:: Title
:widths: 25 25 50
:header-rows: 1
:caption: And another table

* - Heading row 1, column 1
- Heading row 1, column 2
- Heading row 1, column 3
* - Row 1, column 1
-
- Row 1, column 3
* - Row 2, column 1
- Row 2, column 2
- Row 2, column 3

0 comments on commit fc73303

Please sign in to comment.