型・トレイト関係図
この章は現行コードの索引用リファレンスとして使う想定で、 「頻出する型がどの crate に属し、何を所有しているか」を中心に整理している。
先に押さえる 3 点
- 通信の境界は
protocolcrate のClientMessage/ServerMessage - 表示の境界は
terminalcrate のGrid - UI 状態の境界は
clientcrate のPaneStore
この 3 つだけ先に頭に入れておくと、他の型の位置づけが追いやすい。
yatamux-protocol
ワイヤを流れる型だけを置く crate。
WorkspaceId(u32)
SurfaceId(u32)
PaneId(u32)
TermSize { cols, rows }
SplitDirection { Horizontal | Vertical }
PaneInfo {
id,
surface,
title,
cols,
rows,
}
CursorInfo {
col,
row,
visible,
}
PaneCapture {
title,
cols,
rows,
lines_requested,
scrollback_len,
cursor,
visible_text,
scrollback_tail,
}
ClientMessage
CreateWorkspace { name }
CreateSurface { workspace }
CreatePane { surface, split_from, direction, size, working_dir }
Input { pane, data }
Resize { pane, size }
ClosePane { pane }
RequestScreen { pane }
Detach
ListPanes
CapturePane { pane, lines, plain_text }
ServerMessage
WorkspaceCreated { id, name }
SurfaceCreated { id, workspace }
PaneCreated { id, surface, split_from?, direction? }
Output { pane, data: Arc<[u8]> }
TitleChanged { pane, title }
Notification { pane, body }
ClipboardWrite { pane, data }
PaneClosed { pane }
CommandFinished { pane, exit_code? }
Error { message }
PanesListed { panes }
PaneContent { pane, content, capture? }
yatamux-terminal
端末エミュレーションのコア。
CjkWidthConfig
TerminalSink
grid: Arc<Mutex<Grid>>
parser: vte::Parser
fn feed(&mut self, data) -> Option<Vec<u8>>
Grid
cols / rows
cells
cursor: CursorPos
dirty
saved_main
scroll_top / scroll_bottom
scrollback
width_config
CursorPos { col, row }
Cell
content: CellContent
style: CellStyle
CellContent
Grapheme { text, width }
Continuation
Empty
CellStyle
fg, bg, bold, italic, underline, reverse, dim ...
PTY 関連
PtySession
fn spawn(size, shell, output_tx, working_dir)
fn write(&mut self, data)
fn resize(&mut self, size)
fn take_child()
fn clone_child_killer()
VT 関連
VtProcessor<'a>
grid: &'a mut Grid
current_style
title
notification
clipboard_data
command_finished
bell
→ impl vte::Perform
ここで通知やクリップボードまで抜いているのが、現在の terminal crate の特徴だ。
yatamux-server
セッション階層と PTY ライフサイクルを管理する。
Server
workspaces: HashMap<WorkspaceId, Workspace>
surfaces: HashMap<SurfaceId, Surface>
panes: HashMap<PaneId, Pane>
next_*_id
width_config: CjkWidthConfig
client_tx: Sender<ServerMessage>
pane_output_rx / tx
pane_event_rx / tx
セッションモデル
Workspace
id
name: Arc<str>
surfaces: Vec<SurfaceId>
active_surface
Surface
id
workspace
pane_tree: Option<PaneTree>
active_pane
PaneTree
Leaf(PaneId)
Split { direction, ratio, first, second }
ペイン
Pane
id
grid: Arc<tokio::sync::Mutex<Grid>>
cmd_tx: Sender<PtyCmd>
title: Arc<std::sync::Mutex<Arc<str>>>
size: Arc<std::sync::Mutex<TermSize>>
child_killer
PtyCmd
Input(Vec<u8>)
Resize(TermSize)
PaneEvent
Notification(String)
Bell
ProcessExited
CommandFinished(Option<i32>)
Pane は server 内部型であり、protocol crate には出てこない。
yatamux-client
UI と描画を担当する crate。
レイアウト関連
LayoutNode
Leaf(PaneId)
Split { direction, ratio, first, second }
PaneRect { x, y, w, h }
Direction { Left, Right, Up, Down }
LayoutPreview
node: LayoutNode
commands: Vec<Option<String>>
LauncherState
entries: Vec<(String, Option<LayoutPreview>)>
selected
ThemeLauncherState
entries: Vec<String>
selected
PaneStore
PaneStore
grids: HashMap<PaneId, Arc<Mutex<Grid>>>
layout: LayoutNode
active: PaneId
pending_clipboard: Option<Vec<u8>>
pending_toasts: VecDeque<Toast>
scroll_offset: usize
floating: Option<PaneId>
floating_visible: bool
pre_float_active: Option<PaneId>
should_quit: bool
launcher: Option<LauncherState>
copy_mode: Option<CopyState>
normal_selection: Option<(usize, usize, usize, usize)>
save_prompt: Option<String>
theme_launcher: Option<ThemeLauncherState>
pane_commands: HashMap<PaneId, String>
UI 補助型
CopyState
cursor: (usize, usize)
anchor: Option<(usize, usize)>
Toast
pane_id
message
elapsed_ms
セッション永続化
LayoutNodeDef
Leaf { id }
Split { direction, ratio, first, second }
LayoutSnapshot
root: LayoutNodeDef
active: PaneId
LayoutNode は描画時の実体、LayoutNodeDef は保存時の鏡像型という関係だ。
Win32 側の実行状態
ClientState
panes: Arc<Mutex<PaneStore>>
ime: ImeHandler
msg_tx
split_tx
float_tx
layout_tx
active_toasts
content_rect
app_focused
native_notif_queue
mode: Cell<ClientMode>
theme: Cell<WinTheme>
ClientMode
Normal
Pane
Copy
ルート crate (src/)
workspace を束ねる型はここにある。
AppConfig
hooks: HooksConfig
appearance: AppearanceConfig
HooksConfig
on_pane_created
on_pane_closed
AppearanceConfig
font_family
font_size
background
foreground
cursor
selection_bg
status_bar_bg
起動と bridge
BootstrapHandles
client_tx
server_rx
ipc_out_tx
surf_id
pane_id
BridgeEvent
PaneOutput
PaneCreated
PaneClosed
UserNotification
CommandFinished
所有関係の最重要ポイント
server の Grid と client の Grid は別インスタンスで、
client 側は TerminalSink が PTY 生データを再適用して画面を保っている。
この点は monolith 的に 1 つの Grid を共有していた時期の説明と混同しやすいので注意したい。
型の追い方
実装を読むときは、次の順序が分かりやすい。
protocolのメッセージ型を確認するserver::handle_client_message()で入口を見るpane.rsとterminalcrate で PTY と Grid の更新を見るapp/bridge.rsで GUI 側への反映を見るclient::windowで描画と入力を見る
この順に追うと、workspace 分割されていても迷いにくい。