use std::fs::{File, OpenOptions};
use std::io::Write;
use anyhow::{Context, Result};
pub fn device() -> Result<File> {
let path = if cfg!(windows) { "CONOUT$" } else { "/dev/tty" };
OpenOptions::new()
.read(true)
.write(true)
.open(path)
.with_context(|| format!("failed to open the terminal device ({path})"))
}
pub fn report(message: &str) {
if let Ok(mut device) = device()
&& device.write_all(message.as_bytes()).is_ok()
{
return;
}
eprint!("{message}");
}
#[cfg(target_os = "macos")]
pub fn adopt_terminal_as_stdin() {
use std::os::fd::AsRawFd;
if unsafe { libc::isatty(libc::STDIN_FILENO) } == 1 {
return;
}
let Some(terminal) = controlling_terminal() else {
return;
};
unsafe {
libc::dup2(terminal.as_raw_fd(), libc::STDIN_FILENO);
}
}
#[cfg(target_os = "macos")]
fn controlling_terminal() -> Option<File> {
use std::os::fd::AsRawFd;
use std::os::unix::fs::OpenOptionsExt;
let session = unsafe { libc::getsid(0) };
std::fs::read_dir("/dev")
.ok()?
.flatten()
.filter(|entry| entry.file_name().to_string_lossy().starts_with("ttys"))
.find_map(|entry| {
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_NOCTTY)
.open(entry.path())
.ok()?;
let owner = unsafe { libc::tcgetsid(file.as_raw_fd()) };
(owner == session).then_some(file)
})
}
#[cfg(not(target_os = "macos"))]
pub fn adopt_terminal_as_stdin() {}