# 帳票設計書 14-grid

## 概要

本ドキュメントは、Nushellの`grid`コマンドの設計仕様を定義する帳票設計書である。このコマンドは、データをグリッド形式でターミナルにレンダリング表示する機能を提供する。

### 本帳票の処理概要

`grid`コマンドは、Nushellのリストやレコードデータを、ターミナル幅に合わせて最適なカラム数で配置したグリッド形式で表示するコマンドである。特に`ls`コマンドの出力に最適化されており、ファイル名を横方向に効率的に並べて表示する。LS_COLORSによる色付けやNerd Fontアイコンの表示にも対応している。

**業務上の目的・背景**：大量のファイル名や短いデータ項目を一覧表示する際、縦長のテーブル形式よりも横方向に並べたグリッド形式の方が視認性が高い場合がある。`grid`コマンドは、`ls`のような従来のUNIXコマンドのグリッド表示に相当する機能を提供し、画面スペースを効率的に活用したデータ表示を実現する。

**帳票の利用シーン**：`ls`出力のコンパクト表示、短いデータ項目の一覧表示、タグやカテゴリの視覚的確認、ファイルシステムのブラウジングに利用される。

**主要な出力内容**：
1. ターミナル幅に最適化されたグリッドレイアウト
2. LS_COLORSに基づくファイルパスの色付け
3. Nerd Fontアイコン付きのファイル表示
4. カスタマイズ可能なセパレータ

**帳票の出力タイミング**：パイプライン内で`grid`コマンドが実行されたとき、入力データがグリッド形式で出力される。

**帳票の利用者**：Nushellユーザー、特にファイル操作を行うユーザー

## 帳票種別

表示出力（Viewer）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Nushellコマンドライン | - | `grid`コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（ANSI装飾付き） |
| 用紙サイズ | N/A（ターミナル幅に依存） |
| 向き | N/A |
| ファイル名 | N/A（標準出力） |
| 出力方法 | 標準出力（ターミナル表示） |
| 文字コード | UTF-8 |

### グリッド表示固有設定

| 項目 | 内容 |
|-----|------|
| デフォルト幅 | 80カラム（ターミナル幅取得失敗時） |
| デフォルトセパレータ | " │ "（パイプ記号両側にスペース） |
| 配置方向 | TopToBottom（上から下、左から右） |
| 色付け | --colorオプションで有効化 |
| アイコン表示 | --iconsオプションで有効化 |

## 帳票レイアウト

### レイアウト概要

グリッドは以下の構造で表示される。

```
┌─────────────────────────────────────────────┐
│ item1 │ item2 │ item3 │ item4 │ item5     │
│ item6 │ item7 │ item8 │ item9 │ item10    │
│ ...   │ ...   │ ...   │ ...   │ ...       │
└─────────────────────────────────────────────┘
```

### コマンドオプション

| No | オプション | 短縮形 | 型 | 説明 |
|----|-----------|-------|-----|------|
| 1 | --width | -w | Int | 出力幅（ターミナルカラム数） |
| 2 | --color | -c | Switch | 色付け表示を有効化 |
| 3 | --icons | -i | Switch | アイコン表示（Nerd Font使用） |
| 4 | --separator | -s | String | グリッドセパレータ文字列 |

### 入力データの処理

| No | 入力型 | 処理方法 | 表示対象 |
|----|--------|---------|---------|
| 1 | Value::List | convert_to_list変換 | 'name'カラムの値 |
| 2 | ListStream | convert_to_list変換 | 'name'カラムの値 |
| 3 | Value::Record | カラム値展開 | 各カラムの値 |
| 4 | その他 | そのまま返却 | - |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 入力データ | リスト、レコード | Yes |
| 'name'カラム | グリッド表示対象 | No（リストの場合は自動生成） |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| - | N/A（入力順序を維持） | - |

### 改ページ条件

N/A（一括出力）

## データベース参照仕様

### 参照テーブル一覧

N/A（入力パイプラインデータを表示）

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| セル幅 | unicode_width_strip_ansi() | - | ANSI除去後のUnicode幅 |
| カラム数 | fit_into_width()で最適化 | - | 幅に収まる最大カラム数 |
| 行数 | cells / columns (切り上げ) | 切り上げ | セル数÷カラム数 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[grid実行] --> B[オプション解析]
    B --> C{入力型判定}
    C -->|Value::List| D[convert_to_list]
    C -->|ListStream| D
    C -->|Value::Record| E[レコード展開]
    C -->|Other| F[そのまま返却]
    D --> G{データあり?}
    E --> G
    G -->|No| H[空データ返却]
    G -->|Yes| I[create_grid_output]
    I --> J[Grid::new作成]
    J --> K{各項目ループ}
    K --> L{header=="name"?}
    L -->|Yes| M{--color?}
    L -->|No| K
    M -->|Yes| N{--icons?}
    M -->|No| O{--icons?}
    N -->|Yes| P[アイコン+色付きセル]
    N -->|No| Q[色付きセル]
    O -->|Yes| R[アイコン付きセル]
    O -->|No| S[プレーンセル]
    P --> T[grid.add]
    Q --> T
    R --> T
    S --> T
    T --> K
    K --> U[fit_into_width]
    U --> V{収まる?}
    V -->|Yes| W[文字列出力]
    V -->|No| X[エラー]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 幅不足 | グリッドがターミナル幅に収まらない | "Couldn't fit grid into N columns" | --widthで幅を指定、またはターミナルを拡大 |
| 値エラー | 入力にエラー値が含まれる | 元のエラーメッセージ | 入力データを確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | メモリに収まる範囲 |
| 目標出力時間 | N/A（データサイズに比例） |
| 同時出力数上限 | 1（シングルパイプライン） |

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

- LS_COLORS環境変数を参照してファイルパスを色付け
- ANSIカラーコードの出力は--colorオプションで制御
- アイコン表示はNerd Fontがインストールされている前提

## 備考

- 'name'カラムを持つテーブルやレコードに最適化されている
- リストの場合は仮想的な'name'カラムが生成される
- nu-term-gridクレートを使用してグリッドレイアウトを計算

---

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

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

### 推奨読解順序

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

グリッドライブラリのCell構造体とGrid構造体を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | grid.rs | `crates/nu-term-grid/src/grid.rs` | Cell構造体（119-129行目） |
| 1-2 | grid.rs | `crates/nu-term-grid/src/grid.rs` | Grid構造体（224-231行目） |
| 1-3 | grid.rs | `crates/nu-term-grid/src/grid.rs` | GridOptions構造体（189-197行目） |

**読解のコツ**: Cellはcontentsとwidthとalignmentからなるシンプルな構造体。Gridは複数のCellを管理し、指定幅に収まるようレイアウトを計算する。

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

処理の起点となるコマンド実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | griddle.rs | `crates/nu-command/src/viewers/griddle.rs` | Griddle構造体のCommand実装（13-177行目） |

**主要処理フロー**:
1. **22-47行目**: シグネチャ定義（width, color, icons, separator）
2. **58-141行目**: run関数（入力型判定、create_grid_output呼び出し）
3. **143-176行目**: examplesによる使用例定義

#### Step 3: グリッド出力処理を理解する

グリッドセルの生成とレイアウト処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | griddle.rs | `crates/nu-command/src/viewers/griddle.rs` | create_grid_output関数（179-270行目） |

**主要処理フロー**:
- **190-198行目**: ターミナル幅とセパレータの決定
- **205-208行目**: Grid::new()でGridOptions設定
- **210-257行目**: 各項目をCellに変換してgrid.add()
- **259-269行目**: fit_into_width()でレイアウト計算

#### Step 4: リスト変換処理を理解する

入力データをグリッド表示用に変換する処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | griddle.rs | `crates/nu-command/src/viewers/griddle.rs` | convert_to_list関数（272-347行目） |

**主要処理フロー**:
- **279-284行目**: ヘッダー抽出
- **286-316行目**: 各行のデータ抽出
- **319-326行目**: 'name'カラムがない場合の仮想ヘッダー生成
- **328-342行目**: インターリーブ形式への変換

#### Step 5: グリッドライブラリの最適化アルゴリズムを理解する

幅に収まる最適なカラム数を計算するアルゴリズムを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | grid.rs | `crates/nu-term-grid/src/grid.rs` | fit_into_width関数（267-272行目） |
| 5-2 | grid.rs | `crates/nu-term-grid/src/grid.rs` | width_dimensions関数（332-402行目） |

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

```
Griddle::run (griddle.rs:58)
    │
    ├─ call.get_flag("width") - 幅取得
    ├─ call.has_flag("color") - 色フラグ
    ├─ call.get_flag("separator") - セパレータ
    ├─ call.has_flag("icons") - アイコンフラグ
    │
    ├─ 入力型判定
    │       │
    │       ├─ Value::List → convert_to_list()
    │       │
    │       ├─ ListStream → convert_to_list()
    │       │
    │       └─ Value::Record → 直接展開
    │
    └─ create_grid_output()
           │
           ├─ get_ls_colors() - LS_COLORS取得
           │
           ├─ Grid::new() - グリッド作成
           │       │
           │       └─ GridOptions { direction, filling }
           │
           ├─ 各項目ループ
           │       │
           │       ├─ header == "name" チェック
           │       │
           │       ├─ --color && --icons → アイコン+色付きセル
           │       ├─ --color → 色付きセル
           │       ├─ --icons → アイコン付きセル
           │       └─ else → プレーンセル
           │       │
           │       └─ grid.add(cell)
           │
           └─ grid.fit_into_width()
                  │
                  └─ Display::to_string()
```

### データフロー図

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

PipelineData ───▶ 型判定
                     │
         ┌──────────┼──────────┐
         ▼          ▼          ▼
     Value::     List        Value::
     Record     Stream       List
         │          │          │
         ▼          ▼          ▼
       直接    convert_to  convert_to
       展開      _list()     _list()
         │          │          │
         └──────────┴──────────┘
                     │
                     ▼
           Vec<(index, header, value)>
                     │
                     ▼
              create_grid_output()
                     │
                     ▼
              Grid::new()
                     │
                     ▼
              各セル追加 (name列のみ)
                     │
                     ├─ 色付け処理 (optional)
                     └─ アイコン追加 (optional)
                     │
                     ▼
              fit_into_width()
                     │
                     ▼
                  Display
                     │
                     ▼
              Value::string() ───▶ PipelineData
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| griddle.rs | `crates/nu-command/src/viewers/griddle.rs` | ソース | gridコマンドの実装 |
| grid.rs | `crates/nu-term-grid/src/grid.rs` | ソース | グリッドレイアウトライブラリ |
| griddle.rs | `crates/nu-command/tests/commands/griddle.rs` | テスト | テストケース |
| devicons (crate) | 外部クレート | 依存 | ファイルアイコン取得 |
| lscolors (crate) | 外部クレート | 依存 | LS_COLORS解析 |
