Skip to content

[Linux] VTE terminal pane + tmux attachment #134

@2witstudios

Description

@2witstudios

Overview

Implement VTE-based terminal panes that attach to tmux sessions, matching the macOS app's TerminalPane.swift + ScrollableTerminalView.swift.

Terminal Attachment Flow

Exactly mirrors macOS — VTE spawns a shell that creates a grouped tmux session:

let cmd = format!(
    "if [ -x /usr/libexec/path_helper ]; then eval $(/usr/libexec/path_helper -s); fi; \
     [ -f ~/.zprofile ] && source ~/.zprofile; \
     [ -f ~/.zshrc ] && source ~/.zshrc; \
     tmux set-option -t '{}' status off 2>/dev/null; \
     exec tmux new-session -t '{}' -s '{}' \
       \; set-option destroy-unattached on \
       \; set-option status off \
       \; set-option mouse on \
       \; select-window -t ':{}'",
    tmux_target, session_name, view_session_name, window_index
);

terminal.spawn_async(
    vte::PtyFlags::DEFAULT,
    Some(&working_dir),
    &["/bin/zsh", "-c", &cmd],
    &[], SpawnFlags::DEFAULT, -1,
    None::<&gio::Cancellable>,
    |_| {}
);

The -t <session> flag creates a "grouped" session that shares windows with the original ppg session but has independent window selection — this is critical so each terminal view can show a different agent without affecting others.

The view session name format: <session>-view-<agentId>-<4random> with destroy-unattached so it auto-cleans when the terminal closes.

VTE Configuration

  • Font: from AppSettings (default "Monospace 13")
  • Colors: match theme (dark/light adaptive)
    • Background: #1a1b26 (dark), #f8f8f2 (light)
    • Foreground: #c0caf5 (dark), #383a42 (light)
    • 16-color ANSI palette matching macOS app's Theme.terminalColors
  • Mouse: enabled for tmux interaction
  • Scrollback: from AppSettings history_limit
  • Allow bold, cursor blink

Scroll Handling

VTE handles mouse scroll natively when tmux's alternate screen is active (for vim/less/etc.), unlike macOS SwiftTerm which needed manual mouse button 4/5 escape sequence forwarding. VTE's built-in scroll should work correctly.

Drag and Drop

Accept file URL drops → shell-escape the path → terminal.feed_child() to send the text.

Lazy Creation

Only create the VTE terminal when the pane is actually visible (similar to macOS viewDidMoveToWindow pattern). Use gtk::Widget::connect_map signal.

Teardown

On pane close: the view session auto-destroys (via destroy-unattached). Call terminal.reset() and drop the widget.

References

  • macOS: PPG CLI/PPG CLI/TerminalPane.swift (tmux attachment)
  • macOS: PPG CLI/PPG CLI/ScrollableTerminalView.swift (VT100 rendering, scroll, theme)

Acceptance Criteria

  • VTE terminal spawns and attaches to tmux session
  • Shows live agent output with correct ANSI colors
  • Keyboard input works (types into tmux)
  • Mouse scroll works in both normal mode and alternate screen (vim/less)
  • Font and colors update from settings
  • Terminal tears down cleanly when pane closes
  • View session auto-destroys via destroy-unattached

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions