Transformery
Transformery pozwalają przekształcać wyróżnione wyjście na każdym etapie — od surowego ciągu źródłowego, przez siatkę tokenów, po końcowe drzewo HAST i HTML. shikiphp odwzorowuje model transformerów Shiki hook po hooku, dlatego transformery działają identycznie jak ich odpowiedniki JavaScript.
Przekaż je za pomocą opcji transformers:
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(),
],
]);
Potok przetwarzania
Każdy transformer to obiekt implementujący Shikiphp\Transformer\Transformer.
Potok uruchamia hooki w podanej kolejności podczas tworzenia pojedynczego bloku:
| Hook | Sygnatura | Kiedy |
|---|---|---|
preprocess |
(string $code, array &$options, $context): ?string |
przed tokenizacją; może przepisać źródło i zmodyfikować opcje |
tokens |
(array $tokens, $context): ?array |
po tokenizacji, na siatce ThemedToken 2D |
root |
(Element $el, $context): ?Element |
na korzeniu HAST |
pre |
(Element $el, $context): ?Element |
na elemencie <pre> |
code |
(Element $el, $context): ?Element |
na elemencie <code> |
line |
(Element $el, int $line, $context): ?Element |
dla każdego elementu wiersza (indeksowanie od 1) |
span |
(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element |
dla każdego zakresu tokenu |
postprocess |
(string $html, array $options, $context): ?string |
na końcowym zserializowanym ciągu HTML |
Każdy hook jest opcjonalny. Zwrócenie wartości zastępuje dane wejściowe; zwrócenie null pozostawia je bez zmian.
enforce() kontroluje kolejność działania transformerów: najpierw uruchamiane jest 'pre', na końcu 'post', a null (domyślnie) działa pomiędzy nimi, zgodnie z kolejnością rejestracji.
Pisanie transformera
Rozszerz Shikiphp\Transformer\AbstractTransformer i nadpisz tylko potrzebne hooki;
pozostałe nie wykonują żadnych działań. Kontekst transformera udostępnia
addClassToHast() do dodawania klas do elementów.
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" …>
Wbudowane transformery
Transformery notacji
Odczytują specjalne komentarze // [!code …] w kodzie źródłowym (składnia komentarzy
jest wykrywana automatycznie), zamieniają je na klasy i usuwają same komentarze. To bezpośrednie porty zestawu notacji @shikijs/transformers.
NotationHighlight
Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (lub
// [!code hl]) dodaje do wiersza klasę highlighted.
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]
NotationDiff
Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] oznacza wiersz jako
Dodany (diff add), a // [!code --] jako usunięty (diff remove).
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
NotationFocus
Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] dodaje klasę
focused.
console.log('focus on me') // [!code focus]
NotationErrorLevel
Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error],
// [!code warning] i // [!code info] dodają klasę highlighted oraz
error / warning / info.
throwSomething() // [!code error]
maybeRisky() // [!code warning]
NotationWordHighlight
Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo]
(opcjonalnie // [!code word:foo:2], aby ograniczyć działanie do kolejnych N wierszy) opakowuje każde
wystąpienie foo w element span z highlighted-word.
// [!code word:config]
const config = loadConfig()
Transformery metadanych
Odczytują one ciąg metadanych bloku kodu, przekazany przez opcję
meta (meta['__raw']), podobnie jak Shiki odczytuje
tekst po języku bloku kodu z potrójnymi backtickami.
MetaHighlight
Shikiphp\Transformer\MetaHighlight — wyróżnia wiersze wskazane w zakresie metadanych,
na przykład {1,3-5}, dodając klasę highlighted.
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 — wyróżnia słowa wskazane w ciągu metadanych
za pomocą składni /word/, dodając highlighted-word.
Białe znaki i struktura
RenderWhitespace
Shikiphp\Transformer\RenderWhitespace — opakowuje znaki spacji i tabulatora w
spanach (domyślnie klasy space i tab), aby można je było widocznie wyrenderować.
Konstruktor przyjmuje (classSpace, classTab, position), gdzie position to
'all' (domyślnie), 'boundary', 'trailing' lub 'leading'.
CompactLineOptions
Shikiphp\Transformer\CompactLineOptions — przypisuje klasy określonym wierszom
na podstawie listy wpisów {line, classes}.
use Shikiphp\Transformer\CompactLineOptions;
$transformer = new CompactLineOptions([
['line' => 1, 'classes' => 'highlighted'],
['line' => 3, 'classes' => ['highlighted', 'error']],
]);
Numery wierszy zaczynają się od 1. Przekaż obiekt w opcji transformers, tak jak
każdy inny transformer.
RemoveNotationEscape
Shikiphp\Transformer\RemoveNotationEscape — usuwa znaki ucieczki z formy [\!code …],
używanej do zapisania dosłownego komentarza notacji bez uruchamiania transformera notacji.
RemoveLineBreak
Shikiphp\Transformer\RemoveLineBreak — usuwa węzły tekstowe znaków końca wiersza
między wierszami (Shiki: transformerRemoveLineBreak).
StyleToClass
Shikiphp\Transformer\StyleToClass — przenosi style inline do generowanych klas
i gromadzi arkusz stylów pobierany za pomocą getCSS(). Nazwy klas są skrótem stylu
obliczonym przy użyciu Shiki: cyrb53, dlatego wynik jest identyczny bajt po bajcie z @shikijs/transformers
4.2.0, łącznie z zakresem:
- Styl
<pre>zawsze staje się klasą. - Spany tokenów są konwertowane tylko wtedy, gdy mają wstępnie utworzony styl, co
ma miejsce w przypadku mapy
themes. Przy pojedynczymthemespany tokenów zachowują style inlinestyle="color:…", tak jak w Shiki.
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
Konstruktor przyjmuje (classPrefix, classSuffix, classReplacer); domyślny
prefiks to __shiki_.