Skip to content

Commit 63d8481

Browse files
authored
fix: Terminal escape sequence responses displayed on first prompt when starting tmux (#90)
* fix: Replace crossterm event parsing with raw stdin reading to prevent terminal escape sequence corruption When running tmux inside bssh PTY sessions, terminal escape sequence responses (DA1, DA2, DA3, XTGETTCAP) were appearing as raw text on the first prompt. This occurred because crossterm::event::read() parses escape sequences, consuming the ESC byte (0x1b) and corrupting terminal responses. Solution: - Keep using crossterm for terminal mode management (enable_raw_mode/disable_raw_mode) - Replace crossterm::event::read() with direct stdin.read() using nix::poll for polling - Add RawInputReader module for transparent byte passthrough - Add LocalEscapeDetector for OpenSSH-style ~. disconnect handling Changes: - Add nix crate dependency with poll feature - Create src/pty/session/raw_input.rs: Raw byte input reader - Create src/pty/session/local_escape.rs: Local escape sequence detector - Modify session_manager.rs: Use RawInputReader instead of crossterm event parsing - Update mod.rs: Include new modules This approach matches OpenSSH's behavior, providing transparent passthrough of all bytes including terminal responses, arrow keys, function keys, and other escape sequences. Fixes #87 * docs: Add PTY escape sequence documentation for ~. disconnect * fix: Address code review feedback - improve safety docs and suppress dead code warnings * update: cargo fmt * fix: Correct doc comment overindentation in raw_input.rs Fix clippy doc_overindented_list_items warning by reducing indentation of continued list item text from 14 to 2 spaces. * feat: Add comprehensive unit tests for PTY session modules Add missing test coverage for PTY-related modules: - RawInputReader: 10 new tests for poll timeout clamping, boundary conditions (u16::MAX), and duration handling - TerminalModes: 18 new tests verifying control characters, signal generation, canonical mode, echo, baud rates, flow control, and mode completeness - LocalEscapeDetector: 19 new edge case tests for buffer boundaries, CR/LF handling, Unicode, and state transitions - EscapeSequenceFilter: 32 new tests for buffer boundaries, consecutive sequences, OSC/DCS filtering, and stress scenarios Total: 79 new tests, 858 lines of test code added.
1 parent 3c4b1a7 commit 63d8481

11 files changed

Lines changed: 1353 additions & 22 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ regex = "1.12.2"
4343
lazy_static = "1.5"
4444
ctrlc = "3.5.1"
4545
signal-hook = "0.3.18"
46+
nix = { version = "0.29", features = ["poll"] }
4647
atty = "0.2.14"
4748
arrayvec = "0.7.6"
4849
smallvec = "1.15.1"

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ bssh -o StrictHostKeyChecking=no user@host
101101
bssh -Q cipher
102102
```
103103

104+
**PTY Session Escape Sequences:**
105+
106+
Like OpenSSH, bssh supports escape sequences in PTY sessions. These must be typed at the beginning of a line (after pressing Enter):
107+
108+
| Escape | Description |
109+
|--------|-------------|
110+
| `~.` | Disconnect from the remote host |
111+
104112
### Port Forwarding
105113
```bash
106114
# Local port forwarding (-L)

src/pty/session/constants.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,32 @@
1313
// limitations under the License.
1414

1515
//! Terminal constants and key sequence definitions
16+
//!
17+
//! NOTE: Many key sequence constants are currently unused since we switched to
18+
//! raw byte passthrough (see issue #87), but are kept for reference and potential
19+
//! future debugging use.
20+
21+
// Allow dead code for unused key sequence constants
22+
#![allow(dead_code)]
1623

1724
// Buffer size constants for allocation optimization
1825
// These values are chosen based on empirical testing and SSH protocol characteristics
1926

2027
/// Maximum size for terminal key sequences (ANSI escape sequences are typically 3-7 bytes)
2128
/// Value: 8 bytes - Accommodates the longest standard ANSI sequences (F-keys: ESC[2x~)
2229
/// Rationale: Most key sequences are 1-5 bytes, 8 provides safe headroom without waste
23-
#[allow(dead_code)]
2430
pub const MAX_KEY_SEQUENCE_SIZE: usize = 8;
2531

2632
/// Buffer size for SSH I/O operations (4KB aligns with typical SSH packet sizes)
2733
/// Value: 4096 bytes - Matches common SSH packet fragmentation boundaries
2834
/// Rationale: SSH protocol commonly uses 4KB packets; larger buffers reduce syscalls
2935
/// but increase memory usage. 4KB provides optimal balance for interactive sessions.
30-
#[allow(dead_code)]
3136
pub const SSH_IO_BUFFER_SIZE: usize = 4096;
3237

3338
/// Maximum size for terminal output chunks processed at once
3439
/// Value: 1024 bytes - Balance between responsiveness and efficiency
3540
/// Rationale: Smaller chunks improve perceived responsiveness for interactive use,
3641
/// while still being large enough to batch terminal escape sequences efficiently.
37-
#[allow(dead_code)]
3842
pub const TERMINAL_OUTPUT_CHUNK_SIZE: usize = 1024;
3943

4044
/// PTY message channel sizing:
@@ -57,7 +61,7 @@ pub const INPUT_POLL_TIMEOUT_MS: u64 = 500;
5761
/// - Tasks should check cancellation signal frequently (10-50ms intervals)
5862
pub const TASK_CLEANUP_TIMEOUT_MS: u64 = 100;
5963

60-
// Const arrays for frequently used key sequences to avoid repeated allocations
64+
// Const arrays for frequently used key sequences to avoid repeated allocations.
6165
/// Control key sequences - frequently used in terminal input
6266
pub const CTRL_C_SEQUENCE: &[u8] = &[0x03]; // Ctrl+C (SIGINT)
6367
pub const CTRL_D_SEQUENCE: &[u8] = &[0x04]; // Ctrl+D (EOF)

0 commit comments

Comments
 (0)