Treci la conținut

Transformatoare

Transformatoarele vă permit să remodelați rezultatul evidențiat în fiecare etapă — de la șirul sursă brut, prin grila de tokenuri, până la arborele HAST final și HTML. shikiphp preia modelul de transformatoare al Shiki hook cu hook, astfel încât transformatoarele se comportă la fel ca omoloagele lor JavaScript.

Transmiteți-le prin opțiunea 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(),
    ],
]);

Procesul de lucru

Fiecare transformator este un obiect care implementează Shikiphp\Transformer\Transformer. Fluxul execută hook-urile în ordine, pe parcursul construirii unui singur bloc:

Hook Semnătură Când
preprocess (string $code, array &$options, $context): ?string înainte de tokenizare; poate rescrie sursa și modifica opțiunile
tokens (array $tokens, $context): ?array după tokenizare, asupra grilei 2D ThemedToken
root (Element $el, $context): ?Element asupra rădăcinii HAST
pre (Element $el, $context): ?Element asupra elementului <pre>
code (Element $el, $context): ?Element asupra elementului <code>
line (Element $el, int $line, $context): ?Element pentru fiecare element de linie (începând de la 1)
span (Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element pentru fiecare interval de token
postprocess (string $html, array $options, $context): ?string asupra șirului HTML serializat final

Toate hook-urile sunt opționale. Returnarea unei valori înlocuiește intrarea; returnarea lui null o păstrează neschimbată.

enforce() controlează ordinea transformatoarelor: 'pre' rulează primul, 'post' rulează ultimul, iar null (valoarea implicită) rulează între acestea, în ordinea înregistrării.

Scrierea unui transformator

Extindeți Shikiphp\Transformer\AbstractTransformer pentru a suprascrie doar hook-urile necesare; restul nu fac nimic. Contextul transformatorului expune addClassToHast() pentru adăugarea claselor la elemente.

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

Transformatoare incluse

Transformatoare de notație

Acestea citesc comentarii speciale // [!code …] din sursă (sintaxa comentariilor limbii este detectată automat) și le transformă în clase, eliminând comentariul propriu-zis. Sunt portări directe ale setului de notație @shikijs/transformers.

NotationHighlight

Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (sau // [!code hl]) adaugă clasa highlighted liniei respective.

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

NotationDiff

Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] marchează o linie ca adăugată (diff add), iar // [!code --] ca ștearsă (diff remove).

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

NotationFocus

Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] adaugă clasa focused.

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

NotationErrorLevel

Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error], // [!code warning] și // [!code info] adaugă clasa highlighted plus error / warning / info.

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

NotationWordHighlight

Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo] (opțional // [!code word:foo:2] pentru a limita la următoarele N linii) încadrează fiecare apariție a foo într-un span care conține highlighted-word.

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

Transformatoare meta

Acestea citesc șirul meta al blocului de cod, furnizat prin opțiunea meta (meta['__raw']), așa cum Shiki citește textul de după limbajul unui bloc de cod delimitat.

MetaHighlight

Shikiphp\Transformer\MetaHighlight — evidențiază liniile specificate într-un interval meta precum {1,3-5}, adăugând clasa 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 — evidențiază cuvintele specificate în șirul meta cu sintaxa /word/, adăugând highlighted-word.

Spații albe și structură

RenderWhitespace

Shikiphp\Transformer\RenderWhitespace — încadrează caracterele spațiu și tabulație în span-uri (clasele space și tab în mod implicit), astfel încât să poată fi redate vizibil. Constructorul primește (classSpace, classTab, position), unde position este 'all' (implicit), 'boundary', 'trailing' sau 'leading'.

CompactLineOptions

Shikiphp\Transformer\CompactLineOptions — aplică clase unor linii specifice dintr-o listă de intrări {line, classes}.

PHP
use Shikiphp\Transformer\CompactLineOptions;

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

Numerotarea liniilor începe de la 1. Transmiteți obiectul în opțiunea transformers, ca orice alt transformator.

RemoveNotationEscape

Shikiphp\Transformer\RemoveNotationEscape — elimină escape-ul din forma [\!code …] folosită pentru a scrie un comentariu de notație literală fără a declanșa un transformator de notație.

RemoveLineBreak

Shikiphp\Transformer\RemoveLineBreak — elimină nodurile text cu întrerupere de linie dintre linii (transformerRemoveLineBreak din Shiki).

StyleToClass

Shikiphp\Transformer\StyleToClass — mută stilurile inline în clase generate și colectează o foaie de stiluri pe care o preluați cu getCSS(). Numele claselor hash-uiesc stilul cu Shiki al cyrb53, astfel încât rezultatul este identic la nivel de octeți cu 4.2.0 @shikijs/transformers, inclusiv domeniul său de aplicare:

  • Stilul <pre> devine întotdeauna o clasă.
  • Span-urile tokenurilor sunt convertite doar când au un stil predefinit, ceea ce se întâmplă cu o mapare themes. Cu un singur theme, span-urile tokenurilor își păstrează stilul inline style="color:…", la fel ca în 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

Constructorul primește (classPrefix, classSuffix, classReplacer); prefixul implicit este __shiki_.