如何创建扩展以解析 thephpleague/commonmark 的多行
How to create an extension to parse multiple line for 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>
诀窍是您的块应该始终具有 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;
}
}
对象渲染器:
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% - 只是足以让我的叉子继续工作并找出有效的方法:)
全部,
我正在尝试创建一个扩展(我相信是为了扩展 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>
诀窍是您的块应该始终具有 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;
}
}
对象渲染器:
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% - 只是足以让我的叉子继续工作并找出有效的方法:)