
# shikiphp

shikiphpは[Shiki](https://shiki.style)の純粋なPHP移植版です。ShikiはVS Codeと同じTextMate文法とテーマでコードを色付けする構文ハイライターです。同じ**TextMate文法**でコードをトークン化し、Shikiと同じ**VS Codeテーマ**で色付けすることで、Shiki 3.23.0と同じHTMLを生成します。すべてPHPで動作します。

Nodeランタイムは不要です。`json`と`mbstring`以外のPHP拡張機能も不要です。ネイティブOnigurumaバインディングも、JavaScriptプロセスの起動やホスト型APIの利用も必要ありません。

```php
use Shikiphp\Shikiphp;

echo Shikiphp::codeToHtml(<<<'PHP'
<?php
function greet(string $name): string {
    return "Hello, {$name}!";
}
PHP, [
    'lang'  => 'php',
    'theme' => 'github-dark',
]);
```

## shikiphpを選ぶ理由

PHPでサーバー側構文ハイライトを行うには、通常3つの妥協が必要です。Nodeを起動する、ホスト型のAPIを呼び出す、または言語を実際には理解しない正規表現ベースのハイライターで済ませることです。いずれもLaravel、WordPress、静的サイトのビルド工程にはうまく適合しません。

shikiphpはShikiの実際の処理パイプラインをPHPに移植することで、こうした妥協をなくします。

- TextMate文法トークナイザー（忠実な移植版は[`vscode-textmate`](https://github.com/microsoft/vscode-textmate)）。埋め込み言語、インジェクション、ネストしたリポジトリにも対応
- スコープセレクターの詳細度と親スコープの照合に対応したVS Codeテーマ解決
- Shiki互換のHTML：CSS変数によるライト／ダーク両テーマ、`codeToHast`、トランスフォーマー（すべてのフック）、装飾、`colorReplacements`、`structure: 'inline'`、ANSI（`lang: 'ansi'`）ハイライト
- **Shikiの全バンドル** — `tm-grammars`言語すべて（235と、それらに埋め込まれた補助文法18種）、および`tm-themes`テーマすべて（65種）

## Shiki 3.23.0との照合

出力は「十分近い」ものではなく、固定したShikiのリリースと照合されています。

| パッケージ | バージョン | 用途 |
| --- | --- | --- |
| `shiki` | 3.23.0 | JavaScript正規表現エンジンで実行する正解の基準 |
| `tm-grammars` | 1.31.15 | 同梱文法 |
| `tm-themes` | 1.12.2 | 同梱テーマ |
| `@shikijs/transformers` | 4.2.0 | トランスフォーマーの同等性テスト |

Shiki自体を正解の基準としています。回帰テストハーネスには**214のシナリオ**があり、それぞれ既定オプションを使い、1つの言語とテーマで1つのサンプルを扱います。各シナリオをShikiとshikiphpでハイライトし、先頭と末尾の空白を取り除いた後の2つのHTML文字列が完全に一致することを確認します。シナリオ全体で、同梱されている253個の文法のうち167個、`lang: 'ansi'`、65個すべてのテーマをカバーします。オプション（`structure`、`tabindex`、`colorReplacements`、デュアルテーマ、`defaultColor`など）、`codeToTokensWithThemes`、組み込みトランスフォーマーは個別の同等性テストで確認します。期待される出力は、同じバージョンのShikiから取得しています。

これに伴い、2つの制約があります。Shikiの既定エンジンはWebAssemblyにコンパイルされたOnigurumaですが、正解の基準には代わりにShikiのJavaScript正規表現エンジンを使っています。これはshikiphpが移植しているエンジンです。また、後発のShiki（4.x系）は検証されていません。

## 仕組み

shikiphpは、[`inline0/phasis`](https://github.com/inline0/phasis)の純粋PHP**JavaScript正規表現エンジン**を同梱し、[`oniguruma-to-es`](https://github.com/slevithan/oniguruma-to-es)のPHP移植版を入力として使います。ShikiのJavaScript正規表現エンジンは、TextMate文法のOnigurumaパターンをJavaScript`RegExp`に変換します。そのため、JS正規表現エンジンが自然な基盤となり、shikiphpはそのエンジンの出力とオフセット単位で一致できます。

```
code → grammar tokenizer → theme resolver → themed tokens → HTML
              │
              └─ OnigScanner → PatternConverter (oniguruma-to-es) → Shikiphp\Regex (JS RegExp engine)
```

パイプライン全体については[アーキテクチャ](https://shikiphp.inline0.dev/ja/docs/architecture)を参照してください。

## 必要条件

- PHP 8.2以降（CIではPHP 8.4でテストスイートを実行）
- `ext-json`と`ext-mbstring`（ほぼすべてのPHPビルドに同梱）

## 次に読むページ

- [はじめに](https://shikiphp.inline0.dev/ja/docs/getting-started) — インストールして最初のブロックを描画します。
- [API](https://shikiphp.inline0.dev/ja/docs/api) — メソッドの全容。
- [オプション](https://shikiphp.inline0.dev/ja/docs/options) — `codeToHtml`で使えるすべてのオプション。
- [トランスフォーマー](https://shikiphp.inline0.dev/ja/docs/transformers) — フックのパイプラインと組み込み機能。
- [CLI](https://shikiphp.inline0.dev/ja/docs/cli) — `bin/shikiphp highlight`、`langs`、`themes`。

## ライセンス

MIT、著作権はinline0。TextMate文法とテーマは、各上流プロジェクトのライセンスに従います。
