summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 23:15:50 +0800
committerSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 23:15:50 +0800
commit80979a179f924af87a33fc81ccca055ce6df5636 (patch)
tree05cfb353642fad61170e8584d0d9bdfe676dd0f8
parente811effe6424cd691260b07d1187d7c2d34ad4f1 (diff)
Don't try to shutdown keyinput thread to not lose input events
-rw-r--r--Cargo.lock16
-rw-r--r--Cargo.toml1
-rw-r--r--src/interactive/app/eventloop.rs173
-rw-r--r--src/interactive/app_test/utils.rs3
-rw-r--r--src/main.rs4
5 files changed, 98 insertions, 99 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 859b786..6c5f99d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -189,6 +189,7 @@ dependencies = [
"failure",
"failure-tools",
"filesize",
+ "flume",
"itertools 0.9.0",
"jwalk",
"log",
@@ -256,6 +257,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
+name = "flume"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "855e285c3835897065a6ba6f9463b44553eb9f29c7988d692f3d41283b47388b"
+dependencies = [
+ "spin",
+]
+
+[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -498,6 +508,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
+[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index e786b0a..a21faa0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,6 +26,7 @@ tui-react = { path = "./tui-react", version = "0.2" }
num_cpus = "1.10.0"
unicode-segmentation = "1.3.0"
filesize = "0.2.0"
+flume = {version = "0.7.1", default-features = false}
[[bin]]
name="dua"
diff --git a/src/interactive/app/eventloop.rs b/src/interactive/app/eventloop.rs
index 94b6123..9e93102 100644
--- a/src/interactive/app/eventloop.rs
+++ b/src/interactive/app/eventloop.rs
@@ -62,13 +62,13 @@ impl AppState {
draw_window(window, props, terminal)
}
- pub fn process_event<B>(
+ pub fn process_events<B>(
&mut self,
window: &mut MainWindow,
traversal: &mut Traversal,
display: &mut DisplayOptions,
terminal: &mut Terminal<B>,
- key: Key,
+ keys: impl Iterator<Item = Result<Key, io::Error>>,
) -> Result<ProcessingResult, Error>
where
B: Backend,
@@ -76,82 +76,61 @@ impl AppState {
use termion::event::Key::*;
use FocussedPane::*;
- self.reset_message();
- match key {
- Char('?') => self.toggle_help_pane(window),
- Char('\t') => {
- self.cycle_focus(window);
- }
- Ctrl('c') => {
- return Ok(ProcessingResult::ExitRequested(WalkResult {
- num_errors: traversal.io_errors,
- }))
- }
- Char('q') | Esc => match self.focussed {
- Main => {
+ self.draw(window, traversal, display.clone(), terminal)?;
+ for key in keys.filter_map(Result::ok) {
+ self.reset_message();
+ match key {
+ Char('?') => self.toggle_help_pane(window),
+ Char('\t') => {
+ self.cycle_focus(window);
+ }
+ Ctrl('c') => {
return Ok(ProcessingResult::ExitRequested(WalkResult {
num_errors: traversal.io_errors,
}))
}
- Mark => self.focussed = Main,
- Help => {
- self.focussed = Main;
- window.help_pane = None
- }
- },
- _ => {}
- }
-
- match self.focussed {
- FocussedPane::Mark => {
- self.dispatch_to_mark_pane(key, window, traversal, display.clone(), terminal)
- }
- FocussedPane::Help => {
- window.help_pane.as_mut().expect("help pane").key(key);
+ Char('q') | Esc => match self.focussed {
+ Main => {
+ return Ok(ProcessingResult::ExitRequested(WalkResult {
+ num_errors: traversal.io_errors,
+ }))
+ }
+ Mark => self.focussed = Main,
+ Help => {
+ self.focussed = Main;
+ window.help_pane = None
+ }
+ },
+ _ => {}
}
- FocussedPane::Main => match key {
- Char('O') => self.open_that(traversal),
- Char(' ') => self.mark_entry(false, window, traversal),
- Char('d') => self.mark_entry(true, window, traversal),
- Char('u') | Char('h') | Backspace | Left => {
- self.exit_node_with_traversal(traversal)
+
+ match self.focussed {
+ FocussedPane::Mark => {
+ self.dispatch_to_mark_pane(key, window, traversal, display.clone(), terminal)
}
- Char('o') | Char('l') | Char('\n') | Right => {
- self.enter_node_with_traversal(traversal)
+ FocussedPane::Help => {
+ window.help_pane.as_mut().expect("help pane").key(key);
}
- Ctrl('u') | PageUp => self.change_entry_selection(CursorDirection::PageUp),
- Char('k') | Up => self.change_entry_selection(CursorDirection::Up),
- Char('j') | Down => self.change_entry_selection(CursorDirection::Down),
- Ctrl('d') | PageDown => self.change_entry_selection(CursorDirection::PageDown),
- Char('s') => self.cycle_sorting(traversal),
- Char('g') => display.byte_vis.cycle(),
- _ => {}
- },
- };
- self.draw(window, traversal, display.clone(), terminal)?;
- Ok(ProcessingResult::Finished(WalkResult {
- num_errors: traversal.io_errors,
- }))
- }
- pub fn process_events<B>(
- &mut self,
- window: &mut MainWindow,
- traversal: &mut Traversal,
- display: &mut DisplayOptions,
- terminal: &mut Terminal<B>,
- keys: impl Iterator<Item = Result<Key, io::Error>>,
- ) -> Result<ProcessingResult, Error>
- where
- B: Backend,
- {
- self.reset_message();
- self.draw(window, traversal, display.clone(), terminal)?;
- for key in keys.filter_map(Result::ok) {
- if let r @ ProcessingResult::ExitRequested(_) =
- self.process_event(window, traversal, display, terminal, key)?
- {
- return Ok(r);
- }
+ FocussedPane::Main => match key {
+ Char('O') => self.open_that(traversal),
+ Char(' ') => self.mark_entry(false, window, traversal),
+ Char('d') => self.mark_entry(true, window, traversal),
+ Char('u') | Char('h') | Backspace | Left => {
+ self.exit_node_with_traversal(traversal)
+ }
+ Char('o') | Char('l') | Char('\n') | Right => {
+ self.enter_node_with_traversal(traversal)
+ }
+ Ctrl('u') | PageUp => self.change_entry_selection(CursorDirection::PageUp),
+ Char('k') | Up => self.change_entry_selection(CursorDirection::Up),
+ Char('j') | Down => self.change_entry_selection(CursorDirection::Down),
+ Ctrl('d') | PageDown => self.change_entry_selection(CursorDirection::PageDown),
+ Char('s') => self.cycle_sorting(traversal),
+ Char('g') => display.byte_vis.cycle(),
+ _ => {}
+ },
+ };
+ self.draw(window, traversal, display.clone(), terminal)?;
}
Ok(ProcessingResult::Finished(WalkResult {
num_errors: traversal.io_errors,
@@ -206,7 +185,7 @@ impl TerminalApp {
options: WalkOptions,
input: Vec<PathBuf>,
mode: Interaction,
- ) -> Result<Option<TerminalApp>, Error>
+ ) -> Result<Option<(flume::Receiver<io::Result<Key>>, TerminalApp)>, Error>
where
B: Backend,
{
@@ -215,7 +194,7 @@ impl TerminalApp {
let mut display: DisplayOptions = options.clone().into();
display.byte_vis = ByteVisualization::PercentageAndBar;
let mut window = MainWindow::default();
- let (keys_tx, keys_rx) = std::sync::mpsc::channel(); // unbounded
+ let (keys_tx, keys_rx) = flume::unbounded();
match mode {
Interaction::None => drop(keys_tx),
Interaction::Full => drop(std::thread::spawn(move || {
@@ -228,7 +207,7 @@ impl TerminalApp {
})),
}
- let fetch_buffered_key_events = move || {
+ let fetch_buffered_key_events = || {
let mut keys = Vec::new();
while let Ok(key) = keys_rx.try_recv() {
keys.push(key);
@@ -273,30 +252,32 @@ impl TerminalApp {
Some(t) => t,
None => return Ok(None),
};
- drop(fetch_buffered_key_events); // shutdown input event handler early for good measure
- Ok(Some(TerminalApp {
- state: {
- let mut s = state.unwrap_or_else(|| {
- let sorting = Default::default();
- let root = traversal.root_index;
- let entries = sorted_entries(&traversal.tree, root, sorting);
- AppState {
- root,
- sorting,
- entries,
- ..Default::default()
- }
- });
- s.is_scanning = false;
- s.entries = sorted_entries(&traversal.tree, s.root, s.sorting);
- s.selected = s.selected.or_else(|| s.entries.get(0).map(|b| b.index));
- s
+ Ok(Some((
+ keys_rx,
+ TerminalApp {
+ state: {
+ let mut s = state.unwrap_or_else(|| {
+ let sorting = Default::default();
+ let root = traversal.root_index;
+ let entries = sorted_entries(&traversal.tree, root, sorting);
+ AppState {
+ root,
+ sorting,
+ entries,
+ ..Default::default()
+ }
+ });
+ s.is_scanning = false;
+ s.entries = sorted_entries(&traversal.tree, s.root, s.sorting);
+ s.selected = s.selected.or_else(|| s.entries.get(0).map(|b| b.index));
+ s
+ },
+ display,
+ traversal,
+ window,
},
- display,
- traversal,
- window,
- }))
+ )))
}
}
diff --git a/src/interactive/app_test/utils.rs b/src/interactive/app_test/utils.rs
index e46f9e7..8fde29f 100644
--- a/src/interactive/app_test/utils.rs
+++ b/src/interactive/app_test/utils.rs
@@ -178,7 +178,8 @@ pub fn initialized_app_and_terminal_with_closure<P: AsRef<Path>>(
},
input,
Interaction::None,
- )?;
+ )?
+ .map(|(_, app)| app);
Ok((
terminal,
app.expect("app that didn't try to abort iteration"),
diff --git a/src/main.rs b/src/main.rs
index 9c42272..e9ea37e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,7 +10,7 @@ use failure::{Error, ResultExt};
use failure_tools::ok_or_exit;
use std::{fs, io, io::Write, path::PathBuf, process};
use structopt::StructOpt;
-use termion::{input::TermRead, raw::IntoRawMode, screen::AlternateScreen};
+use termion::{raw::IntoRawMode, screen::AlternateScreen};
use tui::backend::TermionBackend;
use tui_react::Terminal;
@@ -49,7 +49,7 @@ fn run() -> Result<(), Error> {
paths_from(input)?,
Interaction::Full,
)?
- .map(|mut app| app.process_events(&mut terminal, io::stdin().keys()));
+ .map(|(keys_rx, mut app)| app.process_events(&mut terminal, keys_rx.into_iter()));
drop(terminal);
io::stdout().flush().ok();