# 画面設計書 31-折りたたみ（textDocument/foldingRange）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供する `textDocument/foldingRange` リクエストハンドラの画面設計書である。エディタ上でソースコードの折りたたみ可能な範囲を特定し、クライアントに返却する機能を定義する。

### 本画面の処理概要

本機能は、D言語ソースコードにおけるコメント、インポート文、リージョン等の折りたたみ可能な範囲を検出し、エディタのコード折りたたみ機能を実現する。

**業務上の目的・背景**：大規模なD言語ソースファイルにおいて、開発者がコードの見通しを良くするために不要な部分を折りたたむ必要がある。本機能はLSPプロトコルの `textDocument/foldingRange` を実装し、エディタが適切な折りたたみ範囲を認識できるようにする。コメントブロック、インポート文ブロック、リージョンなどの論理的な区切りに基づいて折りたたみ範囲を決定する。

**画面へのアクセス方法**：エディタがD言語ファイルを開いた際、またはドキュメントの変更後にクライアントが `textDocument/foldingRange` リクエストをサーバーに送信することで自動的に呼び出される。ユーザーが明示的に操作する必要はなく、エディタのUI上でコード折りたたみアイコンとして表示される。

**主要な操作・処理内容**：
1. クライアントから `textDocument/foldingRange` リクエストを受信する
2. 対象ドキュメントをドキュメントストアから取得する
3. DCDExtComponentの存在確認を行い、利用不可の場合は空を返す
4. DCDExtComponentの `getFoldingRanges` メソッドでソースコードを解析し折りたたみ範囲を取得する
5. バイトオフセットからLSP Position（行・文字）に変換する
6. 折りたたみ範囲の種別（comment/imports/region）をLSP仕様のFoldingRangeKindに変換する
7. 変換済みのFoldingRange配列をクライアントに返却する

**画面遷移**：本機能は単独のリクエスト・レスポンスであり、他の画面への遷移は発生しない。エディタがドキュメントを開いた際やドキュメント変更時に自動的に呼び出される。

**権限による表示制御**：特別な権限制御は存在しない。DCDExtComponentが利用可能かどうかによって機能の有効・無効が決まる。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 31 | 折りたたみ範囲 (textDocument/foldingRange) | 主機能 | コメント・インポート・リージョン等の折りたたみ可能な範囲を返却する |

## 画面種別

LSPリクエスト・レスポンス（コード折りたたみ情報提供）

## URL/ルーティング

LSPメソッド: `textDocument/foldingRange`

## 入出力項目

### 入力（リクエストパラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI |

### 出力（レスポンス）

| 項目名 | 型 | 説明 |
|--------|------|------|
| (配列要素).startLine | uint | 折りたたみ開始行（0始まり） |
| (配列要素).endLine | uint | 折りたたみ終了行（0始まり） |
| (配列要素).startCharacter | uint | 折りたたみ開始文字位置 |
| (配列要素).endCharacter | uint | 折りたたみ終了文字位置 |
| (配列要素).kind | FoldingRangeKind | 折りたたみ種別（comment/imports/region） |

## 表示項目

本機能はエディタ上のコード折りたたみUIとして表示される。

| 表示項目 | 説明 |
|----------|------|
| 折りたたみアイコン | エディタのガター領域に表示される折りたたみ/展開アイコン |
| 折りたたみ範囲 | コメントブロック、インポート文ブロック、リージョンに対応 |

## イベント仕様

### 1-foldingRangeリクエスト

クライアントが `textDocument/foldingRange` を送信すると、サーバーは以下の処理を実行する。

1. `FoldingRangeParams` からドキュメントURIを取得
2. ドキュメントストアからドキュメントオブジェクトを取得
3. DCDExtComponentの利用可能性を確認（`backend.hasBest!DCDExtComponent`）
4. 利用不可の場合は `null` を返却
5. ドキュメントのrawTextを取得
6. `DCDExtComponent.getFoldingRanges` を呼び出し
7. 各rangeについてバイトオフセット→Position変換を実施
8. `FoldingRangeType` → `FoldingRangeKind` の変換を実施（`mapFoldingRangeKind`）
9. FoldingRange配列を返却

## データベース更新仕様

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

本機能はデータベースへの更新を行わない（読み取り専用）。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| foldingRangeリクエスト | なし | SELECT | ドキュメントストアからの読み取りのみ |

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|---------------|------|---------------|
| 空応答 | DCDExtComponentが利用不可 | null（空のレスポンス）を返却 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| DCDExtComponentが利用不可 | `typeof(return).init`（null）を返却し、エディタ側で折りたたみ非対応として扱われる |
| ドキュメントが見つからない | ドキュメントストアのデフォルト処理によりエラー |

## 備考

- FoldingRangeType は3種類のみ対応：comment（コメント）、imports（インポート文）、region（リージョン）
- バイトオフセットからPositionへの変換には `document.nextPositionBytes` メソッドが使用され、キャッシュにより効率化されている
- DCDExtComponentはworkspace-d経由でD言語ソースの構文解析を行うコンポーネントである

---

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

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

### 推奨読解順序

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

まず、FoldingRangeおよび関連する型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | FoldingRange, FoldingRangeKind, FoldingRangeParams の型定義を確認する |
| 1-2 | dcdext.d (workspaced) | `subpackages/workspaced/com/dcdext.d` | getFoldingRanges の戻り値型および FoldingRangeType の定義を確認する |

**読解のコツ**: serve-dではLSPプロトコルの型定義が `served.types` モジュールに集約されている。workspaced側のFoldingRangeTypeとserved側のFoldingRangeKindは別の型であり、`mapFoldingRangeKind` で変換される点に注意する。

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

処理の起点となる `provideFoldingRange` 関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | folding.d | `source/served/commands/folding.d` | `@protocolMethod("textDocument/foldingRange")` アトリビュートで登録されたエントリーポイント |

**主要処理フロー**:
1. **行12**: `provideFoldingRange` 関数 - リクエストハンドラのエントリーポイント
2. **行14**: `documents[params.textDocument.uri]` - ドキュメントストアからドキュメントを取得
3. **行17-18**: `backend.hasBest!DCDExtComponent(file)` - DCDExtComponentの利用可能性チェック
4. **行26**: `backend.best!DCDExtComponent(file).getFoldingRanges(codeText)` - 折りたたみ範囲の取得
5. **行28-29**: `document.nextPositionBytes` - バイトオフセットからPositionへの変換
6. **行35**: `mapFoldingRangeKind(range.type)` - 種別の変換

#### Step 3: 種別変換ロジックを理解する

FoldingRangeType から FoldingRangeKind への変換処理。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | folding.d | `source/served/commands/folding.d` | `mapFoldingRangeKind` 関数（行42-49）のfinal switchによる1対1変換 |

**主要処理フロー**:
- **行42-49**: comment→FoldingRangeKind.comment, imports→FoldingRangeKind.imports, region→FoldingRangeKind.region の3種変換

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

```
provideFoldingRange (folding.d:12)
    |
    +-- documents[uri] (ドキュメントストア参照)
    |
    +-- backend.hasBest!DCDExtComponent (利用可能性確認)
    |
    +-- backend.best!DCDExtComponent.getFoldingRanges (workspaced)
    |       |
    |       +-- D言語ソースコードの構文解析
    |
    +-- document.nextPositionBytes (バイトオフセット→Position変換)
    |
    +-- mapFoldingRangeKind (folding.d:42)
            |
            +-- FoldingRangeType → FoldingRangeKind 変換
```

### データフロー図

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

FoldingRangeParams  --->  provideFoldingRange        --->  FoldingRange[]
  .textDocument.uri        |                                .startLine
                           +-- ドキュメント取得              .endLine
                           +-- DCDExtComponent確認           .startCharacter
                           +-- getFoldingRanges              .endCharacter
                           +-- バイト→Position変換           .kind
                           +-- Kind変換
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| folding.d | `source/served/commands/folding.d` | ソース | 折りたたみ範囲リクエストハンドラ本体（全51行） |
| types.d | `source/served/types.d` | ソース | FoldingRange等のLSP型定義 |
| extension.d | `source/served/extension.d` | ソース | backend, documents等のグローバル変数定義 |
| dcdext.d | workspacedサブパッケージ | ソース | getFoldingRanges の実装（DCDExtComponent） |
