# 機能設計書 39-ドキュメントフォーマット (textDocument/formatting)

## 概要

本ドキュメントは、Lua Language Serverにおける「ドキュメントフォーマット機能」の設計詳細を記載したものである。ファイル全体のLuaコードを整形し、一貫したコーディングスタイルを適用する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
手動でコードスタイルを統一することは時間がかかり、人為的なミスが生じやすい。本機能は、ファイル全体のコードを自動的にフォーマットし、インデント、空白、改行などを統一することで、チーム全体でのコードスタイルの一貫性を維持し、コードレビューの効率化を実現する。

**機能の利用シーン**：
- ファイル保存時の自動フォーマット
- エディタのフォーマットコマンド実行時
- コミット前のコード整形

**主要な処理内容**：
1. 対象ファイルのテキストを取得する
2. code_formatモジュールでフォーマットを実行する
3. 元テキストとフォーマット後テキストを比較する
4. 変更がある場合、テキスト編集として返却する

**関連システム・外部連携**：
- LSP (Language Server Protocol)クライアント（VSCode等のエディタ）との連携
- `textDocument/formatting`リクエストのハンドラ
- code_formatモジュール（C++拡張）

**権限による制御**：
- 設定`Lua.format.enable`でフォーマット機能の有効/無効を制御可能
- 設定`Lua.format.defaultConfig`でデフォルトスタイルを指定可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | フォーマット | 主機能 | ドキュメント全体のコード整形を実行する主処理 |

## 機能種別

コードフォーマット / テキスト変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | フォーマット対象ファイルのURI | 有効なファイルURIであること |
| options | table | No | フォーマットオプション（タブサイズ等） | - |

### 入力データソース

- ファイルシステムから読み込まれたLuaソースコード
- `files.getOriginText(uri)`から元テキスト
- EditorConfigファイル（.editorconfig）からスタイル設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | 変更範囲の開始オフセット（通常はファイル先頭） |
| finish | integer | 変更範囲の終了オフセット（通常はファイル末尾） |
| text | string | フォーマット後のテキスト |

### 出力先

- LSPクライアントへのテキスト編集レスポンス
- エディタがファイル内容を更新

## 処理フロー

### 処理シーケンス

```
1. code_formatモジュールの確認
   └─ pcall(require, 'code_format')でモジュール存在確認
2. テキストの取得
   └─ files.getOriginText(uri)で元テキスト取得
3. ファイル状態の取得
   └─ files.getState(uri)でAST情報取得
4. フォーマット実行
   └─ codeFormat.format(uri, text, options)
5. 結果の検証
   └─ text == formattedTextなら変更なし
6. テキスト編集の返却
   └─ { start, finish, text }を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{code_formatロード可能?}
    B -->|No| C[nil返却]
    B -->|Yes| D[テキスト取得]
    D --> E[ファイル状態取得]
    E --> F{状態が存在するか?}
    F -->|No| C
    F -->|Yes| G[codeFormat.format実行]
    G --> H{status == true?}
    H -->|No| I[エラーログ出力]
    I --> C
    H -->|Yes| J{text == formattedText?}
    J -->|Yes| C
    J -->|No| K[テキスト編集を返却]
    K --> L[終了]
    C --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | モジュール必須 | code_formatモジュールが必須 | pcallでロード確認 |
| BR-39-02 | 変更なし判定 | フォーマット前後でテキストが同一なら変更なし | text == formattedText |
| BR-39-03 | 全体置換 | ファイル全体を置換（state.ast.start～state.ast.finish） | フォーマット適用時 |
| BR-39-04 | オプション適用 | optionsパラメータでタブサイズ等を指定可能 | クライアント指定時 |

### 計算ロジック

#### フォーマット処理

```lua
return function(uri, options)
    local suc, codeFormat = pcall(require, "code_format")
    if not suc then
        return
    end
    local text = files.getOriginText(uri)
    local state = files.getState(uri)
    if not state then
        return
    end
    local status, formattedText = codeFormat.format(uri, text, options)

    if not status then
        if formattedText ~= nil then
            log.error(formattedText)
        end
        return
    end

    if text == formattedText then
        return
    end

    return {
        {
            start = state.ast.start,
            finish = state.ast.finish,
            text = formattedText,
        }
    }
end
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | モジュールなし | code_formatがロードできない場合 | nilを返却して正常終了 |
| - | ファイル状態なし | files.getState(uri)がnilを返す場合 | nilを返却して正常終了 |
| - | フォーマット失敗 | status == falseの場合 | エラーをログ出力してnil返却 |

### リトライ仕様

リトライは行わない。ユーザーが再度フォーマットコマンドを実行する。

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

該当なし（読み取り専用処理、変更はクライアント側で適用）

## パフォーマンス要件

- フォーマット処理は通常1秒以内に完了すること
- 大規模ファイル（数万行）でも適切に処理できること

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

- ユーザーコードの読み取りのみを行う
- フォーマット結果はクライアントに返却され、ユーザーの確認後に適用される

## 備考

- code_formatモジュール（C++拡張）が必要
- フォーマット設定はEditorConfigまたはLua.format.defaultConfigで指定

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | formatting.lua | `script/core/formatting.lua` | フォーマット処理のメインロジック |

**読解のコツ**: シンプルな構造で、code_formatモジュールへの委譲が中心。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | formatting.lua | `script/core/formatting.lua` | メイン関数 |

**主要処理フロー**:
1. **4-7行目**: pcall(require, "code_format")でモジュールロード
2. **8行目**: files.getOriginText(uri)でテキスト取得
3. **9-12行目**: files.getState(uri)でファイル状態取得
4. **13行目**: codeFormat.format(uri, text, options)実行
5. **15-20行目**: エラーハンドリング
6. **22-24行目**: 変更なし判定
7. **26-33行目**: テキスト編集の返却

#### Step 3: LSPプロバイダーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | provider.lua | `script/provider/provider.lua` | textDocument/formattingのハンドラ登録 |

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

```
LSPクライアント
    │
    ├─ textDocument/formatting リクエスト
    │
    ▼
script/provider/provider.lua (ハンドラ登録)
    │
    ├─ require('core.formatting')
    │      │
    │      ├─ pcall(require, 'code_format')
    │      │
    │      ├─ files.getOriginText(uri)
    │      │
    │      ├─ files.getState(uri)
    │      │
    │      └─ codeFormat.format(uri, text, options)
    │             └─ C++拡張によるフォーマット処理
    │
    └─ TextEdit[]をレスポンス
           │
           ▼
    LSPクライアントがファイルを更新
```

### データフロー図

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

textDocument/formatting ───▶ プロバイダー ───▶ formatting.lua
        │                                          │
        ▼                                          ▼
  options (タブサイズ等)              files.getOriginText(uri)
                                                   │
                                                   ▼
                               codeFormat.format(uri, text, options)
                                                   │
                                                   ▼
                               ┌───────────────────┴───────────────────┐
                               │                                        │
                               ▼                                        ▼
                         変更あり                                  変更なし
                               │                                        │
                               ▼                                        ▼
                         TextEdit[]                                   nil
                               │
                               ▼
                    LSPクライアントへレスポンス
                               │
                               ▼
                         ファイル更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| formatting.lua | `script/core/formatting.lua` | ソース | ドキュメントフォーマットのメインロジック |
| provider.lua | `script/provider/provider.lua` | ソース | LSPハンドラ登録 |
| formatting.lua | `script/provider/formatting.lua` | ソース | フォーマット設定管理 |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| log.lua | `script/log.lua` | ソース | ログ出力 |
