/
CodeBlockHighlighter.php
104 lines (79 loc) · 2.79 KB
/
CodeBlockHighlighter.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php
namespace Spatie\CommonMarkHighlighter;
use DomainException;
use Highlight\Highlighter;
use function HighlightUtilities\splitCodeIntoArray;
class CodeBlockHighlighter
{
/** @var \Highlight\Highlighter */
protected $highlighter;
public function __construct(array $autodetectLanguages = [])
{
$this->highlighter = new Highlighter();
$this->highlighter->setAutodetectLanguages($autodetectLanguages);
}
public function highlight(string $codeBlock, ?string $infoLine = null)
{
$codeBlockWithoutTags = strip_tags($codeBlock);
$contents = htmlspecialchars_decode($codeBlockWithoutTags);
$definition = $this->parseLangAndLines($infoLine);
$language = $definition['lang'];
try {
$result = $language
? $this->highlighter->highlight($language, $contents)
: $this->highlighter->highlightAuto($contents);
$code = $result->value;
if (count($definition['lines']) > 0) {
$loc = splitCodeIntoArray($code);
foreach ($loc as $i => $line) {
$loc[$i] = vsprintf('<span class="loc%s">%s</span>', [
isset($definition['lines'][$i + 1]) ? ' highlighted' : '',
$line,
]);
}
$code = implode("\n", $loc);
}
return vsprintf('<code class="%s hljs %s" data-lang="%s">%s</code>', [
'language-'.($language ? $language : $result->language),
$result->language,
$language ? $language : $result->language,
$code,
]);
} catch (DomainException $e) {
return $codeBlock;
}
}
private function parseLangAndLines(?string $language)
{
$parsed = [
'lang' => $language,
'lines' => [],
];
if ($language === null) {
return $parsed;
}
$bracePos = strpos($language, '{');
if ($bracePos === false) {
return $parsed;
}
$parsed['lang'] = substr($language, 0, $bracePos);
$lineDef = substr($language, $bracePos + 1, -1);
$lineNums = explode(',', $lineDef);
foreach ($lineNums as $lineNum) {
if (strpos($lineNum, '-') === false) {
$parsed['lines'][intval($lineNum)] = true;
continue;
}
$extremes = explode('-', $lineNum);
if (count($extremes) !== 2) {
continue;
}
$start = intval($extremes[0]);
$end = intval($extremes[1]);
for ($i = $start; $i <= $end; $i++) {
$parsed['lines'][$i] = true;
}
}
return $parsed;
}
}