機能全覧:自動フォーマットの魔法
このレッスンでできること
- プラグインの8つのコア機能を理解する
- どのシーンでこのプラグインを使うべきか知る
- プラグインの境界線を理解する(何ができないか)
現在の課題
プラグイン情報
本プラグインの正式名称は @franlol/opencode-md-table-formatter、以下「テーブルフォーマットプラグイン」と呼びます。
AIが生成するMarkdownテーブルは、よくこんな感じです:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |列幅がバラバラで、見づらいです。手動で調整?AIが新しいテーブルを生成するたびに調整するのは、あまりに面倒です。
いつ使うか
- AIがMarkdownテーブルを生成したので、もっときれいにしたい
- OpenCodeの非表示モード(Concealment Mode)を有効にしているが、テーブルの整列がいつも問題になる
- 手動でテーブルの列幅を調整するのが面倒
コアアイデア
このプラグインの動作原理はとてもシンプルです:
AIがテキストを生成 → プラグインがテーブルを検出 → 構造を検証 → フォーマット → 美化されたテキストを返すOpenCodeの experimental.text.complete フックにマウントされており、AIがテキストを生成するたびに自動的に処理します。手動でトリガーする必要はなく、完全に意識しません。
8つのコア機能
1. 自動テーブルフォーマット
プラグインはAIが生成したテキスト内のMarkdownテーブルを自動的に検出し、列幅を統一してテーブルを整列美しくします。
フォーマット前:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |フォーマット後:
| 名称 | 描述 | 状态 |
|--- | --- | ---|
| **用户管理** | 管理系统用户 | ✅ 完成 |
| API | 接口文档 | 🚧 进行中 |トリガー条件
プラグインは experimental.text.complete フックにマウントされており、AIがテキストを生成した後に自動的にトリガーされます。手動操作は不要です。
2. 非表示モード互換
OpenCodeはデフォルトで非表示モード(Concealment Mode)を有効にしており、Markdown記号(**、*、~~ など)を非表示にします。
通常のテーブルフォーマットツールはこれを考慮せず、幅を計算する際に ** も含めて計算するため、整列がずれます。
このプラグインは非表示モード向けに最適化されています:
- 幅を計算する際、
**太字**、*斜体*、~~取り消し線~~などの記号を剥離 - 出力時は元のMarkdown構文を保持
- 最終的な効果:非表示モードでテーブルが完璧に整列
技術詳細:幅計算ロジック
// Markdown記号を剥離(幅計算用)
visualText = visualText
.replace(/\*\*\*(.+?)\*\*\*/g, "$1") // ***太斜体*** → テキスト
.replace(/\*\*(.+?)\*\*/g, "$1") // **太字** → 太字
.replace(/\*(.+?)\*/g, "$1") // *斜体* → 斜体
.replace(/~~(.+?)~~/g, "$1") // ~~取り消し線~~ → 取り消し線ソースコード位置:index.ts:181-185
3. 整列サポート
Markdownテーブルの3つの整列方式をサポートします:
| 構文 | 整列方式 | 効果 |
|---|---|---|
--- または :--- | 左揃え | テキストを左に寄せる(2つの構文は同じ効果) |
:---: | 中央揃え | テキストを中央に配置 |
---: | 右揃え | テキストを右に寄せる |
例:
| 左揃え | 中央揃え | 右揃え |
|--- | --- | ---|
| テキスト | テキスト | テキスト |フォーマット後、各列は指定された方法で整列され、区切り行は整列方式に応じて再生成されます。
4. ネストされたMarkdown処理
テーブルセル内にはネストされたMarkdown構文が含まれる場合があります。例えば ***太斜体*** など。
プラグインは複数回の正規表現アルゴリズムを使用し、外側から内側へと逐次的に剥離します:
***太斜体*** → **太斜体** → *太斜体* → 太斜体これにより、ネストが何層になっても幅計算は正確です。
5. コードブロック保護
インラインコード(バッククォートで囲まれたもの)内のMarkdown記号は、そのまま保持され、剥離されません。
例えば `**bold**`、ユーザーが見るのは bold という4文字ではなく、**bold** という8文字です。
プラグインはまずコードブロックの内容を抽出し、他の部分のMarkdown記号を剥離した後、コードブロックの内容を元に戻します。
技術詳細:コードブロック保護ロジック
// ステップ1:インラインコードを抽出して保護
const codeBlocks: string[] = []
let textWithPlaceholders = text.replace(/`(.+?)`/g, (match, content) => {
codeBlocks.push(content)
return `\x00CODE${codeBlocks.length - 1}\x00`
})
// ステップ2:コード以外の部分のMarkdown記号を剥離
// ...
// ステップ3:インラインコードの内容を復元
visualText = visualText.replace(/\x00CODE(\d+)\x00/g, (match, index) => {
return codeBlocks[parseInt(index)]
})ソースコード位置:index.ts:168-193
6. 境界ケース処理
プラグインは様々な境界ケースを正しく処理できます:
| シーン | 処理方法 |
|---|---|
| Emoji絵文字 | Bun.stringWidth を使用して表示幅を正しく計算 |
| Unicode文字 | 中国語、日本語などの等幅文字を正しく整列 |
| 空セル | 最小幅(3文字)までスペースで埋める |
| 超長コンテンツ | 通常通り処理、切り捨てなし |
7. サイレント操作
プラグインはバックグラウンドで静かに動作します:
- ログ出力なし:コンソールに何も出力しません
- エラーによる中断なし:フォーマットに失敗しても、AIの通常の出力に影響しません
フォーマット中にエラーが発生した場合、プラグインは元のテキストを保持し、末尾にHTMLコメントを追加します:
<!-- table formatting failed: [エラー情報] -->8. 検証フィードバック
プラグインはテーブル構造が有効かどうかを検証します。無効なテーブルはフォーマットされず、そのまま保持され、ヒントが追加されます:
<!-- table not formatted: invalid structure -->有効なテーブルの要件:
- 少なくとも2行(区切り行を含む)
- すべての行の列数が一致している
- 区切り行が必要(形式:
|---|---|)
プラグインの境界
サポートされないシーン
- HTMLテーブル:Markdownパイプテーブル(
| ... |)のみ処理 - 複数行セル:
<br>タグを含むセルはサポートしない - 区切り行なしテーブル:
|---|---|区切り行が必要 - ヘッダーなしテーブル:ヘッダー行が必要
チェックポイント
このレッスンを完了したら、以下の質問に答えられるはずです:
- [ ] プラグインはどのように自動的にトリガーされますか?(答え:
experimental.text.completeフック) - [ ] なぜ「非表示モード互換」が必要ですか?(答え:非表示モードはMarkdown記号を非表示にするため、幅計算に影響する)
- [ ] インラインコード内のMarkdown記号は剥離されますか?(答え:いいえ、コード内のMarkdown記号は完全に保持されます)
- [ ] 無効なテーブルはどう処理されますか?(答え:そのまま保持し、エラーコメントを追加)
このレッスンのまとめ
| 機能 | 説明 |
|---|---|
| 自動フォーマット | AIがテキストを生成した後に自動的にトリガー、手動操作不要 |
| 非表示モード互換 | Markdown記号が非表示になった後の表示幅を正しく計算 |
| 整列サポート | 左揃え、中央揃え、右揃え |
| ネストされたMarkdown | 複数回の正規表現剥離、ネスト構文をサポート |
| コードブロック保護 | インラインコード内の記号はそのまま保持 |
| 境界ケース | Emoji、Unicode、空セル、超長コンテンツ |
| サイレント操作 | ログなし、エラーによる中断なし |
| 検証フィードバック | 無効なテーブルにエラーコメントを追加 |
次のレッスンの予告
次のレッスンでは 非表示モードの原理 を深掘りします。
学べること:
- OpenCode非表示モードの動作原理
- プラグインが表示幅を正しく計算する方法
Bun.stringWidthの役割
付録:ソースコード参照
クリックしてソースコードの場所を表示
更新日時:2026-01-26
| 機能 | ファイルパス | 行番号 |
|---|---|---|
| プラグインエントリ | index.ts | 9-23 |
| テーブル検出 | index.ts | 58-61 |
| テーブル検証 | index.ts | 70-88 |
| 幅計算(非表示モード) | index.ts | 161-196 |
| 整列方式解析 | index.ts | 141-149 |
| コードブロック保護 | index.ts | 168-173 |
重要な定数:
colWidths[col] = 3:列の最小幅は3文字(index.ts:115)
重要な関数:
formatMarkdownTables():メイン処理関数、テキスト内のすべてのテーブルをフォーマットgetStringWidth():文字列の表示幅を計算、Markdown記号を剥離isValidTable():テーブル構造が有効か検証