Trasformatori
I transformer consentono di rielaborare l'output evidenziato in ogni fase, dalla stringa sorgente grezza, alla griglia di token, fino all'albero HAST finale e a HTML. shikiphp riproduce fedelmente il modello dei transformer di Shiki, hook per hook, così si comportano come le controparti di JavaScript.
Passateli tramite l'opzione 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(),
],
]);
La pipeline
Ogni trasformatore è un oggetto che implementa Shikiphp\Transformer\Transformer.
La pipeline esegue gli hook in ordine durante la creazione di un singolo blocco:
| Hook | Firma | Quando |
|---|---|---|
preprocess |
(string $code, array &$options, $context): ?string |
prima della tokenizzazione; può riscrivere la sorgente e modificare le opzioni |
tokens |
(array $tokens, $context): ?array |
dopo la tokenizzazione, sulla griglia 2D ThemedToken |
root |
(Element $el, $context): ?Element |
sulla radice HAST |
pre |
(Element $el, $context): ?Element |
sull'elemento <pre> |
code |
(Element $el, $context): ?Element |
sull'elemento <code> |
line |
(Element $el, int $line, $context): ?Element |
per ogni elemento riga (base 1) |
span |
(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element |
per ogni span di token |
postprocess |
(string $html, array $options, $context): ?string |
sulla stringa HTML serializzata finale |
Tutti gli hook sono facoltativi. Restituire un valore sostituisce l'input; restituire null lo lascia invariato.
enforce() controlla l'ordine tra i trasformatori: 'pre' viene eseguito per primo, 'post' per ultimo e null (valore predefinito) nel mezzo, nell'ordine di registrazione.
Scrivere un trasformatore
Estendete Shikiphp\Transformer\AbstractTransformer per sovrascrivere solo gli hook necessari; gli altri non eseguono operazioni. Il contesto del trasformatore espone addClassToHast() per aggiungere classi agli elementi.
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" …>
Trasformatori integrati
Trasformatori di notazione
Leggono commenti // [!code …] speciali nel sorgente (la sintassi dei commenti del linguaggio viene rilevata automaticamente), li convertono in classi e rimuovono il commento. Sono port diretti del set di notazioni @shikijs/transformers.
NotationHighlight
Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (o // [!code hl]) aggiunge la classe highlighted alla riga.
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]
NotationDiff
Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] contrassegna una riga come aggiunta (diff add), mentre // [!code --] la contrassegna come rimossa (diff remove).
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
NotationFocus
Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] aggiunge la classe focused.
console.log('focus on me') // [!code focus]
NotationErrorLevel
Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error], // [!code warning] e // [!code info] aggiungono la classe highlighted e error / warning / info.
throwSomething() // [!code error]
maybeRisky() // [!code warning]
NotationWordHighlight
Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo] (facoltativamente // [!code word:foo:2] per limitarsi alle successive N righe) racchiude ogni occorrenza di foo in uno span con highlighted-word.
// [!code word:config]
const config = loadConfig()
Trasformatori dei metadati
Leggono la stringa di metadati del blocco di codice fornita tramite l'opzione meta (meta['__raw']), come fa Shiki con il testo dopo il linguaggio di un blocco di codice delimitato.
MetaHighlight
Shikiphp\Transformer\MetaHighlight — evidenzia le righe indicate in un intervallo di metadati, come {1,3-5}, aggiungendo 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 — evidenzia le parole indicate nella stringa di metadati con la sintassi /word/, aggiungendo highlighted-word.
Spazi bianchi e struttura
RenderWhitespace
Shikiphp\Transformer\RenderWhitespace — racchiude spazi e tabulazioni in span (classi predefinite space e tab) per renderli visibili.
Il costruttore accetta (classSpace, classTab, position), dove position è 'all' (predefinito), 'boundary', 'trailing' o 'leading'.
CompactLineOptions
Shikiphp\Transformer\CompactLineOptions — applica classi a righe specifiche usando un elenco di voci {line, classes}.
use Shikiphp\Transformer\CompactLineOptions;
$transformer = new CompactLineOptions([
['line' => 1, 'classes' => 'highlighted'],
['line' => 3, 'classes' => ['highlighted', 'error']],
]);
I numeri di riga partono da 1. Passate l'oggetto nell'opzione transformers, come qualsiasi altro trasformatore.
RemoveNotationEscape
Shikiphp\Transformer\RemoveNotationEscape — rimuove gli escape dalla forma [\!code …] usata per scrivere un commento di notazione letterale senza attivare un trasformatore di notazione.
RemoveLineBreak
Shikiphp\Transformer\RemoveLineBreak — rimuove i nodi di testo delle interruzioni di riga tra le righe (Shiki di transformerRemoveLineBreak).
StyleToClass
Shikiphp\Transformer\StyleToClass — sposta gli stili inline in classi generate e raccoglie un foglio di stile recuperabile con getCSS(). I nomi delle classi calcolano un hash dello stile con Shiki cyrb53, quindi l'output è identico byte per byte a @shikijs/transformers 4.2.0, incluso il relativo scope:
- Lo stile
<pre>diventa sempre una classe. - Gli span dei token vengono convertiti solo quando hanno uno stile predefinito, come nel caso di una mappa
themes. Con un unicotheme, gli span dei token mantengono il lorostyle="color:…"inline, come in 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
Il costruttore accetta (classPrefix, classSuffix, classReplacer); il prefisso predefinito è __shiki_.