1use std::{
24 io::{self, Write},
25 ops,
26 os::fd::AsFd,
27};
28
29use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr};
30use sys::Termios;
31
32pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100;
34
35pub struct RawTerminal<W: Write + AsFd> {
40 prev_ios: Termios,
41 output: W,
42}
43
44impl<W: Write + AsFd> Drop for RawTerminal<W> {
45 fn drop(&mut self) {
46 let _ = set_terminal_attr(self.output.as_fd(), &self.prev_ios);
47 }
48}
49
50impl<W: Write + AsFd> ops::Deref for RawTerminal<W> {
51 type Target = W;
52
53 fn deref(&self) -> &W {
54 &self.output
55 }
56}
57
58impl<W: Write + AsFd> ops::DerefMut for RawTerminal<W> {
59 fn deref_mut(&mut self) -> &mut W {
60 &mut self.output
61 }
62}
63
64impl<W: Write + AsFd> Write for RawTerminal<W> {
65 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
66 self.output.write(buf)
67 }
68
69 fn flush(&mut self) -> io::Result<()> {
70 self.output.flush()
71 }
72}
73
74#[cfg(unix)]
75mod unix_impl {
76 use super::*;
77 use std::os::unix::io::{AsFd, BorrowedFd};
78
79 impl<W: Write + AsFd> AsFd for RawTerminal<W> {
80 fn as_fd(&self) -> BorrowedFd {
81 self.output.as_fd()
82 }
83 }
84}
85
86pub trait IntoRawMode: Write + AsFd + Sized {
93 fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>;
99}
100
101impl<W: Write + AsFd> IntoRawMode for W {
102 fn into_raw_mode(self) -> io::Result<RawTerminal<W>> {
103 let mut ios = get_terminal_attr(self.as_fd())?;
104 let prev_ios = ios;
105
106 raw_terminal_attr(&mut ios);
107
108 set_terminal_attr(self.as_fd(), &ios)?;
109
110 Ok(RawTerminal {
111 prev_ios,
112 output: self,
113 })
114 }
115}
116
117impl<W: Write + AsFd> RawTerminal<W> {
118 pub fn suspend_raw_mode(&self) -> io::Result<()> {
120 set_terminal_attr(self.as_fd(), &self.prev_ios)?;
121 Ok(())
122 }
123
124 pub fn activate_raw_mode(&self) -> io::Result<()> {
126 let mut ios = get_terminal_attr(self.as_fd())?;
127 raw_terminal_attr(&mut ios);
128 set_terminal_attr(self.as_fd(), &ios)?;
129 Ok(())
130 }
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 use std::io::{stdout, Write};
137
138 #[test]
139 fn test_into_raw_mode() {
140 let mut out = stdout().into_raw_mode().unwrap();
141
142 out.write_all(b"this is a test, muahhahahah\r\n").unwrap();
143
144 drop(out);
145 }
146}