mirror of
https://github.com/erusev/parsedown.git
synced 2023-08-10 21:13:06 +03:00
Implement FencedCode
This commit is contained in:
parent
194c916c6a
commit
57c6350184
117
src/Components/Blocks/FencedCode.php
Normal file
117
src/Components/Blocks/FencedCode.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Erusev\Parsedown\Components\Blocks;
|
||||
|
||||
use Erusev\Parsedown\AST\StateRenderable;
|
||||
use Erusev\Parsedown\Components\Block;
|
||||
use Erusev\Parsedown\Components\ContinuableBlock;
|
||||
use Erusev\Parsedown\Html\Renderables\Element;
|
||||
use Erusev\Parsedown\Html\Renderables\Text;
|
||||
use Erusev\Parsedown\Parsedown;
|
||||
use Erusev\Parsedown\Parsing\Context;
|
||||
use Erusev\Parsedown\State;
|
||||
|
||||
final class FencedCode implements ContinuableBlock
|
||||
{
|
||||
use ContinuableBlockDefaultInterrupt, BlockAcquisition;
|
||||
|
||||
/** @var string */
|
||||
private $code;
|
||||
|
||||
/** @var string */
|
||||
private $infostring;
|
||||
|
||||
/** @var string */
|
||||
private $marker;
|
||||
|
||||
/** @var int */
|
||||
private $openerLength;
|
||||
|
||||
/** @var bool */
|
||||
private $isComplete;
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
* @param string $infostring
|
||||
* @param string $marker
|
||||
* @param int $openerLength
|
||||
* @param bool $isComplete
|
||||
*/
|
||||
public function __construct($code, $infostring, $marker, $openerLength, $isComplete)
|
||||
{
|
||||
$this->code = $code;
|
||||
$this->infostring = $infostring;
|
||||
$this->marker = $marker;
|
||||
$this->openerLength = $openerLength;
|
||||
$this->isComplete = $isComplete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Context $Context
|
||||
* @param Block|null $Block
|
||||
* @param State|null $State
|
||||
* @return static|null
|
||||
*/
|
||||
public static function build(
|
||||
Context $Context,
|
||||
Block $Block = null,
|
||||
State $State = null
|
||||
) {
|
||||
$marker = $Context->line()->text()[0];
|
||||
|
||||
$openerLength = \strspn($Context->line()->text(), $marker);
|
||||
|
||||
if ($openerLength < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$infostring = \trim(\substr($Context->line()->text(), $openerLength), "\t ");
|
||||
|
||||
if (\strpos($infostring, '`') !== false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new self('', $infostring, $marker, $openerLength, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Context $Context
|
||||
* @return self|null
|
||||
*/
|
||||
public function continue(Context $Context)
|
||||
{
|
||||
if ($this->isComplete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$newCode = $this->code;
|
||||
|
||||
if ($Context->previousEmptyLines() > 0) {
|
||||
$newCode .= \str_repeat("\n", $Context->previousEmptyLines());
|
||||
}
|
||||
|
||||
if (($len = \strspn($Context->line()->text(), $this->marker)) >= $this->openerLength
|
||||
and \chop(\substr($Context->line()->text(), $len), ' ') === ''
|
||||
) {
|
||||
$newCode = \substr($newCode, 1);
|
||||
|
||||
return new self($newCode, $this->infostring, $this->marker, $this->openerLength, true);
|
||||
}
|
||||
|
||||
$newCode .= "\n" . $Context->line()->rawLine();
|
||||
|
||||
return new self($newCode, $this->infostring, $this->marker, $this->openerLength, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Element
|
||||
*/
|
||||
public function stateRenderable(Parsedown $_)
|
||||
{
|
||||
return new Element('pre', [], [new Element(
|
||||
'code',
|
||||
$this->infostring !== '' ? ['class' => "language-{$this->infostring}"] : [],
|
||||
[new Text($this->code)]
|
||||
)]);
|
||||
}
|
||||
}
|
@ -334,78 +334,6 @@ class Parsedown
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# Fenced Code
|
||||
|
||||
protected function blockFencedCode(Context $Context)
|
||||
{
|
||||
$marker = $Context->line()->text()[0];
|
||||
|
||||
$openerLength = \strspn($Context->line()->text(), $marker);
|
||||
|
||||
if ($openerLength < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
$infostring = \trim(\substr($Context->line()->text(), $openerLength), "\t ");
|
||||
|
||||
if (\strpos($infostring, '`') !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$Element = [
|
||||
'name' => 'code',
|
||||
'text' => '',
|
||||
];
|
||||
|
||||
if ($infostring !== '') {
|
||||
$Element['attributes'] = ['class' => "language-$infostring"];
|
||||
}
|
||||
|
||||
$Block = [
|
||||
'char' => $marker,
|
||||
'openerLength' => $openerLength,
|
||||
'element' => [
|
||||
'name' => 'pre',
|
||||
'element' => $Element,
|
||||
],
|
||||
];
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
protected function blockFencedCodeContinue(Context $Context, $Block)
|
||||
{
|
||||
if (isset($Block['complete'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($Context->previousEmptyLines() > 0) {
|
||||
$Block['element']['element']['text'] .= \str_repeat("\n", $Context->previousEmptyLines());
|
||||
|
||||
unset($Block['interrupted']);
|
||||
}
|
||||
|
||||
if (($len = \strspn($Context->line()->text(), $Block['char'])) >= $Block['openerLength']
|
||||
and \chop(\substr($Context->line()->text(), $len), ' ') === ''
|
||||
) {
|
||||
$Block['element']['element']['text'] = \substr($Block['element']['element']['text'], 1);
|
||||
|
||||
$Block['complete'] = true;
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
$Block['element']['element']['text'] .= "\n" . $Context->line()->rawLine();
|
||||
|
||||
return $Block;
|
||||
}
|
||||
|
||||
protected function blockFencedCodeComplete($Block)
|
||||
{
|
||||
return $Block;
|
||||
}
|
||||
|
||||
#
|
||||
# Header
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user