# 機能設計書 18-LSP操作(SPC l)

## 概要

本ドキュメントは、space-vimにおけるLSP操作機能（SPC l）の設計仕様を記述する。SPCキーに続いて「l」を押下することで、Language Server Protocol（LSP）関連の操作（定義ジャンプ、リファレンス検索、リネーム、コードアクション等）を提供する機能である。

### 本機能の処理概要

LSP操作機能は、coc.nvim、vim-lsp、LanguageClient-neovimなどのLSPクライアントと連携し、統一的なキーバインディングでLSP機能を提供する。使用するLSPエンジンはg:spacevim_lsp_engineで設定可能で、設定に応じて適切なバックエンドが呼び出される。

**業務上の目的・背景**：現代のプログラミング言語開発では、IDEと同等のコード補完、定義ジャンプ、リファクタリング支援などが期待される。LSPを利用することで、各言語のLanguage Serverが提供する高度な機能をVim上で利用可能になる。SPC lプレフィックスにより、これらの機能に統一的にアクセスできる。

**機能の利用シーン**：
- 関数やクラスの定義にジャンプしたい場合（SPC l g d）
- 変数や関数のリファレンス（参照箇所）を検索したい場合（SPC l r）
- シンボルのリネーム（名前変更）を行いたい場合（SPC l R）
- コードフォーマットを適用したい場合（SPC l f）
- ホバー情報を表示したい場合（SPC l h）
- コードアクションを実行したい場合（SPC l a）

**主要な処理内容**：
1. SPC l g d：定義ジャンプ
2. SPC l g t：型定義ジャンプ
3. SPC l g i：実装ジャンプ
4. SPC l r：リファレンス検索
5. SPC l R：リネーム
6. SPC l f：フォーマット
7. SPC l h：ホバー情報
8. SPC l a：コードアクション
9. SPC l s：ドキュメントシンボル
10. SPC l S：ワークスペースシンボル

**関連システム・外部連携**：
- coc.nvim：メインのLSPクライアント
- vim-lsp：代替LSPクライアント
- LanguageClient-neovim：NeoVim向けLSPクライアント
- 各言語のLanguage Server

**権限による制御**：本機能に権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 9 | LSP診断画面 | 補助機能 | SPC lによるLSP関連の操作（定義ジャンプ、リファレンス検索等） |

## 機能種別

コード解析 / ナビゲーション / リファクタリング

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| キーシーケンス | String | Yes | SPC l に続くキー入力 | 定義済みキーのみ受付 |
| g:spacevim_lsp_engine | String | No | LSPエンジン指定（coc/lcn/vim_lsp） | デフォルト: coc |

### 入力データソース

- ユーザーキー入力
- カーソル位置情報
- Language Serverからのレスポンス

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 定義位置 | Vim位置 | 定義ジャンプ先 |
| リファレンス一覧 | Quickfix | 参照箇所の一覧 |
| ホバー情報 | ポップアップ | シンボル情報の表示 |
| シンボル一覧 | fzf/Quickfix | ドキュメント/ワークスペースのシンボル |

### 出力先

- Vimバッファ（定義ジャンプ）
- Quickfixリスト（リファレンス検索結果）
- フローティングウィンドウ（ホバー情報）

## 処理フロー

### 処理シーケンス

```
1. SPC l キー入力
   └─ which-keyによるサブキー一覧表示
2. サブキー入力に応じた処理分岐
   └─ spacevim#lang#util#*() 関数呼び出し
3. LSPエンジン判定
   ├─ coc: CocAction/CocActionAsync
   ├─ lcn: LanguageClient#*
   └─ vim_lsp: <Plug>(lsp-*)
4. Language Serverへリクエスト送信
5. レスポンス処理
6. 結果表示（ジャンプ/Quickfix/ポップアップ）
```

### フローチャート

```mermaid
flowchart TD
    A[SPC l 入力] --> B{サブキー?}
    B -->|g d| C[定義ジャンプ]
    B -->|g t| D[型定義ジャンプ]
    B -->|g i| E[実装ジャンプ]
    B -->|r| F[リファレンス検索]
    B -->|R| G[リネーム]
    B -->|f| H[フォーマット]
    B -->|h| I[ホバー]
    B -->|a| J[コードアクション]
    B -->|s| K[ドキュメントシンボル]
    B -->|S| L[ワークスペースシンボル]
    C --> M{LSPエンジン?}
    M -->|coc| N[CocAction jumpDefinition]
    M -->|lcn| O[LanguageClient textDocument_definition]
    M -->|vim_lsp| P[lsp-definition]
    N --> Q[Language Serverへリクエスト]
    O --> Q
    P --> Q
    Q --> R[定義位置へジャンプ]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | LSPエンジン選択 | g:spacevim_lsp_engineでエンジンを選択 | LSP操作実行時 |
| BR-002 | cocデフォルト | デフォルトはcoc.nvimを使用 | g:spacevim_lsp_engine未設定時 |
| BR-003 | フォールバック | LSP未対応時はautoformat/ALEFixにフォールバック | フォーマット実行時 |
| BR-004 | which-key連携 | vim-lsp使用時はwhich-keyに動的にキーマッピングを追加 | vim_lspエンジン選択時 |

### 計算ロジック

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 定義未検出 | 定義が見つからない | "Not found!"メッセージ表示 |
| - | LSP未起動 | Language Serverが起動していない | LSPエンジンの設定確認 |
| - | Language Server busy | Language Serverがビジー状態 | 再試行を促すメッセージ表示 |

### リトライ仕様

- Language Serverがビジー状態の場合、ユーザーに再試行を促す

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

該当なし

## パフォーマンス要件

- 定義ジャンプは1秒以内
- ホバー情報表示は500ミリ秒以内
- リファレンス検索はLanguage Server性能に依存

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

- Language Serverは信頼できるものを使用すること

## 備考

- 言語ごとにLanguage Serverのインストールが必要
- coc.nvimは:CocInstallコマンドでLanguage Serverをインストール可能
- vim-lsp使用時はキーマッピングが動的に変更される

---

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

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

### 推奨読解順序

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

LSP操作のキーマッピング定義を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | leader.vim | `core/autoload/spacevim/map/leader.vim` | s:leader_map['l']の構造を理解 |

**読解のコツ**: LSP操作は関数呼び出しが多く、実装はutil.vimに委譲されている。また、'g'サブグループにgoto系操作がまとめられている。

**主要データ構造**:
- **123行目**: `let s:leader_map['l'] = {` - LSP操作グループ開始
- **124行目**: `'name' : '+lsp'` - グループ名
- **125行目**: `'a' : ['spacevim#lang#util#CodeAction()', 'code-action']` - コードアクション
- **126行目**: `'f' : ['spacevim#lang#util#Format()', 'formatting']` - フォーマット
- **127行目**: `'h' : ['spacevim#lang#util#Hover()', 'hover']` - ホバー
- **128行目**: `'r' : ['spacevim#lang#util#FindReferences()', 'references']` - リファレンス
- **129行目**: `'R' : ['spacevim#lang#util#Rename()', 'rename']` - リネーム
- **130行目**: `'s' : ['spacevim#lang#util#DocumentSymbol()', 'document-symbol']` - ドキュメントシンボル
- **131行目**: `'S' : ['spacevim#lang#util#WorkspaceSymbol()', 'workspace-symbol']` - ワークスペースシンボル
- **132-137行目**: `'g' : {...}` - gotoサブグループ

#### Step 2: ユーティリティ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | util.vim | `core/autoload/spacevim/lang/util.vim` | LSP操作の実装 |

**主要処理フロー**:
- **16-29行目**: `s:dispatch()` - LSPエンジン判定とコマンドディスパッチ
- **34-36行目**: `spacevim#lang#util#FindReferences()` - リファレンス検索
- **125-152行目**: `spacevim#lang#util#Definition()` - 定義ジャンプ（Vimファイルは特別処理）
- **73-85行目**: `spacevim#lang#util#Format()` - フォーマット（フォールバック対応）

#### Step 3: LSPレイヤー設定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | config.vim | `layers/+tools/lsp/config.vim` | LSPレイヤーの設定 |

**主要処理フロー**:
- **16-57行目**: `s:coc()` - coc.nvim設定
- **59-115行目**: `s:lcn()` - LanguageClient-neovim設定
- **117-228行目**: `s:vim_lsp()` - vim-lsp設定とwhich-key連携
- **231行目**: `call s:{g:spacevim_lsp_engine}()` - 設定されたエンジンの初期化

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

```
SPC l キー入力
    │
    ├─ SPC l g d（定義ジャンプ）
    │      └─ spacevim#lang#util#Definition()
    │             ├─ coc: CocActionAsync('jumpDefinition')
    │             └─ lcn: LanguageClient#textDocument_definition()
    │
    ├─ SPC l r（リファレンス検索）
    │      └─ spacevim#lang#util#FindReferences()
    │             └─ s:dispatch('jumpReferences', 'textDocument_references')
    │                    ├─ coc: CocAction('jumpReferences')
    │                    └─ lcn: LanguageClient#textDocument_references()
    │
    ├─ SPC l f（フォーマット）
    │      └─ spacevim#lang#util#Format()
    │             ├─ coc: CocActionAsync('format')
    │             ├─ RustFmt（Rustの場合）
    │             ├─ LanguageClient#textDocument_formatting()
    │             ├─ :Autoformat
    │             └─ :ALEFix
    │
    └─ SPC l R（リネーム）
           └─ spacevim#lang#util#Rename()
                  └─ s:dispatch('rename', 'textDocument_rename')
```

### データフロー図

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

ユーザーキー入力 ────▶ which-keyディスパッチ ────────▶ サブキー選択UI
    │                       │
    ▼                       ▼
SPC l + サブキー ────▶ util関数呼び出し ─────────────▶ LSPエンジン判定
                            │
                            ├─▶ coc: CocAction ─────────▶ coc Language Server
                            ├─▶ lcn: LanguageClient ────▶ LanguageClient-neovim
                            └─▶ vim_lsp: <Plug> ────────▶ vim-lsp
                                    │
                                    ▼
                            Language Server Response
                                    │
                                    ▼
                            結果表示（ジャンプ/Quickfix/ポップアップ）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| leader.vim | `core/autoload/spacevim/map/leader.vim` | ソース | LSP操作キーマッピング定義 |
| util.vim | `core/autoload/spacevim/lang/util.vim` | ソース | LSP操作実装 |
| config.vim | `layers/+tools/lsp/config.vim` | 設定 | LSPレイヤー設定 |
| lsp.vim | `core/autoload/spacevim/lang/lsp.vim` | ソース | LSP基盤機能 |
| lsp_ui.vim | `core/autoload/spacevim/lang/lsp_ui.vim` | ソース | LSP UI関連 |
| coc.vim | `core/autoload/spacevim/plug/coc.vim` | ソース | coc.nvim連携 |
