# 機能設計書 57-範囲トークン

## 概要

本ドキュメントは、clojure-lspにおける範囲トークン（Semantic Tokens Range）機能の設計を記述する。この機能はLSPプロトコルの`textDocument/semanticTokens/range`リクエストを実装し、指定された範囲のみのセマンティックトークンを取得する。

### 本機能の処理概要

**業務上の目的・背景**：
大きなファイルに対してセマンティックトークン全体を取得すると、処理時間とメモリ使用量が増大する。エディタが表示している範囲のみのトークンを取得することで、パフォーマンスを最適化できる。特にスクロール時や部分的な再描画時に、この最適化が効果を発揮する。

**機能の利用シーン**：
1. エディタがファイルの一部を表示している場合
2. スクロール時に新しく表示された範囲のハイライト取得
3. 大きなファイルの初期表示時の高速化
4. 部分的な編集後の再描画最適化

**主要な処理内容**：
1. 指定範囲情報を受信
2. 解析データから範囲内の要素のみをフィルタ
3. フィルタされた要素をトークンに変換
4. 相対位置エンコードして返却

**関連システム・外部連携**：
- 構文ハイライト機能（No.56）：同じトークン変換ロジックを共有
- LSPクライアント（エディタ）：範囲指定とトークンの適用

**権限による制御**：
`semantic-tokens?`設定で機能を有効/無効化可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | エディタ | 主画面 | 表示範囲のハイライト |

## 機能種別

情報表示処理 / データ変換処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | string | Yes | 対象ドキュメントのURI | 有効なファイルURI形式 |
| range.start.line | integer | Yes | 範囲開始行（0始まり） | 0以上の整数 |
| range.start.character | integer | Yes | 範囲開始列（0始まり） | 0以上の整数 |
| range.end.line | integer | Yes | 範囲終了行（0始まり） | 0以上の整数 |
| range.end.character | integer | Yes | 範囲終了列（0始まり） | 0以上の整数 |

### 入力データソース

- LSPクライアントからの`textDocument/semanticTokens/range`リクエスト
- 解析データ（db.analysis）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | array<integer> | 相対位置エンコードされたトークン配列 |

### 出力先

LSPクライアントへのレスポンス

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ textDocument/semanticTokens/rangeを受信
2. 範囲情報構築
   └─ LSP位置から内部形式に変換
3. 解析データ取得
   └─ URIに対応するbucket情報を取得
4. 範囲フィルタ
   └─ element-inside-range?で範囲内要素のみ抽出
5. トークン変換
   └─ elements->absolute-tokensで変換
6. 相対位置変換
   └─ absolute-tokens->relative-tokensで変換
7. レスポンス返却
```

### フローチャート

```mermaid
flowchart TD
    A[semanticTokens/range受信] --> B[範囲情報構築]
    B --> C[解析データ取得]
    C --> D[各bucketを処理]
    D --> E[element-inside-range?でフィルタ]
    E --> F[elements->absolute-tokens]
    F --> G[absolute-tokens->relative-tokens]
    G --> H[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-57-01 | 範囲判定 | 要素のname-row/name-end-rowが範囲内に収まるかで判定 | 常時 |
| BR-57-02 | トークン変換共有 | full-tokensと同じトークン変換ロジックを使用 | 常時 |
| BR-57-03 | #_ノード非対応 | 範囲トークンでは#_ノードのトークンは生成しない | 常時 |

### 計算ロジック

**範囲内判定**:
```clojure
(defn element-inside-range?
  [{element-row :name-row element-end-row :name-end-row}
   {:keys [name-row name-end-row]}]
  (and (>= element-row name-row)
       (<= element-end-row name-end-row)))
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 解析データ取得 | db.analysis | SELECT | 対象URIのbucket情報を取得 |

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

#### db.analysis

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 全buckets | uri = 対象URI | フィルタは取得後に実行 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | タイムアウト | 変更待機超過 | エラーレスポンス返却 |
| - | キャンセル | クライアントキャンセル | 処理中断 |

### リトライ仕様

リトライは行わない。

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

読み取り専用のため、トランザクション管理は不要。

## パフォーマンス要件

- 範囲指定により、full-tokensより高速に応答
- スクロール時に呼び出されるため、数十ミリ秒以内を目標

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

- 特になし

## 備考

- `semantic-tokens-provider`の`:range true`設定でこの機能を有効化
- full-tokensと異なり、#_（uneval）ノードのトークンは生成されない

---

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

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

### 推奨読解順序

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

範囲トークンの入力データ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | **470-476行目**: 範囲パラメータの構造 |

**読解のコツ**: 範囲はname-row/name-col/name-end-row/name-end-col形式の内部マップに変換される。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | server.clj | `cli/src/clojure_lsp/server.clj` | **396-401行目**: semanticTokens/rangeハンドラ |
| 2-2 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | **463-477行目**: semantic-tokens-range関数 |

**主要処理フロー**:
1. **396-401行目**: `textDocument/semanticTokens/range`リクエストを受信
2. **464行目**: 対象URIを取得
3. **470-471行目**: 開始位置を1始まりに変換
4. **472-475行目**: 範囲情報を構築
5. **476行目**: `f.semantic-tokens/range-tokens`を呼び出し

#### Step 3: 範囲トークン生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | semantic_tokens.clj | `lib/src/clojure_lsp/feature/semantic_tokens.clj` | **265-272行目**: `range-tokens`関数 |

**主要処理フロー**:
- **267行目**: URIに対応するbucketsを取得
- **268-270行目**: bucketsから各要素を抽出し、範囲内要素をフィルタ
- **271行目**: `elements->absolute-tokens`でトークン変換
- **272行目**: `absolute-tokens->relative-tokens`で相対位置変換

#### Step 4: 範囲フィルタを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | semantic_tokens.clj | `lib/src/clojure_lsp/feature/semantic_tokens.clj` | **62-66行目**: `element-inside-range?`関数 |

**主要処理フロー**:
- **63行目**: 要素のname-rowとname-end-rowを取得
- **64行目**: 範囲のname-rowとname-end-rowを取得
- **65-66行目**: 要素の行範囲が範囲内に収まるか判定

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

```
textDocument/semanticTokens/range (server.clj:396-401)
    │
    ├─ handler/semantic-tokens-range (handlers.clj:463-477)
    │      │
    │      └─ f.semantic-tokens/range-tokens (semantic_tokens.clj:265-272)
    │             │
    │             ├─ element-inside-range? (semantic_tokens.clj:62-66)
    │             │
    │             ├─ elements->absolute-tokens (semantic_tokens.clj:174-207)
    │             │
    │             └─ absolute-tokens->relative-tokens (semantic_tokens.clj:230-235)
    │
    └─ conform-or-log
```

### データフロー図

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

semanticTokens/range       ┌──────────────────────────────────┐
Request                    │                                  │
  ├─ uri ─────────────────►│  range-tokens                    │
  └─ range ───────────────►│                                  │
       ├─ start            │    ├─ 範囲情報構築              │
       └─ end              │    │    └─ [name-row, name-col, │
                           │    │        name-end-row,        │
                           │    │        name-end-col]        │
db.analysis                │    │                             │
  └─ buckets ─────────────►│    ├─ element-inside-range?     │
       ├─ var-usages       │    │    └─ 範囲内要素のみ抽出   │
       ├─ var-definitions  │    │                             │
       └─ ...              │    ├─ elements->absolute-tokens │         {data: [...]}
                           │    │                             │────────►
                           │    └─ absolute->relative変換    │
                           │                                  │
                           └──────────────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| server.clj | `cli/src/clojure_lsp/server.clj` | ソース | LSPサーバーハンドラ定義 |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | 各機能のハンドラ実装 |
| semantic_tokens.clj | `lib/src/clojure_lsp/feature/semantic_tokens.clj` | ソース | Semantic Tokensの実装 |
| semantic_tokens_test.clj | `lib/test/clojure_lsp/feature/semantic_tokens_test.clj` | テスト | Semantic Tokensのテスト |
