diff --git a/UPSTREAM_MAPPING.md b/UPSTREAM_MAPPING.md
index 9bf892b..c44ea25 100644
--- a/UPSTREAM_MAPPING.md
+++ b/UPSTREAM_MAPPING.md
@@ -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` |
@@ -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.
diff --git a/src/program.rs b/src/program.rs
index 844a6bd..04f4913 100644
--- a/src/program.rs
+++ b/src/program.rs
@@ -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 {
diff --git a/src/tty.rs b/src/tty.rs
index 178b4a5..3cdc5f6 100644
--- a/src/tty.rs
+++ b/src/tty.rs
@@ -1,23 +1,28 @@
//! Cleanroom Rust port of upstream Go source file: `tty.go`
//! Upstream Target Tag / Version: `v2.0.8`
//!
-//!
+//!
//! # TTY Terminal Management
//!
//! TTY initialization, input stream setup, raw mode toggles, and window dimension queries for Bubble Tea v2.0.8.
-//!
+//! On Windows, raw-mode operations are compile-safe no-ops until the native
+//! console adapter is completed; window-size queries remain available.
+//!
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>> = 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();
@@ -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
@@ -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> {
enable_raw_mode()?;
diff --git a/tests/interactive.rs b/tests/interactive.rs
index b0b982c..546e80d 100644
--- a/tests/interactive.rs
+++ b/tests/interactive.rs
@@ -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.
diff --git a/tests/tea_test.rs b/tests/tea_test.rs
index 004437d..8c7b29f 100644
--- a/tests/tea_test.rs
+++ b/tests/tea_test.rs
@@ -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::>();
#[cfg(unix)]
- rusty_bubbletea::signals_unix::listen_for_resize(&tx_sig);
+ rusty_bubbletea::signals_unix::listen_for_resize(&_tx_sig);
}
#[test]
@@ -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");
}
diff --git a/tests/windows_platform.rs b/tests/windows_platform.rs
new file mode 100644
index 0000000..9063f1f
--- /dev/null
+++ b/tests/windows_platform.rs
@@ -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");
+}