# 機能設計書 1-オートコンプリート

## 概要

本ドキュメントは、Clojure LSP サーバーにおけるオートコンプリート機能（コード補完）の設計仕様を記載する。この機能は LSP プロトコルの `textDocument/completion` リクエストに対応し、エディタ上でカーソル位置に応じた補完候補を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Clojure開発において、開発者がコードを効率的に記述できるようにするため、コード補完機能を提供する。変数名、関数名、名前空間、キーワード、Java クラスなど多様なシンボルの補完候補を提示することで、タイプミスの防止、API の発見、開発速度の向上を実現する。特に Clojure は動的型付け言語であるため、静的解析に基づく補完機能がなければ、開発者はドキュメントやソースコードを頻繁に参照する必要がある。

**機能の利用シーン**：開発者がエディタ（VSCode、Emacs、Neovim 等）で Clojure コードを編集中に、変数名や関数名を途中まで入力し、補完候補の表示をトリガーした場合に本機能が呼び出される。また、名前空間エイリアス入力後のスラッシュ、キーワードのコロン入力後など、特定のコンテキストでも自動的に補完候補が提供される。

**主要な処理内容**：
1. カーソル位置の解析とコンテキスト判定（コメント内、require 内、refer 内等）
2. カーソル位置のシンボルに基づくマッチング関数の生成
3. ローカル変数、名前空間定義、var 定義、キーワード等の補完候補収集
4. clojure.core/cljs.core のシンボル補完
5. Java クラスおよびスタティックメンバーの補完
6. スニペット（コードテンプレート）の統合
7. 優先度によるソートと重複除去
8. クライアントの機能サポートに応じた遅延解決データの付与

**関連システム・外部連携**：clj-kondo による静的解析結果、ClojureDocs、Clojars/Maven Central（ライブラリバージョン補完時）

**権限による制御**：本機能に権限による実行制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトは LSP サーバー実装であり、UI 画面は存在しない。エディタのコード補完 UI から呼び出される。 |

## 機能種別

データ検索処理 / コード解析処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| text-document.uri | string | Yes | 補完対象のドキュメント URI | 有効な file:// URI |
| position.line | integer | Yes | カーソル行位置（0-indexed） | 0 以上 |
| position.character | integer | Yes | カーソル列位置（0-indexed） | 0 以上 |

### 入力データソース

- 解析済みドキュメントの AST（rewrite-clj による解析）
- clj-kondo による静的解析結果（db の :analysis）
- クライアント機能情報（:client-capabilities）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| label | string | 補完候補の表示名 |
| kind | integer | 補完候補の種類（Function=3, Variable=6, Keyword=14 等） |
| detail | string | 補足情報（名前空間/シグネチャ等） |
| documentation | string/MarkupContent | ドキュメント文字列（遅延解決の場合あり） |
| deprecated | boolean | 非推奨フラグ |
| tags | integer[] | タグ配列（1=deprecated） |
| insert-text | string | 挿入テキスト（スニペット時） |
| insert-text-format | integer | 1=PlainText, 2=Snippet |
| text-edit | TextEdit | 補完時の編集範囲とテキスト |
| additional-text-edits | TextEdit[] | 追加編集（require 追加等） |
| score | integer | 優先度スコア |
| data | object | 遅延解決用データ |

### 出力先

LSP プロトコルを通じてエディタクライアントへ返却

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ handlers/completion が textDocument/completion を受信

2. 前処理・コンテキスト判定
   └─ カーソル位置の zloc 取得、コメント内判定

3. 補完コンテキストの分析
   └─ require/refer 内、キーワード、エイリアス等の判定

4. 補完候補の収集
   ├─ ローカルシンボル（変数、名前空間、var）
   ├─ clojure.core/cljs.core シンボル
   ├─ Java クラス/スタティックメンバー
   ├─ キーワード
   ├─ 名前空間エイリアス経由のシンボル
   └─ スニペット

5. ソート・重複除去
   └─ 優先度順ソート、600件制限

6. レスポンス構築
   └─ text-edit 付与、クライアントへ返却
```

### フローチャート

```mermaid
flowchart TD
    A[completion リクエスト受信] --> B{コメント内?}
    B -->|Yes| C[空配列を返却]
    B -->|No| D{コンテキスト判定}
    D -->|require 内| E[名前空間補完]
    D -->|refer 内| F[参照可能 var 補完]
    D -->|キーワード| G[キーワード補完]
    D -->|エイリアス付き| H[エイリアス経由の var 補完]
    D -->|その他| I[汎用補完]
    E --> J[スニペット統合]
    F --> J
    G --> K[ソート・重複除去]
    H --> K
    I --> J
    J --> K
    K --> L[600件制限]
    L --> M[text-edit 付与]
    M --> N[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | コメント除外 | コメント内ではコード補完を行わない | カーソル位置が :comment タグの場合 |
| BR-02 | 優先度順序 | snippet > java > core > ns > alias > refer > keyword > local の優先度 | 全補完候補 |
| BR-03 | 件数制限 | 最大 600 件の補完候補を返却 | 全ケース |
| BR-04 | 遅延解決 | ドキュメントと追加編集は遅延解決可能 | クライアントが対応している場合 |

### 計算ロジック

- 優先度スコア: priority-kw->number マップにより、優先度キーワードを数値に変換
- マッチング: カーソル位置の値で始まる候補のみ抽出（prefix match）

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 補完候補検索 | db :analysis | SELECT | 静的解析結果からシンボル情報を検索 |

### テーブル別操作詳細

#### db :analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | :var-definitions | カーソル位置の URI とマッチング条件 | 変数定義の補完候補 |
| SELECT | :namespace-definitions | 名前でマッチング | 名前空間補完 |
| SELECT | :keyword-usages/:keyword-definitions | 名前/名前空間でマッチング | キーワード補完 |
| SELECT | :java-class-definitions | クラス名でマッチング | Java クラス補完 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空配列返却 | コメント内、解析エラー | 空の補完リストを返却 |
| :request-cancelled | キャンセル | クライアントがリクエストをキャンセル | 処理中断 |
| :request-failed | タイムアウト | 解析待ちが 60 秒を超過 | タイムアウトエラー返却 |

### リトライ仕様

リトライは行わない。クライアント側で再度補完リクエストを送信する。

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

本機能は読み取り専用であり、トランザクション管理は不要。

## パフォーマンス要件

- 応答時間: 通常 100ms 以内
- 解析待ち時にはバックオフ（5ms から最大 200ms）で待機
- 補完候補は最大 600 件に制限
- Java クラス補完は入力がある場合のみ実行（パフォーマンス考慮）

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

- 外部ネットワーク通信なし（ライブラリバージョン補完を除く）
- ファイルシステムアクセスは解析対象ファイルのみ

## 備考

- 解析モードとして :fast-but-stale（デフォルト）と :slow-but-accurate を設定可能
- クライアントの completionItem/resolveSupport に応じて遅延解決を活用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | completion-kind-enum（22-25行目）で補完アイテムの種別を定義。priority-order（27-45行目）で優先度の定義を確認 |

**読解のコツ**: Clojure の keyword を使った enum 定義パターン。priority-kw->number で優先度を数値化している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | completion 関数（254-268行目）が LSP リクエストのエントリーポイント |
| 2-2 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | completion 関数（628-740行目）がメインロジック |

**主要処理フロー**:
1. **254-263行目**: handlers/completion でリクエスト受信、skip-feature-for-uri? でスキップ判定
2. **628-635行目**: カーソル位置の zloc（zipper location）を取得
3. **644-645行目**: コメント内なら空配列を返却
4. **688-734行目**: コンテキストに応じた補完候補収集の分岐

#### Step 3: 補完候補収集を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | with-local-items（312-329行目）でローカルシンボル収集 |
| 3-2 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | with-clojure-core-items（508-514行目）で core シンボル収集 |
| 3-3 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | with-java-definition-items（524-547行目）で Java クラス収集 |

**主要処理フロー**:
- **312-329行目**: ローカルバケットから各種シンボルを抽出し補完アイテムに変換
- **374-434行目**: エイリアス経由のシンボル補完処理

#### Step 4: 補完アイテム解決を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | resolve-item（774-785行目）で遅延解決処理 |
| 4-2 | completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | resolve-unresolved マルチメソッド（753-771行目）で解決タイプ別処理 |

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

```
handlers/completion
    │
    ├─ f.completion/completion
    │      ├─ parser/safe-zloc-of-file
    │      ├─ parser/to-pos
    │      ├─ q/find-element-under-cursor
    │      │
    │      ├─ [コンテキスト分岐]
    │      │   ├─ f.completion-lib/complete (deps.edn等)
    │      │   ├─ with-refer-elements
    │      │   ├─ with-ns-definition-elements
    │      │   ├─ with-elements-from-aliased-keyword
    │      │   ├─ with-elements-from-keyword
    │      │   └─ with-local-items / with-clojure-core-items / with-java-definition-items
    │      │
    │      ├─ merging-snippets
    │      │      └─ f.completion-snippet/known-snippets
    │      │
    │      ├─ sorting-and-distincting-items
    │      └─ add-text-edit
    │
    └─ [遅延解決]
        └─ f.completion/resolve-item
               └─ resolve-unresolved (multimethod)
```

### データフロー図

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

textDocument/completion ──▶ handlers/completion ──▶ CompletionItem[]
  - uri                          │
  - position (line, char)        ▼
                            completion.clj
                                 │
                                 ├──▶ zloc 取得
                                 │      (rewrite-clj)
                                 │
                                 ├──▶ コンテキスト判定
                                 │
                                 ├──▶ db :analysis 参照
                                 │      - var-definitions
                                 │      - namespace-definitions
                                 │      - keyword-usages
                                 │      - java-class-definitions
                                 │
                                 ├──▶ common-sym/clj-syms
                                 │      (clojure.core symbols)
                                 │
                                 └──▶ completion-snippet
                                        (known-snippets)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| completion.clj | `lib/src/clojure_lsp/feature/completion.clj` | ソース | 補完機能のメインロジック |
| completion_lib.clj | `lib/src/clojure_lsp/feature/completion_lib.clj` | ソース | ライブラリバージョン補完 |
| completion_snippet.clj | `lib/src/clojure_lsp/feature/completion_snippet.clj` | ソース | スニペット定義 |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSP リクエストハンドラー |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 解析データのクエリ |
| parser.clj | `lib/src/clojure_lsp/parser.clj` | ソース | コード解析（rewrite-clj） |
| common_symbols.clj | `lib/src/clojure_lsp/common_symbols.clj` | ソース | clojure.core シンボル定義 |
| completion_test.clj | `lib/test/clojure_lsp/feature/completion_test.clj` | テスト | ユニットテスト |
