summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 17:02:40 +0800
committerSebastian Thiel <sebastian.thiel@icloud.com>2020-03-29 17:02:40 +0800
commit0e25706db7e25d53678b23548eddf5809a789ab4 (patch)
treef22fda059be3c0526fada7ba1d73b7c31936f973
parentb5564057fd999a87a7e0f9470964d05595f12556 (diff)
Now there could possibly be abortable and navigatable GUI while scanning…
…even though it will be wonky at first
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/interactive/app/eventloop.rs66
-rw-r--r--src/interactive/app_test/journeys_readonly.rs39
-rw-r--r--src/interactive/app_test/journeys_with_writes.rs8
-rw-r--r--src/main.rs4
6 files changed, 72 insertions, 47 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 11a3e00..91e4ee1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -186,6 +186,7 @@ version = "3.0.0"
dependencies = [
"atty",
"byte-unit",
+ "crossbeam-channel",
"failure",
"failure-tools",
"filesize",
diff --git a/Cargo.toml b/Cargo.toml
index e786b0a..4b6635a 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"
+crossbeam-channel = "0.4.2"
[[bin]]
name="dua"
diff --git a/src/interactive/app/eventloop.rs b/src/interactive/app/eventloop.rs
index 02519bb..4baaa7f 100644
--- a/src/interactive/app/eventloop.rs
+++ b/src/interactive/app/eventloop.rs
@@ -10,6 +10,8 @@ use dua::{
use failure::Error;
use std::{collections::BTreeMap, io, io::Write, path::PathBuf};
use termion::event::Key;
+use termion::input::TermRead;
+use termion::screen::ToMainScreen;
use tui::backend::Backend;
use tui_react::Terminal;
@@ -61,7 +63,7 @@ impl AppState {
window: &mut MainWindow,
traversal: &mut Traversal,
display: &mut DisplayOptions,
- mut terminal: Terminal<B>,
+ terminal: &mut Terminal<B>,
keys: impl Iterator<Item = Result<Key, io::Error>>,
) -> Result<WalkResult, Error>
where
@@ -70,24 +72,25 @@ impl AppState {
use termion::event::Key::*;
use FocussedPane::*;
- fn exit_now<B: Backend>(terminal: Terminal<B>) -> ! {
- drop(terminal);
+ fn exit_now() -> ! {
+ write!(io::stdout(), "{}", ToMainScreen).ok();
io::stdout().flush().ok();
// Exit 'quickly' to avoid having to wait for all memory to be freed by us.
// Let the OS do it - we have nothing to lose, literally.
std::process::exit(0);
}
- self.draw(window, traversal, display.clone(), &mut terminal)?;
+ 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') => exit_now(terminal),
+ Ctrl('c') => exit_now(),
Char('q') | Esc => match self.focussed {
- Main => exit_now(terminal),
+ Main => exit_now(),
Mark => self.focussed = Main,
Help => {
self.focussed = Main;
@@ -98,13 +101,9 @@ impl AppState {
}
match self.focussed {
- FocussedPane::Mark => self.dispatch_to_mark_pane(
- key,
- window,
- traversal,
- display.clone(),
- &mut terminal,
- ),
+ 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);
}
@@ -127,7 +126,7 @@ impl AppState {
_ => {}
},
};
- self.draw(window, traversal, display.clone(), &mut terminal)?;
+ self.draw(window, traversal, display.clone(), terminal)?;
}
Ok(WalkResult {
num_errors: traversal.io_errors,
@@ -160,7 +159,7 @@ pub struct TerminalApp {
impl TerminalApp {
pub fn process_events<B>(
&mut self,
- terminal: Terminal<B>,
+ terminal: &mut Terminal<B>,
keys: impl Iterator<Item = Result<Key, io::Error>>,
) -> Result<WalkResult, Error>
where
@@ -189,21 +188,43 @@ impl TerminalApp {
let mut display_options: DisplayOptions = options.clone().into();
display_options.byte_vis = ByteVisualization::Bar;
let mut window = MainWindow::default();
+ let (keys_tx, keys_rx) = crossbeam_channel::unbounded();
+ match mode {
+ Interaction::None => drop(keys_tx),
+ Interaction::Full => drop(std::thread::spawn(move || {
+ let keys = std::io::stdin().keys();
+ for key in keys {
+ if let Err(_) = keys_tx.try_send(key) {
+ break;
+ }
+ }
+ })),
+ }
+
+ let fetch_buffered_key_events = || {
+ let mut keys = Vec::new();
+ while let Ok(key) = keys_rx.try_recv() {
+ keys.push(key);
+ }
+ keys
+ };
let traversal = Traversal::from_walk(options, input, move |traversal| {
- let state = AppState {
+ let mut state = AppState {
root: traversal.root_index,
sorting: Default::default(),
message: Some("-> scanning <-".into()),
entries: sorted_entries(&traversal.tree, traversal.root_index, Default::default()),
..Default::default()
};
- let props = MainWindowProps {
+ state.process_events(
+ &mut window,
traversal,
- display: display_options,
- state: &state,
- };
- draw_window(&mut window, props, terminal)
+ &mut display_options,
+ terminal,
+ fetch_buffered_key_events().into_iter(),
+ )?;
+ Ok(())
})?;
let sorting = Default::default();
@@ -227,6 +248,7 @@ impl TerminalApp {
}
pub enum Interaction {
- Limited,
+ Full,
+ #[allow(dead_code)]
None,
}
diff --git a/src/interactive/app_test/journeys_readonly.rs b/src/interactive/app_test/journeys_readonly.rs
index 8f5eb1a..7acc85a 100644
--- a/src/interactive/app_test/journeys_readonly.rs
+++ b/src/interactive/app_test/journeys_readonly.rs
@@ -1,7 +1,7 @@
use crate::{
interactive::app_test::utils::{
- fixture_str, index_by_name, initialized_app_and_terminal_from_fixture, new_test_terminal,
- node_by_index, node_by_name,
+ fixture_str, index_by_name, initialized_app_and_terminal_from_fixture, node_by_index,
+ node_by_name,
},
interactive::app_test::FIXTURE_PATH,
interactive::SortMode,
@@ -15,7 +15,8 @@ use termion::input::TermRead;
fn simple_user_journey_read_only() -> Result<(), Error> {
let long_root = "sample-02/dir";
let short_root = "sample-01";
- let (terminal, mut app) = initialized_app_and_terminal_from_fixture(&[short_root, long_root])?;
+ let (mut terminal, mut app) =
+ initialized_app_and_terminal_from_fixture(&[short_root, long_root])?;
// POST-INIT
// after initialization, we expect that...
@@ -48,7 +49,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// SORTING
{
// when hitting the S key
- app.process_events(terminal, b"s".keys())?;
+ app.process_events(&mut terminal, b"s".keys())?;
assert_eq!(
app.state.sorting,
SortMode::SizeAscending,
@@ -60,7 +61,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
"it recomputes the cached entries"
);
// when hitting the S key again
- app.process_events(new_test_terminal()?, b"s".keys())?;
+ app.process_events(&mut terminal, b"s".keys())?;
assert_eq!(
app.state.sorting,
SortMode::SizeDescending,
@@ -76,35 +77,35 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// Entry-Navigation
{
// when hitting the j key
- app.process_events(new_test_terminal()?, b"j".keys())?;
+ app.process_events(&mut terminal, b"j".keys())?;
assert_eq!(
node_by_name(&app, fixture_str(long_root)),
node_by_index(&app, *app.state.selected.as_ref().unwrap()),
"it moves the cursor down and selects the next entry based on the current sort mode"
);
// when hitting it while there is nowhere to go
- app.process_events(new_test_terminal()?, b"j".keys())?;
+ app.process_events(&mut terminal, b"j".keys())?;
assert_eq!(
node_by_name(&app, fixture_str(long_root)),
node_by_index(&app, *app.state.selected.as_ref().unwrap()),
"it stays at the previous position"
);
// when hitting the k key
- app.process_events(new_test_terminal()?, b"k".keys())?;
+ app.process_events(&mut terminal, b"k".keys())?;
assert_eq!(
node_by_name(&app, fixture_str(short_root)),
node_by_index(&app, *app.state.selected.as_ref().unwrap()),
"it moves the cursor up and selects the next entry based on the current sort mode"
);
// when hitting the k key again
- app.process_events(new_test_terminal()?, b"k".keys())?;
+ app.process_events(&mut terminal, b"k".keys())?;
assert_eq!(
node_by_name(&app, fixture_str(short_root)),
node_by_index(&app, *app.state.selected.as_ref().unwrap()),
"it stays at the current cursor position as there is nowhere to go"
);
// when hitting the o key with a directory selected
- app.process_events(new_test_terminal()?, b"o".keys())?;
+ app.process_events(&mut terminal, b"o".keys())?;
{
let new_root_idx = index_by_name(&app, fixture_str(short_root));
assert_eq!(
@@ -118,7 +119,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
);
// when hitting the u key while inside a sub-directory
- app.process_events(new_test_terminal()?, b"u".keys())?;
+ app.process_events(&mut terminal, b"u".keys())?;
{
assert_eq!(
app.traversal.root_index, app.state.root,
@@ -133,7 +134,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
}
// when hitting the u key while inside of the root directory
// We are moving the cursor down just to have a non-default selection
- app.process_events(new_test_terminal()?, b"ju".keys())?;
+ app.process_events(&mut terminal, b"ju".keys())?;
{
assert_eq!(
app.traversal.root_index, app.state.root,
@@ -150,9 +151,9 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// Deletion
{
// when hitting the 'd' key (also move cursor back to start)
- app.process_events(new_test_terminal()?, b"k".keys())?;
+ app.process_events(&mut terminal, b"k".keys())?;
let previously_selected_index = *app.state.selected.as_ref().unwrap();
- app.process_events(new_test_terminal()?, b"d".keys())?;
+ app.process_events(&mut terminal, b"d".keys())?;
{
assert_eq!(
Some(1),
@@ -174,7 +175,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// when hitting the 'd' key again
{
- app.process_events(new_test_terminal()?, b"d".keys())?;
+ app.process_events(&mut terminal, b"d".keys())?;
assert_eq!(
Some(2),
@@ -191,7 +192,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// when hitting the 'd' key once again
{
- app.process_events(new_test_terminal()?, b"d".keys())?;
+ app.process_events(&mut terminal, b"d".keys())?;
assert_eq!(
Some(1),
@@ -208,7 +209,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
}
// when hitting the spacebar (after moving up to the first entry)
{
- app.process_events(new_test_terminal()?, b"k ".keys())?;
+ app.process_events(&mut terminal, b"k ".keys())?;
assert_eq!(
None,
@@ -227,7 +228,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
// Marking
{
// select something
- app.process_events(new_test_terminal()?, b" j ".keys())?;
+ app.process_events(&mut terminal, b" j ".keys())?;
assert_eq!(
Some(false),
app.window.mark_pane.as_ref().map(|p| p.has_focus()),
@@ -241,7 +242,7 @@ fn simple_user_journey_read_only() -> Result<(), Error> {
);
// when advancing the selection to the marker pane
- app.process_events(new_test_terminal()?, b"\t".keys())?;
+ app.process_events(&mut terminal, b"\t".keys())?;
{
assert_eq!(
Some(true),
diff --git a/src/interactive/app_test/journeys_with_writes.rs b/src/interactive/app_test/journeys_with_writes.rs
index 465be54..cbd51cd 100644
--- a/src/interactive/app_test/journeys_with_writes.rs
+++ b/src/interactive/app_test/journeys_with_writes.rs
@@ -1,5 +1,5 @@
use crate::interactive::app_test::utils::{
- initialized_app_and_terminal_from_paths, new_test_terminal, WritableFixture,
+ initialized_app_and_terminal_from_paths, WritableFixture,
};
use failure::Error;
use pretty_assertions::assert_eq;
@@ -9,10 +9,10 @@ use termion::input::TermRead;
#[test]
fn basic_user_journey_with_deletion() -> Result<(), Error> {
let fixture = WritableFixture::from("sample-02");
- let (terminal, mut app) = initialized_app_and_terminal_from_paths(&[fixture.root.clone()])?;
+ let (mut terminal, mut app) = initialized_app_and_terminal_from_paths(&[fixture.root.clone()])?;
// With a selection of items
- app.process_events(terminal, b"doddd".keys())?;
+ app.process_events(&mut terminal, b"doddd".keys())?;
assert_eq!(
app.window.mark_pane.as_ref().map(|p| p.marked().len()),
@@ -28,7 +28,7 @@ fn basic_user_journey_with_deletion() -> Result<(), Error> {
// When selecting the marker window and pressing the combination to delete entries
app.process_events(
- new_test_terminal()?,
+ &mut terminal,
vec![Ok(Key::Char('\t')), Ok(Key::Ctrl('r'))].into_iter(),
)?;
assert_eq!(
diff --git a/src/main.rs b/src/main.rs
index f5c6197..9b0faad 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -47,9 +47,9 @@ fn run() -> Result<(), Error> {
&mut terminal,
walk_options,
paths_from(input)?,
- Interaction::Limited,
+ Interaction::Full,
)?;
- let res = app.process_events(terminal, io::stdin().keys())?;
+ let res = app.process_events(&mut terminal, io::stdin().keys())?;
io::stdout().flush().ok();
res
}