From 5606fe301d0c23b7ea98f9da2a60f9f431d8a3b9 Mon Sep 17 00:00:00 2001 From: Jiayi Zhao Date: Sat, 14 Mar 2020 18:22:18 -0400 Subject: rework input event thread handling - this fixes issues where joshuto steals the inputs of terminal applications --- src/run.rs | 2 +- src/ui/widgets/tui_menu.rs | 29 +++++---- src/ui/widgets/tui_prompt.rs | 6 +- src/ui/widgets/tui_textfield.rs | 138 +++++++++++++++++++++------------------- src/util/event.rs | 44 +++++++------ 5 files changed, 123 insertions(+), 96 deletions(-) diff --git a/src/run.rs b/src/run.rs index b6b03c8..0291a34 100644 --- a/src/run.rs +++ b/src/run.rs @@ -98,6 +98,7 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io: } } } + context.events.flush(); } } let mut view = TuiView::new(&context); @@ -109,6 +110,5 @@ pub fn run(config_t: JoshutoConfig, keymap_t: JoshutoCommandMapping) -> std::io: } } } - eprintln!("{:#?}", context.message_queue); Ok(()) } diff --git a/src/ui/widgets/tui_menu.rs b/src/ui/widgets/tui_menu.rs index 5f628cc..4088d6d 100644 --- a/src/ui/widgets/tui_menu.rs +++ b/src/ui/widgets/tui_menu.rs @@ -32,6 +32,7 @@ impl TuiCommandMenu { ) -> Option<&'a Box> { let mut map: &JoshutoCommandMapping = &m; let terminal = backend.terminal_mut(); + context.events.flush(); loop { terminal.draw(|mut frame| { @@ -73,20 +74,26 @@ impl TuiCommandMenu { TuiMenu::new(&display_str).render(&mut frame, menu_rect); } }); + if let Ok(event) = context.events.next() { match event { - Event::Input(Key::Esc) => { - return None; - } - Event::Input(key) => match map.get(&key) { - Some(CommandKeybind::SimpleKeybind(s)) => { - return Some(s); + Event::Input(key) => { + match key { + Key::Esc => return None, + key => { + match map.get(&key) { + Some(CommandKeybind::SimpleKeybind(s)) => { + return Some(s); + } + Some(CommandKeybind::CompositeKeybind(m)) => { + map = m; + } + None => return None, + } + } } - Some(CommandKeybind::CompositeKeybind(m)) => { - map = m; - } - None => return None, - }, + context.events.flush(); + } _ => {} } } diff --git a/src/ui/widgets/tui_prompt.rs b/src/ui/widgets/tui_prompt.rs index dd947a9..1f4826f 100644 --- a/src/ui/widgets/tui_prompt.rs +++ b/src/ui/widgets/tui_prompt.rs @@ -21,6 +21,8 @@ impl<'a> TuiPrompt<'a> { pub fn get_key(&mut self, backend: &mut TuiBackend, context: &JoshutoContext) -> Key { let terminal = backend.terminal_mut(); + + context.events.flush(); loop { terminal.draw(|mut frame| { let f_size = frame.size(); @@ -52,7 +54,9 @@ impl<'a> TuiPrompt<'a> { if let Ok(event) = context.events.next() { match event { - Event::Input(key) => return key, + Event::Input(key) => { + return key; + } _ => {} }; } diff --git a/src/ui/widgets/tui_textfield.rs b/src/ui/widgets/tui_textfield.rs index 602fa5d..c663b95 100644 --- a/src/ui/widgets/tui_textfield.rs +++ b/src/ui/widgets/tui_textfield.rs @@ -64,6 +64,8 @@ impl<'a> TuiTextField<'a> { backend: &mut TuiBackend, context: &JoshutoContext, ) -> Option { + context.events.flush(); + let mut line_buffer = line_buffer::LineBuffer::with_capacity(255); let completer = FilenameCompleter::new(); @@ -140,74 +142,80 @@ impl<'a> TuiTextField<'a> { if let Ok(event) = context.events.next() { match event { - Event::Input(Key::Backspace) => { - if line_buffer.backspace(1) { - completion_tracker.take(); - } - } - Event::Input(Key::Left) => { - if line_buffer.move_backward(1) { - completion_tracker.take(); - } - } - Event::Input(Key::Right) => { - if line_buffer.move_forward(1) { - completion_tracker.take(); - } - } - Event::Input(Key::Delete) => { - if line_buffer.delete(1).is_some() { - completion_tracker.take(); - } - } - Event::Input(Key::Home) => { - line_buffer.move_home(); - completion_tracker.take(); - } - Event::Input(Key::End) => { - line_buffer.move_end(); - completion_tracker.take(); - } - Event::Input(Key::Up) => {} - Event::Input(Key::Down) => {} - Event::Input(Key::Esc) => { - terminal.hide_cursor(); - return None; - } - Event::Input(Key::Char('\t')) => { - if completion_tracker.is_none() { - let res = - completer.complete_path(line_buffer.as_str(), line_buffer.pos()); - if let Ok((pos, mut candidates)) = res { - candidates.sort_by(|x, y| { - x.display() - .partial_cmp(y.display()) - .unwrap_or(std::cmp::Ordering::Less) - }); - let ct = CompletionTracker::new( - pos, - candidates, - String::from(line_buffer.as_str()), - ); - completion_tracker = Some(ct); + Event::Input(key) => { + match key { + Key::Backspace => { + if line_buffer.backspace(1) { + completion_tracker.take(); + } } - } - - if let Some(ref mut s) = completion_tracker { - if s.index < s.candidates.len() { - let candidate = &s.candidates[s.index]; - completer.update(&mut line_buffer, s.pos, candidate.replacement()); - s.index += 1; + Key::Left => { + if line_buffer.move_backward(1) { + completion_tracker.take(); + } } + Key::Right => { + if line_buffer.move_forward(1) { + completion_tracker.take(); + } + } + Key::Delete => { + if line_buffer.delete(1).is_some() { + completion_tracker.take(); + } + } + Key::Home => { + line_buffer.move_home(); + completion_tracker.take(); + } + Key::End => { + line_buffer.move_end(); + completion_tracker.take(); + } + Key::Up => {} + Key::Down => {} + Key::Esc => { + terminal.hide_cursor(); + return None; + } + Key::Char('\t') => { + if completion_tracker.is_none() { + let res = + completer.complete_path(line_buffer.as_str(), line_buffer.pos()); + if let Ok((pos, mut candidates)) = res { + candidates.sort_by(|x, y| { + x.display() + .partial_cmp(y.display()) + .unwrap_or(std::cmp::Ordering::Less) + }); + let ct = CompletionTracker::new( + pos, + candidates, + String::from(line_buffer.as_str()), + ); + completion_tracker = Some(ct); + } + } + + if let Some(ref mut s) = completion_tracker { + if s.index < s.candidates.len() { + let candidate = &s.candidates[s.index]; + completer.update(&mut line_buffer, s.pos, candidate.display()); + s.index += 1; + } + } + } + Key::Char('\n') => { + break; + } + Key::Char(c) => { + if line_buffer.insert(c, 1).is_some() { + completion_tracker.take(); + } + } + _ => {} } - } - Event::Input(Key::Char('\n')) => { - break; - } - Event::Input(Key::Char(c)) => { - if line_buffer.insert(c, 1).is_some() { - completion_tracker.take(); - } + context.events.flush(); } _ => {} }; diff --git a/src/util/event.rs b/src/util/event.rs index 5a76702..9ec41f7 100644 --- a/src/util/event.rs +++ b/src/util/event.rs @@ -27,7 +27,7 @@ pub struct Events { prefix: &'static str, pub event_tx: mpsc::Sender, event_rx: mpsc::Receiver, - pub sync_tx: mpsc::SyncSender<()>, + pub input_tx: mpsc::SyncSender<()>, // fileio_handle: thread::JoinHandle<()>, } @@ -41,7 +41,7 @@ impl Events { } pub fn with_config(prefix: &'static str) -> Self { - let (sync_tx, sync_rx) = mpsc::sync_channel(1); + let (input_tx, input_rx) = mpsc::sync_channel(1); let (event_tx, event_rx) = mpsc::channel(); { @@ -49,16 +49,26 @@ impl Events { thread::spawn(move || { let stdin = io::stdin(); let mut keys = stdin.keys(); - while let Ok(_) = sync_rx.recv() { - if let Some(evt) = keys.next() { - match evt { - Ok(key) => { - if let Err(e) = event_tx.send(Event::Input(key)) { - eprintln!("[{}] Input thread send err: {:#?}", prefix, e); - return; - } + match keys.next() { + Some(key) => match key { + Ok(key) => { + if let Err(e) = event_tx.send(Event::Input(key)) { + eprintln!("[{}] Input thread send err: {:#?}", prefix, e); + return; + } + } + _ => return, + } + _ => return, + } + + while let Ok(_) = input_rx.recv() { + if let Some(key) = keys.next() { + if let Ok(key) = key { + if let Err(e) = event_tx.send(Event::Input(key)) { + eprintln!("[{}] Input thread send err: {:#?}", prefix, e); + return; } - _ => {} } } } @@ -68,19 +78,17 @@ impl Events { Events { event_tx, event_rx, - sync_tx, + input_tx, prefix, } } pub fn next(&self) -> Result { - self.sync_tx.try_send(()); let event = self.event_rx.recv()?; Ok(event) } - /* - pub fn flush(&self) { - self.sync_rx.try_recv(); - } - */ + + pub fn flush(&self) { + self.input_tx.send(()); + } } -- cgit v1.2.3