Transformadores
Os transformadores permitem remodelar a saída realçada em cada etapa — da string de origem bruta, passando pela grade de tokens, até a árvore HAST final e HTML. shikiphp implementa o modelo de transformadores de Shiki hook por hook, para que os transformadores se comportem da mesma forma que seus equivalentes em JavaScript.
Passe-os pela opção 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(),
],
]);
O pipeline
Cada transformador é um objeto que implementa Shikiphp\Transformer\Transformer.
O pipeline executa os hooks em ordem durante a construção de um único bloco:
| Hook | Assinatura | Quando |
|---|---|---|
preprocess |
(string $code, array &$options, $context): ?string |
antes da tokenização; pode reescrever a origem e alterar opções |
tokens |
(array $tokens, $context): ?array |
após a tokenização, na grade 2D ThemedToken |
root |
(Element $el, $context): ?Element |
na raiz HAST |
pre |
(Element $el, $context): ?Element |
no elemento <pre> |
code |
(Element $el, $context): ?Element |
no elemento <code> |
line |
(Element $el, int $line, $context): ?Element |
por elemento de linha (base 1) |
span |
(Element $el, int $line, int $col, Element $lineEl, ThemedToken $token, $context): ?Element |
por trecho de token |
postprocess |
(string $html, array $options, $context): ?string |
na string HTML serializada final |
Todos os hooks são opcionais. Retornar um valor substitui a entrada; retornar null
a mantém inalterada.
enforce() controla a ordem entre transformadores: 'pre' é executado primeiro, 'post'
por último e null (o padrão) entre eles, na ordem de registro.
Criando um transformador
Estenda Shikiphp\Transformer\AbstractTransformer para substituir apenas os hooks
necessários; os demais não fazem nada. O contexto do transformador expõe
addClassToHast() para adicionar classes aos elementos.
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" …>
Transformadores integrados
Transformadores de notação
Eles leem comentários especiais // [!code …] na origem (a sintaxe de comentário do
idioma é detectada automaticamente) e os convertem em classes,
removendo o próprio comentário. São implementações diretas do conjunto de
notações @shikijs/transformers.
NotationHighlight
Shikiphp\Transformer\Notation\NotationHighlight — // [!code highlight] (ou
// [!code hl]) adiciona a classe highlighted à linha.
console.log('kept plain')
console.log('this line is highlighted') // [!code highlight]
NotationDiff
Shikiphp\Transformer\Notation\NotationDiff — // [!code ++] marca uma linha como
adicionada (diff add), e // [!code --] como removida (diff remove).
console.log('old line') // [!code --]
console.log('new line') // [!code ++]
NotationFocus
Shikiphp\Transformer\Notation\NotationFocus — // [!code focus] adiciona a
classe focused.
console.log('focus on me') // [!code focus]
NotationErrorLevel
Shikiphp\Transformer\Notation\NotationErrorLevel — // [!code error],
// [!code warning] e // [!code info] adicionam a classe highlighted, além de
error / warning / info.
throwSomething() // [!code error]
maybeRisky() // [!code warning]
NotationWordHighlight
Shikiphp\Transformer\Notation\NotationWordHighlight — // [!code word:foo]
(opcionalmente // [!code word:foo:2] para limitar às próximas N linhas) envolve cada
ocorrência de foo em um span com highlighted-word.
// [!code word:config]
const config = loadConfig()
Transformadores de metadados
Eles leem a string de metadados do bloco de código fornecida pela opção
meta (meta['__raw']), como Shiki lê
o texto após o idioma de um bloco de código delimitado.
MetaHighlight
Shikiphp\Transformer\MetaHighlight — realça linhas indicadas em um intervalo de metadados
como {1,3-5}, adicionando a 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 — realça palavras indicadas na
string de metadados com a sintaxe /word/, adicionando highlighted-word.
Espaços em branco e estrutura
RenderWhitespace
Shikiphp\Transformer\RenderWhitespace — envolve caracteres de espaço e tabulação em
spans (classes space e tab por padrão) para que possam ser exibidos visualmente.
O construtor recebe (classSpace, classTab, position), em que position é
'all' (padrão), 'boundary', 'trailing' ou 'leading'.
CompactLineOptions
Shikiphp\Transformer\CompactLineOptions — aplica classes a linhas específicas
com base em uma lista de entradas {line, classes}.
use Shikiphp\Transformer\CompactLineOptions;
$transformer = new CompactLineOptions([
['line' => 1, 'classes' => 'highlighted'],
['line' => 3, 'classes' => ['highlighted', 'error']],
]);
Os números das linhas começam em 1. Passe o objeto na opção transformers como faria
com qualquer outro transformador.
RemoveNotationEscape
Shikiphp\Transformer\RemoveNotationEscape — remove o escape da forma [\!code …]
usada para escrever um comentário de notação literal sem acionar um
transformador de notação.
RemoveLineBreak
Shikiphp\Transformer\RemoveLineBreak — remove os nós de texto de quebra de linha
entre linhas (Shiki transformerRemoveLineBreak).
StyleToClass
Shikiphp\Transformer\StyleToClass — transfere estilos inline para classes geradas
e reúne uma folha de estilos que você pode obter com getCSS(). Os nomes das classes usam um hash do estilo
com Shiki cyrb53, então a saída é idêntica byte a byte a @shikijs/transformers
4.2.0, inclusive seu escopo:
- O estilo
<pre>sempre se torna uma classe. - Os spans de token só são convertidos quando incluem um estilo pré-construído, como
ocorre com um mapa
themes. Com um únicotheme, os spans de token mantêm seu estilo inlinestyle="color:…", como em 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
O construtor recebe (classPrefix, classSuffix, classReplacer); o prefixo
padrão é __shiki_.