# Terminal Popup Feature

## Overview

The terminal popup feature provides an interactive pseudo-terminal (PTY) interface within the Origami CLI TUI application. This allows users to execute commands that require interactive input (such as entering sudo passwords) directly within the application, without switching to an external terminal.

## Architecture

The terminal popup system consists of three main components:

### 1. PTY Session (`src/terminal/pty.rs`)

The `PtySession` struct manages the pseudo-terminal session:

- **Spawning**: Creates a new PTY with specified dimensions and spawns a command
- **Input/Output**: Handles bidirectional communication with the spawned process
- **Terminal Emulation**: Uses the `vt100` crate to parse and maintain terminal state
- **Process Management**: Tracks process completion and exit codes

**Key Methods:**
```rust
// Create a new PTY session
PtySession::spawn(command: &str, args: &[&str], cols: u16, rows: u16) -> Result<Self>

// Send input to the PTY
send_input(&mut self, data: &[u8]) -> Result<()>

// Get current screen content
get_screen(&self) -> Vec<String>

// Check if process has finished
is_finished(&self) -> bool

// Get exit code
get_exit_code(&self) -> Option<i32>
```

### 2. Terminal Widget (`src/terminal/widget.rs`)

The `TerminalWidget` renders terminal output in the TUI:

- **Rendering**: Displays terminal content with proper formatting
- **Scrolling**: Supports scrolling through terminal output
- **Styling**: Converts VT100 ANSI escape codes to Ratatui styles

**Usage:**
```rust
let widget = TerminalWidget::new(lines)
    .block(Block::default().borders(Borders::ALL))
    .scroll_offset(0);
```

### 3. Terminal Popup (`src/terminal/popup.rs`)

The `TerminalPopup` provides the complete popup interface:

- **State Management**: Tracks whether the process is running or finished
- **Event Handling**: Forwards keyboard input to the PTY
- **Rendering**: Displays the terminal in a centered popup window
- **Lifecycle**: Manages popup opening and closing

**Key Methods:**
```rust
// Create a new popup
TerminalPopup::new(title: String) -> Self

// Start the PTY session
start(&mut self, command: &str, args: &[&str]) -> Result<()>

// Handle keyboard input
handle_key(&mut self, key: KeyEvent) -> Result<bool>

// Render the popup
render(&mut self, frame: &mut Frame, area: Rect)
```

## Integration with System Updates

The terminal popup is integrated into the System Updates module to handle privileged operations:

### Commands Using Terminal Popup:

1. **Apply Updates**: `sudo rpm-ostree upgrade`
2. **Rollback**: `sudo rpm-ostree rollback`
3. **Cleanup Deployments**: `sudo rpm-ostree cleanup -b`
4. **Pin Deployment**: `sudo ostree admin pin 0`
5. **Unpin Deployment**: `sudo ostree admin pin --unpin 0`

### Flow:

1. User selects an action from the System Updates menu
2. For privileged operations, a confirmation dialog is shown
3. Upon confirmation, the view sets `terminal_command` with the command to execute
4. The App detects the pending command and creates a `TerminalPopup`
5. The popup spawns the PTY and displays the interactive terminal
6. User can interact with the command (e.g., enter sudo password)
7. When the command completes, the popup shows the exit status
8. User presses Enter or Esc to close the popup

## Usage Example

### From a View Module:

```rust
// In your view struct
pub struct MyView {
    pub terminal_command: Option<(String, Vec<String>)>,
    // ... other fields
}

// When you need to run a command
fn execute_privileged_command(&mut self) {
    self.terminal_command = Some((
        "sudo".to_string(),
        vec!["some-command".to_string(), "arg1".to_string()],
    ));
}

// Provide a method to take the command
pub fn take_terminal_command(&mut self) -> Option<(String, Vec<String>)> {
    self.terminal_command.take()
}
```

### From the App:

```rust
// In your event handling
if let Some((cmd, args)) = view.take_terminal_command() {
    let mut popup = TerminalPopup::new(format!("Running: {} {}", cmd, args.join(" ")));
    let args_refs: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
    if let Ok(()) = popup.start(&cmd, &args_refs) {
        self.terminal_popup = Some(popup);
    }
}

// In your render method
if let Some(popup) = &mut self.terminal_popup {
    popup.render(frame, frame.area());
}

// In your event handling (before other handlers)
if let Some(popup) = &mut self.terminal_popup {
    if let Event::Key(key) = event::read()? {
        if key.kind == KeyEventKind::Press {
            let should_close = popup.handle_key(key)?;
            if should_close {
                self.terminal_popup = None;
            }
        }
    }
    return Ok(());
}
```

## Keyboard Controls

### While Command is Running:

- **Any character**: Sent to the PTY
- **Ctrl+C**: Send interrupt signal (SIGINT)
- **Ctrl+D**: Send EOF
- **Ctrl+Z**: Send suspend signal
- **Arrow keys**: Sent to the PTY (for command history, etc.)
- **Enter**: Send newline
- **Backspace**: Send delete character
- **Tab**: Send tab character
- **PageUp/PageDown**: Scroll terminal output

### When Command is Finished:

- **Enter**: Close popup
- **Esc**: Close popup
- **q**: Close popup

## Technical Details

### Dependencies:

- **portable-pty** (v0.8.1): Cross-platform PTY implementation
- **vt100** (v0.15.2): VT100 terminal emulator parser

### Terminal Emulation:

The system uses a VT100 parser to handle:
- ANSI escape codes
- Cursor positioning
- Text styling (colors, bold, italic, underline)
- Screen clearing and scrolling

### Thread Safety:

The PTY reader runs in a separate thread to avoid blocking the UI. The terminal state is protected by a `Mutex` and shared via `Arc`.

### Process Management:

- The PTY automatically detects when the child process exits
- Exit codes are captured and displayed to the user
- The popup changes color based on exit status (green for success, red for failure)

## Limitations

1. **Terminal Size**: The terminal size is fixed when the PTY is spawned. Resizing the TUI window won't resize the PTY (though the resize method is available).

2. **Complex TUI Programs**: Programs that use complex terminal features (like ncurses) may not render perfectly.

3. **Signal Handling**: Only basic signals (Ctrl+C, Ctrl+D, Ctrl+Z) are supported.

4. **Scrollback**: Limited to the visible terminal buffer.

## Future Enhancements

Potential improvements for the terminal popup:

1. **Dynamic Resizing**: Automatically resize the PTY when the TUI window is resized
2. **Scrollback Buffer**: Maintain a larger scrollback buffer for long-running commands
3. **Copy/Paste**: Support copying text from the terminal output
4. **Search**: Add search functionality for terminal output
5. **Command History**: Maintain a history of executed commands
6. **Logging**: Save terminal output to a log file
7. **Multiple Terminals**: Support multiple concurrent terminal sessions

## Troubleshooting

### Command Not Starting:

- Ensure the command exists in the system PATH
- Check that you have permission to execute the command
- Verify that PTY support is available on your system

### Sudo Password Not Working:

- Make sure you're using `sudo` as the command, not `pkexec`
- Verify that sudo is configured correctly on your system
- Check that the terminal is properly forwarding input

### Display Issues:

- Some programs may not render correctly in the VT100 emulator
- Try using simpler commands or flags that produce plain text output
- Check the terminal size matches your expectations

## Security Considerations

1. **Password Visibility**: Sudo passwords are handled by the PTY and not visible in the UI (as expected)
2. **Command Injection**: Always validate and sanitize command arguments before passing to the PTY
3. **Privilege Escalation**: Be cautious when running commands with sudo - only use for necessary operations
4. **Output Sanitization**: Terminal output is rendered as-is, so be aware of potential ANSI escape code exploits

## Contributing

When adding new commands that use the terminal popup:

1. Add the command to your view's `terminal_command` field
2. Ensure proper error handling
3. Provide clear user feedback about what the command does
4. Test with various edge cases (command not found, permission denied, etc.)
5. Document the command in your module's documentation
