Skip to Content
アーキテクチャ

アーキテクチャ

概要

ccmux は約 2,800 行の Rust コードで、6 つのモジュールで構成されています:

src/ ├── main.rs # エントリーポイント、イベントループ、panic hook ├── app.rs # ワークスペース/タブ状態、レイアウトツリー、入力処理 ├── pane.rs # PTY 管理、vt100 エミュレーション、シェル検出 ├── ui.rs # ratatui 描画、テーマ、レイアウト ├── filetree.rs # ファイルツリー走査、ナビゲーション └── preview.rs # シンタックスハイライト付きファイルプレビュー

ターミナルエミュレーション

ccmux は vt100 クレートでターミナルエミュレーションを行います(単純な ANSI ストリッピングではありません)。Claude Code はカーソル移動、色、代替スクリーンバッファ、スピナーなどの複雑なターミナル機能を使うため、これが不可欠です。

PTY リーダースレッド メインスレッド ┌──────────────┐ ┌──────────────┐ │ read(PTY) │ │ イベントポーリング │ │ ↓ │ mpsc │ ↓ │ │ vt100.parse()│ ──────→ │ dirty チェック │ │ ↓ │ channel │ ↓ │ │ イベント送信 │ │ UI 描画 │ └──────────────┘ └──────────────┘

各ペインは独自のリーダースレッドを持ち、PTY から読み取ったバイトを vt100::Parser に投入し、mpsc チャネルでメインスレッドに通知します。

レイアウトツリー

ペインレイアウトは二分木で表現されます:

enum LayoutNode { Leaf { pane_id: usize }, Split { direction: Vertical | Horizontal, ratio: f32, // 0.0..1.0 first: Box<LayoutNode>, second: Box<LayoutNode>, }, }

再帰的な分割を自然にサポートし、レイアウト計算が直感的です。ratio フィールドにより、マウスドラッグでペイン境界のリサイズが可能です。

レンダリングパイプライン

  1. dirty フラグチェック — 変更があった時のみ描画(PTY 出力、キー入力、マウスイベント、リサイズ)
  2. レイアウト計算 — 二分木から各ペインの Rect を計算
  3. PTY リサイズ — サイズが変わった時のみ更新(キャッシュ)
  4. セル単位描画 — vt100 スクリーンバッファを読み、ゼロアロケーションで ratatui セルにマッピング
  5. 選択オーバーレイ — 選択テキストに青いハイライトを適用

パフォーマンス

  • バイナリサイズ: 約 2 MB
  • 起動時間: 約 0.5 秒
  • アイドル時 CPU: ほぼ 0%(dirty フラグによる差分描画)
  • セル描画: ゼロアロケーション
  • npm パッケージ: 1.9 KB(バイナリは初回インストール時にダウンロード)
  • スクロールバック: ペインあたり 10,000 行(約 1 MB/ペイン)

OSC 検出

ccmux は bash の PROMPT_COMMAND に OSC 7(カレントディレクトリ通知)を注入します。PTY リーダースレッドが以下のシーケンスを検出します:

  • OSC 7 (\x1b]7;file://HOST/PATH\x07) → ファイルツリーとタブ名を更新
  • OSC 0/2 (\x1b]0;TITLE\x07) → Claude Code の実行を検出(タイトルに “claude” を含む)

依存クレート

クレート用途
ratatui + crosstermTUI フレームワーク + ターミナルバックエンド
portable-ptyクロスプラットフォーム PTY(Windows は ConPTY)
vt100ターミナルエミュレーション
syntectシンタックスハイライト
arboardクリップボードアクセス
unicode-widthCJK 文字幅計算
anyhowエラーハンドリング

セキュリティ

  • OOM 防止 — ファイルプレビューは 10MB 制限、バイナリ判定は 8KB のみ読み取り
  • シンボリックリンク防護 — ファイルツリーでシンボリックリンクをスキップ
  • Mutex poison 回復unwrap_or_else(|e| e.into_inner()) を使用
  • panic hook — クラッシュ時にターミナル状態を復元
  • リソース制限 — 最大 16 ペイン、ディレクトリあたり 500 エントリ
Last updated on