# 機能設計書 19-company

## 概要

本ドキュメントは、Doom Emacsのテキスト補完モジュール「company」の機能設計を定義する。このモジュールは、company-modeを使用したドロップダウン形式のコード補完機能を提供する。

### 本機能の処理概要

companyモジュールは、Emacs用の汎用テキスト補完フレームワークであるcompany-modeをDoom Emacs向けに設定・拡張したものである。入力中にリアルタイムで補完候補を表示し、効率的なコード入力を支援する。

**業務上の目的・背景**：プログラミングにおいて、コード補完は生産性向上に不可欠な機能である。company-modeは最も広く使用されているEmacs補完フレームワークの一つであり、多くのプログラミング言語やツール（LSP等）と統合されている。Doomのcompanyモジュールは、この強力な補完機能を最適な設定で提供し、Evil（Vim）モードとの統合やパフォーマンス最適化を行う。

**機能の利用シーン**：
- コード入力中の変数名・関数名補完
- ファイルパスの補完
- スニペットの挿入
- LSPを使用したインテリジェントな補完

**主要な処理内容**：
1. company-modeのグローバル有効化（doom-first-inputフック）
2. モード別バックエンドの設定（+company-backend-alist）
3. 補完候補のフィルタリングと表示
4. Evil統合（ノーマルモード時の自動中止等）
5. company-box（+childframeフラグ）によるチャイルドフレーム表示
6. company-dictによるプロジェクト固有辞書対応

**関連システム・外部連携**：
- LSP（lsp-mode/eglot）: 言語サーバー補完
- yasnippet: スニペット補完
- Evil: Vimエミュレーション統合

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | Company | 主機能 | ドロップダウン形式コード補完表示 |
| 8 | Company | 補助機能 | company-yasnippet連携 |
| 8 | Company | API連携 | company-capf連携（LSP） |

## 機能種別

テキスト補完 / UI拡張 / 入力支援

## 入力仕様

### 入力パラメータ

モジュールフラグ:
| フラグ名 | 説明 |
|---------|------|
| +tng | Tab-and-Goスタイルの補完を有効化 |
| +childframe | company-boxによるチャイルドフレーム表示を有効化 |

### 入力データソース

- ユーザー入力（キーストローク）
- 各バックエンドからの補完候補

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 補完候補リスト | リスト | マッチした補完候補の一覧 |
| 候補メタデータ | 文字列 | 選択中の候補のドキュメント |

### 出力先

- 補完ポップアップ（オーバーレイまたはチャイルドフレーム）
- エコーエリア（メタデータ表示）

## 処理フロー

### 処理シーケンス

```
1. トリガー検出
   └─ company-idle-delay経過後に自動起動
   └─ または手動起動（company-manual-begin）

2. プレフィックス取得
   └─ カーソル前のテキストを取得

3. バックエンド選択
   └─ +company--backendsで現在のモードに適したバックエンドを決定

4. 候補取得
   └─ 各バックエンドに候補をクエリ

5. 候補表示
   └─ company-pseudo-tooltip-frontendでポップアップ表示
   └─ または company-box（+childframeの場合）

6. 選択・確定
   └─ ユーザーが候補を選択
   └─ company-complete-selectionで確定
```

### フローチャート

```mermaid
flowchart TD
    A[入力開始] --> B{アイドル<br>タイムアウト?}
    B -->|Yes| C[プレフィックス取得]
    B -->|No| D{手動起動?}
    D -->|Yes| C
    D -->|No| A
    C --> E{プレフィックス<br>長さ >= 2?}
    E -->|No| A
    E -->|Yes| F[バックエンド選択]
    F --> G[候補取得]
    G --> H{候補<br>あり?}
    H -->|No| I[補完中止]
    H -->|Yes| J[ポップアップ表示]
    J --> K{選択?}
    K -->|確定| L[テキスト挿入]
    K -->|キャンセル| I
    K -->|継続入力| G
    I --> A
    L --> A
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 最小プレフィックス | 2文字以上で補完開始 | company-minimum-prefix-length |
| BR-02 | アイドル遅延 | MacOS: 0.4秒、その他: 0.26秒 | 自動補完時 |
| BR-03 | 除外モード | erc, circe, message, help, gud, vterm-modeでは無効 | company-global-modes |
| BR-04 | Evilノーマル | ノーマルモード移行時に補完中止 | evil-normal-state-entry-hook |

### 設定値

```elisp
company-minimum-prefix-length 2
company-tooltip-limit 14
company-tooltip-align-annotations t
company-require-match 'never
company-idle-delay (if (featurep :system 'macos) 0.4 0.26)
company-backends '(company-capf)
company-auto-commit nil
company-dabbrev-other-buffers nil
company-dabbrev-ignore-case nil
company-dabbrev-downcase nil
```

### 計算ロジック

**バックエンド決定ロジック（+company--backends）**:
```elisp
(defun +company--backends ()
  (let (backends)
    ;; メジャーモードの継承チェーンを辿る
    (let ((mode major-mode)
          (modes (list major-mode)))
      (while (setq mode (get mode 'derived-mode-parent))
        (push mode modes))
      ;; 各モードのバックエンドを収集
      (dolist (mode modes)
        (dolist (backend (append (cdr (assq mode +company-backend-alist))
                                 (default-value 'company-backends)))
          (push backend backends)))
      ;; マイナーモードのバックエンドも追加
      (delete-dups
       (append (cl-loop for (mode . backends) in +company-backend-alist
                        if (or (eq major-mode mode)
                               (and (boundp mode) (symbol-value mode)))
                        append backends)
               (nreverse backends))))))
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 補完失敗 | バックエンドがエラーを返す | 他のバックエンドにフォールバック |

### リトライ仕様

特になし。

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

補完はステートレスな処理のため、トランザクション管理は不要。

## パフォーマンス要件

- company-dabbrev-other-buffers: nilで他バッファのスキャンを無効化
- company-idle-delay: MacOSでは0.4秒に調整
- company-tooltip-limit: 14件で表示数を制限

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

特になし。

## 備考

- +tngフラグでTab-and-Goスタイルを有効化可能
- +childframeフラグでcompany-boxを使用したモダンなUI
- set-company-backend!マクロでモード別バックエンドを設定可能

---

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

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

### 推奨読解順序

#### Step 1: バックエンド設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | autoload.el | `modules/completion/company/autoload.el` | 4-9行目のバックエンドalist |

**読解のコツ**: `+company-backend-alist`はモード別のバックエンド設定を保持。text-modeにはdabbrev+yasnippet+ispell、prog-modeにはcapf+yasnippetが設定される。

**主要処理フロー**:
- **4-9行目**: +company-backend-alist - デフォルトバックエンド設定
- **12-39行目**: set-company-backend! - バックエンド設定マクロ
- **45-61行目**: +company--backends - バックエンド決定関数

#### Step 2: メイン設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | config.el | `modules/completion/company/config.el` | 3-86行目のuse-package!設定 |

**主要処理フロー**:
- **10-45行目**: company-modeの基本設定
- **47-49行目**: +tngフラグの処理
- **51-66行目**: Evil統合設定
- **68行目**: +company-init-backends-hのフック登録

#### Step 3: company-box設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | config.el | `modules/completion/company/config.el` | 97-176行目のcompany-box設定 |

**主要処理フロー**:
- **97-99行目**: +childframeフラグ時のみ有効化
- **101-142行目**: アイコン設定（nerd-icons）
- **157-163行目**: Elisp用アイコン関数

#### Step 4: コマンド群を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | autoload.el | `modules/completion/company/autoload.el` | 81-173行目のコマンド |

**主要処理フロー**:
- **90-96行目**: +company/toggle-auto-completion - 自動補完のトグル
- **99-109行目**: +company/complete - 補完実行
- **122-139行目**: +company/whole-lines - 行全体の補完
- **160-172行目**: +company/completing-read - ミニバッファ補完

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

```
global-company-mode
    │
    └─ company-mode (各バッファ)
           │
           ├─ +company-init-backends-h
           │      └─ +company--backends
           │             └─ +company-backend-alist参照
           │
           ├─ company-idle-begin (自動補完)
           │      └─ company-complete-common
           │
           └─ company-frontends
                  ├─ company-pseudo-tooltip-frontend
                  ├─ company-echo-metadata-frontend
                  └─ company-box (if +childframe)
```

### データフロー図

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

キー入力            ───▶  プレフィックス検出 ───▶  補完開始判定

+company-backend-alist ───▶  バックエンド選択 ───▶  候補クエリ

各バックエンド       ───▶  候補収集      ───▶  候補リスト
(capf, dabbrev等)

候補リスト          ───▶  フロントエンド ───▶  ポップアップ表示

選択               ───▶  挿入          ───▶  バッファ更新
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| config.el | `modules/completion/company/config.el` | ソース | 主設定ファイル |
| autoload.el | `modules/completion/company/autoload.el` | ソース | 自動ロード関数 |
| packages.el | `modules/completion/company/packages.el` | 設定 | パッケージ定義 |
| company.el | (外部パッケージ) | ソース | company-mode本体 |
| company-box.el | (外部パッケージ) | ソース | チャイルドフレームUI |
| company-dict.el | (外部パッケージ) | ソース | 辞書補完 |
