# 画面設計書 33-自動require

## 概要

本ドキュメントは、Lua Language ServerのLSPコマンド「自動require（lua.autoRequire）」の画面設計書です。

### 本画面の処理概要

この画面（LSPコマンド）は、Luaファイルに自動的にrequireステートメントを挿入する機能を提供します。

**業務上の目的・背景**：
Lua開発において、モジュールを使用する際にrequireステートメントを手動で記述する作業は頻繁に発生します。特に大規模なプロジェクトでは、正しいモジュールパスを覚えておくことが困難です。本コマンドは、補完機能と連携して、選択したシンボルに対応するモジュールのrequireステートメントを自動的にファイルの適切な位置に挿入します。これにより、開発者の手間を削減し、タイプミスによるエラーを防止します。

**画面へのアクセス方法**：
本コマンドは、以下の方法でトリガーされます：
- コード補完で外部モジュールのシンボルを選択した際に自動実行
- LSPクライアントからの `workspace/executeCommand` リクエストで `lua.autoRequire` コマンドを実行
- コードアクションからの呼び出し

**主要な操作・処理内容**：
1. 対象ファイルのパスから可視的なrequireパスを取得
2. 複数のパス候補がある場合、ユーザーに選択を求める
3. ファイル内の適切な挿入位置を特定（既存のrequire文の後）
4. フォーマット（引用符、括弧、列位置）を既存のスタイルに合わせる
5. requireステートメントをファイルに挿入

**画面遷移**：
- 入力元：コード補完機能、コードアクション
- 出力先：ファイル編集後、元の処理に復帰

**権限による表示制御**：
特別な権限制御はありません。ただし、設定 `Lua.completion.autoRequire` がfalseの場合、ユーザーに無効化オプションが提示されます。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | 自動require (auto-require) | 主機能 | requireステートメントを自動追加するコマンド処理 |

## 画面種別

LSPコマンド（非同期処理）

## URL/ルーティング

- LSPコマンド名: `lua.autoRequire`
- プロトコル: `workspace/executeCommand`
- ハンドラファイル: `script/core/command/autoRequire.lua`

## 入出力項目

### 入力パラメータ

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| uri | uri | Yes | requireを挿入するファイルのURI |
| target | string | Yes | require対象モジュールのファイルパス |
| name | string | Yes | ローカル変数名（例: `myModule`） |
| requireName | string | No | 指定されたrequireパス（省略時はユーザー選択） |
| fullKeyPath | string | No | 完全キーパス（サブモジュール用） |

### 出力

| 項目名 | 型 | 説明 |
|--------|-----|------|
| (なし) | void | 本コマンドは戻り値を返さない（ファイル編集で結果を反映） |

## 表示項目

ユーザー選択時に表示されるメッセージ：

| 項目名 | 表示内容 |
|--------|---------|
| 選択メッセージ | "COMPLETION_ASK_AUTO_REQUIRE" |
| 選択肢 | 可視的なrequireパスの一覧 |
| 無効化オプション | "COMPLETION_DISABLE_AUTO_REQUIRE" |

## イベント仕様

### 1-自動require実行

1. **リクエスト受信**: コマンドパラメータを受信
2. **ファイル状態確認**: files.getState()でファイルが読み込まれているか確認
3. **可視パス取得**: rpath.getVisiblePath()で利用可能なrequireパスを取得
4. **パスソート**: パス長でソート（短いパスを優先）
5. **ユーザー選択**: requireNameが未指定の場合、ユーザーに選択を求める
6. **挿入位置特定**: findInsertRow()で適切な行を特定
7. **フォーマット適用**: 既存のrequireスタイルに合わせる
8. **ファイル編集**: client.editText()でrequire文を挿入

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

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

本機能はデータベースを使用しませんが、以下のファイルへの影響があります：

| 操作（イベント） | 対象 | 操作種別 | 概要 |
|----------------|------|---------|------|
| require挿入 | 対象Luaファイル | UPDATE | requireステートメントを挿入 |

## メッセージ仕様

| メッセージID | 種別 | 表示条件 | メッセージ内容 |
|-------------|------|---------|--------------|
| COMPLETION_ASK_AUTO_REQUIRE | Info | requireパス選択時 | requireパスの選択を求める |
| COMPLETION_DISABLE_AUTO_REQUIRE | Info | 選択肢として表示 | 自動requireを無効にする |

## 例外処理

| 例外条件 | 処理内容 |
|---------|---------|
| ファイル状態取得失敗 | 処理を中断（return） |
| 可視パスなし | 処理を中断（return） |
| ユーザーがキャンセル | 処理を中断（return） |
| ユーザーが無効化を選択 | Lua.completion.autoRequireをfalseに設定 |

## 備考

- 既存のrequireスタイル（引用符、括弧）を自動検出して適用します
- 列位置（=の位置）も既存のrequireに合わせて調整されます
- コメント行内にはrequireを挿入しません
- ファイル先頭のコメント（ライセンス等）をスキップして挿入位置を決定します

---

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

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

### 推奨読解順序

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

まず、require-pathで使用されるデータ構造を理解します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | require-path.lua | `script/workspace/require-path.lua` | visibleResult型の定義を理解 |

**読解のコツ**: `require-manager.visibleResult`は`{ searcher: string, name: string }`の形式です。searcherはLua.runtime.pathのパターン、nameは実際のrequire文字列です。

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

コマンドの起点となるファイルを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | autoRequire.lua | `script/core/command/autoRequire.lua` | メイン処理（133-164行目） |

**主要処理フロー**:
1. **135-142行目**: パラメータ抽出とファイル状態確認
2. **144-151行目**: 可視パス取得とソート
3. **153-158行目**: requireName決定（ユーザー選択）
4. **160-163行目**: 挿入位置特定とrequire挿入

#### Step 3: 可視パス取得処理を理解する

rpath.getVisiblePath()の内部実装を追跡します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | require-path.lua | `script/workspace/require-path.lua` | getVisiblePath関数（250-256行目） |
| 3-2 | require-path.lua | `script/workspace/require-path.lua` | getRequireResultByPath関数（62-125行目） |

**主要処理フロー**:
- **250-256行目**: スコープのrequireManagerを取得し、キャッシュを活用
- **62-125行目**: Lua.runtime.pathの各パターンとファイルパスをマッチング

#### Step 4: 挿入位置決定処理を理解する

findInsertRow()の実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | autoRequire.lua | `script/core/command/autoRequire.lua` | findInsertRow関数（20-66行目） |
| 4-2 | autoRequire.lua | `script/core/command/autoRequire.lua` | inComment関数（8-18行目） |

**主要処理フロー**:
- **33-63行目**: 各行をスキャンしてrequire文を探し、最後のrequire文の次の行を特定
- **27-31行目**: フォーマット情報（引用符、括弧、列位置）を抽出

#### Step 5: ファイル編集処理を理解する

applyAutoRequire()の実装を確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | autoRequire.lua | `script/core/command/autoRequire.lua` | applyAutoRequire関数（104-130行目） |

**主要処理フロー**:
- **105-116行目**: フォーマットに応じてrequire文を構築
- **123-129行目**: client.editText()でファイルに挿入

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

```
workspace/executeCommand (lua.autoRequire)
    │
    └─ autoRequire.lua (エントリーポイント)
           │
           ├─ files.getState()
           │
           ├─ furi.decode()
           │
           ├─ rpath.getVisiblePath()
           │      │
           │      └─ require-manager:getVisiblePath()
           │             └─ getRequireResultByPath()
           │
           ├─ askAutoRequire() [ユーザー選択が必要な場合]
           │      │
           │      ├─ client.awaitRequestMessage()
           │      │
           │      └─ client.setConfig() [無効化選択時]
           │
           ├─ findInsertRow()
           │      └─ inComment()
           │
           └─ applyAutoRequire()
                  └─ client.editText()
```

### データフロー図

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

{ uri, target,     ───▶ autoRequire.lua ───▶ ファイル編集
  name, requireName }          │
                               ▼
                    rpath.getVisiblePath()
                               │
                               ▼
                    visiblePaths[]
                               │
                    ┌──────────┴──────────┐
                    ▼                     ▼
            requireName指定あり    askAutoRequire()
                    │                     │
                    └──────────┬──────────┘
                               ▼
                    findInsertRow()
                               │
                               ▼
                    applyAutoRequire()
                               │
                               ▼
                    client.editText()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| autoRequire.lua | `script/core/command/autoRequire.lua` | ソース | コマンドエントリーポイント |
| require-path.lua | `script/workspace/require-path.lua` | ソース | requireパス解決 |
| client.lua | `script/client.lua` | ソース | ユーザーインタラクション、ファイル編集 |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| file-uri.lua | `script/file-uri.lua` | ソース | URIエンコード/デコード |
| guide.lua | `script/parser/guide.lua` | ソース | 位置計算ユーティリティ |
| language.lua | `script/language.lua` | ソース | 多言語メッセージ |
