shrub_core/sys/unix/
terminal.rs1use std::io::IsTerminal;
4use std::os::fd::AsFd;
5use std::path::PathBuf;
6
7use crate::{error, openfiles, sys, terminal};
8
9#[derive(Clone, Debug)]
11pub struct Config {
12 termios: nix::sys::termios::Termios,
13}
14
15impl Config {
16 pub fn from_term(file: &openfiles::OpenFile) -> Result<Self, error::Error> {
23 let fd = file.try_borrow_as_fd()?;
24 let termios = nix::sys::termios::tcgetattr(fd)?;
25 Ok(Self { termios })
26 }
27
28 pub fn apply_to_term(&self, file: &openfiles::OpenFile) -> Result<(), error::Error> {
35 let fd = file.try_borrow_as_fd()?;
36 nix::sys::termios::tcsetattr(fd, nix::sys::termios::SetArg::TCSANOW, &self.termios)?;
37 Ok(())
38 }
39
40 pub fn update(&mut self, settings: &terminal::Settings) {
48 if settings.raw_input {
49 nix::sys::termios::cfmakeraw(&mut self.termios);
50 }
51
52 if let Some(echo_input) = &settings.echo_input {
53 if *echo_input {
54 self.termios.local_flags |= nix::sys::termios::LocalFlags::ECHO;
55 } else {
56 self.termios.local_flags -= nix::sys::termios::LocalFlags::ECHO;
57 }
58 }
59
60 if let Some(line_input) = &settings.line_input {
61 if *line_input {
62 self.termios.local_flags |= nix::sys::termios::LocalFlags::ICANON;
63 } else {
64 self.termios.local_flags -= nix::sys::termios::LocalFlags::ICANON;
65 }
66 }
67
68 if let Some(interrupt_signals) = &settings.interrupt_signals {
69 if *interrupt_signals {
70 self.termios.local_flags |= nix::sys::termios::LocalFlags::ISIG;
71 } else {
72 self.termios.local_flags -= nix::sys::termios::LocalFlags::ISIG;
73 }
74 }
75
76 if let Some(output_nl_as_nlcr) = &settings.output_nl_as_nlcr {
77 if *output_nl_as_nlcr {
78 self.termios.output_flags |=
79 nix::sys::termios::OutputFlags::OPOST | nix::sys::termios::OutputFlags::ONLCR;
80 } else {
81 self.termios.output_flags -= nix::sys::termios::OutputFlags::ONLCR;
82 }
83 }
84 }
85}
86
87pub fn get_parent_process_id() -> Option<sys::process::ProcessId> {
89 Some(nix::unistd::getppid().as_raw())
90}
91
92pub fn get_process_group_id() -> Option<sys::process::ProcessId> {
94 Some(nix::unistd::getpgrp().as_raw())
95}
96
97pub fn get_foreground_pid() -> Option<sys::process::ProcessId> {
99 nix::unistd::tcgetpgrp(std::io::stdin())
100 .ok()
101 .map(|pgid| pgid.as_raw())
102}
103
104pub fn move_to_foreground(pid: sys::process::ProcessId) -> Result<(), error::Error> {
106 nix::unistd::tcsetpgrp(std::io::stdin(), nix::unistd::Pid::from_raw(pid))?;
107 Ok(())
108}
109
110pub fn move_self_to_foreground() -> Result<(), std::io::Error> {
114 if std::io::stdin().is_terminal() {
115 let pgid = nix::unistd::getpgid(None)?;
116
117 let _ = nix::unistd::tcsetpgrp(std::io::stdin(), pgid);
121 }
122
123 Ok(())
124}
125
126pub fn try_get_terminal_device_path() -> Option<PathBuf> {
130 nix::unistd::ttyname(std::io::stdin()).ok()
131}
132
133pub fn get_columns(file: &openfiles::OpenFile) -> Option<usize> {
140 let fd = file.try_borrow_as_fd().ok()?;
141 let (terminal_size::Width(columns), _) = terminal_size::terminal_size_of(fd)?;
142 Some(usize::from(columns))
143}