
# ANSI 输出

将 `lang` 设为 `'ansi'`，即可高亮终端输出（包含 ANSI 转义序列的文本），而不使用语法进行分词。shikiphp 会解析转义码，并使用主题的 ANSI 调色板为文本着色。它移植自 Shiki 的 `lang: 'ansi'` 分词器，并通过四个基准对照场景检查其 HTML 与 Shiki 3.23.0 的一致性。

```php
use Shikiphp\Shikiphp;

echo Shikiphp::codeToHtml("\e[31merror\e[0m: something broke", [
    'lang'  => 'ansi',
    'theme' => 'github-dark',
]);
```

这是呈现捕获的 CLI 输出的自然方式，例如测试运行器和构建日志中的 `git` 输出，同时保留原有颜色。输出中的转义序列会被移除，只保留包裹在彩色 span 中的文本。

注意双引号括起的 PHP 字符串：`"\e"` 是转义字符。从进程捕获输出时（例如使用 `shell_exec` 或 `proc_open`），转义字符已经包含在字符串中。

## 支持的内容

分词器会读取 SGR（选择图形再现）序列 `ESC [ … m`，其中可包含任意数量由 `;` 分隔的代码：

| 代码 | 效果 |
| --- | --- |
| `0` | 重置所有颜色和属性 |
| `1`、`3`、`4`、`9` | 粗体、斜体、下划线、删除线 |
| `2` | 暗淡：前景色以半透明度绘制 |
| `7` | 反转：交换前景色和背景色 |
| `21`、`23`、`24`、`27`、`29` | 关闭对应属性 |
| `22` | 正常强度：关闭暗淡和粗体 |
| `30`–`37`、`90`–`97` | 前景色：8 种标准色和 8 种亮色 |
| `40`–`47`、`100`–`107` | 背景色：8 种标准色和 8 种亮色 |
| `38;5;n`、`48;5;n` | 从 256 色表中设置前景色或背景色 |
| `38;2;r;g;b`、`48;2;r;g;b` | 24 位真彩色前景色或背景色 |
| `39`、`49` | 默认前景色或背景色 |

隐藏（`8`）和上划线（`53`）会被解析，但不会改变输出；其他代码会被忽略。样式会像在终端中一样跨越换行保留，直到被重置。

## 颜色

16 种命名颜色来自主题的 `terminal.ansi*` 颜色（`terminal.ansiRed`、`terminal.ansiBrightBlue` 等）。如果主题未定义某种颜色，则使用 VS Code 默认调色板（红色为 `#cd3131`、蓝色为 `#2472C8` 等）。未设置颜色的文本使用主题前景色，代码块背景使用主题背景色，与基于语法的高亮方式相同。在 256 色表中，0–15 项是相同的 16 种命名颜色；16–255 项（6×6×6 色立方体和灰度阶）以及真彩色值不受主题影响。

[`colorReplacements`](https://shikiphp.inline0.dev/zh/docs/options#colorreplacements) 也适用于 ANSI 颜色。

## 双主题

ANSI 与基于语法的高亮一样，遵循 `themes` 映射，并为非默认主题输出 CSS 变量：

```php
use Shikiphp\Shikiphp;

$log = "\e[32mPASS\e[0m tests/Unit\n\e[31mFAIL\e[0m tests/Integration";

echo Shikiphp::codeToHtml($log, [
    'lang'   => 'ansi',
    'themes' => ['light' => 'github-light', 'dark' => 'github-dark'],
]);
```

每种命名颜色都会根据各主题自己的调色板解析，因此浅色主题中的红色可能与深色主题中的红色不同。

## 无语法状态

由于 ANSI 不使用 TextMate 语法，因此没有语法状态可供保留。`getLastGrammarState` 在 `lang: 'ansi'` 情况下会抛出异常，而 `codeToTokensResult` 会返回一个 `null` `grammarState`。
