diff options
author | Martin Samuelsson <msamuelsson@storvix.eu> | 2023-07-12 11:42:29 +0200 |
---|---|---|
committer | Martin Samuelsson <msamuelsson@storvix.eu> | 2023-07-12 11:53:05 +0200 |
commit | a2c20a841048d9a92f6069b50b0bf4738881ea3e (patch) | |
tree | f42d939d0b7ec3f3073701e930f18014f5bed2fd | |
parent | a855443e93bc1b31cdcee84f8ed0aa55bdc55aa1 (diff) | |
download | rustyline-a2c20a841048d9a92f6069b50b0bf4738881ea3e.zip |
Use termios from termios cratefix/use_termios_crate
The termios interface from the nix crate is lacking a thought through
design. Severely broken on at least one platform. Please see [#2071][]
for details.
The termios crate stays closer to the C API and thus both works with
illumos and reduces the risk of bugs on other platforms.
[#2071]: https://github.com/nix-rust/nix/issues/2071
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/tty/unix.rs | 46 |
2 files changed, 25 insertions, 22 deletions
@@ -46,6 +46,7 @@ nix = { version = "0.26", default-features = false, features = ["fs", "ioctl", " utf8parse = "0.2" skim = { version = "0.10", optional = true, default-features = false } signal-hook = { version = "0.3", optional = true, default-features = false } +termios = "0.3.3" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["consoleapi", "handleapi", "synchapi", "minwindef", "processenv", "std", "winbase", "wincon", "winuser"] } diff --git a/src/tty/unix.rs b/src/tty/unix.rs index 23bfcce..8166db7 100644 --- a/src/tty/unix.rs +++ b/src/tty/unix.rs @@ -13,7 +13,7 @@ use log::{debug, warn}; use nix::errno::Errno; use nix::poll::{self, PollFlags}; use nix::sys::select::{self, FdSet}; -use nix::sys::termios::{self, SetArg, SpecialCharacterIndices as SCI, Termios}; +use termios::{tcsetattr, tcgetattr, Termios}; use nix::unistd::{close, isatty, read, write}; use unicode_segmentation::UnicodeSegmentation; use utf8parse::{Parser, Receiver}; @@ -106,7 +106,8 @@ pub type Mode = PosixMode; impl RawMode for PosixMode { /// Disable RAW mode for the terminal. fn disable_raw_mode(&self) -> Result<()> { - termios::tcsetattr(self.tty_in, SetArg::TCSADRAIN, &self.termios)?; + let mut termios = self.termios; + tcgetattr(self.tty_in, &mut termios)?; // disable bracketed paste if let Some(out) = self.tty_out { write_all(out, BRACKETED_PASTE_OFF)?; @@ -1202,8 +1203,10 @@ impl SigWinCh { } } -fn map_key(key_map: &mut HashMap<KeyEvent, Cmd>, raw: &Termios, index: SCI, name: &str, cmd: Cmd) { - let cc = char::from(raw.control_chars[index as usize]); +fn map_key( + key_map: &mut HashMap<KeyEvent, Cmd>, raw: &Termios, index: usize, name: &str, cmd: Cmd) +{ + let cc = char::from(raw.c_cc[index]); let key = KeyEvent::new(cc, M::NONE); debug!(target: "rustyline", "{}: {:?}", name, key); key_map.insert(key, cmd); @@ -1326,38 +1329,37 @@ impl Term for PosixTerminal { fn enable_raw_mode(&mut self) -> Result<(Self::Mode, PosixKeyMap)> { use nix::errno::Errno::ENOTTY; - use nix::sys::termios::{ControlFlags, InputFlags, LocalFlags}; if !self.is_in_a_tty { return Err(ENOTTY.into()); } - let original_mode = termios::tcgetattr(self.tty_in)?; - let mut raw = original_mode.clone(); + let original_mode = Termios::from_fd(self.tty_in)?; + let mut raw = original_mode; // disable BREAK interrupt, CR to NL conversion on input, // input parity check, strip high bit (bit 8), output flow control - raw.input_flags &= !(InputFlags::BRKINT - | InputFlags::ICRNL - | InputFlags::INPCK - | InputFlags::ISTRIP - | InputFlags::IXON); + raw.c_iflag &= !(termios::BRKINT + | termios::ICRNL + | termios::INPCK + | termios::ISTRIP + | termios::IXON); // we don't want raw output, it turns newlines into straight line feeds // disable all output processing // raw.c_oflag = raw.c_oflag & !(OutputFlags::OPOST); // character-size mark (8 bits) - raw.control_flags |= ControlFlags::CS8; + raw.c_cflag |= termios::CS8; // disable echoing, canonical mode, extended input processing and signals - raw.local_flags &= - !(LocalFlags::ECHO | LocalFlags::ICANON | LocalFlags::IEXTEN | LocalFlags::ISIG); - raw.control_chars[SCI::VMIN as usize] = 1; // One character-at-a-time input - raw.control_chars[SCI::VTIME as usize] = 0; // with blocking read + raw.c_lflag &= + !(termios::ECHO | termios::ICANON | termios::IEXTEN | termios::ISIG); + raw.c_cc[termios::VMIN] = 1; // One character-at-a-time input + raw.c_cc[termios::VTIME] = 0; // with blocking read let mut key_map: HashMap<KeyEvent, Cmd> = HashMap::with_capacity(4); - map_key(&mut key_map, &raw, SCI::VEOF, "VEOF", Cmd::EndOfFile); - map_key(&mut key_map, &raw, SCI::VINTR, "VINTR", Cmd::Interrupt); - map_key(&mut key_map, &raw, SCI::VQUIT, "VQUIT", Cmd::Interrupt); - map_key(&mut key_map, &raw, SCI::VSUSP, "VSUSP", Cmd::Suspend); + map_key(&mut key_map, &raw, termios::VEOF, "VEOF", Cmd::EndOfFile); + map_key(&mut key_map, &raw, termios::VINTR, "VINTR", Cmd::Interrupt); + map_key(&mut key_map, &raw, termios::VQUIT, "VQUIT", Cmd::Interrupt); + map_key(&mut key_map, &raw, termios::VSUSP, "VSUSP", Cmd::Suspend); - termios::tcsetattr(self.tty_in, SetArg::TCSADRAIN, &raw)?; + tcsetattr(self.tty_in, termios::TCSADRAIN, &raw)?; self.raw_mode.store(true, Ordering::SeqCst); // enable bracketed paste |