brush_core/terminal.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
use crate::{error, sys};
/// Encapsulates the state of a controlled terminal.
#[allow(clippy::module_name_repetitions)]
pub struct TerminalControl {
prev_fg_pid: Option<u32>,
}
impl TerminalControl {
/// Acquire the terminal for the shell.
pub fn acquire() -> Result<Self, error::Error> {
let prev_fg_pid = sys::terminal::get_foreground_pid();
// Break out into new process group.
// TODO: jobs: Investigate why this sometimes fails with EPERM.
let _ = sys::signal::lead_new_process_group();
// Take ownership.
sys::terminal::move_self_to_foreground()?;
// Mask out SIGTTOU.
sys::signal::mask_sigttou()?;
Ok(Self { prev_fg_pid })
}
fn try_release(&mut self) {
// Restore the previous foreground process group.
if let Some(pid) = self.prev_fg_pid {
if sys::terminal::move_to_foreground(pid).is_ok() {
self.prev_fg_pid = None;
}
}
}
}
impl Drop for TerminalControl {
fn drop(&mut self) {
self.try_release();
}
}