Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion UPSTREAM_MAPPING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ upstream tag `v2.0.8`, checked out locally in `upstream-go/` (gitignored).
| `termios_other.go` | `src/termios_other.rs` | Non-POSIX fallback |
| `termios_unix.go` | `src/termios_unix.rs` | POSIX termios helper |
| `termios_windows.go` | `src/termios_windows.rs` | Windows console mode helper |
| `tty.go` | `src/tty.rs` | `init_terminal` / `restore_terminal` |
| `tty.go` | `src/tty.rs` | `init_terminal` / `restore_terminal`; Unix raw-mode implementation with compile-safe Windows no-op boundary |
| `tty_unix.go` | `src/tty_unix.rs` | Unix TTY reader + raw mode |
| `tty_windows.go` | `src/tty_windows.rs` | Windows VT console helper |
| `xterm.go` | `src/xterm.rs` | XTVERSION query, `TerminalVersionMsg` |
Expand Down Expand Up @@ -160,6 +160,11 @@ byte-for-byte.
| `tutorials/basics/main.go` | `examples/tutorial_basics.rs` | Tutorial: counter; quits on 'q' |
| `tutorials/commands/main.go` | `examples/tutorial_commands.rs` | Tutorial: commands; quits on 'q' |

Rust-only portability regression coverage is maintained in `tests/windows_platform.rs`; it
exercises the Windows raw-mode and terminal-restoration boundary that has no standalone
upstream Go test file. The PTY-driven `tests/interactive.rs` suite remains Unix-gated because
its real pseudo-terminal dependency is intentionally not claimed as native Windows support.

Example support files (`examples/go.mod`, `examples/go.sum`, `examples/table/demo.tape`,
per-example `README.md`/`.gif` assets, `tutorials/go.mod`, `tutorials/go.sum`) are documented
in the Support Files section.
Expand Down
3 changes: 2 additions & 1 deletion src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,9 +921,10 @@ fn uv_mouse_to_mouse(m: rusty_ultraviolet::Mouse) -> crate::mouse::Mouse {
/// CheckOptimizedMovements reads the stdin termios and reports whether hard
/// tabs (TABDLY==TAB0) and backspace (BSDLY==BS0) optimizations are enabled.
fn check_optimized_movements() -> (bool, bool) {
use std::os::fd::AsRawFd;
#[cfg(unix)]
{
use std::os::fd::AsRawFd;

let fd = std::io::stdin().as_raw_fd();
let mut t: libc::termios = unsafe { std::mem::zeroed() };
if unsafe { libc::tcgetattr(fd, &mut t) } != 0 {
Expand Down
24 changes: 22 additions & 2 deletions src/tty.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
//! Cleanroom Rust port of upstream Go source file: `tty.go`
//! Upstream Target Tag / Version: `v2.0.8`
//!
//! <public-docs>
//! <user-docs>
//! # TTY Terminal Management
//!
//! TTY initialization, input stream setup, raw mode toggles, and window dimension queries for Bubble Tea v2.0.8.
//! </public-docs>
//! On Windows, raw-mode operations are compile-safe no-ops until the native
//! console adapter is completed; window-size queries remain available.
//! </user-docs>

use crossterm::terminal::size as term_size;
#[cfg(unix)]
use std::sync::{Mutex, OnceLock};

/// Saved terminal state for the raw mode toggle, mirroring the upstream
/// `p.previousTtyInputState` (x/term `MakeRaw`/`Restore`).
#[cfg(unix)]
static SAVED_TERMIOS: OnceLock<Mutex<Option<libc::termios>>> = OnceLock::new();

/// Initializes terminal raw mode, mirroring the upstream `initInput` ->
/// `term.MakeRaw` path (`tty_unix.go`). Unlike a fully-zeroed `cfmakeraw`,
/// only `OPOST` is cleared from the output flags, so `TABDLY` (and thus the
/// hard-tab cursor optimization) behaves exactly as it does upstream.
#[cfg(unix)]
pub fn enable_raw_mode() -> std::io::Result<()> {
use std::os::fd::AsRawFd;
let fd = std::io::stdin().as_raw_fd();
Expand Down Expand Up @@ -52,8 +57,16 @@ pub fn enable_raw_mode() -> std::io::Result<()> {
Ok(())
}

/// Keeps the raw-mode API available on Windows while native console mode
/// support remains deferred.
#[cfg(not(unix))]
pub fn enable_raw_mode() -> std::io::Result<()> {
Ok(())
}

/// Restores the terminal state saved by [`enable_raw_mode`], mirroring the
/// upstream `term.Restore` path.
#[cfg(unix)]
pub fn disable_raw_mode() -> std::io::Result<()> {
use std::os::fd::AsRawFd;
let saved = SAVED_TERMIOS
Expand All @@ -70,6 +83,13 @@ pub fn disable_raw_mode() -> std::io::Result<()> {
Ok(())
}

/// Keeps terminal restoration deterministic on Windows when no raw mode was
/// enabled by the compile-safe fallback.
#[cfg(not(unix))]
pub fn disable_raw_mode() -> std::io::Result<()> {
Ok(())
}

/// Initializes terminal raw mode.
pub fn init_terminal() -> Result<(), Box<dyn std::error::Error>> {
enable_raw_mode()?;
Expand Down
2 changes: 2 additions & 0 deletions tests/interactive.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![cfg(unix)]

//! Interactive integration tests for the Bubble Tea examples, driven through
//! a real pseudo-terminal (Playwright-style): keys, typing, mouse, resizing,
//! and assertions on the reconstructed on-screen state.
Expand Down
10 changes: 7 additions & 3 deletions tests/tea_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,9 @@ fn test_clipboard_and_color_commands() {

// TTY helpers
let _ = rusty_bubbletea::tty::get_window_size();
let (tx_sig, _rx_sig) = std::sync::mpsc::channel();
let (_tx_sig, _rx_sig) = std::sync::mpsc::channel::<Box<dyn Msg>>();
#[cfg(unix)]
rusty_bubbletea::signals_unix::listen_for_resize(&tx_sig);
rusty_bubbletea::signals_unix::listen_for_resize(&_tx_sig);
}

#[test]
Expand Down Expand Up @@ -596,7 +596,11 @@ fn test_keyboard_and_mouse_and_env_and_logging() {
nil.reset();
assert!(nil.close().is_ok());

let mut logger = logging::log_to_file("/tmp/test_bubbletea.log", "test").unwrap();
let log_path = std::env::temp_dir()
.join("rusty-bubbletea-test.log")
.to_string_lossy()
.into_owned();
let mut logger = logging::log_to_file(&log_path, "test").unwrap();
logger.log("test message");
}

Expand Down
17 changes: 17 additions & 0 deletions tests/windows_platform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![cfg(windows)]

//! Windows regression coverage for the compile-safe terminal boundary.

use rusty_bubbletea::tty::{disable_raw_mode, enable_raw_mode, init_terminal, restore_terminal};

#[test]
fn raw_mode_operations_are_safe_no_ops_on_windows() {
enable_raw_mode().expect("Windows raw-mode fallback should succeed");
disable_raw_mode().expect("Windows raw-mode restoration fallback should succeed");
}

#[test]
fn terminal_lifecycle_uses_the_same_windows_boundary() {
init_terminal().expect("Windows terminal initialization fallback should succeed");
restore_terminal().expect("Windows terminal restoration fallback should succeed");
}
Loading