^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;
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();
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)));
}, 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;},

View File

@ -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;

View File

@ -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; },
_ => {},
}

View File

@ -176,7 +176,7 @@ pub struct State<W: Write> {
rows: usize,
grid: CellBuffer,
stdout: termion::screen::AlternateScreen<termion::raw::RawTerminal<W>>,
stdout: Option<termion::screen::AlternateScreen<termion::raw::RawTerminal<W>>>,
child: Option<ForkType>,
pub mode: UIMode,
sender: Sender<ThreadEvent>,
@ -188,16 +188,18 @@ pub struct State<W: Write> {
impl<W: Write> Drop for State<W> {
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<W: Write> State<W> {
pub fn new(stdout: W, sender: Sender<ThreadEvent>, input_thread: chan::Sender<bool>) -> Self {
impl State<std::io::Stdout> {
pub fn new(sender: Sender<ThreadEvent>, input_thread: chan::Sender<bool>) -> 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<W: Write> State<W> {
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<W: Write> State<W> {
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<W: Write> State<W> {
}
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) {
let termsize = termion::terminal_size().ok();
let termcols = termsize.map(|(w,_)| w);
@ -269,27 +287,27 @@ impl<W: Write> State<W> {
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<W: Write> State<W> {
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<W: Write> State<W> {
}
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)]
pub enum Key {
/// Backspace.
@ -468,6 +493,7 @@ pub enum Key {
Esc,
}
impl From<TermionKey> 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;
}
}