# 機能設計書 30-範囲フォーマット (textDocument/rangeFormatting)

## 概要

本ドキュメントは、serve-d LSPサーバーにおける範囲フォーマット機能（textDocument/rangeFormatting）の設計を記述する。選択範囲のみに対してコードフォーマットを実行する機能である。

### 本機能の処理概要

**業務上の目的・背景**：ドキュメント全体のフォーマットではなく、特定の選択範囲のみをフォーマットしたい場合がある。例えば、新しく追加した関数のみをフォーマットしたい場合や、既存コードのスタイルを崩さずに特定部分だけを整形したい場合に本機能が利用される。

**機能の利用シーン**：開発者がエディタ上でテキスト範囲を選択した状態で「Format Selection」コマンドを実行した際に呼び出される。

**主要な処理内容**：
1. ドキュメント全体のフォーマットを実行する（provideFormattingを内部利用）
2. フォーマット結果のTextEdit配列から、指定された範囲と交差するものだけをフィルタする
3. フィルタされたTextEdit配列を返却する

**関連システム・外部連携**：ドキュメントフォーマット機能（No.29）を内部利用

**権限による制御**：ドキュメントフォーマット機能（No.29）の設定に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 24 | 範囲フォーマット（textDocument/rangeFormatting） | 主画面 | 選択範囲のみに対してdfmtによるコードフォーマットを実行する |

## 機能種別

変換処理（範囲限定コードフォーマット）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なドキュメントURIであること |
| range | TextRange | Yes | フォーマット対象の選択範囲 | ドキュメント範囲内であること |
| options.tabSize | int | Yes | タブのスペース数 | - |
| options.insertSpaces | bool | Yes | タブの代わりにスペースを使用するか | - |

### 入力データソース

- LSPクライアントからのtextDocument/rangeFormattingリクエストのDocumentRangeFormattingParams

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | TextRange | 編集対象の位置範囲（指定範囲と交差するもののみ） |
| newText | string | 新しいテキスト |

### 出力先

LSPクライアント（JSON-RPCレスポンスとして返却）

## 処理フロー

### 処理シーケンス

```
1. textDocument/rangeFormattingリクエスト受信
   └─ DocumentRangeFormattingParamsからURI・範囲・オプションを取得
2. provideFormatting呼び出し（ドキュメント全体フォーマット）
   └─ textDocumentとoptionsをDocumentFormattingParamsに変換して委譲
3. 範囲フィルタリング
   └─ 各TextEditのrangeが指定rangeと交差するかチェック
   └─ edit.range.intersects(params.range)
4. フィルタ結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[rangeFormatting リクエスト受信] --> B[provideFormatting 呼び出し ドキュメント全体フォーマット]
    B --> C[TextEdit配列取得]
    C --> D[各TextEditを範囲フィルタ]
    D --> E{edit.range.intersects params.range?}
    E -->|Yes| F[結果に含める]
    E -->|No| G[スキップ]
    F --> H[フィルタ済みTextEdit配列返却]
    G --> D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | 全体フォーマット委譲 | 内部的にはドキュメント全体のフォーマットを実行し、結果をフィルタする | 常に |
| BR-30-02 | 交差判定 | TextEditのrangeとリクエストのrangeが交差（intersects）するものだけを返す | フィルタ時（192行目） |
| BR-30-03 | 設定依存 | ドキュメントフォーマット機能（No.29）の設定（enableFormatting等）に従う | 内部呼び出し時 |

### 計算ロジック

`intersects`メソッドによる範囲交差判定: TextEditのrangeと指定されたparams.rangeが重複する部分を持つかどうかを判定する。

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

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

データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | ドキュメントフォーマットが無効の場合 | 空配列（provideFormattingの結果がそのまま伝搬） |
| - | 空結果 | 指定範囲と交差するTextEditがない場合 | 空配列 |

### リトライ仕様

リトライは不要。

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

トランザクションは使用しない。

## パフォーマンス要件

- 内部的にドキュメント全体のフォーマットを実行するため、パフォーマンス特性はドキュメントフォーマット機能（No.29）と同一
- フィルタ処理自体は軽量（O(n), nはTextEditの数）

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

特になし。

## 備考

- 本機能は非常にシンプルな実装で、provideFormattingの結果をフィルタするだけの薄いラッパーである（183-194行目、わずか12行）
- ドキュメント全体をフォーマットしてからフィルタするアプローチのため、フォーマッタの出力が範囲境界をまたぐ場合でも正しいTextEditが返される
- D言語のdfmtはファイル単位でのフォーマットを前提としているため、この「全体フォーマット+範囲フィルタ」のアプローチは合理的である

---

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

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

### 推奨読解順序

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

本機能は非常に短い実装のため、エントリーポイントの理解で全体を把握できる。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | format.d | `source/served/commands/format.d` | provideRangeFormatting関数（183-194行目）がLSPプロトコルメソッドのエントリーポイント |

**主要処理フロー**:
1. **189-190行目**: `provideFormatting(DocumentFormattingParams(params.textDocument, params.options))` ドキュメント全体フォーマットの委譲
2. **191-193行目**: `.filter!((edit) => edit.range.intersects(params.range))` 範囲フィルタリング
3. **193行目**: `.array` 結果の配列化

**読解のコツ**: D言語のUFCS（Uniform Function Call Syntax）とレンジベースのプログラミングにより、`provideFormatting(...).filter!(...).array`というパイプライン風の記述が可能。provideFormattingの返り値であるTextEdit[]に対してfilterを適用し、最終的にarrayで具体的な配列に変換している。

#### Step 2: 委譲先を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | format.d | `source/served/commands/format.d` | provideFormatting関数（130-171行目）がドキュメント全体フォーマットの実装。No.29の設計書を参照 |

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

```
provideRangeFormatting (format.d:184)
    |
    +-- provideFormatting (format.d:131)
    |       |
    |       +-- [D言語] DfmtComponent.format + diff
    |       +-- [SDL] sdlfmt.format + diff
    |
    +-- filter (edit.range.intersects)
    +-- array
```

### データフロー図

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

DocumentRangeFormattingParams -> provideRangeFormatting ---------> TextEdit[]
  (uri, range, options)               |                         (範囲内のみ)
                                      v
                               provideFormatting
                               (ドキュメント全体フォーマット)
                                      |
                                      v
                               TextEdit[] (全体の差分)
                                      |
                                      v
                               filter (intersects)
                                      |
                                      v
                               TextEdit[] (指定範囲に交差するもの)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| format.d | `source/served/commands/format.d` | ソース | 範囲フォーマットのメイン実装（provideRangeFormatting: 183-194行目）およびドキュメントフォーマット委譲先 |
| types.d | `source/served/types.d` | ソース | LSP型定義（DocumentRangeFormattingParams, TextEdit, TextRange.intersects等） |
