# 機能設計書 51-ファイルリネーム (workspace/didRenameFiles)

## 概要

本ドキュメントは、Lua Language Serverにおけるファイルリネーム機能の設計を記載する。この機能は、ワークスペース内でファイル名が変更された際に、関連するrequireパスを自動的に更新する機能を提供する。

### 本機能の処理概要

ファイルリネーム機能は、エディタ（VSCode等）でLuaファイルの名前を変更した際に、そのファイルをrequireしている他のファイル内のrequireパスを自動的に更新する機能である。

**業務上の目的・背景**：Luaプロジェクトでは、モジュール構造の変更やリファクタリングでファイル名を変更することが頻繁に発生する。ファイル名変更時に、そのファイルをrequireしている箇所を手動で修正するのは煩雑でエラーを招きやすい。この機能により、ファイル名変更に伴うrequireパスの整合性を自動的に維持でき、開発者の作業負担を軽減する。

**機能の利用シーン**：
- モジュール名のリファクタリング時
- ファイル構造の再編成時
- ディレクトリ階層の変更時

**主要な処理内容**：
1. エディタからファイル名変更通知を受信
2. 変更されたファイルがLuaファイルかどうかを検証
3. ワークスペース内の全Luaファイルをスキャンし、変更前のファイルをrequireしている箇所を特定
4. requireパスを変更後のファイル名に対応するパスに変換
5. ユーザーに変更確認ダイアログを表示
6. ユーザーが承認した場合、該当箇所のテキストを一括編集

**関連システム・外部連携**：LSPプロトコルのworkspace/didRenameFilesリクエストを受信し、クライアントのテキスト編集機能を呼び出す。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | エディタファイルエクスプローラー | 主画面 | ファイル名変更操作のトリガー |
| - | 確認ダイアログ | 参照画面 | requireパス変更の確認 |

## 機能種別

データ連携 / テキスト編集

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params.files | array | Yes | リネームされたファイルのリスト | - |
| params.files[].oldUri | string | Yes | 変更前のファイルURI | 有効なfile:// URI形式 |
| params.files[].newUri | string | Yes | 変更後のファイルURI | 有効なfile:// URI形式 |

### 入力データソース

LSPクライアント（エディタ）からのworkspace/didRenameFiles通知

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| changes | array | テキスト編集内容のリスト |
| changes[].uri | string | 編集対象ファイルのURI |
| changes[].start | integer | 編集開始位置 |
| changes[].finish | integer | 編集終了位置 |
| changes[].text | string | 置換後のテキスト |

### 出力先

LSPクライアントのテキスト編集API（workspace/applyEdit）

## 処理フロー

### 処理シーケンス

```
1. LSP通知受信
   └─ workspace/didRenameFilesメッセージを受信

2. ファイル検証
   └─ 変更前後のURIがLuaファイルかどうかを検証
   └─ ディレクトリの場合は子ファイルを列挙

3. requireパス検索
   └─ ワークスペース内の全ファイルをスキャン
   └─ 各ファイルのAST内のrequire呼び出しを検出
   └─ 引数のパスが変更前のファイルにマッチするか判定

4. 新パス計算
   └─ 変更後のファイルパスから新しいrequireパスを計算
   └─ 最適なvisible pathを選択

5. ユーザー確認
   └─ 変更確認ダイアログを表示
   └─ ユーザーの応答を待機

6. テキスト編集
   └─ ユーザーが承認した場合、一括テキスト編集を実行
```

### フローチャート

```mermaid
flowchart TD
    A[workspace/didRenameFiles受信] --> B{Luaファイル?}
    B -->|No| C[処理終了]
    B -->|Yes| D[renames配列に追加]
    D --> E{ディレクトリ?}
    E -->|Yes| F[子ファイルを列挙]
    F --> D
    E -->|No| G[modifyRequirePath実行]
    G --> H[全ファイルをスキャン]
    H --> I{require呼び出し検出?}
    I -->|Yes| J[パスマッチング]
    J --> K{マッチ?}
    K -->|Yes| L[新パス計算]
    L --> M[変更リストに追加]
    K -->|No| I
    I -->|No| N{変更あり?}
    M --> N
    N -->|No| C
    N -->|Yes| O[確認ダイアログ表示]
    O --> P{ユーザー承認?}
    P -->|Yes| Q[テキスト編集実行]
    P -->|No| C
    Q --> C
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-51-01 | Luaファイル限定 | Luaファイル以外はスキップ | 常時 |
| BR-51-02 | ユーザー確認必須 | 変更前に必ずユーザー確認を行う | 変更がある場合 |
| BR-51-03 | ディレクトリ対応 | ディレクトリ変更時は子ファイルも処理 | ディレクトリ変更時 |

### 計算ロジック

requireパスの変換は、Lua.runtime.path設定に基づいて以下のように計算される：

1. 変更後のファイルパスからworkspace.require-pathモジュールのgetVisiblePath関数を呼び出し
2. 設定されたsearcerパターンに基づいて最適なrequire名を決定
3. 文字列リテラルの引用符スタイル（シングル/ダブル）を保持

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル未存在 | 変更後のファイルが存在しない | 処理をスキップ |
| - | パス解決不可 | 新しいrequireパスが計算できない | 該当箇所をスキップ |

### リトライ仕様

リトライは行わない。

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

LSPのテキスト編集はatomicに実行される。

## パフォーマンス要件

ワークスペース内の全ファイルをスキャンするため、大規模プロジェクトでは処理に時間がかかる可能性がある。非同期処理（await.delay）により、UIのブロッキングを防止する。

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

ファイルシステムへの書き込みは、LSPクライアント経由で行われるため、クライアントのセキュリティポリシーに従う。

## 備考

- この機能はLSPのFileOperations機能を使用する
- クライアントがdidRenameFilesをサポートしている必要がある

---

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

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

### 推奨読解順序

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

まず、プログラム間で受け渡されるデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | modifyRequirePath.lua | `script/core/modifyRequirePath.lua` | rename型エイリアスの定義（10行目） |

**読解のコツ**: Luaでは`---@alias`アノテーションで型エイリアスを定義する。`rename`型は`{ oldUri: uri, newUri: uri }`の形式。

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

処理の起点となるファイル・関数を特定。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | provider.lua | `script/provider/provider.lua` | workspace/didRenameFilesハンドラ（190-244行目） |

**主要処理フロー**:
1. **190-213行目**: capability定義、ワークスペースフォルダに基づくファイルフィルター設定
2. **215-216行目**: パラメータのログ出力
3. **217-240行目**: リネームファイルリストの構築、ディレクトリの場合は子ファイルを列挙
4. **241-242行目**: core.modifyRequirePathモジュールの呼び出し

#### Step 3: コア処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | modifyRequirePath.lua | `script/core/modifyRequirePath.lua` | require文の検出と変換処理 |

**主要処理フロー**:
- **15-50行目**: checkConvert関数 - 各ファイル内のrequire呼び出しを検出しパスマッチングを行う
- **21行目**: guide.eachSpecialOfでAST内の特殊関数（require）を列挙
- **34-48行目**: リネーム対象とのマッチング、新パスの計算
- **54-74行目**: メイン関数 - 全ファイルをスキャン、ユーザー確認、編集実行

#### Step 4: パス解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | require-path.lua | `script/workspace/require-path.lua` | requireパス解決ロジック |

**主要処理フロー**:
- **38-58行目**: getRequireNameByPath - パスからrequire名を計算
- **135-148行目**: getVisiblePath - URIから可視パスリストを取得
- **274-298行目**: isMatchedUri - URIがrequire名にマッチするか判定

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

```
provider.lua::m.register 'workspace/didRenameFiles'
    │
    ├─ workspace.isValidLuaUri(oldUri)
    ├─ workspace.isValidLuaUri(newUri)
    ├─ files.getChildFiles(oldUri)
    │
    └─ core/modifyRequirePath.lua (main function)
           │
           ├─ files.eachFile()
           │      └─ checkConvert(changes, uri, renames)
           │             │
           │             ├─ files.getState(uri)
           │             ├─ guide.eachSpecialOf(state.ast, 'require', ...)
           │             │
           │             └─ rpath.isMatchedUri(uri, rename.oldUri, name)
           │             └─ rpath.getVisiblePath(uri, furi.decode(rename.newUri))
           │
           ├─ client.awaitRequestMessage(...) [ユーザー確認]
           │
           └─ client.editMultiText(changes) [テキスト編集]
```

### データフロー図

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

params.files     ───▶  provider.lua                 ───▶  確認ダイアログ
(oldUri, newUri)       ファイル検証・リスト構築

                       modifyRequirePath.lua
                       ├─ AST解析
                       ├─ requireパターン検出
                       └─ 新パス計算

                                                    ───▶  workspace/applyEdit
                                                          (テキスト変更)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSPリクエストハンドラ |
| modifyRequirePath.lua | `script/core/modifyRequirePath.lua` | ソース | requireパス変換コアロジック |
| require-path.lua | `script/workspace/require-path.lua` | ソース | requireパス解決ユーティリティ |
| files.lua | `script/files.lua` | ソース | ファイル管理 |
| guide.lua | `script/parser/guide.lua` | ソース | ASTユーティリティ |
| client.lua | `script/client/client.lua` | ソース | LSPクライアント通信 |
| file-uri.lua | `script/file-uri.lua` | ソース | URIとパスの変換 |
