Přejít k obsahu

Transformátory

Transformátory umožňují upravovat zvýrazněný výstup v každé fázi — od původního zdrojového řetězce přes mřížku tokenů až po výsledný strom HAST a HTML. shikiphp přebírá model transformátorů Shiki včetně všech hooků, takže se transformátory chovají stejně jako jejich protějšky v JavaScript.

Předávejte je prostřednictvím volby 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(),
    ],
]);

Postup zpracování

Každý transformátor je objekt implementující Shikiphp\Transformer\Transformer. Řetězec zpracování spouští hooky v daném pořadí při sestavování jednoho bloku:

Hook Signatura Kdy
preprocess (string $code, array &$options, $context): ?string před tokenizací; může přepsat zdroj a změnit možnosti
tokens (array $tokens, $context): ?array po tokenizaci, na 2D mřížce ThemedToken
root (Element $el, $context): ?Element na kořenovém uzlu HAST
pre (Element $el, $context): ?Element na prvku <pre>
code (Element $el, $context): ?Element na prvku <code>
line (Element $el, int $line, $context): ?Element pro každý prvek řádku (index od 1)
span (Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element pro každý rozsah tokenu
postprocess (string $html, array $options, $context): ?string s výsledným serializovaným řetězcem HTML

Všechny hooky jsou nepovinné. Vrácená hodnota nahradí vstup; vrácení null zachová původní hodnotu.

Pořadí mezi transformátory řídí enforce(): 'pre' se spouští první, 'post' poslední a null (výchozí hodnota) mezi nimi v pořadí registrace.

Vytvoření transformátoru

Rozšiřte Shikiphp\Transformer\AbstractTransformer a přepište pouze hooky, které potřebujete; ostatní neprovedou žádnou akci. Kontext transformátoru zpřístupňuje addClassToHast() pro přidávání tříd prvkům.

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" …>

Vestavěné transformátory

Transformátory zápisu

Tyto nástroje čtou speciální komentáře // [!code …] ve zdrojovém kódu (syntaxe komentářů jazyka se rozpozná automaticky) a převádějí je na třídy, přičemž samotný komentář odstraní. Jde o přímé porty sady zápisu @shikijs/transformers.

NotationHighlight

Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (nebo // [!code hl]) přidá řádku třídu highlighted.

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

NotationDiff

Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] označí řádek jako přidaný (diff add), // [!code --] jako odebraný (diff remove).

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

NotationFocus

Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] přidá třídu focused.

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

NotationErrorLevel

Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error], // [!code warning] a // [!code info] přidají třídu highlighted a také error / warning / info.

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

NotationWordHighlight

Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo] (volitelně // [!code word:foo:2] omezí na následujících N řádků) obalí každý výskyt foo prvkem span nesoucím highlighted-word.

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

Transformátory metadat

Čtou meta řetězec zadaný v metadatech bloku kódu přes volbu meta (meta['__raw']), tedy text za jazykem bloku kódu, který čte Shiki.

MetaHighlight

Shikiphp\Transformer\MetaHighlight — zvýrazní řádky uvedené v rozsahu metadat, například {1,3-5}, a přidá třídu 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 — zvýrazní slova uvedená v meta řetězci pomocí syntaxe /word/ a přidá highlighted-word.

Bílé znaky a struktura

RenderWhitespace

Shikiphp\Transformer\RenderWhitespace — obalí mezery a tabulátory do prvků span (ve výchozím nastavení třídy space a tab), aby je bylo možné viditelně vykreslit. Konstruktor přijímá (classSpace, classTab, position), kde position je 'all' (výchozí hodnota), 'boundary', 'trailing' nebo 'leading'.

CompactLineOptions

Shikiphp\Transformer\CompactLineOptions — použije třídy na konkrétní řádky podle seznamu položek {line, classes}.

PHP
use Shikiphp\Transformer\CompactLineOptions;

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

Číslování řádků začíná od 1. Objekt předejte ve volbě transformers stejně jako jakýkoli jiný transformátor.

RemoveNotationEscape

Shikiphp\Transformer\RemoveNotationEscape — odstraní escape z podoby [\!code …], která slouží k zápisu doslovného komentáře se zápisem bez spuštění transformátoru zápisu.

RemoveLineBreak

Shikiphp\Transformer\RemoveLineBreak — odstraní textové uzly zalomení řádků mezi řádky (transformerRemoveLineBreak nástroje Shiki).

StyleToClass

Shikiphp\Transformer\StyleToClass — přesune vložené styly do generovaných tříd a shromáždí šablonu stylů, kterou získáte přes getCSS(). Názvy tříd jsou hashem stylu pomocí cyrb53 nástroje Shiki, takže výstup je bajtově totožný s @shikijs/transformers 4.2.0 včetně jeho rozsahu:

  • Styl <pre> se vždy převede na třídu.
  • Rozpětí tokenů se převádějí jen tehdy, když nesou předem vytvořený styl, což nastává u mapy themes. Při jediném theme si rozpětí tokenů zachovají vložené style="color:…", stejně jako v 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

Konstruktor přijímá (classPrefix, classSuffix, classReplacer); výchozí prefix je __shiki_.