summaryrefslogtreecommitdiffstats
path: root/src/interactive
diff options
context:
space:
mode:
authorSebastian Thiel <sthiel@thoughtworks.com>2019-06-06 10:55:42 +0530
committerSebastian Thiel <sthiel@thoughtworks.com>2019-06-06 10:55:42 +0530
commit2f3f214e03de477ad05aa12a1ac2ba0775a36c14 (patch)
treef6949498836097d5e296245e99de6f002c2c3e9e /src/interactive
parent53add13094a39751158f8cae27988bcbee47d08d (diff)
preparing for displaying the marked state in entries list
Diffstat (limited to 'src/interactive')
-rw-r--r--src/interactive/app/eventloop.rs7
-rw-r--r--src/interactive/app/handlers.rs17
-rw-r--r--src/interactive/app_test.rs84
-rw-r--r--src/interactive/widgets/entries.rs5
-rw-r--r--src/interactive/widgets/header.rs8
-rw-r--r--src/interactive/widgets/main.rs3
6 files changed, 113 insertions, 11 deletions
diff --git a/src/interactive/app/eventloop.rs b/src/interactive/app/eventloop.rs
index 5d02a1f..c89113e 100644
--- a/src/interactive/app/eventloop.rs
+++ b/src/interactive/app/eventloop.rs
@@ -25,6 +25,10 @@ impl Default for FocussedPane {
}
}
+pub struct EntryMark {
+ pub index: TreeIndex,
+}
+
#[derive(Default)]
pub struct AppState {
pub root: TreeIndex,
@@ -33,6 +37,7 @@ pub struct AppState {
pub sorting: SortMode,
pub message: Option<String>,
pub focussed: FocussedPane,
+ pub marked: Vec<EntryMark>,
}
/// State and methods representing the interactive disk usage analyser for the terminal
@@ -109,6 +114,8 @@ impl TerminalApp {
},
FocussedPane::Main => match key {
Char('O') => self.open_that(),
+ Char(' ') => self.mark_entry(false),
+ Char('d') => self.mark_entry(true),
Char('u') | Backspace => self.exit_node(),
Char('o') | Char('\n') => self.enter_node(),
Ctrl('u') => self.change_entry_selection(CursorDirection::PageUp),
diff --git a/src/interactive/app/handlers.rs b/src/interactive/app/handlers.rs
index 2971e4a..af5a3b2 100644
--- a/src/interactive/app/handlers.rs
+++ b/src/interactive/app/handlers.rs
@@ -1,5 +1,5 @@
use crate::interactive::{
- app::{FocussedPane, TerminalApp},
+ app::{EntryMark, FocussedPane, TerminalApp},
sorted_entries,
widgets::HelpPane,
};
@@ -120,4 +120,19 @@ impl TerminalApp {
self.state.entries =
sorted_entries(&self.traversal.tree, self.state.root, self.state.sorting);
}
+
+ pub fn mark_entry(&mut self, advance_cursor: bool) {
+ if let Some(index) = self.state.selected {
+ if let Some((existing, _)) =
+ self.state.marked.iter().find_position(|e| e.index == index)
+ {
+ self.state.marked.remove(existing);
+ } else {
+ self.state.marked.push(EntryMark { index });
+ }
+ if advance_cursor {
+ self.change_entry_selection(CursorDirection::Down)
+ }
+ }
+ }
}
diff --git a/src/interactive/app_test.rs b/src/interactive/app_test.rs
index cce83c8..a321719 100644
--- a/src/interactive/app_test.rs
+++ b/src/interactive/app_test.rs
@@ -63,12 +63,7 @@ fn index_by_name_and_size(
.node_indices()
.map(|idx| (idx, node_by_index(app, idx)))
.filter_map(|(idx, e)| {
- if e.name == name
- && match size {
- Some(s) => s == e.size,
- None => true,
- }
- {
+ if e.name == name && size.map(|s| s == e.size).unwrap_or(true) {
Some(idx)
} else {
None
@@ -129,6 +124,11 @@ fn simple_user_journey() -> Result<(), Error> {
SortMode::SizeAscending,
"it sets the sort mode to ascending by size"
);
+ assert_eq!(
+ node_by_index(&app, app.state.entries[0].index),
+ node_by_name(&app, fixture_str(long_root)),
+ "it recomputes the cached entries"
+ );
// when hitting the S key again
app.process_events(&mut terminal, b"s".keys())?;
assert_eq!(
@@ -136,6 +136,11 @@ fn simple_user_journey() -> Result<(), Error> {
SortMode::SizeDescending,
"it sets the sort mode to descending by size"
);
+ assert_eq!(
+ node_by_index(&app, app.state.entries[0].index),
+ node_by_name(&app, fixture_str(short_root)),
+ "it recomputes the cached entries"
+ );
}
// Entry-Navigation
@@ -212,6 +217,73 @@ fn simple_user_journey() -> Result<(), Error> {
}
}
+ // Deletion
+ {
+ // when hitting the 'd' key (also move cursor back to start)
+ app.process_events(&mut terminal, b"k".keys())?;
+ let previously_selected_index = *app.state.selected.as_ref().unwrap();
+ app.process_events(&mut terminal, b"d".keys())?;
+ {
+ assert_eq!(1, app.state.marked.len(), "it marks only a single node",);
+ assert_eq!(
+ node_by_index(&app, previously_selected_index),
+ node_by_index(&app, app.state.marked[0].index),
+ "it marks the selected node"
+ );
+ assert_eq!(
+ app.state.selected.as_ref().unwrap().index(),
+ app.state.entries[1].index.index(),
+ "moves the cursor down one level to facilitate many markings in a row"
+ );
+ }
+
+ // when hitting the 'd' key again
+ {
+ app.process_events(&mut terminal, b"d".keys())?;
+
+ assert_eq!(
+ 2,
+ app.state.marked.len(),
+ "it marks the currently selected, second node",
+ );
+
+ assert_eq!(
+ app.state.selected.as_ref().unwrap().index(),
+ app.state.entries[1].index.index(),
+ "it could not advance the cursor, thus the newly marked item is still selected"
+ );
+ }
+
+ // when hitting the 'd' key once again
+ {
+ app.process_events(&mut terminal, b"d".keys())?;
+
+ assert_eq!(
+ 1,
+ app.state.marked.len(),
+ "it toggled the previous selected entry off",
+ );
+
+ assert_eq!(
+ node_by_index(&app, previously_selected_index),
+ node_by_index(&app, app.state.marked[0].index),
+ "it leaves the first selected entry marked"
+ );
+ }
+ // when hitting the spacebar (after moving up to the first entry)
+ {
+ app.process_events(&mut terminal, b"k ".keys())?;
+
+ assert_eq!(0, app.state.marked.len(), "it toggles the item off",);
+
+ assert_eq!(
+ node_by_index(&app, previously_selected_index),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it does not advance the selection"
+ );
+ }
+ }
+
Ok(())
}
diff --git a/src/interactive/widgets/entries.rs b/src/interactive/widgets/entries.rs
index 8a740e3..f364110 100644
--- a/src/interactive/widgets/entries.rs
+++ b/src/interactive/widgets/entries.rs
@@ -1,4 +1,4 @@
-use crate::interactive::{DisplayOptions, EntryDataBundle};
+use crate::interactive::{DisplayOptions, EntryDataBundle, EntryMark};
use dua::traverse::{Tree, TreeIndex};
use itertools::Itertools;
use std::{borrow::Borrow, path::Path};
@@ -16,6 +16,7 @@ pub struct EntriesProps<'a> {
pub display: DisplayOptions,
pub selected: Option<TreeIndex>,
pub entries: &'a [EntryDataBundle],
+ pub marked: &'a [EntryMark],
pub border_style: Style,
pub is_focussed: bool,
}
@@ -38,6 +39,7 @@ impl Entries {
display,
entries,
selected,
+ marked: _,
border_style,
is_focussed,
} = props.borrow();
@@ -128,6 +130,7 @@ impl Entries {
.into(),
style,
);
+
let name = Text::Styled(
fill_background_to_right(
format!(
diff --git a/src/interactive/widgets/header.rs b/src/interactive/widgets/header.rs
index 7026b4b..bc241a0 100644
--- a/src/interactive/widgets/header.rs
+++ b/src/interactive/widgets/header.rs
@@ -6,8 +6,12 @@ use tui::widgets::{Paragraph, Text, Widget};
pub struct Header;
impl Header {
- pub fn render(&self, area: Rect, buf: &mut Buffer) {
- let bg_color = Color::LightYellow;
+ pub fn render(&self, has_marked_entries: bool, area: Rect, buf: &mut Buffer) {
+ let bg_color = if has_marked_entries {
+ Color::LightYellow
+ } else {
+ Color::White
+ };
let text_color = Color::Black;
let standard = Style {
fg: text_color,
diff --git a/src/interactive/widgets/main.rs b/src/interactive/widgets/main.rs
index 3325d91..c357383 100644
--- a/src/interactive/widgets/main.rs
+++ b/src/interactive/widgets/main.rs
@@ -78,12 +78,13 @@ impl MainWindow {
FocussedPane::Help => (grey, white),
};
- Header.render(header_area, buf);
+ Header.render(!state.marked.is_empty(), header_area, buf);
let props = EntriesProps {
tree: &tree,
root: state.root,
display: *display,
entries: &state.entries,
+ marked: &state.marked,
selected: state.selected,
border_style: entries_style,
is_focussed: if let FocussedPane::Main = state.focussed {