# 機能設計書 64-ファイル検索

## 概要

本ドキュメントは、serve-dにおけるファイル検索機能（served/searchFile）の設計を記述する。ファイル名でプロジェクトと依存関係（標準ライブラリ含む）を横断検索し、一致するファイルパスの一覧を返却する機能である。

### 本機能の処理概要

**業務上の目的・背景**：D言語のプロジェクト開発では、インポートパスや依存関係に含まれるファイルの実体を特定する必要が生じる場合がある。本機能は、ファイル名の末尾一致（サフィックスマッチ）により、プロジェクトのインポートファイルやインポートパス配下のファイルを横断的に検索する手段を提供する。

**機能の利用シーン**：
- エディタの拡張機能からD言語のソースファイルを名前で検索する場合
- 依存関係内の特定ファイルの実体パスを取得したい場合
- 標準ライブラリのファイルパスを特定したい場合

**主要な処理内容**：
1. クエリが絶対パスの場合、ファイルの存在を直接確認して返却する
2. 全ワークスペースインスタンスのインポートファイルとインポートパスを収集する
3. 標準ライブラリパスをインポートパスに追加する
4. インポートファイル一覧からクエリと末尾一致するファイルを抽出する
5. インポートパス配下のファイルを走査し、クエリと末尾一致するファイルを抽出する

**関連システム・外部連携**：ファイルシステムへの直接アクセス。workspace-dバックエンドのインスタンス情報を利用。

**権限による制御**：特別な権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 61 | ファイル検索（served/searchFile） | 主画面 | ファイル名でプロジェクトと依存関係を横断検索する |

## 機能種別

データ検索・取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| query | string | Yes | 検索するファイル名またはパス | 空文字列の場合nullを返却 |

### 入力データソース

LSPクライアントからの `served/searchFile` メソッド呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | string[] | 一致したファイルの絶対パスの配列。一致なしの場合null |

### 出力先

LSPクライアントへのレスポンス（JSON-RPC応答）。

## 処理フロー

### 処理シーケンス

```
1. served/searchFileリクエストを受信
   └─ searchFile(query)関数が呼び出される
2. 空文字列チェック
   └─ queryが空の場合はnullを返却
3. 絶対パスチェック
   └─ queryが絶対パスの場合、ファイル存在確認して結果返却
4. インポートファイルとインポートパスの収集
   └─ 標準ライブラリパスをimportPathsに追加
   └─ 全インスタンスからimportFilesとimportPathsを収集
5. インポートファイル一覧からの検索
   └─ 各ファイルがqueryとサフィックス一致するか確認
   └─ パスセパレータ境界での一致を検証
6. インポートパス配下のファイル走査
   └─ 各ディレクトリ配下のファイルをbreadth走査
   └─ queryとサフィックス一致するファイルを収集
7. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[served/searchFile リクエスト受信] --> B{query は空?}
    B -->|Yes| C[null を返却]
    B -->|No| D{query は絶対パス?}
    D -->|Yes| E{ファイル存在?}
    E -->|Yes| F[query を配列で返却]
    E -->|No| C
    D -->|No| G[stdlibPath + 全インスタンスの importFiles/importPaths を収集]
    G --> H[importFiles からサフィックス一致検索]
    H --> I[importPaths 配下からサフィックス一致検索]
    I --> J[結果配列を返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-64-01 | サフィックスマッチ | ファイルパスの末尾がqueryと一致し、残りの部分がパスセパレータで終わるか空であること | 全検索 |
| BR-64-02 | 重複排除 | importFilesとimportPathsをソートしuniqで重複排除 | 常時 |
| BR-64-03 | 絶対パス直接検索 | queryが絶対パスの場合はファイル存在確認のみ行う | query.isAbsolute == true |
| BR-64-04 | 標準ライブラリ含む | 検索対象に標準ライブラリのパスを含む | 常時 |

### 計算ロジック

サフィックスマッチの判定：
```
file.endsWith(query) && (rest.length == 0 || rest.endsWith("/", "\\"))
```

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

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

データベース操作はない。ファイルシステムのみ走査。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイルシステムエラー | ディレクトリの走査に失敗した場合 | D言語の例外処理に委ねる |

### リトライ仕様

なし。

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

トランザクション管理は不要。読み取り専用操作。

## パフォーマンス要件

インポートパス配下のファイルを `fs.SpanMode.breadth` で再帰走査するため、多数の依存関係がある場合は走査に時間がかかる可能性がある。

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

ファイルシステムの読み取りアクセスのみ。パスインジェクションのリスクはD言語の標準ライブラリの `isAbsolute` による判定で軽減。

## 備考

- `@protocolMethod("served/searchFile")` アノテーションにより登録
- selectedWorkspace.stdlibPath() で標準ライブラリパスを取得
- ファイルの存在確認にfs.exists, fs.isFile, fs.isDirを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | file_search.d | `source/served/commands/file_search.d` | importFiles, importPathsの変数定義とその収集方法 |

**読解のコツ**: D言語の `fs = std.file` はモジュールエイリアス。`fs.dirEntries` でディレクトリ走査、`fs.SpanMode.breadth` で幅優先走査を行う。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | file_search.d | `source/served/commands/file_search.d` | searchFile関数（18-72行目） |

**主要処理フロー**:
1. **19-20行目**: 空文字列チェック
2. **22-30行目**: 絶対パスの直接存在確認
3. **32-40行目**: importFiles/importPathsの収集（stdlibPath + 全インスタンス）
4. **42-43行目**: ソートと重複排除
5. **45-54行目**: importFilesからのサフィックスマッチ検索
6. **55-69行目**: importPaths配下のファイル走査とサフィックスマッチ検索
7. **71行目**: 結果配列の返却

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

```
searchFile(query) [file_search.d:18-72]
    |
    +-- query.isAbsolute (絶対パス判定)
    |   +-- fs.exists(query) (ファイル存在確認)
    |
    +-- selectedWorkspace.stdlibPath() (標準ライブラリパス取得)
    |
    +-- backend.instances (全ワークスペースインスタンスの列挙)
    |   +-- instance.importFiles (インポートファイル一覧)
    |   +-- instance.importPaths (インポートパス一覧)
    |
    +-- importFiles.uniq (重複排除・サフィックスマッチ)
    |
    +-- fs.dirEntries(dir, breadth) (ディレクトリ走査)
        +-- サフィックスマッチ判定
```

### データフロー図

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

served/searchFile     ──▶  searchFile(query)              ──▶  string[] (マッチしたファイルパス)
(query: string)              |
                            +-- 標準ライブラリパス
                            +-- 全インスタンスのimportFiles
                            +-- 全インスタンスのimportPaths
                            +-- ファイルシステム走査
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| file_search.d | `source/served/commands/file_search.d` | ソース | searchFile関数の定義（18-72行目） |
| extension.d | `source/served/extension.d` | ソース | バックエンドインスタンス管理、selectedWorkspace |
| types.d | `source/served/types.d` | ソース | ワークスペース設定、stdlibPath |
