diff options
author | Sebastian Thiel <sthiel@thoughtworks.com> | 2019-06-06 10:55:42 +0530 |
---|---|---|
committer | Sebastian Thiel <sthiel@thoughtworks.com> | 2019-06-06 10:55:42 +0530 |
commit | 2f3f214e03de477ad05aa12a1ac2ba0775a36c14 (patch) | |
tree | f6949498836097d5e296245e99de6f002c2c3e9e /src/interactive | |
parent | 53add13094a39751158f8cae27988bcbee47d08d (diff) |
preparing for displaying the marked state in entries list
Diffstat (limited to 'src/interactive')
-rw-r--r-- | src/interactive/app/eventloop.rs | 7 | ||||
-rw-r--r-- | src/interactive/app/handlers.rs | 17 | ||||
-rw-r--r-- | src/interactive/app_test.rs | 84 | ||||
-rw-r--r-- | src/interactive/widgets/entries.rs | 5 | ||||
-rw-r--r-- | src/interactive/widgets/header.rs | 8 | ||||
-rw-r--r-- | src/interactive/widgets/main.rs | 3 |
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 { |