diff --git a/src/bin.rs b/src/bin.rs index 9f8726111..43af70bf8 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -39,7 +39,9 @@ extern crate chan_signal; use chan_signal::Signal; -fn make_input_thread(sx: chan::Sender, rx: chan::Receiver) -> () { +extern crate nix; + +fn make_input_thread(sx: chan::Sender, rx: chan::Receiver) -> thread::JoinHandle<()> { let stdin = std::io::stdin(); thread::Builder::new().name("input-thread".to_string()).spawn(move || { @@ -49,14 +51,12 @@ fn make_input_thread(sx: chan::Sender, rx: chan::Receiver) -> }, || { sx.send(ThreadEvent::UIEventType(UIEventType::ChangeMode(UIMode::Fork))); - }, rx)}).unwrap(); - - + }, rx)}).unwrap() } fn main() { /* Lock all stdio outs */ - let _stdout = stdout(); - let mut _stdout = _stdout.lock(); + //let _stdout = stdout(); + //let mut _stdout = _stdout.lock(); /* let _stderr = stderr(); let mut _stderr = _stderr.lock(); @@ -75,11 +75,11 @@ fn main() { * stdin, see get_events() for details * */ let (tx, rx) = chan::async(); - /* Get input thread handle to kill it if we need to */ - make_input_thread(sender.clone(), rx.clone()); + /* Get input thread handle to join it if we need to */ + let mut _thread_handler = make_input_thread(sender.clone(), rx.clone()); /* Create the application State. This is the 'System' part of an ECS architecture */ - let mut state = State::new(_stdout, sender.clone(), tx ); + let mut state = State::new(sender.clone(), tx ); /* Register some reasonably useful interfaces */ let menu = Entity {component: Box::new(AccountMenu::new(&state.context.accounts)) }; @@ -109,6 +109,18 @@ fn main() { chan_select! { receiver.recv() -> r => { match r.unwrap() { + ThreadEvent::Input(Key::Ctrl('z')) => { + state.to_main_screen(); + //_thread_handler.join().expect("Couldn't join on the associated thread"); + let self_pid = nix::unistd::Pid::this(); + nix::sys::signal::kill(self_pid, nix::sys::signal::Signal::SIGSTOP).unwrap(); + state.to_alternate_screen(); + _thread_handler = make_input_thread(sender.clone(), rx.clone()); + // BUG: thread sends input event after one received key + state.update_size(); + state.render(); + state.redraw(); + }, ThreadEvent::Input(k) => { match state.mode { UIMode::Normal => { @@ -183,10 +195,9 @@ fn main() { }, Some(false) => { use std::{thread, time}; - let ten_millis = time::Duration::from_millis(1500); - thread::sleep(ten_millis); + continue 'reap; }, None => {break 'reap;}, diff --git a/ui/src/components/mail/listing.rs b/ui/src/components/mail/listing.rs index a419c81e9..205db1117 100644 --- a/ui/src/components/mail/listing.rs +++ b/ui/src/components/mail/listing.rs @@ -456,7 +456,7 @@ impl Component for MailListing { context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::ChangeMode(UIMode::Fork) }); return; }, - UIEventType::Input(Key::Esc) | UIEventType::Input(Key::Char('i')) if self.unfocused == true => { + UIEventType::Input(Key::Char('i')) if self.unfocused == true => { self.unfocused = false; self.dirty = true; self.view = None; diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index d9e969c57..f0d47c874 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -167,10 +167,18 @@ impl Component for MailView { fn process_event(&mut self, event: &UIEvent, context: &mut Context) { match event.event_type { + UIEventType::Input(Key::Esc) => { + match self.mode { + ViewMode::Url => { + self.cmd_buf.clear(); + return; + }, + _ => {}, + } + }, UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { //TODO:this should be an Action match self.mode { ViewMode::Url => { self.cmd_buf.push(c); - eprintln!("buf is {}", self.cmd_buf); return; }, _ => {}, } diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 81b9f57a3..669a8fe58 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -176,7 +176,7 @@ pub struct State { rows: usize, grid: CellBuffer, - stdout: termion::screen::AlternateScreen>, + stdout: Option>>, child: Option, pub mode: UIMode, sender: Sender, @@ -188,16 +188,18 @@ pub struct State { impl Drop for State { fn drop(&mut self) { // When done, restore the defaults to avoid messing with the terminal. - write!(self.stdout, "{}{}{}{}", clear::All, style::Reset, cursor::Goto(1, 1), cursor::Show).unwrap(); - self.stdout.flush().unwrap(); + write!(self.stdout(), "{}{}{}{}", clear::All, style::Reset, cursor::Goto(1, 1), cursor::Show).unwrap(); + self.flush(); } } -impl State { - pub fn new(stdout: W, sender: Sender, input_thread: chan::Sender) -> Self { +impl State { + pub fn new(sender: Sender, input_thread: chan::Sender) -> Self { + let _stdout = std::io::stdout(); + _stdout.lock(); let settings = Settings::new(); let backends = Backends::new(); - let stdout = AlternateScreen::from(stdout.into_raw_mode().unwrap()); + let stdout = AlternateScreen::from(_stdout.into_raw_mode().unwrap()); let termsize = termion::terminal_size().ok(); let termcols = termsize.map(|(w,_)| w); @@ -210,7 +212,7 @@ impl State { cols: cols, rows: rows, grid: CellBuffer::new(cols, rows, Cell::with_char(' ')), - stdout: stdout, + stdout: Some(stdout), child: None, mode: UIMode::Normal, sender: sender, @@ -228,8 +230,8 @@ impl State { input_thread: input_thread, }, }; - write!(s.stdout, "{}{}{}", cursor::Hide, clear::All, cursor::Goto(1,1)).unwrap(); - s.stdout.flush().unwrap(); + write!(s.stdout(), "{}{}{}", cursor::Hide, clear::All, cursor::Goto(1,1)).unwrap(); + s.flush(); for account in &mut s.context.accounts { let sender = s.sender.clone(); account.watch(RefreshEventConsumer::new(Box::new(move |r| { @@ -239,6 +241,22 @@ impl State { } s } + pub fn to_main_screen(&mut self) { + write!(self.stdout(), "{}{}", termion::screen::ToMainScreen, cursor::Show).unwrap(); + self.flush(); + self.stdout = None; + self.context.input_thread.send(false); + } + pub fn to_alternate_screen(&mut self) { + let s = std::io::stdout(); + s.lock(); + self.stdout = Some(AlternateScreen::from(s.into_raw_mode().unwrap())); + + write!(self.stdout(), "{}", termion::screen::ToAlternateScreen).unwrap(); + self.flush(); + } +} +impl State { pub fn update_size(&mut self) { let termsize = termion::terminal_size().ok(); let termcols = termsize.map(|(w,_)| w); @@ -269,27 +287,27 @@ impl State { let bottom_right = bottom_right!(area); for y in get_y(upper_left)..=get_y(bottom_right) { - write!(self.stdout, "{}", cursor::Goto(get_x(upper_left) as u16 + 1,(y+1) as u16)).unwrap(); + write!(self.stdout(), "{}", cursor::Goto(get_x(upper_left) as u16 + 1,(y+1) as u16)).unwrap(); for x in get_x(upper_left)..=get_x(bottom_right) { let c = self.grid[(x,y)]; if c.bg() != cells::Color::Default { - write!(self.stdout, "{}", termion::color::Bg(c.bg().as_termion())).unwrap(); + write!(self.stdout(), "{}", termion::color::Bg(c.bg().as_termion())).unwrap(); } if c.fg() != cells::Color::Default { - write!(self.stdout, "{}", termion::color::Fg(c.fg().as_termion())).unwrap(); + write!(self.stdout(), "{}", termion::color::Fg(c.fg().as_termion())).unwrap(); } - write!(self.stdout, "{}",c.ch()).unwrap(); + write!(self.stdout(), "{}",c.ch()).unwrap(); if c.bg() != cells::Color::Default { - write!(self.stdout, "{}", termion::color::Bg(termion::color::Reset)).unwrap(); + write!(self.stdout(), "{}", termion::color::Bg(termion::color::Reset)).unwrap(); } if c.fg() != cells::Color::Default { - write!(self.stdout, "{}", termion::color::Fg(termion::color::Reset)).unwrap(); + write!(self.stdout(), "{}", termion::color::Fg(termion::color::Reset)).unwrap(); } } } - self.stdout.flush().unwrap(); + self.flush(); } pub fn render(&mut self) { self.update_size(); @@ -338,7 +356,7 @@ impl State { UIEventType::Fork(child) => { self.mode = UIMode::Fork; self.child = Some(child); - self.stdout.flush().unwrap(); + self.flush(); return; }, UIEventType::EditDraft(dir) => { @@ -422,10 +440,17 @@ impl State { } Some(false) } + fn flush(&mut self) { + self.stdout.as_mut().map(|s| s.flush().unwrap()); + + } + fn stdout(&mut self) -> &mut termion::screen::AlternateScreen> { + self.stdout.as_mut().unwrap() + + } } -// TODO: Pass Ctrl C etc to the terminal. #[derive(Debug)] pub enum Key { /// Backspace. @@ -468,6 +493,7 @@ pub enum Key { Esc, } + impl From for Key { fn from(k: TermionKey ) -> Self { match k { @@ -510,6 +536,8 @@ pub fn get_events(stdin: std::io::Stdin, mut closure: impl FnMut(Key), mut exit: if let Some(true) = val { exit(); return; + } else if let Some(false) = val { + return; } }