Skip to content

fix: paste not working in PTY sessions #88

@inureyes

Description

@inureyes

Problem / Background

When using PTY mode for SSH sessions, clipboard paste operations (Cmd+V on macOS / Ctrl+V on Linux/Windows) do not work. Users cannot paste text from their clipboard into the interactive SSH session.

Root Cause Analysis

The issue stems from two related problems in the PTY input handling:

  1. Missing Event::Paste handler (src/pty/session/input.rs, line 42)

    • The handle_input_event() function has a catch-all _ => None pattern that silently ignores Event::Paste events from crossterm
    • Even when bracketed paste is enabled, paste events are discarded
  2. Bracketed Paste not enabled (src/pty/terminal.rs)

    • crossterm::event::EnableBracketedPaste is not called during terminal initialization in TerminalStateGuard::new()
    • Without bracketed paste mode, the terminal cannot properly distinguish paste operations from rapid keystrokes
    • DisableBracketedPaste is also not called in the Drop implementation for cleanup
  3. No fallback for rapid keystroke paste

    • Even without bracketed paste, some terminals send pasted text as rapid key events, but the current implementation doesn't handle this case efficiently

Proposed Solution

1. Enable Bracketed Paste Mode

In src/pty/terminal.rs, modify TerminalStateGuard::new():

use crossterm::event::{EnableBracketedPaste, DisableBracketedPaste};

// In new():
execute!(std::io::stdout(), EnableBracketedPaste)?;

// In Drop or restore_terminal_state():
execute!(std::io::stdout(), DisableBracketedPaste)?;

2. Handle Event::Paste in input handler

In src/pty/session/input.rs, add a new match arm before the catch-all:

Event::Paste(text) => {
    let bytes = text.into_bytes();
    Some(SmallVec::from_slice(&bytes))
}

Note: For large paste content exceeding SmallVec<[u8; 8]> capacity, consider using a Vec<u8> return type or returning an enum that can handle both small and large payloads efficiently.

Acceptance Criteria

  • EnableBracketedPaste is activated in TerminalStateGuard::new()
  • DisableBracketedPaste is called during terminal state restoration (Drop)
  • Event::Paste(text) is handled in handle_input_event() and text is sent to SSH channel
  • Paste operations work correctly on macOS (Cmd+V), Linux (Ctrl+Shift+V), and Windows (Ctrl+V)
  • Large paste content (>8 bytes) is handled without truncation
  • Terminal state is properly restored after session ends (bracketed paste disabled)
  • Unit tests added for paste event handling

Technical Considerations

  • SmallVec capacity: The current SmallVec<[u8; 8]> may not be sufficient for paste operations. Consider:

    • Increasing capacity (e.g., SmallVec<[u8; 64]>)
    • Using Cow<'static, [u8]> for zero-copy small sequences
    • Changing return type to Vec<u8> for paste events specifically
  • Performance: Paste operations can involve large amounts of text. Ensure efficient memory handling to avoid unnecessary allocations.

  • Security: Be aware of paste-jacking attacks. Consider adding optional paste confirmation for multi-line or large pastes in future iterations.

Affected Files

  • src/pty/terminal.rs - Enable/disable bracketed paste mode
  • src/pty/session/input.rs - Handle Event::Paste events

Additional Context

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions