# 画面設計書 62-モジュール検索（served/findFilesByModule）

## 概要

本ドキュメントは、serve-d LSPサーバーのカスタムリクエスト `served/findFilesByModule` の画面設計書である。D言語のモジュール名を指定して、プロジェクトおよび依存関係内から対応するファイルパスを検索して返却する。

### 本画面の処理概要

本リクエストは、D言語のモジュール名（例: `std.stdio`）から対応するソースファイルのパスを逆引き検索する機能を提供する。

**業務上の目的・背景**：D言語のimport文に記載されたモジュール名から、そのモジュールの実体ファイルを特定する必要がある。例えば、import文からファイルを開く機能や、モジュール依存関係の解析に使用される。標準ライブラリ（std.*）のモジュールについてはキャッシュ機構を持ち、繰り返しの検索を高速化している。

**画面へのアクセス方法**：LSPクライアントから `served/findFilesByModule` カスタムリクエストを送信することでアクセスする。エディタ拡張のimportナビゲーション機能等から呼び出される。

**主要な操作・処理内容**：
1. クライアントからモジュール名（文字列）を受信する
2. モジュール名が空の場合はnullを返却する
3. キャッシュにヒットした場合はキャッシュされたパスを返却する
4. 全インスタンスのインポートファイルを走査し、ModulemanComponentでモジュール名を解決する
5. 全インスタンスのインポートパスを再帰走査し、ファイルからモジュール名を解決する
6. 標準ライブラリ（std.*）のモジュールはキャッシュに登録する
7. マッチしたファイルパスの一覧を返却する

**画面遷移**：
- 遷移元：エディタのimportナビゲーション、コードアクション
- 遷移先：検索結果のファイルを開く操作

**権限による表示制御**：特になし。全てのクライアントが利用可能。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 65 | モジュール名でファイル検索 (served/findFilesByModule) | 主機能 | モジュール名からプロジェクトと依存関係内の対応するファイルを検索する |

## 画面種別

カスタムLSPリクエスト（検索結果返却型）

## URL/ルーティング

LSPカスタムメソッド: `served/findFilesByModule`

## 入出力項目

### リクエストパラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| module_ | string | はい | 検索するD言語モジュール名（例: "std.stdio"） |

### レスポンス

| 項目名 | 型 | 説明 |
|--------|------|------|
| (戻り値) | string[] | マッチしたファイルの絶対パスの配列。該当なしの場合はnull |

## 表示項目

本リクエストはデータ返却のみであり、エディタ上の表示はクライアント側の実装に依存する。

## イベント仕様

### 1-モジュール検索リクエスト受信

1. クライアントから `served/findFilesByModule` リクエストを受信する
2. モジュール名が空文字列の場合、即座にnullを返却する
3. キャッシュ（`modFileCache`）にモジュール名が存在する場合、キャッシュされたパスを返却する
4. 8KBのバッファを確保し、ファイル読み込み用に使用する
5. インポートファイル走査：
   - 全インスタンスのインポートファイルを収集・ソート・重複排除する
   - キャッシュ済みファイルはスキップする
   - 各ファイルの内容を読み込み、ModulemanComponentでモジュール名を解決する
   - `std` で始まるモジュールはキャッシュに登録する
   - モジュール名が一致すれば結果に追加する
6. インポートパス走査：
   - 全インスタンスのインポートパスを収集・ソート・重複排除する
   - ディレクトリ配下を幅優先で再帰走査する
   - `moduleNameForFile` でファイルからモジュール名を解決する
   - `std` で始まるモジュールはキャッシュに登録する
   - モジュール名が一致すれば結果に追加する
7. 結果の配列を返却する

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

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

本リクエストはデータベースへの更新を行わない。ファイルシステムの読み取り専用操作のみを実施する。ただし、モジュール名とファイルパスのインメモリキャッシュ（`modFileCache`, `cachedModuleFiles`）を更新する。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| モジュール検索リクエスト | modFileCache（インメモリ） | 読み取り/書き込み | 標準ライブラリモジュールのキャッシュを更新 |
| モジュール検索リクエスト | cachedModuleFiles（インメモリ） | 読み取り/書き込み | キャッシュ済みファイルリストを更新 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|--------------|
| なし | - | - | 本リクエストはエラーメッセージを直接クライアントに表示しない |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| モジュール名が空文字列 | nullを返却する |
| ファイル読み込みエラー | 該当ファイルをスキップして処理を継続する |

## 備考

- `std` で始まるモジュール名のファイルはキャッシュに登録される。これにより、同じ標準ライブラリモジュールへの繰り返し検索が高速化される
- `moduleNameForFile` 関数はモジュール名をファイルから解決する補助関数であり、ファイルの内容からモジュール宣言を読み取り、見つからない場合はパスからモジュール名を推定する
- バッファサイズは8KBで固定されている

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | file_search.d | `source/served/commands/file_search.d` | 行74-75のキャッシュ変数（cachedModuleFiles, modFileCache）の定義 |

**読解のコツ**: `modFileCache` は `string[string]` 型で、モジュール名からファイルパスへの辞書。`cachedModuleFiles` は既にキャッシュ処理済みのファイルパス一覧。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | file_search.d | `source/served/commands/file_search.d` | `findFilesByModule` 関数（行76-140）がエントリーポイント |

**主要処理フロー**:
1. **行76-77**: `@protocolMethod("served/findFilesByModule")` で定義。引数は `module_`（string型）
2. **行79-80**: 空モジュール名の場合はnullを返却
3. **行82-83**: キャッシュヒット判定。`modFileCache` に存在すればキャッシュ値を返却
4. **行85-87**: 8KBバッファの確保とスコープ終了時の破棄
5. **行91**: 標準ライブラリパスの取得
6. **行93-97**: 全インスタンスからインポートファイル・パスを収集
7. **行102-118**: インポートファイル走査とモジュール名解決
8. **行119-137**: インポートパス配下の再帰走査とモジュール名解決

#### Step 3: モジュール名解決ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | file_search.d | `source/served/commands/file_search.d` | `moduleNameForFile` 関数（行142-154）の補助ロジック |

**主要処理フロー**:
- **行144-145**: ModulemanComponentでファイル内容からモジュール名を取得
- **行148-151**: モジュール名が見つからない場合、ファイルパスからモジュール名を推定（ディレクトリパスを `.` 区切りに変換）
- **行153**: 上記いずれも該当しない場合、ファイルのベース名（拡張子除去）を返却

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

```
served/findFilesByModule リクエスト
    |
    +-- findFilesByModule(string module_)       [file_search.d:77]
           |
           +-- modFileCache（キャッシュ参照）       [file_search.d:82]
           |
           +-- selectedWorkspace.stdlibPath()    [extension.d 経由]
           |
           +-- backend.instances                 [全インスタンスのパス取得]
           |
           +-- ModulemanComponent.moduleName()   [モジュール名解決]
           |
           +-- readCodeWithBuffer()              [ファイル内容読み込み]
           |
           +-- moduleNameForFile()               [file_search.d:142]
                  |
                  +-- ModulemanComponent.moduleName()
                  +-- buildNormalizedPath()
                  +-- stripExtension / translate
```

### データフロー図

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

module_(string) ----------> findFilesByModule()              --> string[] (ファイルパス一覧)
                               |
                               +-- キャッシュ検索
                               +-- importFiles走査
                               |     +-- ModulemanComponent.moduleName()
                               +-- importPaths再帰走査
                               |     +-- moduleNameForFile()
                               +-- std.*キャッシュ登録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| file_search.d | `source/served/commands/file_search.d` | ソース | ファイル検索・モジュール検索の実装 |
| extension.d | `source/served/extension.d` | ソース | selectedWorkspaceの定義やbackendインスタンス管理 |
| types.d | `source/served/types.d` | ソース | 共通型定義 |
| filereader.d | `source/served/lsp/filereader.d` | ソース | readCodeWithBuffer関数の提供 |
