Перейти до вмісту

Перетворювачі

Перетворювачі дають змогу змінювати підсвічений вивід на кожному етапі — від початкового рядка коду через сітку токенів до підсумкового дерева HAST і HTML. Порт shikiphp точно відтворює модель перетворювачів Shiki, хук за хуком, тож перетворювачі працюють так само, як їхні відповідники в JavaScript.

Передайте їх через параметр transformers:

PHP
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\Notation\NotationHighlight;
use Shikiphp\Transformer\Notation\NotationDiff;

$code = <<<'JS'
console.log('this line is highlighted') // [!code highlight]
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
JS;

echo Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'theme'        => 'vitesse-dark',
    'transformers' => [
        new NotationHighlight(),
        new NotationDiff(),
    ],
]);

Конвеєр

Кожен перетворювач — це об’єкт, що реалізує Shikiphp\Transformer\Transformer. Конвеєр послідовно запускає хуки під час побудови одного блока:

Хук Сигнатура Коли виконується
preprocess (string $code, array &$options, $context): ?string до токенізації; може змінити вихідний код і параметри
tokens (array $tokens, $context): ?array після токенізації, на двовимірній сітці ThemedToken
root (Element $el, $context): ?Element для кореня HAST
pre (Element $el, $context): ?Element для елемента <pre>
code (Element $el, $context): ?Element для елемента <code>
line (Element $el, int $line, $context): ?Element для кожного елемента рядка (нумерація від 1)
span (Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element для кожного діапазону токена
postprocess (string $html, array $options, $context): ?string для остаточного серіалізованого рядка HTML

Усі хуки необов’язкові. Повернення значення замінює вхідні дані; повернення null залишає їх без змін.

За порядок виконання перетворювачів відповідає enforce(): спершу виконується 'pre', останнім — 'post', а null (стандартне значення) — між ними, у порядку реєстрації.

Створення перетворювача

Розширте Shikiphp\Transformer\AbstractTransformer, щоб перевизначати лише потрібні вам хуки; решта залишаться порожніми операціями. Контекст трансформера надає addClassToHast() для додавання класів до елементів.

PHP
use Shikiphp\Hast\Element;
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\AbstractTransformer;
use Shikiphp\Transformer\TransformerContext;

final class AddLanguageClass extends AbstractTransformer
{
    public function pre(Element $element, TransformerContext $context): ?Element
    {
        if ($context->lang !== null) {
            $context->addClassToHast($element, 'language-' . $context->lang);
        }

        return $element;
    }
}

echo Shikiphp::codeToHtml('const answer = 42', [
    'lang'         => 'js',
    'theme'        => 'nord',
    'transformers' => [new AddLanguageClass()],
]);
// <pre class="shiki nord language-js" …>

Вбудовані трансформери

Трансформери нотацій

Вони читають спеціальні коментарі // [!code …] у вихідному коді (синтаксис коментарів мови визначається автоматично) і перетворюють їх на класи, видаляючи сам коментар. Це прямі порти набору нотацій @shikijs/transformers.

NotationHighlight

Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (або // [!code hl]) додає до свого рядка клас highlighted.

JavaScript
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]

NotationDiff

Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] позначає рядок як доданий (diff add), а // [!code --] — як видалений (diff remove).

JavaScript
console.log('old line') // [!code --]
console.log('new line') // [!code ++]

NotationFocus

Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] додає клас focused.

JavaScript
console.log('focus on me') // [!code focus]

NotationErrorLevel

Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error], // [!code warning] і // [!code info] додають клас highlighted, а також error / warning / info.

JavaScript
throwSomething() // [!code error]
maybeRisky()     // [!code warning]

NotationWordHighlight

Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo] (необов’язково // [!code word:foo:2], щоб обмежити дію наступними N рядками) обгортає кожен збіг foo у span з атрибутом highlighted-word.

JavaScript
// [!code word:config]
const config = loadConfig()

Метатрансформери

Вони читають рядок метаданих блоку коду, переданий через опцію meta (meta['__raw']), так само як Shiki читає текст після назви мови в огородженому блоці коду.

MetaHighlight

Shikiphp\Transformer\MetaHighlight — підсвічує рядки, зазначені в діапазоні метаданих, наприклад {1,3-5}, додаючи клас highlighted.

PHP
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\MetaHighlight;

$code = "const a = 1\nconst b = 2\nconst c = 3\nconst d = 4\nconst e = 5";

echo Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'theme'        => 'nord',
    'meta'         => ['__raw' => '{1,3-5}'],
    'transformers' => [new MetaHighlight()],
]);

MetaWordHighlight

Shikiphp\Transformer\MetaWordHighlight — підсвічує слова, зазначені в рядку метаданих за допомогою синтаксису /word/, додаючи highlighted-word.

Пробіли та структура

RenderWhitespace

Shikiphp\Transformer\RenderWhitespace — обгортає пробіли й символи табуляції у span (класи space і tab за замовчуванням), щоб їх можна було візуально відобразити. Конструктор приймає (classSpace, classTab, position), де position — це 'all' (за замовчуванням), 'boundary', 'trailing' або 'leading'.

CompactLineOptions

Shikiphp\Transformer\CompactLineOptions — застосовує класи до окремих рядків зі списку записів {line, classes}.

PHP
use Shikiphp\Transformer\CompactLineOptions;

$transformer = new CompactLineOptions([
    ['line' => 1, 'classes' => 'highlighted'],
    ['line' => 3, 'classes' => ['highlighted', 'error']],
]);

Нумерація рядків починається з 1. Передайте об’єкт в опції transformers, як і будь-який інший трансформер.

RemoveNotationEscape

Shikiphp\Transformer\RemoveNotationEscape — скасовує екранування форми [\!code …], якою записують буквальний коментар нотації, не запускаючи трансформер нотації.

RemoveLineBreak

Shikiphp\Transformer\RemoveLineBreak — видаляє текстові вузли перенесення рядка між рядками (transformerRemoveLineBreak у Shiki).

StyleToClass

Shikiphp\Transformer\StyleToClass — переносить вбудовані стилі до згенерованих класів і збирає таблицю стилів, яку можна отримати через getCSS(). Назви класів є хешами стилю, обчисленими за допомогою cyrb53 у Shiki, тож результат побайтово ідентичний 4.2.0 @shikijs/transformers, включно з його областю дії:

  • Стиль <pre> завжди перетворюється на клас.
  • Span токенів перетворюються лише тоді, коли мають попередньо створений стиль, як у випадку з мапою themes. Якщо використано один theme, span токенів зберігають вбудований style="color:…", як і в Shiki.
PHP
use Shikiphp\Shikiphp;
use Shikiphp\Transformer\StyleToClass;

$code = 'const answer = 42';
$styleToClass = new StyleToClass();

$html = Shikiphp::codeToHtml($code, [
    'lang'         => 'js',
    'themes'       => ['light' => 'github-light', 'dark' => 'github-dark'],
    'transformers' => [$styleToClass],
]);

$css = $styleToClass->getCSS(); // collected stylesheet for the classes above

Конструктор приймає (classPrefix, classSuffix, classReplacer); префікс за замовчуванням — __shiki_.