fix(ux): properly echo characters and do not mess up exit (#44)

This commit is contained in:
Aram Drevekenin 2020-11-14 13:27:42 +01:00 committed by GitHub
parent 20617c0263
commit 8e6dfded7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 6 deletions

View file

@ -341,6 +341,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: Opt) {
let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.ws_row, 1);
let goodbye_message = format!("{}\n{}Bye from Mosaic!", goto_start_of_last_line, reset_style);
os_input.unset_raw_mode(0);
os_input.get_stdout_writer().write(goodbye_message.as_bytes()).unwrap();
os_input.get_stdout_writer().flush().unwrap();
}

View file

@ -1,6 +1,7 @@
use nix::unistd::{read, write, ForkResult, Pid};
use nix::fcntl::{fcntl, FcntlArg, OFlag};
use nix::sys::termios::{
Termios,
tcgetattr,
cfmakeraw,
tcsetattr,
@ -14,6 +15,7 @@ use std::os::unix::io::RawFd;
use std::process::{Command, Child};
use std::io::{Read, Write};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::env;
@ -26,6 +28,13 @@ fn into_raw_mode(pid: RawFd) {
};
}
fn unset_raw_mode(pid: RawFd, mut orig_termios: Termios) {
match tcsetattr(pid, SetArg::TCSANOW, &mut orig_termios) {
Ok(_) => {},
Err(e) => panic!("error {:?}", e)
};
}
pub fn get_terminal_size_using_fd(fd: RawFd) -> Winsize {
// TODO: do this with the nix ioctl
use libc::ioctl;
@ -91,10 +100,9 @@ fn handle_command_exit(mut child: Child) {
}
}
fn spawn_terminal (file_to_open: Option<PathBuf>) -> (RawFd, RawFd) {
fn spawn_terminal (file_to_open: Option<PathBuf>, orig_termios: Termios) -> (RawFd, RawFd) {
let (pid_primary, pid_secondary): (RawFd, RawFd) = {
let current_termios = tcgetattr(0).unwrap();
match forkpty(None, Some(&current_termios)) {
match forkpty(None, Some(&orig_termios)) {
Ok(fork_pty_res) => {
let pid_primary = fork_pty_res.master;
let pid_secondary = match fork_pty_res.fork_result {
@ -134,12 +142,15 @@ fn spawn_terminal (file_to_open: Option<PathBuf>) -> (RawFd, RawFd) {
}
#[derive(Clone)]
pub struct OsInputOutput {}
pub struct OsInputOutput {
orig_termios: Arc<Mutex<Termios>>,
}
pub trait OsApi: Send + Sync {
fn get_terminal_size_using_fd(&self, pid: RawFd) -> Winsize;
fn set_terminal_size_using_fd(&mut self, pid: RawFd, cols: u16, rows: u16);
fn into_raw_mode(&mut self, pid: RawFd);
fn unset_raw_mode(&mut self, pid: RawFd);
fn spawn_terminal(&mut self, file_to_open: Option<PathBuf>) -> (RawFd, RawFd);
fn read_from_tty_stdout(&mut self, pid: RawFd, buf: &mut [u8]) -> Result<usize, nix::Error>;
fn write_to_tty_stdin(&mut self, pid: RawFd, buf: &mut [u8]) -> Result<usize, nix::Error>;
@ -160,8 +171,13 @@ impl OsApi for OsInputOutput {
fn into_raw_mode(&mut self, pid: RawFd) {
into_raw_mode(pid);
}
fn unset_raw_mode(&mut self, pid: RawFd) {
let orig_termios = self.orig_termios.lock().unwrap();
unset_raw_mode(pid, orig_termios.clone());
}
fn spawn_terminal(&mut self, file_to_open: Option<PathBuf>) -> (RawFd, RawFd) {
spawn_terminal(file_to_open)
let orig_termios = self.orig_termios.lock().unwrap();
spawn_terminal(file_to_open, orig_termios.clone())
}
fn read_from_tty_stdout(&mut self, pid: RawFd, buf: &mut [u8]) -> Result<usize, nix::Error> {
read(pid, buf)
@ -201,5 +217,9 @@ impl Clone for Box<dyn OsApi>
}
pub fn get_os_input () -> OsInputOutput {
OsInputOutput {}
let current_termios = tcgetattr(0).unwrap();
let orig_termios = Arc::new(Mutex::new(current_termios));
OsInputOutput {
orig_termios
}
}

View file

@ -14,6 +14,7 @@ pub enum IoEvent {
Kill(RawFd),
SetTerminalSizeUsingFd(RawFd, u16, u16),
IntoRawMode(RawFd),
UnsetRawMode(RawFd),
TcDrain(RawFd),
}
@ -123,6 +124,9 @@ impl OsApi for FakeInputOutput {
fn into_raw_mode(&mut self, pid: RawFd) {
self.io_events.lock().unwrap().push(IoEvent::IntoRawMode(pid));
}
fn unset_raw_mode(&mut self, pid: RawFd) {
self.io_events.lock().unwrap().push(IoEvent::UnsetRawMode(pid));
}
fn spawn_terminal(&mut self, _file_to_open: Option<PathBuf>) -> (RawFd, RawFd) {
let next_terminal_id = { self.read_buffers.lock().unwrap().keys().len() as RawFd + 1 };
self.add_terminal(next_terminal_id);