^Z causes SIGSTOP

closes #6
embed
Manos Pitsidianakis 2018-07-24 13:28:15 +03:00
parent 0aef7e03a5
commit 2df22c2da9
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
4 changed files with 78 additions and 31 deletions

View File

@ -39,7 +39,9 @@ extern crate chan_signal;
use chan_signal::Signal; use chan_signal::Signal;
fn make_input_thread(sx: chan::Sender<ThreadEvent>, rx: chan::Receiver<bool>) -> () { extern crate nix;
fn make_input_thread(sx: chan::Sender<ThreadEvent>, rx: chan::Receiver<bool>) -> thread::JoinHandle<()> {
let stdin = std::io::stdin(); let stdin = std::io::stdin();
thread::Builder::new().name("input-thread".to_string()).spawn(move || { thread::Builder::new().name("input-thread".to_string()).spawn(move || {
@ -49,14 +51,12 @@ fn make_input_thread(sx: chan::Sender<ThreadEvent>, rx: chan::Receiver<bool>) ->
}, },
|| { || {
sx.send(ThreadEvent::UIEventType(UIEventType::ChangeMode(UIMode::Fork))); sx.send(ThreadEvent::UIEventType(UIEventType::ChangeMode(UIMode::Fork)));
}, rx)}).unwrap(); }, rx)}).unwrap()
} }
fn main() { fn main() {
/* Lock all stdio outs */ /* Lock all stdio outs */
let _stdout = stdout(); //let _stdout = stdout();
let mut _stdout = _stdout.lock(); //let mut _stdout = _stdout.lock();
/* /*
let _stderr = stderr(); let _stderr = stderr();
let mut _stderr = _stderr.lock(); let mut _stderr = _stderr.lock();
@ -75,11 +75,11 @@ fn main() {
* stdin, see get_events() for details * stdin, see get_events() for details
* */ * */
let (tx, rx) = chan::async(); let (tx, rx) = chan::async();
/* Get input thread handle to kill it if we need to */ /* Get input thread handle to join it if we need to */
make_input_thread(sender.clone(), rx.clone()); let mut _thread_handler = make_input_thread(sender.clone(), rx.clone());
/* Create the application State. This is the 'System' part of an ECS architecture */ /* 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 */ /* Register some reasonably useful interfaces */
let menu = Entity {component: Box::new(AccountMenu::new(&state.context.accounts)) }; let menu = Entity {component: Box::new(AccountMenu::new(&state.context.accounts)) };
@ -109,6 +109,18 @@ fn main() {
chan_select! { chan_select! {
receiver.recv() -> r => { receiver.recv() -> r => {
match r.unwrap() { 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) => { ThreadEvent::Input(k) => {
match state.mode { match state.mode {
UIMode::Normal => { UIMode::Normal => {
@ -183,10 +195,9 @@ fn main() {
}, },
Some(false) => { Some(false) => {
use std::{thread, time}; use std::{thread, time};
let ten_millis = time::Duration::from_millis(1500); let ten_millis = time::Duration::from_millis(1500);
thread::sleep(ten_millis); thread::sleep(ten_millis);
continue 'reap; continue 'reap;
}, },
None => {break 'reap;}, None => {break 'reap;},

View File

@ -456,7 +456,7 @@ impl Component for MailListing {
context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::ChangeMode(UIMode::Fork) }); context.replies.push_back(UIEvent { id: 0, event_type: UIEventType::ChangeMode(UIMode::Fork) });
return; 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.unfocused = false;
self.dirty = true; self.dirty = true;
self.view = None; self.view = None;

View File

@ -167,10 +167,18 @@ impl Component for MailView {
fn process_event(&mut self, event: &UIEvent, context: &mut Context) { fn process_event(&mut self, event: &UIEvent, context: &mut Context) {
match event.event_type { 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 UIEventType::Input(Key::Char(c)) if c >= '0' && c <= '9' => { //TODO:this should be an Action
match self.mode { match self.mode {
ViewMode::Url => { self.cmd_buf.push(c); ViewMode::Url => { self.cmd_buf.push(c);
eprintln!("buf is {}", self.cmd_buf);
return; }, return; },
_ => {}, _ => {},
} }

View File

@ -176,7 +176,7 @@ pub struct State<W: Write> {
rows: usize, rows: usize,
grid: CellBuffer, grid: CellBuffer,
stdout: termion::screen::AlternateScreen<termion::raw::RawTerminal<W>>, stdout: Option<termion::screen::AlternateScreen<termion::raw::RawTerminal<W>>>,
child: Option<ForkType>, child: Option<ForkType>,
pub mode: UIMode, pub mode: UIMode,
sender: Sender<ThreadEvent>, sender: Sender<ThreadEvent>,
@ -188,16 +188,18 @@ pub struct State<W: Write> {
impl<W: Write> Drop for State<W> { impl<W: Write> Drop for State<W> {
fn drop(&mut self) { fn drop(&mut self) {
// When done, restore the defaults to avoid messing with the terminal. // 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(); write!(self.stdout(), "{}{}{}{}", clear::All, style::Reset, cursor::Goto(1, 1), cursor::Show).unwrap();
self.stdout.flush().unwrap(); self.flush();
} }
} }
impl<W: Write> State<W> { impl State<std::io::Stdout> {
pub fn new(stdout: W, sender: Sender<ThreadEvent>, input_thread: chan::Sender<bool>) -> Self { pub fn new(sender: Sender<ThreadEvent>, input_thread: chan::Sender<bool>) -> Self {
let _stdout = std::io::stdout();
_stdout.lock();
let settings = Settings::new(); let settings = Settings::new();
let backends = Backends::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 termsize = termion::terminal_size().ok();
let termcols = termsize.map(|(w,_)| w); let termcols = termsize.map(|(w,_)| w);
@ -210,7 +212,7 @@ impl<W: Write> State<W> {
cols: cols, cols: cols,
rows: rows, rows: rows,
grid: CellBuffer::new(cols, rows, Cell::with_char(' ')), grid: CellBuffer::new(cols, rows, Cell::with_char(' ')),
stdout: stdout, stdout: Some(stdout),
child: None, child: None,
mode: UIMode::Normal, mode: UIMode::Normal,
sender: sender, sender: sender,
@ -228,8 +230,8 @@ impl<W: Write> State<W> {
input_thread: input_thread, input_thread: input_thread,
}, },
}; };
write!(s.stdout, "{}{}{}", cursor::Hide, clear::All, cursor::Goto(1,1)).unwrap(); write!(s.stdout(), "{}{}{}", cursor::Hide, clear::All, cursor::Goto(1,1)).unwrap();
s.stdout.flush().unwrap(); s.flush();
for account in &mut s.context.accounts { for account in &mut s.context.accounts {
let sender = s.sender.clone(); let sender = s.sender.clone();
account.watch(RefreshEventConsumer::new(Box::new(move |r| { account.watch(RefreshEventConsumer::new(Box::new(move |r| {
@ -239,6 +241,22 @@ impl<W: Write> State<W> {
} }
s 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<W: Write> State<W> {
pub fn update_size(&mut self) { pub fn update_size(&mut self) {
let termsize = termion::terminal_size().ok(); let termsize = termion::terminal_size().ok();
let termcols = termsize.map(|(w,_)| w); let termcols = termsize.map(|(w,_)| w);
@ -269,27 +287,27 @@ impl<W: Write> State<W> {
let bottom_right = bottom_right!(area); let bottom_right = bottom_right!(area);
for y in get_y(upper_left)..=get_y(bottom_right) { 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) { for x in get_x(upper_left)..=get_x(bottom_right) {
let c = self.grid[(x,y)]; let c = self.grid[(x,y)];
if c.bg() != cells::Color::Default { 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 { 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 { 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 { 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) { pub fn render(&mut self) {
self.update_size(); self.update_size();
@ -338,7 +356,7 @@ impl<W: Write> State<W> {
UIEventType::Fork(child) => { UIEventType::Fork(child) => {
self.mode = UIMode::Fork; self.mode = UIMode::Fork;
self.child = Some(child); self.child = Some(child);
self.stdout.flush().unwrap(); self.flush();
return; return;
}, },
UIEventType::EditDraft(dir) => { UIEventType::EditDraft(dir) => {
@ -422,10 +440,17 @@ impl<W: Write> State<W> {
} }
Some(false) Some(false)
} }
fn flush(&mut self) {
self.stdout.as_mut().map(|s| s.flush().unwrap());
}
fn stdout(&mut self) -> &mut termion::screen::AlternateScreen<termion::raw::RawTerminal<W>> {
self.stdout.as_mut().unwrap()
}
} }
// TODO: Pass Ctrl C etc to the terminal.
#[derive(Debug)] #[derive(Debug)]
pub enum Key { pub enum Key {
/// Backspace. /// Backspace.
@ -468,6 +493,7 @@ pub enum Key {
Esc, Esc,
} }
impl From<TermionKey> for Key { impl From<TermionKey> for Key {
fn from(k: TermionKey ) -> Self { fn from(k: TermionKey ) -> Self {
match k { 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 { if let Some(true) = val {
exit(); exit();
return; return;
} else if let Some(false) = val {
return;
} }
} }