# 機能設計書 68-ブレースマッチング

## 概要

本ドキュメントは、Visual Studio統合におけるF#のブレースマッチング（括弧対応表示）機能の設計について記述する。この機能は、カーソルが括弧（`()`、`[]`、`{}`）の近くにある場合に、対応する括弧をハイライト表示する。

### 本機能の処理概要

**業務上の目的・背景**：
F#コードにおいて、ネストした括弧や複雑な式の中で対応する括弧を視覚的に確認できることは、コードの理解とデバッグに不可欠である。本機能により、開発者は括弧の対応関係を即座に把握でき、構文エラーの早期発見が可能になる。

**機能の利用シーン**：
- カーソルを括弧の近くに移動して対応する括弧を確認したい場合
- ネストした関数呼び出しやリスト式で構造を把握したい場合
- 括弧の過不足によるエラーを調査する場合

**主要な処理内容**：
1. カーソル位置の取得
2. F#コンパイラのMatchBraces APIを呼び出し
3. 位置判定による対応括弧ペアの特定
4. 対応括弧のTextSpanを計算
5. ハイライト表示用のBraceMatchingResultを返却

**関連システム・外部連携**：
- Microsoft.CodeAnalysis.ExternalAccess.FSharp.Editor: Roslynブレースマッチングインターフェース
- FSharp.Compiler.CodeAnalysis.FSharpChecker: MatchBraces API

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 専用の設定画面なし |

## 機能種別

コード表示・ナビゲーション機能

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| document | Document | Yes | 対象のドキュメント | null不可 |
| position | int | Yes | カーソル位置（文字オフセット） | 0以上、ドキュメント長未満 |
| cancellationToken | CancellationToken | Yes | キャンセルトークン | - |

### 入力データソース

- Visual Studioエディタのカーソル位置
- ドキュメントのソーステキスト
- F#パーシングオプション

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| FSharpBraceMatchingResult | Nullable<FSharpBraceMatchingResult> | 対応括弧のスパンペア、または見つからない場合null |
| LeftSpan | TextSpan | 左括弧のテキストスパン |
| RightSpan | TextSpan | 右括弧のテキストスパン |

### 出力先

Visual Studio エディタ上のブレースハイライト表示

## 処理フロー

### 処理シーケンス

```
1. コンパイルオプション取得
   └─ GetFSharpCompilationOptionsAsyncでチェッカーとオプション取得

2. ソーステキスト取得
   └─ document.GetTextAsync

3. MatchBraces呼び出し
   └─ checker.MatchBracesでF#コンパイラAPI呼び出し

4. 位置判定
   └─ カーソル位置を含むブレースペアを探索

5. スパン変換
   └─ F#のrangeをRoslynのTextSpanに変換

6. 結果返却
   └─ FSharpBraceMatchingResultを返却
```

### フローチャート

```mermaid
flowchart TD
    A[カーソル移動] --> B[GetFSharpCompilationOptionsAsync]
    B --> C[GetTextAsync]
    C --> D[MatchBraces]
    D --> E{ブレースペアあり?}
    E -->|No| Z[null返却]
    E -->|Yes| F[各ペアをチェック]
    F --> G{カーソル位置がleft or rightに含まれる?}
    G -->|No| H[次のペア]
    H --> F
    G -->|Yes| I[TryFSharpRangeToTextSpan]
    I --> J{変換成功?}
    J -->|No| Z
    J -->|Yes| K[FSharpBraceMatchingResult生成]
    K --> L[返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | 包含判定 | カーソル位置がTextSpanに含まれる場合にマッチ | 通常の判定時 |
| BR-68-02 | forFormatting拡張 | フォーマット用途ではスパン終端を含めて判定 | forFormatting=true時 |
| BR-68-03 | 両方向マッチ | 左括弧または右括弧のどちらにカーソルがあってもマッチ | 位置判定時 |

### 計算ロジック

位置判定ロジック（29-37行目）:
```fsharp
let isPositionInRange range =
    match RoslynHelpers.TryFSharpRangeToTextSpan(sourceText, range) with
    | ValueNone -> false
    | ValueSome span ->
        if forFormatting then
            let length = position - span.Start
            length >= 0 && length <= span.Length
        else
            span.Contains position
```

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

該当なし（メモリ内解析のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | マッチなし | カーソル位置に対応する括弧がない | nullを返却 |
| - | スパン変換失敗 | rangeをTextSpanに変換できない | nullを返却 |

### リトライ仕様

リトライなし。

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

該当なし（読み取り専用操作）

## パフォーマンス要件

- カーソル移動に追従してリアルタイム更新
- 非同期処理によりUIスレッドをブロックしない

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

該当なし

## 備考

- FSharpBraceMatchingServiceがIFSharpBraceMatcherを実装
- GetBraceMatchingResult静的メソッドは他機能（フォーマット）からも使用される
- forFormattingオプションは閉じ括弧入力時のインデント調整で使用

---

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

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

### 推奨読解順序

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

ブレースマッチングで使用される主要なデータ型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BraceMatchingService.fs | `vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs` | FSharpBraceMatchingResult型 |

**読解のコツ**:
- FSharpBraceMatchingResult: 左右のTextSpanを持つ構造体
- matchedBraces: F#コンパイラが返す(range * range)配列

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

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

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

**主要処理フロー**:
1. **13-14行目**: クラス定義とExportアトリビュート
2. **44-70行目**: IFSharpBraceMatcher.FindBracesAsync実装

#### Step 3: コアロジックを理解する

GetBraceMatchingResult静的メソッドがブレースマッチングの中核。

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

**主要処理フロー**:
- **16-42行目**: GetBraceMatchingResult静的メソッド
- **27行目**: checker.MatchBracesでF#コンパイラAPI呼び出し
- **29-37行目**: isPositionInRange関数定義
- **39-41行目**: 配列からマッチするペアを検索

#### Step 4: インターフェース実装を理解する

FindBracesAsyncがRoslynインターフェースの実装。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BraceMatchingService.fs | `vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs` | FindBracesAsync実装 |

**主要処理フロー**:
- **45-70行目**: FindBracesAsyncメソッド本体
- **46-51行目**: コンパイルオプション取得
- **53行目**: ソーステキスト取得
- **55-63行目**: GetBraceMatchingResult呼び出し
- **65-67行目**: F#のrangeをTextSpanに変換
- **68-69行目**: FSharpBraceMatchingResult生成

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

```
IFSharpBraceMatcher.FindBracesAsync
    │
    ├─ document.GetFSharpCompilationOptionsAsync
    │      └─ FSharpChecker, parsingOptions取得
    │
    ├─ document.GetTextAsync
    │      └─ SourceText取得
    │
    └─ GetBraceMatchingResult
           │
           ├─ checker.MatchBraces
           │      └─ (range * range)[] 取得
           │
           ├─ isPositionInRange (位置判定)
           │      └─ TryFSharpRangeToTextSpan
           │
           ├─ Array.tryFind (マッチ検索)
           │
           └─ FSharpBraceMatchingResult生成
```

### データフロー図

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

Document ─────────────▶ GetFSharpCompilationOptionsAsync ─┐
                              │                           │
                              ▼                           │
                        FSharpChecker                     │
                              │                           │
                              ▼                           │
Position ─────────────▶ MatchBraces ──────────────────────┤
                              │                           │
                              ▼                           │
                        (range * range)[]                 │
                              │                           │
                              ▼                           │
                        isPositionInRange ────────────────┤
                              │                           │
                              ▼                           │
                        Array.tryFind ────────────────────┤
                              │                           │
                              ▼                           ▼
                        FSharpBraceMatchingResult ───▶ エディタハイライト
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BraceMatchingService.fs | `vsintegration/src/FSharp.Editor/Formatting/BraceMatchingService.fs` | ソース | ブレースマッチングサービス実装 |
| RoslynHelpers.fs | `vsintegration/src/FSharp.Editor/Common/RoslynHelpers.fs` | ソース | range→TextSpan変換 |
| EditorFormattingService.fs | `vsintegration/src/FSharp.Editor/Formatting/EditorFormattingService.fs` | ソース | フォーマット機能（連携先） |
