# 機能設計書 97-言語サーバー

## 概要

本ドキュメントはNushellの言語サーバー（nu-lsp）について記述する。Language Server Protocol (LSP) に準拠したエディタ支援機能を提供するサーバーの設計を定義する。

### 本機能の処理概要

nu-lspは、VS CodeやVim等のエディタと連携し、Nushellスクリプトの編集支援機能を提供する。コード補完、定義へのジャンプ、ホバー情報表示、リネーム、参照検索、診断機能など、モダンなエディタに期待される機能をサポートする。

**業務上の目的・背景**：Nushellスクリプトの開発効率を向上させるため、IDEレベルの編集支援機能が必要である。LSPを採用することで、様々なエディタに対して統一的な支援機能を提供できる。

**機能の利用シーン**：
- Nushellスクリプトの編集時のコード補完
- 変数やコマンドの定義へのジャンプ
- シンボルのリネーム
- 型情報やドキュメントのホバー表示
- シンタックスエラーの即時表示
- ワークスペース全体のシンボル検索

**主要な処理内容**：
1. エディタとのJSON-RPC通信（stdio）
2. ドキュメント同期（テキスト変更の追跡）
3. パースと診断情報の生成
4. 補完候補の生成
5. 定義/参照/ホバー情報の検索
6. セマンティックトークンの生成

**関連システム・外部連携**：lsp-serverクレート、lsp-typesクレート

**権限による制御**：特になし。ファイルシステムへの読み取りアクセスが必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はLSPサーバーとして動作し、エディタのUIを通じて利用される |

## 機能種別

言語サービス / コード解析 / エディタ支援

## 入力仕様

### 入力パラメータ

本機能はLSPリクエストとして様々なパラメータを受け付ける。

#### 主要なリクエスト

| リクエスト | 説明 | 主要パラメータ |
|-----------|------|---------------|
| textDocument/completion | コード補完 | TextDocumentPositionParams |
| textDocument/definition | 定義へのジャンプ | GotoDefinitionParams |
| textDocument/hover | ホバー情報 | HoverParams |
| textDocument/references | 参照検索 | ReferenceParams |
| textDocument/rename | リネーム | RenameParams |
| textDocument/documentHighlight | ハイライト | DocumentHighlightParams |
| textDocument/documentSymbol | シンボル一覧 | DocumentSymbolParams |
| workspace/symbol | ワークスペースシンボル | WorkspaceSymbolParams |

### 入力データソース

- エディタからのJSON-RPCメッセージ（stdio経由）
- ワークスペース内のNushellファイル

## 出力仕様

### 出力データ

#### ServerCapabilities

| 機能 | サポート |
|------|---------|
| completion_provider | Yes |
| definition_provider | Yes |
| document_highlight_provider | Yes |
| document_symbol_provider | Yes |
| hover_provider | Yes |
| inlay_hint_provider | Yes |
| references_provider | Yes |
| rename_provider | Yes (prepare_provider: true) |
| text_document_sync | INCREMENTAL |
| workspace_folders | Yes |
| workspace_symbol_provider | Yes |
| semantic_tokens_provider | Yes (full: true) |
| signature_help_provider | Yes |

### 出力先

- エディタへのJSON-RPCレスポンス（stdio経由）

## 処理フロー

### 処理シーケンス

```
LSPサーバー起動:
1. Connection::stdio()で接続確立
2. サーバーケイパビリティの設定
3. initialize_while()でハンドシェイク
4. serve_requests()でメインループ開始

リクエスト処理:
1. メッセージ受信（recv_timeout）
2. リクエスト種別の判定
3. 対応するハンドラ呼び出し
4. レスポンス送信

パースと検索:
1. parse_file()でドキュメントをパース
2. parse_and_find()で位置からIDを特定
3. IDに基づく情報検索
4. 結果をLSP形式に変換
```

### フローチャート

```mermaid
flowchart TD
    A[LSPサーバー起動] --> B[Connection::stdio]
    B --> C[ServerCapabilities設定]
    C --> D[initialize_while]
    D --> E[serve_requests]
    E --> F{メッセージ種別}
    F -->|Request| G[リクエスト処理]
    F -->|Notification| H[通知処理]
    F -->|Response| I[無視]
    G --> J{リクエスト種別}
    J -->|Completion| K[complete]
    J -->|Definition| L[goto_definition]
    J -->|Hover| M[hover]
    J -->|References| N[references]
    J -->|Rename| O[rename]
    K --> P[レスポンス送信]
    L --> P
    M --> P
    N --> P
    O --> P
    H --> Q[診断情報公開]
    P --> E
    Q --> E
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-97-01 | インクリメンタル同期 | テキスト変更は差分のみ同期 | TextDocumentSyncKind::INCREMENTAL |
| BR-97-02 | PWD設定 | パースはドキュメントの親ディレクトリをPWDとして実行 | 全パース処理 |
| BR-97-03 | StateDeltaキャッシュ | テキスト未変更時はパース結果をキャッシュ利用 | need_parse=false時 |
| BR-97-04 | 外部コマンドホバー | 外部コマンドはman/helpでドキュメント取得 | Id::External |

### 計算ロジック

**補完候補の生成**:
1. フォールバック判定（位置0、変数開始、空白後等）
2. NuCompleterで候補生成
3. スニペット形式でコマンド引数を展開
4. CompletionItemKindの設定

**ID検索**:
- Variable(VarId): 変数
- Declaration(DeclId): コマンド宣言
- Module(ModuleId): モジュール
- CellPath(VarId, Vec<PathMember>): セルパス
- External(String): 外部コマンド
- Value(Type): 値

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 1 | パラメータエラー | JSONパース失敗 | 正しいLSPリクエストを送信 |
| 2 | 処理エラー | prepare_rename失敗 | エラーメッセージを確認 |
| 3 | 状態エラー | リネーム準備中に実行 | 準備完了を待機 |

### リトライ仕様

- メッセージ受信は1秒タイムアウトでループ
- バックグラウンドスレッドのキャンセル対応

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

該当なし（読み取り専用処理）。

## パフォーマンス要件

- リクエストは即座に処理
- パース結果のキャッシュによる最適化
- バックグラウンドスレッドでの重い処理実行
- 処理タイムアウト時のキャンセル対応

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

- ワークスペース外のファイルアクセス制限
- 外部コマンドホバー時のman/help実行

## 備考

- LSP仕様: https://microsoft.github.io/language-server-protocol/
- セマンティックトークンは現在スペース付きコマンド名のみサポート
- ワークスペースフォルダ機能をサポート

---

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

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

### 推奨読解順序

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

LanguageServer構造体と関連するIDを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lib.rs | `crates/nu-lsp/src/lib.rs` | Id列挙型の定義（42-49行目） |
| 1-2 | lib.rs | `crates/nu-lsp/src/lib.rs` | LanguageServer構造体（51-70行目） |

**読解のコツ**: Idは解析対象の識別子の種類を表す。Variable、Declaration、Module、CellPath、External、Valueの6種類がある。

#### Step 2: 初期化とメインループを理解する

サーバーの起動とリクエスト処理ループを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lib.rs | `crates/nu-lsp/src/lib.rs` | initialize_stdio_connection（95-98行目） |
| 2-2 | lib.rs | `crates/nu-lsp/src/lib.rs` | serve_requests（121-288行目） |

**主要処理フロー（lib.rs）**:
1. **122-164行目**: ServerCapabilitiesの設定
2. **165-171行目**: 初期化ハンドシェイク
3. **173-281行目**: メインループ
4. **203-265行目**: リクエストのディスパッチ

#### Step 3: 補完機能を理解する

コード補完の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | completion.rs | `crates/nu-lsp/src/completion.rs` | complete メソッド（16-63行目） |
| 3-2 | completion.rs | `crates/nu-lsp/src/completion.rs` | completion_item_from_suggestion（65-172行目） |

**主要処理フロー（completion.rs）**:
1. **26-35行目**: フォールバック判定
2. **39-46行目**: NuCompleterで候補生成
3. **50-62行目**: CompletionResponse構築
4. **75-131行目**: スニペット形式のコマンド引数展開

#### Step 4: 定義ジャンプを理解する

GotoDefinitionの実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | goto.rs | `crates/nu-lsp/src/goto.rs` | goto_definition（87-105行目） |
| 4-2 | goto.rs | `crates/nu-lsp/src/goto.rs` | find_definition_span_by_id（56-85行目） |
| 4-3 | goto.rs | `crates/nu-lsp/src/goto.rs` | get_location_by_span（10-54行目） |

#### Step 5: ホバー機能を理解する

ホバー情報表示の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | hover.rs | `crates/nu-lsp/src/hover.rs` | hover メソッド（119-217行目） |
| 5-2 | hover.rs | `crates/nu-lsp/src/hover.rs` | get_decl_description（11-117行目） |

**主要処理フロー（hover.rs）**:
1. **141-155行目**: Variable - 型と値を表示
2. **156-172行目**: CellPath - セルパスの値と型を表示
3. **173-176行目**: Declaration - コマンドドキュメントを表示
4. **177-185行目**: Module - モジュールコメントを表示
5. **187-215行目**: External - man/helpで情報取得

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

```
LanguageServer::serve_requests()
    │
    ├─ Connection::receiver.recv_timeout()
    │      └─ LSPメッセージ受信
    │
    ├─ Request処理
    │      │
    │      ├─ complete()
    │      │      ├─ new_engine_state()
    │      │      ├─ NuCompleter::new()
    │      │      └─ fetch_completions_at/within_file()
    │      │
    │      ├─ goto_definition()
    │      │      ├─ parse_and_find()
    │      │      │      └─ parse_file() → ast::find_id()
    │      │      ├─ find_definition_span_by_id()
    │      │      └─ get_location_by_span()
    │      │
    │      ├─ hover()
    │      │      ├─ parse_and_find()
    │      │      └─ ID別のホバー情報生成
    │      │
    │      ├─ references()
    │      │      └─ ワークスペース全体検索
    │      │
    │      └─ rename()
    │             └─ occurrences使用
    │
    └─ Notification処理
           └─ publish_diagnostics_for_file()
```

### データフロー図

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

LSPリクエスト ─────────▶  serve_requests     ─────────▶  LSPレスポンス
(JSON-RPC)                │
                          ├─ parse_file()
                          │      └─ nu_parser::parse()
                          │             └─ Block, StateWorkingSet
                          │
                          ├─ parse_and_find()
                          │      └─ ast::find_id()
                          │             └─ Id (Variable/Decl/Module/...)
                          │
                          └─ 機能別処理
                                 ├─ CompletionResponse
                                 ├─ GotoDefinitionResponse
                                 ├─ Hover
                                 └─ Diagnostics
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lib.rs | `crates/nu-lsp/src/lib.rs` | ソース | LanguageServer構造体、メインループ |
| ast.rs | `crates/nu-lsp/src/ast.rs` | ソース | AST解析、find_id |
| completion.rs | `crates/nu-lsp/src/completion.rs` | ソース | コード補完 |
| diagnostics.rs | `crates/nu-lsp/src/diagnostics.rs` | ソース | 診断情報 |
| goto.rs | `crates/nu-lsp/src/goto.rs` | ソース | 定義へのジャンプ |
| hints.rs | `crates/nu-lsp/src/hints.rs` | ソース | インレイヒント |
| hover.rs | `crates/nu-lsp/src/hover.rs` | ソース | ホバー情報 |
| notification.rs | `crates/nu-lsp/src/notification.rs` | ソース | 通知処理 |
| semantic_tokens.rs | `crates/nu-lsp/src/semantic_tokens.rs` | ソース | セマンティックトークン |
| signature.rs | `crates/nu-lsp/src/signature.rs` | ソース | シグネチャヘルプ |
| symbols.rs | `crates/nu-lsp/src/symbols.rs` | ソース | シンボル検索 |
| workspace.rs | `crates/nu-lsp/src/workspace.rs` | ソース | ワークスペース管理 |
