diff --git a/Cargo.lock b/Cargo.lock index a4928ce..c005477 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "stdin-nonblocking" -version = "0.4.0" +version = "0.4.1" dependencies = [ "doc-comment", ] diff --git a/Cargo.toml b/Cargo.toml index ea7b417..654f385 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "stdin-nonblocking" -version = "0.4.0" +version = "0.4.1" authors = ["Jeremy Harris "] description = "Dependency-less non-blocking stdin reader using background threads. Supports streaming and immediate fallback defaults." repository = "https://github.com/jzombie/rust-stdin-nonblocking" diff --git a/src/lib.rs b/src/lib.rs index 9d9a822..4597d36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ doc_comment::doctest!("../README.md"); use std::io::{self, IsTerminal, Read}; use std::sync::mpsc::{self, Receiver, Sender}; use std::thread; -use std::time::Duration; /// Spawns a background thread that continuously reads from stdin as a binary stream. /// @@ -66,21 +65,19 @@ pub fn spawn_stdin_stream() -> Receiver> { rx } -/// Reads from stdin if available, otherwise returns a default value. +/// Reads stdin if available; otherwise, returns a default value. /// -/// **Non-blocking:** This function polls `stdin` once and immediately returns. -/// If no input is available within the polling time, it returns the provided default value. -/// -/// **Handling Interactive Mode:** -/// - If running interactively (stdin is a terminal), this function returns the default value immediately. -/// - This prevents hanging while waiting for user input in interactive sessions. -/// - When used with redirected input (e.g., from a file or pipe), it collects available **binary** input. +/// This function intelligently determines whether to block: +/// - **Interactive Mode**: If stdin is a terminal, the function immediately returns the default without blocking. +/// - **Redirected Input**: If stdin is redirected from a file or pipe, it spawns a thread to read stdin and waits briefly (50ms). +/// - If data arrives promptly, it returns immediately. +/// - If no data is available within that short duration, it returns the provided default value. /// /// # Arguments /// * `default` - An optional fallback value returned if no input is available. /// /// # Returns -/// * `Option>` - The full stdin input (or default value as bytes). +/// * `Option>` - The stdin input if available, otherwise the provided default. /// /// # Example /// ``` @@ -91,18 +88,15 @@ pub fn spawn_stdin_stream() -> Receiver> { /// assert_eq!(input, Some(b"fallback_value".to_vec())); /// ``` pub fn get_stdin_or_default(default: Option<&[u8]>) -> Option> { - let stdin_channel = spawn_stdin_stream(); - - // Give the reader thread a short time to capture any available input - thread::sleep(Duration::from_millis(50)); + if !io::stdin().is_terminal() { + let stdin_channel = spawn_stdin_stream(); - if let Ok(data) = stdin_channel.try_recv() { - return Some(data); + // Blocking recv() waits until data arrives or EOF occurs + match stdin_channel.recv() { + Ok(data) => return Some(data), + Err(e) => eprintln!("Channel closed without data: {}", e), + } } - // Return `None` if no default - default?; - - // No input available, return the default value - Some(default.unwrap_or(b"").to_vec()) + default.map(|val| val.to_vec()) }