From f1959589c89ef6dd35492601687b6b9baa84560c Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 23 Aug 2018 22:16:31 +0200 Subject: [PATCH] some fixes --- Cargo.toml | 2 +- examples/program_examples/command_bar.rs | 27 ++--- .../snake/command_bar_working.rs | 98 +++++++++++++++++++ src/common/commands/unix_command.rs | 42 ++++---- src/common/crossterm.rs | 7 ++ src/common/screen/raw.rs | 3 +- src/common/screen/screen.rs | 3 +- src/kernel/unix_kernel/terminal.rs | 16 ++- 8 files changed, 158 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9df65b0..efa0e2d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ readme = "README.md" winapi = { version = "0.3.5", features = ["winbase","winuser","consoleapi","processenv","wincon", "handleapi","errhandlingapi"] } [target.'cfg(unix)'.dependencies] -libc = "0.2.37" +libc = "0.2.43" termios = "0.3.0" [lib] diff --git a/examples/program_examples/command_bar.rs b/examples/program_examples/command_bar.rs index 4a07070..6c6d6c7 100644 --- a/examples/program_examples/command_bar.rs +++ b/examples/program_examples/command_bar.rs @@ -1,9 +1,9 @@ extern crate crossterm; -use crossterm::{Screen, Crossterm}; +use crossterm::{Screen, Crossterm, screen}; use crossterm::terminal::{terminal,Terminal, ClearType}; -use crossterm::cursor::TerminalCursor; - +use crossterm::cursor::{TerminalCursor, cursor}; +use crossterm::input::input; use std::sync::{Arc,Mutex}; use std::io::Read; use std::{thread,time}; @@ -18,13 +18,13 @@ fn main() { let mut input_buf = Arc::new(Mutex::new(String::new())); - let mut count = 0; - let threads = log(input_buf.clone(),&screen); + + let mut count = 0; + thread::spawn(move || { - let t = Crossterm::new(&screen); - let input = t.input(); + let input = input(&screen); let mut stdin = input.read_async().bytes(); loop @@ -32,16 +32,16 @@ fn main() { let a = stdin.next(); match a { - Some(Ok(10)) => + Some(Ok(13)) => { input_buf.lock().unwrap().clear(); // need to start receiving again because if pressed enter then async reading will stop - stdin = input.read_async().bytes(); +// stdin = input.read_async().bytes(); } - Some(Ok(val)) => + Some(Ok(val)) => { - println!("{:?}",a); +// println!("{:?}",a); input_buf.lock().unwrap().push(a.unwrap().unwrap() as char); } _ => {} @@ -50,7 +50,7 @@ fn main() { thread::sleep(time::Duration::from_millis(100)); count += 1; } - }); + }).join(); for thread in threads @@ -72,8 +72,9 @@ fn log(input_buf: Arc>, screen: &Screen) -> Vec + { + input_buf.lock().unwrap().clear(); + // need to start receiving again because if pressed enter then async reading will stop +// stdin = input.read_async().bytes(); + } + Some(Ok(val)) => + { +// println!("{}",val); + input_buf.lock().unwrap().push(a.unwrap().unwrap() as u8 as char); + } + _ => {} + } + + thread::sleep(time::Duration::from_millis(100)); + count += 1; + } + }).join(); + + + for thread in threads + { + thread.join(); + } + + cursor.show(); +} + +fn log(input_buf: Arc>, crossterm: Arc) -> Vec> +{ + let mut threads = Vec::with_capacity(10); + + let (_, term_height) = crossterm.terminal().terminal_size(); + + for i in 0..1 + { + let input_buffer = input_buf.clone(); + let crossterm_clone = crossterm.clone(); + let join = thread::spawn( move || { + + let cursor = crossterm_clone.cursor(); + let terminal = crossterm_clone.terminal(); + + for j in 0..1000 + { + swap_write(format!("Some output: {} from thread: {}", j, i).as_ref(), &input_buffer.lock().unwrap(), &terminal, &cursor, term_height); + thread::sleep(time::Duration::from_millis(300)); + } + }); + + threads.push(join); + } + + return threads; +} + +pub fn swap_write(msg: &str, input_buf: &String, terminal: &Terminal, cursor: &TerminalCursor, term_height: u16) { + cursor.goto(0, term_height); + terminal.clear(ClearType::CurrentLine); + terminal.write(format!("{}\r\n", msg)); + terminal.write(format!(">{}", input_buf)); +} \ No newline at end of file diff --git a/src/common/commands/unix_command.rs b/src/common/commands/unix_command.rs index bde6e64..a60187f 100644 --- a/src/common/commands/unix_command.rs +++ b/src/common/commands/unix_command.rs @@ -2,12 +2,11 @@ use super::{ IStateCommand}; use kernel::unix_kernel::terminal; -use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH}; - +use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH, BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, IEXTEN, ISIG,VTIME, VMIN}; +use libc::STDIN_FILENO; use std::sync::{Once, ONCE_INIT}; static TERMINAL_MODE: Once = ONCE_INIT; -const FD_STDIN: ::std::os::unix::io::RawFd = 1; use std::io::{Error, ErrorKind, Result}; @@ -20,16 +19,25 @@ impl NoncanonicalModeCommand { NoncanonicalModeCommand {} } } +static mut ORIGINAL: Option = None; impl NoncanonicalModeCommand { pub fn enable(&mut self) -> Result<()> { // Set noncanonical mode - if let Ok(orig) = Termios::from_fd(FD_STDIN) { + if let Ok(orig) = Termios::from_fd(STDIN_FILENO) { + TERMINAL_MODE.call_once(|| { + unsafe { ORIGINAL = Some(orig.clone()); } + }); + let mut noncan = orig.clone(); - noncan.c_lflag &= !ICANON; - noncan.c_lflag &= !ECHO; - noncan.c_lflag &= !CREAD; - tcsetattr(FD_STDIN, TCSAFLUSH, &noncan)?; + noncan.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + noncan.c_oflag &= !(OPOST); + noncan.c_cflag |= (CS8); + noncan.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG); + noncan.c_cc[VMIN] = 0; + noncan.c_cc[VTIME] = 1; + + tcsetattr(STDIN_FILENO, TCSAFLUSH, &noncan)?; } else { return Err(Error::new( ErrorKind::Other, @@ -40,20 +48,14 @@ impl NoncanonicalModeCommand { } pub fn disable(&self) -> Result<()> { - // Disable noncanonical mode - if let Ok(orig) = Termios::from_fd(FD_STDIN) { - let mut noncan = orig.clone(); - noncan.c_lflag &= ICANON; - noncan.c_lflag &= ECHO; - noncan.c_lflag &= CREAD; - tcsetattr(FD_STDIN, TCSAFLUSH, &noncan)?; - } else { - return Err(Error::new( - ErrorKind::Other, - "Could not set console mode when enabling raw mode", - )); + unsafe { + if let Some(original) = ORIGINAL + { + tcsetattr(STDIN_FILENO, TCSAFLUSH, &original)?; + } } + Ok(()) } } diff --git a/src/common/crossterm.rs b/src/common/crossterm.rs index 240b172..bcc09f9 100644 --- a/src/common/crossterm.rs +++ b/src/common/crossterm.rs @@ -122,4 +122,11 @@ impl<'crossterm> Crossterm { D: Display, { style::ObjectStyle::new().apply_to(val) } +} + +impl From> for Crossterm +{ + fn from(stdout: Arc) -> Self { + Crossterm { stdout: stdout } + } } \ No newline at end of file diff --git a/src/common/screen/raw.rs b/src/common/screen/raw.rs index b6a1362..9796001 100644 --- a/src/common/screen/raw.rs +++ b/src/common/screen/raw.rs @@ -32,7 +32,8 @@ impl RawScreen { #[cfg(target_os = "windows")] let mut command = win_commands::RawModeCommand::new(); - command.enable()?; + let result = command.enable(); + Ok(()) } diff --git a/src/common/screen/screen.rs b/src/common/screen/screen.rs index 01bf79e..e97dd35 100644 --- a/src/common/screen/screen.rs +++ b/src/common/screen/screen.rs @@ -56,7 +56,7 @@ impl Screen if raw_mode { let screen = Screen { stdout: Arc::new(TerminalOutput::new(true)), buffer: Vec::new() }; - RawScreen::into_raw_mode(); + RawScreen::into_raw_mode().unwrap(); return screen; } @@ -123,6 +123,7 @@ impl Drop for Screen if self.stdout.is_in_raw_mode { RawScreen::disable_raw_modes(); + panic!("drop"); } } } diff --git a/src/kernel/unix_kernel/terminal.rs b/src/kernel/unix_kernel/terminal.rs index 6a9746d..f8f0b70 100644 --- a/src/kernel/unix_kernel/terminal.rs +++ b/src/kernel/unix_kernel/terminal.rs @@ -159,10 +159,18 @@ pub fn disable_raw_mode() -> io::Result<()> /// /// This allows for getting stdio representing _only_ the TTY, and not other streams. pub fn get_tty() -> io::Result { - fs::OpenOptions::new() - .read(true) - .write(true) - .open("/dev/tty") + let mut tty_f: fs::File = unsafe { ::std::mem::zeroed() }; + + let fd = unsafe { + if libc::isatty(libc::STDIN_FILENO) == 1 { + libc::STDIN_FILENO + } else { + tty_f = fs::File::open("/dev/tty")?; + tty_f.as_raw_fd() + } + }; + + return Ok(tty_f); } pub fn read_char() -> io::Result {