Skip to content

Commit

Permalink
make it work :)
Browse files Browse the repository at this point in the history
  • Loading branch information
hanspagel committed Aug 26, 2021
1 parent c9d30d5 commit 033f6a7
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 61 deletions.
57 changes: 57 additions & 0 deletions src/Hint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Ueberdosis\CommonMark;

use League\CommonMark\Node\Block\AbstractBlock;
use League\CommonMark\Node\StringContainerInterface;

class Hint extends AbstractBlock implements StringContainerInterface
{
private ?string $header = '';

protected string $literal;

public function getTitle(): ?string
{
$words = $this->getHeaderWords();

if (count($words) > 1) {
array_shift($words);

return join(' ', $words);
}

return null;
}

public function getType(): ?string
{
$words = $this->getHeaderWords();

if (count($words) > 0) {
return $words[0];
}

return null;
}

public function getHeaderWords(): array
{
return \preg_split('/\s+/', $this->header ?? '') ?: [];
}

public function setHeader($header)
{
$this->header = $header;
}

public function setLiteral(string $literal): void
{
$this->literal = $literal;
}

public function getLiteral(): string
{
return $this->literal;
}
}
69 changes: 50 additions & 19 deletions src/HintParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,91 @@

namespace Ueberdosis\CommonMark;

use League\CommonMark\Parser\Block\BlockContinueParserInterface;
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Parser\Cursor;
use League\CommonMark\Util\RegexHelper;
use League\CommonMark\Util\ArrayCollection;
use League\CommonMark\Node\Block\AbstractBlock;
use League\CommonMark\Parser\Block\BlockContinue;
use League\CommonMark\Parser\Cursor;
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
use League\CommonMark\Parser\Block\BlockContinueParserInterface;
use League\CommonMark\Parser\Block\BlockContinueParserWithInlinesInterface;
use League\CommonMark\Parser\InlineParserEngineInterface;

class HintParser implements BlockContinueParserInterface
class HintParser extends AbstractBlockContinueParser implements BlockContinueParserWithInlinesInterface
{
/** @psalm-readonly */
private BlockQuote $block;
private Hint $block;

/** @var ArrayCollection<string> */
private ArrayCollection $strings;

public function __construct()
{
$this->block = new BlockQuote();
$this->block = new Hint();
$this->strings = new ArrayCollection();
}

public function getBlock(): BlockQuote
public function getBlock(): Hint
{
return $this->block;
}

public function isContainer(): bool
{
return true;
return false;
}

public function canContain(AbstractBlock $childBlock): bool
{
return false;
}

public function canHaveLazyContinuationLines(): bool
{
return true;
}

public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
public function parseInlines(InlineParserEngineInterface $inlineParser): void
{
if (! $cursor->isIndented() && $cursor->getNextNonSpaceCharacter() === '>') {
$cursor->advanceToNextNonSpaceOrTab();
$cursor->advanceBy(1);
$cursor->advanceBySpaceOrTab();
$inlineParser->parse($this->block->getLiteral(), $this->block);
}

return BlockContinue::at($cursor);
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
{
if ($cursor->getLine() === ':::') {
return BlockContinue::finished();
}

return BlockContinue::none();
}
$cursor->advanceToNextNonSpaceOrTab();
$cursor->advanceBySpaceOrTab();

public function canHaveLazyContinuationLines(): bool
{
return false;
return BlockContinue::at($cursor);
}

// public function canHaveLazyContinuationLines(): bool
// {
// return true;
// }

public function addLine(string $line): void
{
$this->strings[] = $line;
}

public function closeBlock(): void
{
// first line becomes info string
$firstLine = $this->strings->first();
if ($firstLine === false) {
$firstLine = '';
}

$this->block->setHeader(RegexHelper::unescape(\trim($firstLine)));

if ($this->strings->count() === 1) {
$this->block->setLiteral('');
} else {
$this->block->setLiteral(\implode("\n", $this->strings->slice(1)) . "\n");
}
}
}
55 changes: 27 additions & 28 deletions src/HintRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,54 @@

namespace Ueberdosis\CommonMark;

use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;
use League\CommonMark\Util\HtmlElement;
use League\CommonMark\Xml\XmlNodeRendererInterface;

final class HintRenderer implements NodeRendererInterface, XmlNodeRendererInterface
final class HintRenderer implements NodeRendererInterface
{
/**
* @param BlockQuote $node
* @param Hint $node
*
* {@inheritDoc}
*
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function render(Node $node, ChildNodeRendererInterface $childRenderer): \Stringable
{
BlockQuote::assertInstanceOf($node);
Hint::assertInstanceOf($node);

$attrs = $node->data->get('attributes');
isset($attrs['class']) ? $attrs['class'] .= ' hint' : $attrs['class'] = 'hint';

$filling = $childRenderer->renderNodes($node->children());
$innerSeparator = $childRenderer->getInnerSeparator();
if ($filling === '') {
return new HtmlElement('blockquote', $attrs, $innerSeparator);
if ($type = $node->getType()) {
$attrs['class'] = isset($attrs['class']) ? $attrs['class'] . ' ' : '';
$attrs['class'] .= $type;
}

$title = $node->getTitle();
$title = $title
? new HtmlElement(
'h2',
['class' => 'hint-title'],
$title,
)
: '';

$content = new HtmlElement(
'p',
['class' => 'hint-content'],
$childRenderer->renderNodes($node->children())
);

return new HtmlElement(
'blockquote',
'div',
$attrs,
$innerSeparator . $filling . $innerSeparator
"\n" .
$title . "\n" .
$content .
"\n"
);
}

public function getXmlTagName(Node $node): string
{
return 'block_quote';
}

/**
* @param BlockQuote $node
*
* @return array<string, scalar>
*
* @psalm-suppress MoreSpecificImplementedParamType
*/
public function getXmlAttributes(Node $node): array
{
return [];
}
}
7 changes: 2 additions & 5 deletions src/HintStartParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserSta
return BlockStart::none();
}

if ($cursor->getNextNonSpaceCharacter() !== '>') {
$fence = $cursor->match('/^(?:\:{3,}(?!.*`))/');
if ($fence === null) {
return BlockStart::none();
}

$cursor->advanceToNextNonSpaceOrTab();
$cursor->advanceBy(1);
$cursor->advanceBySpaceOrTab();

return BlockStart::of(new HintParser())->at($cursor);
}
}
77 changes: 68 additions & 9 deletions tests/HintExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class HintExtensionTest extends TestCase
{
/** @test */
public function true_is_true()
public function markdown_hints_are_rendered()
{
// Configure the Environment with all the CommonMark parsers/renderers
$environment = new Environment();
Expand All @@ -28,13 +28,72 @@ public function true_is_true()
:::
MARKDOWN;

$this->assertEquals((string) $converter->convertToHtml($markdown), '<div class="hint important">
<h2 class="hint-title">
Warning!
</h2>
<p class="hint-content">
This is how the <strong>Markdown</strong> looks.
</p>
</div>');
$this->assertEquals((string) $converter->convertToHtml($markdown), <<<HTML
<div class="hint important">
<h2 class="hint-title">Warning!</h2>
<p class="hint-content">This is how the <strong>Markdown</strong> looks.</p>
</div>
HTML);
}

/** @test */
public function markdown_hints_after_headings_are_rendered()
{
// Configure the Environment with all the CommonMark parsers/renderers
$environment = new Environment();
$environment->addExtension(new CommonMarkCoreExtension());

// Add this extension
$environment->addExtension(new HintExtension());

// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
$markdown = <<<MARKDOWN
# Test
:::important Warning!
This is how the **Markdown** looks.
:::
MARKDOWN;

$this->assertEquals((string) $converter->convertToHtml($markdown), <<<HTML
<h1>Test</h1>
<div class="hint important">
<h2 class="hint-title">Warning!</h2>
<p class="hint-content">This is how the <strong>Markdown</strong> looks.</p>
</div>
HTML);
}

/** @test */
public function paragraphs_after_hints_are_rendered()
{
// Configure the Environment with all the CommonMark parsers/renderers
$environment = new Environment();
$environment->addExtension(new CommonMarkCoreExtension());

// Add this extension
$environment->addExtension(new HintExtension());

// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
$markdown = <<<MARKDOWN
:::important Warning!
This is how the **Markdown** looks.
:::
Test
MARKDOWN;

$this->assertEquals((string) $converter->convertToHtml($markdown), <<<HTML
<div class="hint important">
<h2 class="hint-title">Warning!</h2>
<p class="hint-content">This is how the <strong>Markdown</strong> looks.</p>
</div>
<p>Test</p>
HTML);
}
}

0 comments on commit 033f6a7

Please sign in to comment.