# 画面設計書 37-インポートソート（served/sortImports）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供する `served/sortImports` カスタムリクエストハンドラの画面設計書である。D言語ソースファイル内の指定位置のimportブロックをソートするテキスト編集を返却する機能を定義する。

### 本画面の処理概要

本機能は、D言語ソースコードのimport文ブロックをアルファベット順にソートし、整理されたコードに変換するためのテキスト編集情報を返却する。

**業務上の目的・背景**：D言語ソースファイルにおいて、import文はファイルの冒頭やスコープの先頭に配置されることが多い。import文が増えると無秩序に並びがちで、可読性やメンテナンス性が低下する。本機能はimport文ブロックをアルファベット順に自動ソートすることで、コードの整理と統一的なスタイルを維持する。LSPの `source.organizeImports` コードアクションとしても呼び出すことが可能であり、保存時の自動実行にも対応する。

**画面へのアクセス方法**：(1) コードアクション経由（"Organize All Imports"）、(2) DScanner診断の "imports_sortedness" に対する修正アクション、(3) `served/sortImports` カスタムリクエストの直接呼び出し、(4) コードアクション解決時（`codeAction/resolve`）の遅延実行。

**主要な操作・処理内容**：
1. クライアントから `served/sortImports` リクエストを受信する
2. 対象ドキュメントを取得する
3. locationパラメータが-1の場合は全importブロックを対象とする
4. ImporterComponentの `findImportCodeSlices` でimportブロックを検出する
5. 各ブロックについて `sortImportBlock` でソート実行
6. ソート結果をTextEdit（置換範囲とソート後テキスト）に変換
7. インデント情報を保持してフォーマットする
8. テキスト編集配列を返却する

**画面遷移**：コードアクション画面（No.19）から遷移してくる場合がある。本機能から他への直接遷移はない。

**権限による表示制御**：特別な権限制御はない。ImporterComponentの利用可能性のみが条件。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | ドキュメントフォーマット (textDocument/formatting) | 主機能 | 指定位置のimportブロックをソートするテキスト編集を返す処理（format.dで実装） |

## 画面種別

LSPカスタムリクエスト・レスポンス

## URL/ルーティング

LSPメソッド: `served/sortImports`

## 入出力項目

### 入力（リクエストパラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|------|------|------|
| textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI |
| location | int | Yes | 対象位置のオフセット（-1で全ブロック対象） |

### 出力（レスポンス）

| 項目名 | 型 | 説明 |
|--------|------|------|
| (配列要素).range | TextRange | 置換対象範囲 |
| (配列要素).newText | string | ソート後のimport文テキスト |

## 表示項目

| 表示項目 | 説明 |
|----------|------|
| ソート後のimport文 | ソート実行後にエディタ上のimport文が並び替えられる |

## イベント仕様

### 1-sortImportsリクエスト

1. `sortImports(SortImportsParams params)` 関数が呼び出される
2. ドキュメントストアから対象ドキュメントを取得
3. `location` パラメータを処理（-1の場合は全体、それ以外はバイトオフセットに変換）
4. `ImporterComponent.findImportCodeSlices` でimportブロックの範囲を検出
5. 各ブロックについて：
   - `location != -1` の場合、ブロックが指定位置を含むか確認（含まなければスキップ）
   - `sortImportBlock` でソート実行
   - ソート結果が空の場合（ImportBlock.init）はスキップ
   - バイトオフセットからPosition変換
   - インデント情報を各行に付加
   - EOL文字列で結合
   - TextEdit（置換範囲 + ソート後テキスト）を生成
6. 結果配列を返却（逆順ループにより位置の整合性を保持）

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

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

本機能はデータベースへの更新を行わない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| sortImportsリクエスト | なし | SELECT | ドキュメントの読み取りと解析のみ |

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|---------------|------|---------------|
| 空応答 | ソート不要または対象ブロックなし | 空のTextEdit配列を返却 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| ImporterComponentが利用不可 | 空配列を返却 |
| 指定位置にimportブロックなし | 空配列を返却 |
| ソート結果が変更なし | 該当ブロックをスキップ |

## 備考

- `foreach_reverse` でブロックを逆順に処理することで、先頭のブロックから変更した場合に後続の位置がずれる問題を回避
- location=-1 は全importブロックをソート対象とする特別な値
- ソート結果にはインデント情報（`sorted.indentation`）が含まれ、2行目以降に自動付加される
- コードアクション解決（`codeAction/resolve`）からも呼び出され、この場合はWorkspaceEditとして返却される
- `sortImportBlock` の第3引数（true）は列0のインポートのみソートすることを示す

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.d | `source/served/types.d` | SortImportsParams型の定義（textDocument, location） |
| 1-2 | importer.d (workspaced) | workspacedサブパッケージ | ImportBlock型の定義（start, end, imports, indentation） |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | code_actions.d | `source/served/commands/code_actions.d` | `sortImports` 関数（行538-566） |

**主要処理フロー**:
1. **行538**: `@protocolMethod("served/sortImports")` でLSPメソッドとして登録
2. **行541**: ドキュメント取得
3. **行543**: location処理（-1チェック、バイトオフセット変換）
4. **行544**: ImporterComponent取得
5. **行546**: `findImportCodeSlices` でimportブロック検出
6. **行548**: ブロック位置チェック
7. **行551**: `sortImportBlock` 呼び出し
8. **行554-555**: バイト→Position変換
9. **行558-561**: インデント付加とテキスト結合
10. **行562**: TextEdit生成

#### Step 3: コードアクション連携を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | code_actions.d | `source/served/commands/code_actions.d` | `resolveCodeAction` 関数（行154-189）の "sortImports" ケース（行163-171） |
| 3-2 | code_actions.d | `source/served/commands/code_actions.d` | `provideCodeActions` 内の "Organize All Imports" アクション生成（行110-136） |

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

```
sortImports (code_actions.d:539)
    |
    +-- documents[uri] ドキュメント取得
    +-- document.offsetToBytes (location変換)
    +-- backend.get!ImporterComponent
    +-- importer.findImportCodeSlices (workspaced)
    |   +-- importブロック検出
    +-- [各ブロック] importer.sortImportBlock (workspaced)
    |   +-- importソート実行
    +-- document.bytesToPosition (位置変換)
    +-- document.movePositionBytes (位置変換)
    +-- TextEdit生成
```

### データフロー図

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

SortImportsParams      --->  sortImports               --->  TextEdit[]
  .textDocument.uri           |                                .range
  .location                   +-- ドキュメント取得              .newText
                              +-- importブロック検出
                              +-- ソート実行
                              +-- インデント付加
                              +-- Position変換
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| code_actions.d | `source/served/commands/code_actions.d` | ソース | sortImports関数およびコードアクション連携 |
| types.d | `source/served/types.d` | ソース | SortImportsParams等のLSP型定義 |
| extension.d | `source/served/extension.d` | ソース | backend, documents等のグローバル変数 |
