# 機能設計書 12-自動補完 (textDocument/completion)

## 概要

本ドキュメントは、serve-d LSPサーバーにおける「自動補完」機能の設計を記述する。LSPの `textDocument/completion` リクエストを処理し、カーソル位置に応じたコード補完候補を提供する機能である。

### 本機能の処理概要

エディタ上でのコード入力中に、カーソル位置のコンテキストを解析し、適切な補完候補リストを生成して返却する。D言語ソースコード、dietテンプレート、DML（D言語UI記述言語）、dscanner.ini設定ファイルの4種類のファイルタイプに対応する。

**業務上の目的・背景**：コード補完はIDEの中核機能であり、開発者の生産性を大幅に向上させる。serve-dはD言語のLSPサーバーとして、DCDエンジンによる高精度なシンボル補完、スニペット補完、自動インポート補完を統合的に提供することで、D言語開発のエクスペリエンスを向上させる。

**機能の利用シーン**：開発者がD言語のソースコードを編集中に、変数名・関数名・型名等の入力時にトリガーされる。また、コメント内でのDDoc記法補完、dscanner.ini設定値の補完も提供する。

**主要な処理内容**：
1. ドキュメント言語IDに応じた補完ルーティング（D / diet / DML / dscanner.ini）
2. DCD（D Completion Daemon）による識別子補完
3. DScanner定義情報によるドキュメント補完（DDocコメント生成）
4. コンテキスト対応スニペット補完
5. インデックスベースの自動インポート補完
6. 補完結果の統合・重複排除・ソート

**関連システム・外部連携**：DCD（D Completion Daemon）、DScanner、SnippetsComponent、IndexComponent、ImporterComponent、DlanguiComponent

**権限による制御**：`d.enableAutoComplete` 設定によるDCD補完の有効/無効制御。`d.enableIndex` および `d.enableAutoImportCompletions` による自動インポート補完の制御。`--provide context-snippets` によるスニペット機能の有効化。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | コード補完（textDocument/completion） | 主機能 | カーソル位置に応じたDCD補完・スニペット補完・自動インポート補完を統合的に提供する |

## 機能種別

データ取得・統合処理 / コード解析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params | TextDocumentPositionParams | Yes | 補完要求の位置情報 | - |
| params.textDocument.uri | DocumentUri | Yes | 対象ドキュメントのURI | 有効なURI文字列 |
| params.position | Position | Yes | カーソル位置（行・列） | 0ベースの行・列番号 |

### 入力データソース

- LSPクライアントからの `textDocument/completion` リクエスト
- ドキュメントマネージャからの現在のドキュメント内容
- DCDサーバーからの補完候補
- DScanner定義リスト
- スニペットコンポーネントからのスニペット候補
- インデックスコンポーネントからのシンボル情報

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| isIncomplete | bool | 補完リストが不完全かどうか（常にfalse） |
| items | CompletionItem[] | 補完候補の配列 |
| items[].label | string | 補完候補の表示テキスト |
| items[].kind | CompletionItemKind | 補完種別（function, variable等） |
| items[].detail | string | 補完候補の詳細（定義情報等） |
| items[].documentation | MarkupContent | ドキュメント情報 |
| items[].insertText | string | 挿入テキスト |
| items[].insertTextFormat | InsertTextFormat | 挿入テキスト形式（plainText/snippet） |
| items[].sortText | string | ソート用テキスト |
| items[].data | JsonValue | 遅延解決用データ |

### 出力先

LSPクライアントへのレスポンスメッセージ

## 処理フロー

### 処理シーケンス

```
1. TextDocumentPositionParams を受信
   └─ documents から対象ドキュメントを取得
2. バックエンドインスタンスの取得
   └─ getBestInstance でワークスペース対応インスタンスを取得
3. ファイルタイプに応じた分岐
   3-a. dscanner.ini の場合:
        └─ DScanner設定フィールド一覧を返却
   3-b. D言語ソースの場合:
        └─ provideDSourceComplete を呼び出し
   3-c. dietテンプレートの場合:
        └─ provideDietSourceComplete を呼び出し
   3-d. DMLの場合:
        └─ provideDMLSourceComplete を呼び出し
4. D言語ソース補完の詳細 (provideDSourceComplete):
   4-1. コメント内判定
        ├─ コメント内: DDocキーワード補完 + ドキュメント補完
        └─ コード内: 以下を並列実行
   4-2. DCD識別子補完（completeDCD）
   4-3. DScanner定義ドキュメント補完（completeDoc）
   4-4. スニペット補完（completeSnippets）
   4-5. 自動インポート補完（completeIndex）
   4-6. 結果統合・重複排除
```

### フローチャート

```mermaid
flowchart TD
    A[textDocument/completion 受信] --> B[ドキュメント取得]
    B --> C{ファイルタイプ判定}
    C -->|dscanner.ini| D[DScanner設定補完]
    C -->|D言語| E[provideDSourceComplete]
    C -->|diet| F[provideDietSourceComplete]
    C -->|DML| G[provideDMLSourceComplete]
    C -->|その他| H[空リスト返却]
    E --> I{コメント内?}
    I -->|Yes| J[DDoc補完]
    I -->|No| K[並列補完実行]
    K --> K1[DCD補完]
    K --> K2[ドキュメント補完]
    K --> K3[スニペット補完]
    K --> K4[自動インポート補完]
    K1 & K2 & K3 & K4 --> L[結果統合・重複排除]
    D & J & L & F & G & H --> M[CompletionList 返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-12-01 | ファイルタイプルーティング | ファイル拡張子・言語IDに基づいて補完プロバイダを選択する | 全リクエスト |
| BR-12-02 | コメント内DDoc補完 | コメント内ではDDocキーワード補完と関数ドキュメント補完を提供する | D言語ソースでコメント内にカーソルがある場合 |
| BR-12-03 | ソートプレフィックス | 補完種別ごとにソートプレフィックスを付与（Doc=0_, Snippets=2_5_, DCD=2_, AutoImport=3_） | D言語ソース補完時 |
| BR-12-04 | '.'後のスニペット抑制 | ドット演算子の直後ではスニペット補完を提供しない | スニペット補完判定時 |
| BR-12-05 | 大容量ファイル遅延 | 50KiB超のファイルでは処理遅延を設定 | DScanner/dfmt関連処理 |
| BR-12-06 | DCD型変換 | DCDのシンボルタイプ文字（c/i/s/f等）をLSP CompletionItemKind に変換する | DCD補完結果のマッピング |

### 計算ロジック

ソートプレフィックスの付与ロジック:
- `sortPrefixDoc = "0_"` - ドキュメント補完（最優先）
- `sortPrefixSnippets = "2_5_"` - スニペット補完
- `sortPrefixDCD = "2_"` - DCD補完（DCD内部でさらにタイプ別ソート）
- `sortPrefixAutoImport = "3_"` - 自動インポート補完（最後）

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

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

本機能ではデータベース操作は行わない。インメモリのインデックス・DCD通信のみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | インスタンス不在 | バックエンドインスタンスが取得できない場合 | 空のCompletionListを返却 |
| - | DCD未起動 | DCDComponentが利用不可の場合 | DCD補完をスキップし他の補完のみ提供 |
| - | コンポーネント不在 | SnippetsComponent等が未ロードの場合 | 該当補完をスキップ |

### リトライ仕様

リトライなし。エラー時は空の補完リストまたは利用可能な補完のみ返却。

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

トランザクション管理なし。読み取り専用操作。

## パフォーマンス要件

リアルタイム入力補完のため、低遅延が求められる。DCD補完・スニペット補完・自動インポート補完は `joinAll` により並列実行される。ファイルサイズに応じた処理最適化あり。

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

特になし。ローカルのソースコード解析のみ。

## 備考

- `doCompleteSnippets` グローバル変数でスニペット補完の有効/無効を制御（`--provide context-snippets` オプション）
- DCD型文字の意味: c=class, i=interface, s=struct, u=union, f=function, F=UFCS function, v=variable, m=member, e=enum member, k=keyword, g=enum, P=package, M=module, l=alias, t=template, T=mixin template, h=template type param, p=template variadic param

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | complete.d | `source/served/commands/complete.d` | ソートプレフィックス定数（34-39行目）、convertFromDCDType関数（41-85行目）でDCDタイプからLSP CompletionItemKindへの変換マッピングを確認 |
| 1-2 | types.d | `source/served/types.d` | Configuration構造体のD設定（enableAutoComplete, enableAutoImportCompletions等）を確認 |

**読解のコツ**: DCDは1文字のタイプコード（'c'=class, 'f'=function等）を使用する。`convertFromDCDType` と `sortFromDCDType` は対になった変換関数。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | complete.d | `source/served/commands/complete.d` | `provideComplete` 関数（304-396行目）がLSPメソッドのエントリーポイント |

**主要処理フロー**:
1. **304行目**: `@protocolMethod("textDocument/completion")` でLSPメソッドとして登録
2. **307-309行目**: ドキュメント取得とバックエンドインスタンス取得
3. **311-375行目**: dscanner.ini の場合の補完処理（セクション名・設定値の補完）
4. **384行目**: D言語の場合 `provideDSourceComplete` を呼び出し
5. **386行目**: dietの場合 `provideDietSourceComplete` を呼び出し
6. **388行目**: DMLの場合 `provideDMLSourceComplete` を呼び出し

#### Step 3: D言語ソース補完の詳細

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | complete.d | `source/served/commands/complete.d` | `provideDSourceComplete` 関数（550-644行目）がD言語補完のメイン処理 |

**主要処理フロー**:
- **553-554行目**: 行のバイト範囲とバイトオフセットの計算
- **570行目**: `isInComment` でコメント内判定
- **605-608行目**: 各補完プロバイダの有効性フラグ設定
- **615-629行目**: `joinAll` による並列補完実行（DCD、ドキュメント、スニペット、自動インポート）
- **631-643行目**: DCD結果の統合と `convertDCDIdentifiers` による変換

#### Step 4: 補完結果の変換・統合処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | complete.d | `source/served/commands/complete.d` | `convertDCDIdentifiers` 関数（1099-1343行目）でDCD結果をCompletionItemに変換・重複排除する処理 |

**主要処理フロー**:
- **1103-1266行目**: 各識別子のCompletionItem変換（ラベル、種別、ドキュメント、ソートテキスト、引数スニペット生成）
- **1269行目**: `sort` による重複検出用ソート
- **1270-1342行目**: `chunkBy` + `map` による同一識別子のマージ（ドキュメント・詳細の結合、オーバーロード表示）

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

```
provideComplete (complete.d:305)
    │
    ├─ [dscanner.ini] DscannerComponent.listAllIniFields
    │
    ├─ [D言語] provideDSourceComplete (complete.d:550)
    │      ├─ isInComment (complete.d:891)
    │      ├─ joinAll (並列実行)
    │      │      ├─ DCDComponent.listCompletion
    │      │      ├─ provideDocComplete (complete.d:646)
    │      │      │      └─ DscannerComponent.listDefinitions
    │      │      ├─ provideSnippetComplete (complete.d:841)
    │      │      │      └─ SnippetsComponent.getSnippetsYield
    │      │      └─ provideAutoImports (complete.d:735)
    │      │             ├─ IndexComponent.iterateSymbolsStartingWith
    │      │             └─ ImporterComponent.get
    │      └─ convertDCDIdentifiers (complete.d:1099)
    │
    ├─ [diet] provideDietSourceComplete (complete.d:491)
    │      ├─ updateDietFile
    │      └─ DCDComponent.listCompletion
    │
    └─ [DML] provideDMLSourceComplete (complete.d:398)
           └─ DlanguiComponent.complete
```

### データフロー図

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

TextDocumentPosition ───▶ provideComplete ──────────────▶ CompletionList
                              │
                              ├── DCD ─────────▶ DCDIdentifiers ─┐
                              ├── DScanner ────▶ Definitions ────┤
                              ├── Snippets ────▶ Snippet[] ──────┤ ──▶ CompletionItem[]
                              └── Index ───────▶ Symbols ────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| complete.d | `source/served/commands/complete.d` | ソース | 補完メイン処理。provideComplete, provideDSourceComplete等 |
| extension.d | `source/served/extension.d` | ソース | コマンド登録・エクスポート |
| types.d | `source/served/types.d` | ソース | Configuration, LSP型定義 |
| ddoc.d | `source/served/utils/ddoc.d` | ソース | DDocパース・Markdown変換 |
| diet.d | `source/served/utils/diet.d` | ソース | dietテンプレートからのDコード抽出 |
| format.d | `source/served/commands/format.d` | ソース | formatCode, formatSnippet関数 |
| ddocs.txt | (コンパイル時埋め込み) | リソース | DDocキーワード一覧 |
