Как создать расширение для разбора нескольких строк на thephpleague / commonmark

Все,

Я пытаюсь создать расширение (для расширения AbstractBlockParser, я полагаю), которое найдет открывающий тег, переместит строки, следующие в блок, а затем остановится, когда будет найден закрывающий тег (сам по себе в последней строке).

Рассматривая приведенные примеры, очень трудно понять, как они строят блок, состоящий из нескольких строк, например, использование ограждения кода, и документация не охватывает этот сценарий.

Код парсера списка, кажется, показывает, что ListItems добавляются в ListBlock, но как он узнает, когда остановиться?

Пример уценки

{{ Object ID
Any markdown goes here.
Some more
* List 1
* List 2
}}

И вывод может быть:

<div class="object">
<span>Object ID</span>
<p>Any markdown goes here.
Some more</p>
<ul>
<li>List 1</li>
<li>List 2</li>
</ul>
</div>

2

Решение

Хитрость в том, что ваш блок должен иметь canContain() а также matchesNextLine() методы всегда return true; — это гарантирует, что последующие строки всегда будут добавлены как дочерние блоки. (Посмотрите на FencedCode а также ListBlock Реализации.)

Вот код, который должен работать:

ObjectBlock.php:

class ObjectBlock extends AbstractBlock
{
private $objectId;

public function __construct($objectId)
{
$this->objectId = $objectId;
}

public function getObjectId()
{
return $this->objectId;
}

public function canContain(AbstractBlock $block)
{
return true;
}

public function acceptsLines()
{
return false;
}

public function isCode()
{
return false;
}

public function matchesNextLine(Cursor $cursor)
{
return true;
}
}

ObjectParser.php:

class ObjectParser extends AbstractBlockParser
{
public function parse(ContextInterface $context, Cursor $cursor)
{
// Look for the starting syntax
if ($cursor->match('/^{{ /')) {
$id = $cursor->getRemainder();
$cursor->advanceToEnd();

$context->addBlock(new ObjectBlock($id));

return true;
// Look for the ending syntax
} elseif ($cursor->match('/^}} +$/')) {
// TODO: I don't know if this is the best approach, but it should work
// Basically, we're going to locate a parent ObjectBlock in the AST...
$container = $context->getContainer();
while ($container) {
if ($container instanceof ObjectBlock) {
$cursor->advanceToEnd();

// Found it!  Now we'll close everything up to (and including) it
$context->getBlockCloser()->setLastMatchedContainer($container->parent());
$context->getBlockCloser()->closeUnmatchedBlocks();
$context->setBlocksParsed(true);

return true;
}

$container = $container->parent();
}
}

return false;
}
}

ObjectRenderer:

class ObjectRenderer implements BlockRendererInterface
{
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, $inTightList = false)
{
$span = sprintf('<span>%s</span>', $block->getObjectId());
$contents = $htmlRenderer->renderBlocks($block->children());

return new HtmlElement('div', ['class' => 'object'],
$span . $contents
);
}
}

Отказ от ответственности: хотя я и являюсь автором этой библиотеки, конкретная логика (контейнеры, подсказки и закрытие блоков) в основном была разветвлена ​​как есть из версии JS, и я понимаю, что только около 75% из нее — достаточно, чтобы держать свою вилку работаем и выясняем подходы, которые работают 🙂

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector