# 機能設計書 44-セマンティックトークン（範囲） (textDocument/semanticTokens/range)

## 概要

本ドキュメントは、Lua Language Serverにおける範囲指定セマンティックトークン機能（textDocument/semanticTokens/range）の設計仕様を記述する。この機能は、指定された範囲内のトークンのみにセマンティック情報を付与し、パフォーマンスを最適化する。

### 本機能の処理概要

範囲指定セマンティックトークン機能は、クライアントから指定された範囲（通常は現在表示されているビューポート）内のトークンのみを解析し、セマンティック情報を返却する。ファイル全体を処理するfull版と比較して、大規模ファイルでのパフォーマンスが大幅に向上する。

**業務上の目的・背景**：大規模なLuaファイルでは、ファイル全体のセマンティックトークンを計算するとパフォーマンスに影響が出る場合がある。範囲指定版を使用することで、ユーザーが実際に見ている部分のみを処理し、応答性を維持できる。また、スクロール時に追加のトークン情報を段階的に取得することで、スムーズなユーザー体験を提供する。

**機能の利用シーン**：
- 大規模ファイルの編集時（数千行以上）
- スクロール時の段階的トークン取得
- 初期表示時のビューポート内のみのハイライト
- useSemanticByRangeオプション有効時

**主要な処理内容**：
1. クライアントからsemanticTokens/rangeリクエストを受信
2. 指定範囲（range）を内部位置に変換
3. 範囲内のAST要素のみを走査
4. セマンティック情報を生成（full版と同じロジック）
5. LSP形式のトークンデータ配列を返却

**関連システム・外部連携**：
- パーサー（script/parser）からのAST情報
- 型推論エンジン（script/vm）からの型情報
- LSPクライアントとのJSON-RPC通信

**権限による制御**：設定（Lua.semantic.enable等）により動作をカスタマイズ可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 18 | セマンティックトークン（範囲） | 主機能 | 指定範囲のセマンティックトークンを取得する主処理 |

## 機能種別

構文ハイライト拡張 / コードインテリジェンス / パフォーマンス最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| textDocument.uri | string | Yes | 対象ドキュメントのURI | 有効なファイルURIであること |
| range | Range | Yes | 処理対象範囲 | start/endを含む有効な範囲 |

### 入力データソース

- LSPクライアントからのJSON-RPCリクエスト
- ファイルシステム上のLuaソースコード（AST経由）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| data | integer[] | エンコードされたトークン情報の配列 |

トークンデータのエンコード（5つ組の連続）:
- deltaLine: 前のトークンからの行差分
- deltaStartChar: 前のトークンからの文字差分
- length: トークンの長さ
- tokenType: トークンタイプのインデックス
- tokenModifiers: 修飾子のビットマスク

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ textDocument/semanticTokens/rangeメッセージを受信

2. ワークスペース準備確認
   └─ workspace.awaitReady(uri)

3. ドキュメント状態取得
   └─ files.getState(uri)でAST情報を取得

4. 範囲変換
   └─ converter.unpackRange()でLSP範囲を内部位置に変換

5. 範囲内AST走査
   └─ guide.eachSourceBetween(ast, start, finish, callback)

6. トークン分類・生成
   └─ full版と同じCareスイッチで処理

7. エンコード
   └─ buildTokens()で差分エンコード

8. レスポンス返却
   └─ { data: integer[] }を返却
```

### フローチャート

```mermaid
flowchart TD
    A[リクエスト受信] --> B[workspace.awaitReady]
    B --> C[await.sleep 0.0]
    C --> D{ドキュメント状態取得}
    D -->|失敗| E[null返却]
    D -->|成功| F[converter.unpackRange]
    F --> G[core/semantic-tokens.lua呼び出し]
    G --> H{Lua.semantic.enable?}
    H -->|false| I[空配列返却]
    H -->|true| J[guide.eachSourceBetween]
    J --> K[Careスイッチ処理]
    K --> L[コメント処理]
    L --> M[solveMultilineAndOverlapping]
    M --> N[buildTokens]
    N --> O[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-44-01 | 範囲制限 | start〜finish範囲内のソースのみ処理 | 常時 |
| BR-44-02 | コメント範囲チェック | comm.start >= start かつ comm.finish <= finish | コメント処理時 |
| BR-44-03 | full版との共通ロジック | トークン分類はfull版と同一のCareスイッチ使用 | 常時 |

### 計算ロジック

範囲変換:
```lua
local start, finish = converter.unpackRange(state, params.range)
-- start, finishは内部位置（offset）
```

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | null返却 | ドキュメント状態が取得できない | クライアントはfull版にフォールバック |
| - | 空配列返却 | Lua.semantic.enable=false | 空のdata配列を返却 |

### リトライ仕様

リトライは行わない。

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

該当なし（メモリ内処理のみ）

## パフォーマンス要件

- range版はfull版より高速（範囲内のみ処理）
- await.sleep(0.0)で他の処理に譲る
- abortByFileUpdate=trueでファイル更新時キャンセル

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

- 特になし

## 備考

- 機能No.43のセマンティックトークン（full）と同じコアロジックを使用
- capability定義はlegendを共有、range: trueを設定

---

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

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

### 推奨読解順序

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

full版と共通のトークンタイプ・修飾子定義を参照。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | define.lua | `script/proto/define.lua` | TokenTypes/TokenModifiersの定義（full版と共通） |

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

LSPリクエストハンドラを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | provider.lua | `script/provider/provider.lua` | semanticTokens/rangeの登録（1111-1140行目） |

**主要処理フロー**:
1. **1112-1119行目**: capability定義（range: true）
2. **1125-1128行目**: ワークスペース準備とsleep
3. **1129-1132行目**: ドキュメント状態取得
4. **1134行目**: converter.unpackRangeで範囲変換
5. **1135行目**: core/semantic-tokens.lua呼び出し（start, finish引数付き）

#### Step 3: コアロジックを理解する

semantic-tokens.luaのエクスポート関数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | semantic-tokens.lua | `script/core/semantic-tokens.lua` | エクスポート関数（873行目〜）の引数start, finishを確認 |

**主要処理フロー**:
- **873行目**: `return function (uri, start, finish)` - 範囲引数を受け取る
- **894行目**: `guide.eachSourceBetween(state.ast, start, finish, ...)` - 範囲指定走査
- **911行目**: `if start <= comm.start and comm.finish <= finish then` - コメント範囲チェック

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

```
provider.lua (m.register 'textDocument/semanticTokens/range')
    │
    ├─ workspace.awaitReady(uri)
    │
    ├─ await.sleep(0.0)
    │      └─ 他の処理に譲る
    │
    ├─ files.getState(uri)
    │      └─ AST取得
    │
    ├─ converter.unpackRange(state, params.range)
    │      └─ LSP範囲→内部位置変換
    │
    └─ core/semantic-tokens.lua(uri, start, finish)
           │
           ├─ config.get(uri, 'Lua.semantic.enable')
           │
           ├─ guide.eachSourceBetween(ast, start, finish, callback)
           │      └─ 範囲内のソースのみ処理
           │
           ├─ state.comms処理（範囲チェック付き）
           │      └─ start <= comm.start and comm.finish <= finish
           │
           ├─ solveMultilineAndOverlapping()
           │
           └─ buildTokens()
```

### データフロー図

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

LSPリクエスト             provider.lua
  ├─ uri                  ├─ workspace.awaitReady()
  └─ range        ───▶    ├─ files.getState()
     ├─ start             └─ converter.unpackRange()
     └─ end                        │
                                   ▼
                        (start, finish) 内部位置
                                   │
                                   ▼
                          semantic-tokens.lua
                          guide.eachSourceBetween(ast, start, finish)
                                   │
                          ┌────────┴────────┐
                          ▼                 ▼
                    範囲内ソース       範囲内コメント
                          │                 │
                          └────────┬────────┘
                                   ▼
                            buildTokens()
                                   │
                                   ▼                    { data: integer[] }
                          LSPレスポンス ────────────▶   [deltaLine, deltaChar, ...]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| provider.lua | `script/provider/provider.lua` | ソース | LSPリクエストハンドラの登録・実行 |
| semantic-tokens.lua | `script/core/semantic-tokens.lua` | ソース | セマンティックトークン生成（full/range共通） |
| define.lua | `script/proto/define.lua` | ソース | TokenTypes/TokenModifiersの定義 |
| converter.lua | `script/proto/converter.lua` | ソース | 位置・範囲変換（unpackRange） |
| files.lua | `script/files.lua` | ソース | ファイル管理・状態取得 |
| guide.lua | `script/parser/guide.lua` | ソース | AST範囲走査（eachSourceBetween） |
