Skip to content

Commit b65913f

Browse files
authored
Merge pull request #849 from phpDocumentor/feature/line-blocks
[FEATURE] Add line block support
2 parents bd883ec + 20ee30c commit b65913f

File tree

6 files changed

+126
-3
lines changed

6 files changed

+126
-3
lines changed

packages/guides-restructured-text/resources/config/guides-restructured-text.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
use phpDocumentor\Guides\RestructuredText\Parser\Productions\GridTableRule;
9090
use phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineMarkupRule;
9191
use phpDocumentor\Guides\RestructuredText\Parser\Productions\InlineRules\InlineRule;
92+
use phpDocumentor\Guides\RestructuredText\Parser\Productions\LineBlockRule;
9293
use phpDocumentor\Guides\RestructuredText\Parser\Productions\LinkRule;
9394
use phpDocumentor\Guides\RestructuredText\Parser\Productions\ListRule;
9495
use phpDocumentor\Guides\RestructuredText\Parser\Productions\LiteralBlockRule;
@@ -256,6 +257,8 @@
256257
->set(EnumeratedListRule::class)
257258
->arg('$productions', service('phpdoc.guides.parser.rst.body_elements'))
258259
->tag('phpdoc.guides.parser.rst.body_element', ['priority' => EnumeratedListRule::PRIORITY])
260+
->set(LineBlockRule::class)
261+
->tag('phpdoc.guides.parser.rst.body_element', ['priority' => ParagraphRule::PRIORITY + 1])
259262
->set(DirectiveRule::class)
260263
->arg('$directives', tagged_iterator('phpdoc.guides.directive'))
261264
->tag('phpdoc.guides.parser.rst.body_element', ['priority' => DirectiveRule::PRIORITY])

packages/guides-restructured-text/src/RestructuredText/NodeRenderers/Html/ContainerNodeRenderer.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use phpDocumentor\Guides\TemplateRenderer;
2222

2323
use function is_a;
24+
use function trim;
2425

2526
/** @implements NodeRenderer<ContainerNode> */
2627
final class ContainerNodeRenderer implements NodeRenderer
@@ -44,7 +45,7 @@ public function render(Node $node, RenderContext $renderContext): string
4445
$renderContext,
4546
'body/container.html.twig',
4647
[
47-
'class' => $node->getOption('class'),
48+
'class' => trim($node->getOption('class') . ' ' . $node->getClassesString()),
4849
'id' => $node->getOption('name'),
4950
'node' => $node->getValue(),
5051
],
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of phpDocumentor.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*
11+
* @link https://phpdoc.org
12+
*/
13+
14+
namespace phpDocumentor\Guides\RestructuredText\Parser\Productions;
15+
16+
use phpDocumentor\Guides\Nodes\CompoundNode;
17+
use phpDocumentor\Guides\Nodes\Inline\InlineNode;
18+
use phpDocumentor\Guides\Nodes\Inline\NewlineInlineNode;
19+
use phpDocumentor\Guides\Nodes\Node;
20+
use phpDocumentor\Guides\RestructuredText\Nodes\ContainerNode;
21+
use phpDocumentor\Guides\RestructuredText\Parser\BlockContext;
22+
use phpDocumentor\Guides\RestructuredText\Parser\Buffer;
23+
use phpDocumentor\Guides\RestructuredText\Parser\LinesIterator;
24+
use phpDocumentor\Guides\RestructuredText\Parser\UnindentStrategy;
25+
26+
use function ltrim;
27+
use function mb_strlen;
28+
use function str_starts_with;
29+
use function substr;
30+
31+
/** @implements Rule<ContainerNode> */
32+
final class LineBlockRule implements Rule
33+
{
34+
public function __construct(
35+
private InlineMarkupRule $inlineMarkupRule,
36+
) {
37+
}
38+
39+
public function applies(BlockContext $blockContext): bool
40+
{
41+
return str_starts_with($blockContext->getDocumentIterator()->current(), '| ')
42+
&& $blockContext->getDocumentIterator()->getNextLine() !== null
43+
&& str_starts_with($blockContext->getDocumentIterator()->getNextLine(), '| ');
44+
}
45+
46+
public function apply(BlockContext $blockContext, CompoundNode|null $on = null): Node|null
47+
{
48+
return $this->createLineBlock($blockContext);
49+
}
50+
51+
private function collectContentLines(BlockContext $blockContext): Buffer
52+
{
53+
$buffer = new Buffer(
54+
[
55+
substr($blockContext->getDocumentIterator()->current(), 2),
56+
],
57+
UnindentStrategy::NONE,
58+
);
59+
60+
$blockContext->getDocumentIterator()->next();
61+
62+
while (
63+
$blockContext->getDocumentIterator()->valid()
64+
&& LinesIterator::isEmptyLine($blockContext->getDocumentIterator()->current()) === false
65+
&& str_starts_with($blockContext->getDocumentIterator()->current(), '|') === false
66+
) {
67+
$buffer->push($blockContext->getDocumentIterator()->current());
68+
$blockContext->getDocumentIterator()->next();
69+
}
70+
71+
return $buffer;
72+
}
73+
74+
/** @return CompoundNode<InlineNode> */
75+
private function createLine(BlockContext $blockContext, Buffer $buffer): CompoundNode
76+
{
77+
$line = $this->inlineMarkupRule->apply(new BlockContext(
78+
$blockContext->getDocumentParserContext(),
79+
$buffer->getLinesString(),
80+
true,
81+
));
82+
83+
if ($line->getChildren() === []) {
84+
$line->addChildNode(new NewlineInlineNode());
85+
}
86+
87+
return $line;
88+
}
89+
90+
private function createLineBlock(BlockContext $blockContext, int $indent = 0): ContainerNode
91+
{
92+
$lineBlock = new ContainerNode();
93+
$lineBlock->setClasses(['line-block']);
94+
95+
while (
96+
$blockContext->getDocumentIterator()->valid()
97+
&& LinesIterator::isEmptyLine($blockContext->getDocumentIterator()->current()) === false
98+
&& ($indent === 0 || LinesIterator::isIndented(substr($blockContext->getDocumentIterator()->current(), 2), $indent))
99+
) {
100+
if (LinesIterator::isIndented(substr($blockContext->getDocumentIterator()->current(), 2), $indent + 1)) {
101+
$line = substr($blockContext->getDocumentIterator()->current(), 2);
102+
$lineBlock->addChildNode(
103+
$this->createLineBlock($blockContext, mb_strlen($line) - mb_strlen(ltrim($line))),
104+
);
105+
continue;
106+
}
107+
108+
$child = new ContainerNode();
109+
$child->setClasses(['line']);
110+
$buffer = $this->collectContentLines($blockContext);
111+
$child->addChildNode($this->createLine($blockContext, $buffer));
112+
$lineBlock->addChildNode($child);
113+
}
114+
115+
return $lineBlock;
116+
}
117+
}

tests/Integration/tests/body-elements/line-blocks/expected/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ <h1>Line Blocks</h1>
1616
Each new line begins with a
1717
</div>
1818
<div class="line">
19-
vertical bar (“|”).
19+
vertical bar (&quot;|&quot;).
2020
</div>
2121
<div class="line-block">
2222
<div class="line">
@@ -32,6 +32,7 @@ <h1>Line Blocks</h1>
3232
with spaces in place of vertical bars.
3333
</div>
3434
</div>
35+
<p>This is normal text</p>
3536
</div>
3637

3738
<!-- content end -->

tests/Integration/tests/body-elements/line-blocks/input/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ Line Blocks
1111
| Continuation lines are wrapped
1212
portions of long lines; they begin
1313
with spaces in place of vertical bars.
14+
15+
This is normal text

tests/Integration/tests/body-elements/line-blocks/input/skip

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)