自作ターミナル
自作ターミナル
https://github.com/o2sh/miro
https://zenn.dev/moutend/articles/72a6cd3db1ee93222317
AIと共にでもやる気にならない大変さやなmrsekut.icon
学習としては良さそうだが
claude code.icon
自作ターミナルエミュレータの概要
全体像
ターミナルエミュレータは見た目以上に複雑なソフトウェアです。主に以下のレイヤーで構成されます。
1. PTY (擬似端末) レイヤー
OSのptyを使ってシェル(zsh等)のプロセスを起動・管理する
stdin/stdout/stderrのストリームを中継する
macOSではforkpty()やposix_openpt()を使う
難易度: 中 — APIは枯れているが、エッジケースが多い
2. VT/ANSIエスケープシーケンスパーサー
これが最も大変な部分
\x1b[31m(赤文字)のような制御シーケンスを解釈する
対応すべき仕様: VT100, VT220, xterm, SGR(色・装飾), CSI, OSC, DCS...
カーソル移動、スクロール領域、代替スクリーンバッファなど数百のシーケンス
vim, tmux, htop, lessなどが正しく動くには高い互換性が必要
難易度: 非常に高 — 仕様が膨大で、実質的に「既存ターミナルの挙動に合わせる」必要がある
3. テキストレンダリング
等幅フォントでのグリッド描画
Unicode対応(CJK全角文字、絵文字、合字、結合文字)
リガチャ対応(Fira Codeなど)
GPU描画(Metal/OpenGL/Vulkan)で60fps以上
難易度: 高 — 特にUnicode幅の計算とGPUレンダリング
4. GUI シェル(ウィンドウ・タブ・UI)
タブ管理、分割ペイン
Cmd+T、Cmd+Shift+T(タブ復元)などのキーバインド
設定画面、検索バーなど
macOSならSwiftUI/AppKit、クロスプラットフォームなら別の選択肢
難易度: 中〜高
5. セッション管理・永続化
ウィンドウを閉じても復元できるようにセッションを永続化
実行中のプロセス検知(閉じる前の警告)
PTYの出力バッファの保存・復元
難易度: 中
6. プログラマブルAPI / 設定システム
WezTermのようにLua/TOML等で全設定を記述可能にする
外部からタブ操作ができるIPC/API
難易度: 中
工数感の目安
table:_
アプローチ 期間目安 備考
VTパーサーを自作、GPU描画も自作 1〜数年 (フルタイム) Alacritty, Kittyがこれ
既存VTパーサーライブラリを使う 6ヶ月〜1年 現実的な選択肢
既存ターミナルをフォークして改造 1〜3ヶ月 最速だが自由度に制約
現実的な戦略
VTパーサーを自作しないのが最も重要な判断です。以下のような既存資産を活用できます。
libvterm — C製のVTパーサー。neovimが使っている
vte (Rust) — Alacrittyのパーサー部分
xterm.js — Web技術ベースで作るなら(VSCodeのターミナルがこれ)
推奨技術スタック (macOS向け)
code:_
Swift + AppKit/SwiftUI — GUI、タブ、ウィンドウ管理
├── libvterm or 自作パーサー — VTエスケープシーケンス解釈
├── Metal (CoreText) — テキスト描画
└── POSIX pty — シェルプロセス管理
または Rust で:
code:_
Rust — コア
├── vte (crate) — VTパーサー
├── wgpu or Metal — GPU描画
└── winit + UI層 — ウィンドウ管理
既存ターミナルの参考になるソースコード
table:_
名前 言語 特徴
Alacritty Rust GPUレンダリング、シンプル
Kitty C + Python 高機能、GPU描画
WezTerm Rust Lua設定、API、タブ管理
Ghostty Zig 最新。libghosttyとしてコア分離
特にGhosttyはコア(VTパーサー+レンダリング)をライブラリとして分離する設計なので、アーキテクチャの参考になります。
まとめ
一番大変なのはVTパーサーとテキストレンダリング。ここを既存ライブラリに任せれば、残りは「普通のGUIアプリ開発」に近づく
やりたい機能(タブ復元、セッション永続化、API)はGUI/セッション層の話なので、コアさえあれば実装自体は素直
既存パーサーライブラリ活用 + macOS AppKitでGUI、という構成なら個人でも数ヶ月で「vimが動く」レベルまで到達可能
もう少し具体的に掘り下げる
まず最初に動くものを作るまでのステップ
Phase 1: 最小限のターミナル (1〜2週間)
1. PTYを開いてzshを起動する
2. キー入力をPTYに送る
3. PTYの出力をそのままウィンドウに描画する(エスケープシーケンス無視)
4. → これだけでlsやechoは動く
Phase 2: VTパーサー統合 (2〜4週間)
1. 既存パーサー(vteやlibvterm)を組み込む
2. セルグリッド(行×列のバッファ)を構築
3. 色・太字・下線などの属性を反映
4. → git log --onelineが色付きで表示される
Phase 3: まともなレンダリング (2〜4週間)
1. CoreText/Metalでグリッドを描画
2. CJK全角文字の幅計算
3. スクロールバック(履歴バッファ)
4. 選択・コピペ
5. → vim, htop, tmuxが動くようになる
Phase 4: タブ・UI・独自機能 (ここからが本番)
1. タブ管理、Cmd+T / Cmd+W
2. セッション永続化
3. 設定システム・API
4. → 「自分のターミナル」になる
技術選択の分岐点
言語の選択
table:_
選択肢 メリット デメリット
Swift macOS UIが自然に書ける。AppKit/SwiftUIがネイティブ クロスプラットフォーム不可。VTパーサーのエコシステムが薄い
Rust vte, wgpu等のエコシステムが充実。WezTermの実績 macOS UIを作るのがやや面倒(objc2クレート等が必要)
Zig Ghosttyの実績。C互換で既存ライブラリを使いやすい エコシステムがまだ若い
Swift + Rust Swiftで UI、RustでVTパーサー+コア FFI境界の設計が必要
個人的には**Swift(UI層) + Rust(コア)**か、Rust一本が現実的です。
最大限楽をする構成
核心は「自分で書くのはGUI層と独自機能だけ」にすること。
各レイヤーで使える既存ライブラリ
table:_
レイヤー 自作しない。これを使う 備考
VTパーサー libvterm or vte (Rust crate) 最も工数が浮く部分
PTY管理 portable-pty (Rust crate) WezTerm作者が作ったcrate。fork/exec/resizeを抽象化
テキスト描画 SwiftUI/AppKit の標準TextView or CoreText GPU描画は後回し
フォント処理 OS標準 (CoreText) リガチャ・fallbackもOS任せ
Unicode幅 unicode-width (Rust crate) WCAGの幅テーブル
設定ファイル toml or mlua (Rust crate) TOML or Lua
IPC/API tonic (gRPC) or Unix domain socket 外部からのタブ操作用
一番楽な技術スタック
code:_
Swift (AppKit/SwiftUI) — UI全体
└── libvterm (C library) — VTパーサー + セルグリッド管理
└── portable-pty相当をSwiftで薄くラップ — PTY管理
なぜSwift一本が最も楽か:
macOS専用でいいなら、AppKitのタブ・ウィンドウ管理がそのまま使える
NSTabViewControllerでタブ、NSWindow.tabbingModeでネイティブタブ
NSSavePanel, NSAlert等のシステムダイアログもそのまま
Cmd+T等のキーバインドはmacOSが標準で提供
libvtermはCライブラリなのでSwiftからそのまま呼べる
もう一つの選択肢: Rust (WezTerm資産の活用)
WezTermは各コンポーネントを独立crateとして公開しています:
code:toml
dependencies
vte = "0.13" # VTエスケープシーケンスパーサー
portable-pty = "0.8" # PTY管理
termwiz = "0.22" # ターミナルUI抽象(セルグリッド、色、属性)
unicode-width = "0.1" # Unicode幅計算
termwizが特に強力で、セルグリッド・色・属性・表面(Surface)バッファまで全部やってくれます。つまりVTパーサーの出力をグリッドに変換する部分も自作不要。
実質的に自分が書くもの
既存ライブラリを最大限使うと、自分で書くのは:
code:_
1. ウィンドウ・タブのUIレイアウト — AppKit or egui
2. グリッドバッファ → 画面への描画 — CoreText or egui
3. キーバインド設定の読み込み・適用
4. セッション永続化 (JSON保存/復元)
5. IPC API (Unix socket)
6. 設定ファイルのパース・ホットリロード
これは普通のGUIアプリ開発の範囲です。
最速プロトタイプ: Electron/Tauri + xterm.js