1use crate::{error, openfiles, sys};
4
5pub struct TerminalControl {
7 prev_fg_pid: Option<sys::process::ProcessId>,
8}
9
10impl TerminalControl {
11 pub fn acquire() -> Result<Self, error::Error> {
13 let prev_fg_pid = sys::terminal::get_foreground_pid();
14
15 let _ = sys::signal::lead_new_process_group();
18
19 sys::terminal::move_self_to_foreground()?;
21
22 sys::signal::mask_sigttou()?;
24
25 Ok(Self { prev_fg_pid })
26 }
27
28 fn try_release(&mut self) {
29 if let Some(pid) = self.prev_fg_pid {
31 if sys::terminal::move_to_foreground(pid).is_ok() {
32 self.prev_fg_pid = None;
33 }
34 }
35 }
36}
37
38impl Drop for TerminalControl {
39 fn drop(&mut self) {
40 self.try_release();
41 }
42}
43
44#[derive(Default, bon::Builder)]
46pub struct Settings {
47 pub echo_input: Option<bool>,
49 pub line_input: Option<bool>,
51 pub interrupt_signals: Option<bool>,
53 pub output_nl_as_nlcr: Option<bool>,
55}
56
57pub struct AutoModeGuard {
59 initial: sys::terminal::Config,
60 file: openfiles::OpenFile,
61}
62
63impl AutoModeGuard {
64 pub fn new(file: openfiles::OpenFile) -> Result<Self, error::Error> {
70 let initial = sys::terminal::Config::from_term(&file)?;
71 Ok(Self { initial, file })
72 }
73
74 pub fn apply_settings(&self, settings: &Settings) -> Result<(), error::Error> {
80 let mut config = sys::terminal::Config::from_term(&self.file)?;
81 config.update(settings);
82 config.apply_to_term(&self.file)?;
83
84 Ok(())
85 }
86}
87
88impl Drop for AutoModeGuard {
89 fn drop(&mut self) {
90 let _ = self.initial.apply_to_term(&self.file);
91 }
92}