Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
CodeHighlighter
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 3
90
0.00% covered (danger)
0.00%
0 / 1
 toNumbers
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 toLines
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 toHtml
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Html;
6
7require_once(__DIR__ . DIRECTORY_SEPARATOR . '../Libs/highlight.php/HighlightUtilities/functions.php');
8
9use DomainException;
10use Highlight\Highlighter;
11//use \HighlightUtilities;
12use PeServer\Core\Collection\Arr;
13use PeServer\Core\Text;
14use PeServer\Core\TypeUtility;
15
16
17/**
18 * HTMLとしてのコードハイライト処理。
19 */
20class CodeHighlighter
21{
22    #region function
23
24    /**
25     * 文字列から強調行番号を取得。
26     *
27     * @param string $value
28     * @return int[]
29     */
30    public function toNumbers(string $value): array
31    {
32        $lineNumbers = [];
33
34        if (!Text::isNullOrWhiteSpace($value)) {
35            $numberStrings = Text::split($value, ',');
36            $numberValues = array_filter($numberStrings, fn ($s) => TypeUtility::tryParseInteger(Text::trim($s), $unused));
37            $lineNumbers = array_map(fn ($s) => (int)Text::trim($s), $numberValues);
38        }
39
40        return $lineNumbers;
41    }
42
43    /**
44     * タグ付けソースを行ごとに返却。
45     *
46     * @param string $language
47     * @param string $source
48     * @return string[]
49     */
50    private function toLines(string $language, string $source): array
51    {
52        if (!Text::isNullOrWhiteSpace($language)) {
53            $hl = new Highlighter(); //@phpstan-ignore-line Highlighter
54            try {
55                $highlighted = $hl->highlight($language, $source); //@phpstan-ignore-line highlight
56                $lines = \HighlightUtilities\splitCodeIntoArray($highlighted->value); //@phpstan-ignore-line splitCodeIntoArray
57                if ($lines !== false) {
58                    return $lines;
59                }
60            } catch (DomainException) {
61                //NOP
62            }
63        }
64
65        return Text::splitLines($source);
66    }
67
68    /**
69     * ソースコードをHTML変換。
70     *
71     * @param string $language
72     * @param string $source
73     * @param int[] $lineNumbers
74     * @return string
75     */
76    public function toHtml(string $language, string $source, array $lineNumbers = []): string
77    {
78        $lines = $this->toLines($language, $source);
79
80        $head = '<pre class="source"><code class="hljs ' . $language . '">' . PHP_EOL;
81        $tail = PHP_EOL . '</code></pre>';
82
83        $sourceLines = [];
84        foreach ($lines as $key => $line) {
85            $number = $key + 1;
86            $addClass = '';
87            if (Arr::in($lineNumbers, $number)) {
88                $addClass = 'strong-line';
89            }
90            $sourceLine = '<span class="code-line ' . $addClass . '" data-line=' . $number . '>' . $line . '</span>';
91            $sourceLines[] = $sourceLine;
92        }
93
94        $values = Text::join(PHP_EOL, $sourceLines);
95
96        return $head . $values . $tail;
97    }
98
99    #endregion
100}