Transformateurs
Les transformateurs vous permettent de remanier la sortie mise en évidence à chaque étape — de la chaîne source brute à l’arbre HAST final, en passant par la grille de jetons et HTML. shikiphp reprend le modèle de transformateurs de Shiki hook par hook ; les transformateurs se comportent donc comme leurs équivalents JavaScript.
Transmettez-les via l’option 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(),
],
]);
Le pipeline
Chaque transformateur est un objet qui implémente Shikiphp\Transformer\Transformer. Le pipeline exécute les hooks dans l’ordre lors de la construction d’un bloc :
| Hook | Signature | Quand |
|---|---|---|
preprocess |
(string $code, array &$options, $context): ?string |
avant la tokenisation ; peut réécrire la source et modifier les options |
tokens |
(array $tokens, $context): ?array |
après la tokenisation, sur la grille ThemedToken en 2D |
root |
(Element $el, $context): ?Element |
sur la racine HAST |
pre |
(Element $el, $context): ?Element |
sur l’élément <pre> |
code |
(Element $el, $context): ?Element |
sur l’élément <code> |
line |
(Element $el, int $line, $context): ?Element |
pour chaque élément de ligne (indexation à partir de 1) |
span |
(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element |
pour chaque étendue de jeton |
postprocess |
(string $html, array $options, $context): ?string |
sur la chaîne HTML finale sérialisée |
Tous les hooks sont facultatifs. Le renvoi d’une valeur remplace l’entrée ; le renvoi de null la laisse inchangée.
enforce() contrôle l’ordre entre les transformateurs : 'pre' s’exécute en premier, 'post' en dernier et null (la valeur par défaut) entre les deux, dans l’ordre d’enregistrement.
Écrire un transformateur
Étendez Shikiphp\Transformer\AbstractTransformer pour ne remplacer que les hooks dont vous avez besoin ; les autres ne font rien. Le contexte du transformateur expose addClassToHast() pour ajouter des classes aux éléments.
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" …>
Transformateurs intégrés
Transformateurs de notation
Ils lisent les commentaires // [!code …] spéciaux dans la source (la syntaxe de commentaire du langage est détectée automatiquement) et les convertissent en classes en supprimant le commentaire lui-même. Il s’agit de ports directs de l’ensemble de notations @shikijs/transformers.
NotationHighlight
Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (ou // [!code hl]) ajoute la classe highlighted à sa ligne.
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]
NotationDiff
Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] marque une ligne comme ajoutée (diff add) ; // [!code --] la marque comme supprimée (diff remove).
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
NotationFocus
Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] ajoute la classe focused.
console.log('focus on me') // [!code focus]
NotationErrorLevel
Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error], // [!code warning] et // [!code info] ajoutent la classe highlighted ainsi que error / warning / info.
throwSomething() // [!code error]
maybeRisky() // [!code warning]
NotationWordHighlight
Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo] (avec // [!code word:foo:2] facultatif pour limiter l’effet aux N lignes suivantes) entoure chaque occurrence de foo dans une étendue portant highlighted-word.
// [!code word:config]
const config = loadConfig()
Transformateurs de métadonnées
Ils lisent la chaîne de métadonnées de la clôture de code fournie via l’option meta (meta['__raw']), comme Shiki lit le texte après le langage d’un bloc de code clôturé.
MetaHighlight
Shikiphp\Transformer\MetaHighlight — met en évidence les lignes indiquées dans une plage de métadonnées comme {1,3-5} et ajoute la classe 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 — met en évidence les mots indiqués dans la chaîne de métadonnées avec la syntaxe /word/ et ajoute highlighted-word.
Espaces blancs et structure
RenderWhitespace
Shikiphp\Transformer\RenderWhitespace — entoure les espaces et les tabulations d’étendues (classes space et tab par défaut) pour les rendre visibles. Le constructeur prend (classSpace, classTab, position), où position vaut 'all' (par défaut), 'boundary', 'trailing' ou 'leading'.
CompactLineOptions
Shikiphp\Transformer\CompactLineOptions — applique des classes à des lignes précises à partir d’une liste d’entrées {line, classes}.
use Shikiphp\Transformer\CompactLineOptions;
$transformer = new CompactLineOptions([
['line' => 1, 'classes' => 'highlighted'],
['line' => 3, 'classes' => ['highlighted', 'error']],
]);
La numérotation des lignes commence à 1. Transmettez l’objet dans l’option transformers, comme tout autre transformateur.
RemoveNotationEscape
Shikiphp\Transformer\RemoveNotationEscape — annule l’échappement de la forme [\!code …], qui permet d’écrire un commentaire de notation littéral sans déclencher de transformateur de notation.
RemoveLineBreak
Shikiphp\Transformer\RemoveLineBreak — supprime les nœuds de texte de saut de ligne entre les lignes (Shiki de transformerRemoveLineBreak).
StyleToClass
Shikiphp\Transformer\StyleToClass — déplace les styles en ligne vers des classes générées et collecte une feuille de style que vous récupérez avec getCSS(). Les noms de classe sont des empreintes du style calculées avec Shiki et son cyrb53 ; la sortie est donc identique octet pour octet à celle de @shikijs/transformers 4.2.0, portée comprise :
- Le style
<pre>devient toujours une classe. - Les étendues de jeton sont converties uniquement si elles portent un style prédéfini, comme c’est le cas avec une map
themes. Avec un seultheme, les étendues de jeton conservent leurs styles en lignestyle="color:…", comme dans 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
Le constructeur prend (classPrefix, classSuffix, classReplacer) ; le préfixe par défaut est __shiki_.