2024-06-20 14:10:42 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* @copyright Copyright 2014 Carsten Brandt, 2024 Daniel Pimley
|
|
|
|
* @license https://github.com/xenocrat/chyrp-markdown/blob/master/LICENSE
|
|
|
|
* @link https://github.com/xenocrat/chyrp-markdown#readme
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace xenocrat\markdown\block;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds indented code blocks.
|
|
|
|
*/
|
|
|
|
trait CodeTrait
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Identify a line as the beginning of a code block.
|
|
|
|
*/
|
|
|
|
protected function identifyCode($line): bool
|
|
|
|
{
|
|
|
|
// Indentation >= 4 or one tab is code.
|
2024-09-05 17:51:48 +00:00
|
|
|
return $line[0] === "\t" || str_starts_with($line, ' ');
|
2024-06-20 14:10:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Consume lines for a code block element.
|
|
|
|
*/
|
|
|
|
protected function consumeCode($lines, $current): array
|
|
|
|
{
|
|
|
|
$content = [];
|
|
|
|
|
|
|
|
// Consume until end of markers...
|
|
|
|
for ($i = $current, $count = count($lines); $i < $count; $i++) {
|
|
|
|
$line = $lines[$i];
|
|
|
|
if (isset($line[0]) && $line[0] === "\t") {
|
|
|
|
// A line belongs to this code block if indented by a tab.
|
|
|
|
$line = substr($line, 1);
|
|
|
|
$content[] = $line;
|
|
|
|
} elseif (str_starts_with($line, ' ')) {
|
|
|
|
// A line belongs to this code block if indented by 4 spaces.
|
|
|
|
$line = substr($line, 4);
|
|
|
|
$content[] = $line;
|
|
|
|
} elseif (
|
|
|
|
($line === '' || ltrim($line) === '')
|
|
|
|
&& isset($lines[$i + 1])
|
|
|
|
) {
|
|
|
|
// ...Or if blank and the next is also blank
|
|
|
|
// or the next is indented by 4 spaces or a tab.
|
|
|
|
$next = $lines[$i + 1];
|
|
|
|
if (
|
|
|
|
$next === ''
|
|
|
|
|| ltrim($next) === ''
|
|
|
|
|| $next[0] === "\t"
|
|
|
|
|| str_starts_with($next, ' ')
|
|
|
|
) {
|
|
|
|
$line = '';
|
|
|
|
$content[] = $line;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Remove leading blank lines.
|
|
|
|
while (
|
|
|
|
count($content) > 1
|
|
|
|
&& ltrim(reset($content)) === ''
|
|
|
|
) {
|
|
|
|
array_shift($content);
|
|
|
|
}
|
|
|
|
// Remove trailing blank lines.
|
|
|
|
while (
|
|
|
|
count($content) > 1
|
|
|
|
&& ltrim(end($content)) === ''
|
|
|
|
) {
|
|
|
|
array_pop($content);
|
|
|
|
}
|
|
|
|
$block = [
|
|
|
|
'code',
|
|
|
|
'content' => implode("\n", $content),
|
|
|
|
];
|
|
|
|
|
|
|
|
return [$block, --$i];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Renders a code block.
|
|
|
|
*/
|
|
|
|
protected function renderCode($block): string
|
|
|
|
{
|
|
|
|
$class = isset($block['language']) ?
|
|
|
|
' class="language-' . $block['language'] . '"' : '';
|
2024-09-05 17:51:48 +00:00
|
|
|
|
2024-06-20 14:10:42 +00:00
|
|
|
return "<pre><code$class>"
|
|
|
|
. $this->escapeHtmlEntities(
|
|
|
|
$block['content'],
|
|
|
|
ENT_COMPAT | ENT_SUBSTITUTE
|
|
|
|
)
|
|
|
|
. ($block['content'] === '' ? '' : "\n" )
|
|
|
|
. "</code></pre>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract protected function escapeHtmlEntities($text, $flags = 0);
|
|
|
|
}
|