use rtoolbox::fix_line_issues::fix_line_issues;
use rtoolbox::print_tty::{print_tty, print_writer};
use std::io::{BufRead, BufReader, Write};
pub fn read_reply() -> std::io::Result<String> {
read_reply_from_bufread(&mut get_tty_reader()?)
}
pub fn read_reply_from_bufread(reader: &mut impl BufRead) -> std::io::Result<String> {
let mut reply = String::new();
reader.read_line(&mut reply)?;
fix_line_issues(reply)
}
pub fn prompt_reply(prompt: impl ToString) -> std::io::Result<String> {
print_tty(prompt).and_then(|_| read_reply_from_bufread(&mut get_tty_reader()?))
}
pub fn prompt_reply_from_bufread(
reader: &mut impl BufRead,
writer: &mut impl Write,
prompt: impl ToString,
) -> std::io::Result<String> {
print_writer(writer, prompt.to_string().as_str()).and_then(|_| read_reply_from_bufread(reader))
}
#[cfg(unix)]
fn get_tty_reader() -> std::io::Result<impl BufRead> {
Ok(BufReader::new(
std::fs::OpenOptions::new().read(true).open("/dev/tty")?,
))
}
#[cfg(windows)]
fn get_tty_reader() -> std::io::Result<impl BufRead> {
use std::os::windows::io::FromRawHandle;
use windows_sys::core::PCSTR;
use windows_sys::Win32::Foundation::{INVALID_HANDLE_VALUE, GENERIC_READ, GENERIC_WRITE};
use windows_sys::Win32::Storage::FileSystem::{
CreateFileA, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING,
};
let handle = unsafe {
CreateFileA(
b"CONIN$\x00".as_ptr() as PCSTR,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
std::ptr::null(),
OPEN_EXISTING,
0,
INVALID_HANDLE_VALUE,
)
};
if handle == INVALID_HANDLE_VALUE {
return Err(std::io::Error::last_os_error());
}
Ok(BufReader::new(unsafe {
std::fs::File::from_raw_handle(handle as _)
}))
}