# 機能設計書 67-フォーマット

## 概要

本ドキュメントは、Visual Studio統合におけるF#のコード整形機能の設計について記述する。この機能は、閉じ括弧入力時のインデント自動調整、貼り付け時の自動フォーマット、改行時のインデント調整など、コードの書式を自動的に整える。

### 本機能の処理概要

**業務上の目的・背景**：
一貫したコードスタイルを維持することは、チーム開発において重要である。本機能により、開発者は書式を意識することなくコーディングに集中でき、自動的に整形されたコードが保たれる。

**機能の利用シーン**：
- 閉じ括弧（`)`、`]`、`}`）を入力して対応する開き括弧のインデントに揃えたい場合
- 他のソースからコードを貼り付けて適切なインデントに調整したい場合
- 改行後に適切なインデントを自動挿入したい場合

**主要な処理内容**：
1. フォーマットトリガーの検出（文字入力、貼り付け、改行）
2. 現在行のトークン解析
3. ブレースマッチングによる対応括弧の特定
4. インデント計算
5. TextChangeの生成と適用

**関連システム・外部連携**：
- Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor: Roslynフォーマットインターフェース
- FSharp.Compiler.Tokenization: トークン解析
- FSharpBraceMatchingService: 括弧対応検出

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | フォーマットオプション画面 | 設定画面 | 貼り付け時の自動フォーマットの有効/無効設定 |

## 機能種別

コード整形・入力支援機能

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象のドキュメント | null不可 |
| position | int | Yes | カーソル位置 | 0以上 |
| typedChar | char | No | 入力された文字 | ')' ']' '}' |
| span | TextSpan | No | 貼り付け範囲 | 貼り付け時のみ |

### 入力データソース

- Visual Studioエディタのカーソル位置
- 入力された文字またはクリップボード内容
- ドキュメントのソーステキスト
- F#パーシングオプション

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| TextChanges | IList<TextChange> | 適用する書式変更のリスト |

### 出力先

Visual Studio のドキュメント（ソースファイル）

## 処理フロー

### 処理シーケンス

```
1. トリガー検出
   └─ SupportsFormattingOnTypedCharacterで対応文字か判定

2. トークン解析
   └─ Tokenizer.tokenizeLineで現在行をトークン化

3. 意味のあるトークン特定
   └─ 空白・コメント以外の最初のトークンを探す

4. ブレースマッチング
   └─ FSharpBraceMatchingService.GetBraceMatchingResultで対応括弧を取得

5. インデント計算
   └─ 対応する開き括弧の行のインデントを取得

6. TextChange生成
   └─ 現在のインデントを開き括弧のインデントに置換

7. 適用
   └─ IList<TextChange>を返却
```

### フローチャート

```mermaid
flowchart TD
    A[文字入力] --> B{スマートインデント有効?}
    B -->|No| Z[なにもしない]
    B -->|Yes| C{対象文字?}
    C -->|No| Z
    C -->|Yes| D[tokenizeLine]
    D --> E[firstMeaningfulToken取得]
    E --> F{括弧?}
    F -->|No| Z
    F -->|Yes| G[GetBraceMatchingResult]
    G --> H{対応あり?}
    H -->|No| Z
    H -->|Yes| I{右括弧が行頭?}
    I -->|No| Z
    I -->|Yes| J[インデント計算]
    J --> K[TextChange生成]
    K --> L[返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-67-01 | スマートインデント必須 | FormattingOptions.IndentStyle.Smartが有効な場合のみ動作 | フォーマット開始時 |
| BR-67-02 | 閉じ括弧のみ対応 | `)`、`]`、`}`の3文字のみがフォーマットトリガー | 文字入力時 |
| BR-67-03 | 行頭括弧条件 | 閉じ括弧が行の最初の意味のあるトークンの場合のみ処理 | インデント調整時 |
| BR-67-04 | 貼り付け設定 | FormatOnPasteオプションで貼り付け時フォーマットを制御 | 貼り付け時 |

### 計算ロジック

インデント計算（86-94行目）:
```fsharp
let startIndent =
    indentChars sourceText.Lines.[sourceText.Lines.IndexOf leftSpan.Start]

let currentIndent = indentChars line

return TextChange(TextSpan(line.Start, currentIndent), String.replicate startIndent " ")
```

貼り付け時のインデント調整（99-185行目）:
- 先頭行のインデントを基準に、貼り付けコードの相対インデントを維持
- 次行がインデントされるべき場合（例：`let`の後）はタブサイズ分を考慮

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

該当なし（メモリ内操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ブレース不一致 | 対応する括弧が見つからない | 変更なし |
| - | 条件不適合 | 閉じ括弧が行頭でない | 変更なし |

### リトライ仕様

リトライなし。

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

該当なし

## パフォーマンス要件

- 文字入力時に即座にフォーマット適用
- 大きなコードの貼り付けでもUIをブロックしない

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

該当なし

## 備考

- FSharpEditorFormattingServiceがIFSharpEditorFormattingServiceWithOptionsを実装
- SupportsFormatDocument/SupportsFormatSelectionはfalse（ドキュメント全体/選択範囲のフォーマットは未サポート）
- SupportsFormatOnPaste/SupportsFormatOnReturnはtrue

---

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

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

### 推奨読解順序

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

フォーマットで使用される主要なオプション型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | FormattingOptions、EditorOptions |

**読解のコツ**:
- FormattingOptions.IndentStyle: Smart/Block/Noneの3種類
- EditorOptions.Formatting.FormatOnPaste: 貼り付け時フォーマットの有効/無効

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

IFSharpEditorFormattingServiceWithOptionsの実装から読み始める。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | FSharpEditorFormattingServiceクラス |

**主要処理フロー**:
1. **19-20行目**: クラス定義とExportアトリビュート
2. **237-271行目**: IFSharpEditorFormattingServiceWithOptionsインターフェース実装
3. **238-241行目**: Supportsプロパティの定義
4. **243-253行目**: SupportsFormattingOnTypedCharacterメソッド

#### Step 3: 文字入力時フォーマットを理解する

GetFormattingChangesが閉じ括弧入力時のインデント調整を行う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | GetFormattingChanges静的メソッド |

**主要処理フロー**:
- **27-97行目**: GetFormattingChanges静的メソッド
- **46行目**: スマートインデントのガード
- **48行目**: 現在行の取得
- **52-62行目**: トークン化
- **64-69行目**: 最初の意味のあるトークン取得
- **71-80行目**: ブレースマッチング
- **82-94行目**: インデント計算とTextChange生成

#### Step 4: 貼り付け時フォーマットを理解する

GetPasteChangesが貼り付けコードのインデント調整を行う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | GetPasteChanges静的メソッド |

**主要処理フロー**:
- **99-185行目**: GetPasteChanges静的メソッド
- **112行目**: FormatOnPaste設定のガード
- **117行目**: 同一行貼り付けのスキップ
- **125-140行目**: 自動インデントのスキップ処理
- **143-149行目**: 現在行のインデント計算
- **154-165行目**: インデント除去関数
- **170-184行目**: インデント調整ロジック

#### Step 5: ブレースマッチングとの連携を理解する

FSharpBraceMatchingServiceを使用して対応括弧を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | BraceMatchingService.fs | `vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs` | GetBraceMatchingResult静的メソッド |

**主要処理フロー**:
- **16-42行目**: GetBraceMatchingResult静的メソッド
- **27行目**: checker.MatchBracesでコンパイラAPI呼び出し
- **29-37行目**: 位置判定ロジック（forFormattingオプション対応）

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

```
IFSharpEditorFormattingServiceWithOptions
    │
    ├─ SupportsFormattingOnTypedCharacter
    │      └─ ')' / ']' / '}' を判定
    │
    ├─ GetFormattingChangesAsync (文字入力時)
    │      │
    │      └─ GetFormattingChanges
    │             │
    │             ├─ Tokenizer.tokenizeLine
    │             │
    │             ├─ FSharpBraceMatchingService.GetBraceMatchingResult
    │             │      └─ checker.MatchBraces
    │             │
    │             └─ TextChange生成
    │
    ├─ GetFormattingChangesOnPasteAsync (貼り付け時)
    │      │
    │      └─ OnPasteAsync
    │             │
    │             └─ GetPasteChanges
    │                    │
    │                    ├─ FSharpIndentationService.IndentShouldFollow
    │                    │
    │                    └─ TextChange[]生成
    │
    └─ GetFormattingChangesOnReturnAsync (改行時)
           │
           └─ GetFormattingChangesAsync
```

### データフロー図

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

typedChar (')', ']', '}')
       │
       └─────────────▶ Tokenizer.tokenizeLine ────────┐
                              │                       │
                              ▼                       │
                        firstMeaningfulToken          │
                              │                       │
                              ▼                       │
position ──────────▶ GetBraceMatchingResult ──────────┤
                              │                       │
                              ▼                       │
                        (left, right) ブレースペア    │
                              │                       │
                              ▼                       │
                        インデント計算 ───────────────┤
                              │                       │
                              ▼                       ▼
                        IList<TextChange> ────────▶ ドキュメント更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | ソース | フォーマットサービス実装 |
| BraceMatchingService.fs | `vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs` | ソース | ブレースマッチング |
| IndentationService.fs | `vsintegration/src/FSharp.Editor/Formatting/IndentationService.fs` | ソース | インデント計算 |
| Tokenizer.fs | `vsintegration/src/FSharp.Editor/Common/Tokenizer.fs` | ソース | トークン化 |
