# 機能設計書 73-Emmet

## 概要

本ドキュメントは、VS Codeの組み込み拡張機能「emmet」が提供するEmmet展開機能の設計を記述する。

### 本機能の処理概要

HTMLやCSSの省略記法（Emmet略語）を展開し、高速なマークアップ・スタイル記述を支援する機能である。

**業務上の目的・背景**：Web開発において、HTMLタグやCSSプロパティを手入力することは時間がかかり、タイプミスの原因となる。Emmetは略語から完全なコードを生成することで、マークアップ作成の効率を大幅に向上させる。例えば`ul>li*5`と入力するだけで5つのリストアイテムを持つulタグを生成できる。

**機能の利用シーン**：
- HTMLファイルでタグ構造を素早く作成する場面
- CSSファイルでプロパティを素早く入力する場面
- JSX/TSXでReactコンポーネントのマークアップを作成する場面
- テンプレートファイル（EJS、Pug等）でマークアップを作成する場面

**主要な処理内容**：
1. Emmet略語の展開（Tab/Enter キーまたはコマンド）
2. 選択テキストを略語でラップ（Wrap with Abbreviation）
3. タグの削除、更新、分割/結合
4. 対応タグへの移動（Match Tag）
5. Balance Out/In（親/子要素の選択）
6. 編集ポイント間の移動
7. 数値のインクリメント/デクリメント
8. CSS値の反映（Reflect CSS Value）
9. 数式の評価

**関連システム・外部連携**：
- @emmetio/abbreviation（略語パーサー）
- @emmetio/html-matcher（HTMLパーサー）
- @emmetio/css-parser（CSSパーサー）

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | テキストエディタ | 主画面 | HTML/CSSファイルの編集、略語展開 |

## 機能種別

コード展開 / コード補完 / テキスト操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| abbreviation | string | Yes | Emmet略語 | 有効なEmmet構文 |
| syntax | string | Yes | 対象言語（html, css等） | サポート言語のいずれか |
| textToWrap | string[] | No | ラップ対象テキスト | wrapWithAbbreviation時のみ |
| filter | string | No | 出力フィルター | 'c'（コメント）等 |

### 入力データソース

- エディタで選択中のテキストまたはカーソル位置
- ユーザー設定（emmet.includeLanguages、emmet.extensionsPath等）
- カスタムスニペット定義ファイル（snippets.json）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| expandedText | string | 展開されたHTML/CSSコード |
| CompletionItem | object | 補完候補としての略語展開結果 |
| InlineCompletionItem | object | インライン補完としての略語展開結果 |

### 出力先

- エディタ（展開結果の挿入/置換）
- 補完リスト（補完候補として表示）

## 処理フロー

### 処理シーケンス

```
1. 拡張機能のアクティベーション
   └─ コマンド登録、補完プロバイダー登録
2. 略語の検出
   └─ カーソル位置から略語を抽出
3. 構文・位置の検証
   └─ 現在の言語モード、カーソル位置の妥当性を検証
4. 略語の展開
   └─ Emmetライブラリで略語をコードに変換
5. 結果の挿入
   └─ エディタに展開結果を挿入（スニペット形式）
```

### フローチャート

```mermaid
flowchart TD
    A[略語入力/コマンド実行] --> B[略語抽出]
    B --> C{有効な略語?}
    C -->|No| D[フォールバック処理]
    C -->|Yes| E[構文・位置検証]
    E --> F{有効な位置?}
    F -->|No| D
    F -->|Yes| G[略語展開]
    G --> H{展開成功?}
    H -->|No| I[エラー表示]
    H -->|Yes| J[スニペット挿入]
    D --> K[Tabキーのデフォルト動作]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-73-01 | Tab展開設定 | emmet.triggerExpansionOnTabが有効な場合のみTabで展開 | 設定値 = true |
| BR-73-02 | 除外言語 | emmet.excludeLanguagesに含まれる言語では無効 | 言語がリストに含まれる |
| BR-73-03 | カスタム言語マッピング | emmet.includeLanguagesで追加言語をサポート | マッピング定義あり |
| BR-73-04 | 空白直後スキップ | 直前文字が空白/タブの場合は展開しない | 単一選択かつ空選択 |

### 計算ロジック

- 略語抽出: カーソル位置から左方向に有効な略語文字を検索
- 構文判定: 言語ID + 親モード + マッピング設定から適用構文を決定
- インデント: エディタ設定（tabSize、insertSpaces）に基づいて出力を整形

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvalidAbbreviation | 無効なEmmet略語 | エラーメッセージ表示、展開スキップ |
| - | InvalidPosition | 展開不可能な位置 | フォールバック処理（Tab/Enter）|
| - | ExpandError | 展開処理の失敗 | "Failed to expand abbreviation"メッセージ |

### リトライ仕様

特になし。エラー発生時は次回入力で再試行。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- 略語展開は100ms以内に完了
- ドキュメントパース結果はキャッシュして再利用
- 1000行超のスタイルシートは部分パースを使用

## セキュリティ考慮事項

- カスタムスニペットファイルはユーザー指定パスから読み込み
- ワークスペース信頼モードに依存しない

## 備考

- インライン補完モード（emmet.useInlineCompletions）で補完リスト不要の展開が可能
- 拡張パスのスニペット定義は自動リロード

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Emmetの内部で使用されるノード構造とパース結果を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EmmetNode.d.ts | `extensions/emmet/src/typings/EmmetNode.d.ts` | Emmetノード型定義 |
| 1-2 | EmmetFlatNode.d.ts | `extensions/emmet/src/typings/EmmetFlatNode.d.ts` | フラットノード型定義 |

**読解のコツ**: HTMLとCSSで異なるノード型（HtmlNode, Stylesheet, Rule, Property等）が使用される。

#### Step 2: エントリーポイントを理解する

拡張機能のアクティベーション処理と各種コマンドの登録を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | emmetCommon.ts | `extensions/emmet/src/emmetCommon.ts` | activateEmmetExtension関数 |

**主要処理フロー**:
1. **24-28行目**: 初期化処理（マイグレーション、補完プロバイダー、拡張パス）
2. **29-31行目**: wrapWithAbbreviationコマンド登録
3. **33-35行目**: expandAbbreviationコマンド登録
4. **37-118行目**: 各種エディターアクションコマンド登録
5. **163-226行目**: refreshCompletionProvidersで言語別補完プロバイダー登録

#### Step 3: 略語展開処理を理解する

Emmet略語の展開ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | abbreviationActions.ts | `extensions/emmet/src/abbreviationActions.ts` | expandEmmetAbbreviation、wrapWithAbbreviation関数 |

**主要処理フロー**:
- **32-262行目**: wrapWithAbbreviation関数で選択テキストをラップ
- **264-418行目**: expandEmmetAbbreviation関数で略語を展開
- **420-425行目**: fallbackTab関数でTabキーのデフォルト動作
- **436-618行目**: isValidLocationForEmmetAbbreviation関数で位置検証
- **625-656行目**: expandAbbreviationInRange関数でスニペット挿入
- **661-700行目**: expandAbbr関数で実際の展開処理

#### Step 4: 補完プロバイダーを理解する

補完候補としてEmmet展開を提供する処理を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | defaultCompletionProvider.ts | `extensions/emmet/src/defaultCompletionProvider.ts` | DefaultCompletionItemProviderクラス |

**主要処理フロー**:
- provideCompletionItemsメソッドで略語を検出して展開結果を返却
- 言語モードとカーソル位置から適用構文を決定

#### Step 5: ユーティリティを理解する

言語モード判定、設定取得などのユーティリティを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | util.ts | `extensions/emmet/src/util.ts` | LANGUAGE_MODES、getMappingForIncludedLanguages等 |

**主要処理フロー**:
- LANGUAGE_MODES: 各言語のトリガー文字定義
- getEmmetMode: 言語IDから適用するEmmetモードを決定
- getEmmetConfiguration: Emmet設定を取得

### プログラム呼び出し階層図

```
activateEmmetExtension (emmetCommon.ts)
    │
    ├─ refreshCompletionProviders
    │      └─ DefaultCompletionItemProvider (defaultCompletionProvider.ts)
    │
    ├─ コマンド: emmet.expandAbbreviation
    │      └─ expandEmmetAbbreviation (abbreviationActions.ts)
    │             ├─ getAbbreviation → 略語抽出
    │             ├─ isValidLocationForEmmetAbbreviation → 位置検証
    │             └─ expandAbbreviationInRange → スニペット挿入
    │
    ├─ コマンド: editor.emmet.action.wrapWithAbbreviation
    │      └─ wrapWithAbbreviation (abbreviationActions.ts)
    │             └─ applyPreview → プレビュー適用
    │
    └─ 各種エディターアクション
           ├─ removeTag (removeTag.ts)
           ├─ updateTag (updateTag.ts)
           ├─ matchTag (matchTag.ts)
           ├─ balanceOut/balanceIn (balance.ts)
           └─ その他...
```

### データフロー図

```
[入力]                    [処理]                         [出力]

略語テキスト ─────────▶ extractAbbreviation ────────▶ Abbreviation
     │                       │
     │                       ▼
     │               isValidLocation ────────────▶ 位置検証結果
     │                       │
     │                       ▼
     └─────────────▶ expandAbbr ─────────────────▶ 展開テキスト
                            │
                            ▼
                      SnippetString ─────────────▶ エディタ挿入
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| emmetCommon.ts | `extensions/emmet/src/emmetCommon.ts` | ソース | 拡張機能エントリーポイント、コマンド登録 |
| abbreviationActions.ts | `extensions/emmet/src/abbreviationActions.ts` | ソース | 略語展開、ラップ処理 |
| defaultCompletionProvider.ts | `extensions/emmet/src/defaultCompletionProvider.ts` | ソース | 補完プロバイダー |
| util.ts | `extensions/emmet/src/util.ts` | ソース | ユーティリティ関数、言語モード定義 |
| parseDocument.ts | `extensions/emmet/src/parseDocument.ts` | ソース | ドキュメントパース |
| removeTag.ts | `extensions/emmet/src/removeTag.ts` | ソース | タグ削除アクション |
| updateTag.ts | `extensions/emmet/src/updateTag.ts` | ソース | タグ更新アクション |
| matchTag.ts | `extensions/emmet/src/matchTag.ts` | ソース | 対応タグ移動 |
| balance.ts | `extensions/emmet/src/balance.ts` | ソース | Balance Out/In |
| toggleComment.ts | `extensions/emmet/src/toggleComment.ts` | ソース | コメントトグル |
| incrementDecrement.ts | `extensions/emmet/src/incrementDecrement.ts` | ソース | 数値増減 |
| package.json | `extensions/emmet/package.json` | 設定 | 拡張機能マニフェスト |
